xref: /aosp_15_r20/external/deqp/modules/gles3/functional/es3fShaderSwitchTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES 3.0 Module
3  * -------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Shader switch statement tests.
22  *
23  * Variables:
24  *  + Selection expression type: static, uniform, dynamic
25  *  + Switch layout - fall-through or use of default label
26  *  + Switch nested in loop/conditional statement
27  *  + Loop/conditional statement nested in switch
28  *//*--------------------------------------------------------------------*/
29 
30 #include "es3fShaderSwitchTests.hpp"
31 #include "glsShaderRenderCase.hpp"
32 #include "glsShaderLibrary.hpp"
33 #include "tcuStringTemplate.hpp"
34 #include "deMath.h"
35 
36 namespace deqp
37 {
38 namespace gles3
39 {
40 namespace Functional
41 {
42 
43 using namespace deqp::gls;
44 using std::map;
45 using std::string;
46 using std::vector;
47 
48 class ShaderSwitchCase : public ShaderRenderCase
49 {
50 public:
51     ShaderSwitchCase(Context &context, const char *name, const char *description, bool isVertexCase,
52                      const char *vtxSource, const char *fragSource, ShaderEvalFunc evalFunc);
53     virtual ~ShaderSwitchCase(void);
54 };
55 
ShaderSwitchCase(Context & context,const char * name,const char * description,bool isVertexCase,const char * vtxSource,const char * fragSource,ShaderEvalFunc evalFunc)56 ShaderSwitchCase::ShaderSwitchCase(Context &context, const char *name, const char *description, bool isVertexCase,
57                                    const char *vtxSource, const char *fragSource, ShaderEvalFunc evalFunc)
58     : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name,
59                        description, isVertexCase, evalFunc)
60 {
61     m_vertShaderSource = vtxSource;
62     m_fragShaderSource = fragSource;
63 }
64 
~ShaderSwitchCase(void)65 ShaderSwitchCase::~ShaderSwitchCase(void)
66 {
67 }
68 
69 enum SwitchType
70 {
71     SWITCHTYPE_STATIC = 0,
72     SWITCHTYPE_UNIFORM,
73     SWITCHTYPE_DYNAMIC,
74 
75     SWITCHTYPE_LAST
76 };
77 
evalSwitchStatic(ShaderEvalContext & evalCtx)78 static void evalSwitchStatic(ShaderEvalContext &evalCtx)
79 {
80     evalCtx.color.xyz() = evalCtx.coords.swizzle(1, 2, 3);
81 }
evalSwitchUniform(ShaderEvalContext & evalCtx)82 static void evalSwitchUniform(ShaderEvalContext &evalCtx)
83 {
84     evalCtx.color.xyz() = evalCtx.coords.swizzle(1, 2, 3);
85 }
evalSwitchDynamic(ShaderEvalContext & evalCtx)86 static void evalSwitchDynamic(ShaderEvalContext &evalCtx)
87 {
88     switch (int(deFloatFloor(evalCtx.coords.z() * 1.5f + 2.0f)))
89     {
90     case 0:
91         evalCtx.color.xyz() = evalCtx.coords.swizzle(0, 1, 2);
92         break;
93     case 1:
94         evalCtx.color.xyz() = evalCtx.coords.swizzle(3, 2, 1);
95         break;
96     case 2:
97         evalCtx.color.xyz() = evalCtx.coords.swizzle(1, 2, 3);
98         break;
99     case 3:
100         evalCtx.color.xyz() = evalCtx.coords.swizzle(2, 1, 0);
101         break;
102     default:
103         evalCtx.color.xyz() = evalCtx.coords.swizzle(0, 0, 0);
104         break;
105     }
106 }
107 
makeSwitchCase(Context & context,const char * name,const char * desc,SwitchType type,bool isVertex,const LineStream & switchBody)108 static tcu::TestCase *makeSwitchCase(Context &context, const char *name, const char *desc, SwitchType type,
109                                      bool isVertex, const LineStream &switchBody)
110 {
111     std::ostringstream vtx;
112     std::ostringstream frag;
113     std::ostringstream &op = isVertex ? vtx : frag;
114 
115     vtx << "#version 300 es\n"
116         << "in highp vec4 a_position;\n"
117         << "in highp vec4 a_coords;\n";
118     frag << "#version 300 es\n"
119          << "layout(location = 0) out mediump vec4 o_color;\n";
120 
121     if (isVertex)
122     {
123         vtx << "out mediump vec4 v_color;\n";
124         frag << "in mediump vec4 v_color;\n";
125     }
126     else
127     {
128         vtx << "out highp vec4 v_coords;\n";
129         frag << "in highp vec4 v_coords;\n";
130     }
131 
132     if (type == SWITCHTYPE_UNIFORM)
133         op << "uniform highp int ui_two;\n";
134 
135     vtx << "\n"
136         << "void main (void)\n"
137         << "{\n"
138         << "    gl_Position = a_position;\n";
139     frag << "\n"
140          << "void main (void)\n"
141          << "{\n";
142 
143     // Setup.
144     op << "    highp vec4 coords = " << (isVertex ? "a_coords" : "v_coords") << ";\n";
145     op << "    mediump vec3 res = vec3(0.0);\n\n";
146 
147     // Switch body.
148     map<string, string> params;
149     params["CONDITION"] = type == SWITCHTYPE_STATIC  ? "2" :
150                           type == SWITCHTYPE_UNIFORM ? "ui_two" :
151                           type == SWITCHTYPE_DYNAMIC ? "int(floor(coords.z*1.5 + 2.0))" :
152                                                        "???";
153 
154     op << tcu::StringTemplate(switchBody.str()).specialize(params).c_str();
155     op << "\n";
156 
157     if (isVertex)
158     {
159         vtx << "    v_color = vec4(res, 1.0);\n";
160         frag << "    o_color = v_color;\n";
161     }
162     else
163     {
164         vtx << "    v_coords = a_coords;\n";
165         frag << "    o_color = vec4(res, 1.0);\n";
166     }
167 
168     vtx << "}\n";
169     frag << "}\n";
170 
171     return new ShaderSwitchCase(context, name, desc, isVertex, vtx.str().c_str(), frag.str().c_str(),
172                                 type == SWITCHTYPE_STATIC  ? evalSwitchStatic :
173                                 type == SWITCHTYPE_UNIFORM ? evalSwitchUniform :
174                                 type == SWITCHTYPE_DYNAMIC ? evalSwitchDynamic :
175                                                              (ShaderEvalFunc)DE_NULL);
176 }
177 
makeSwitchCases(TestCaseGroup * group,const char * name,const char * desc,const LineStream & switchBody,const bool skipDynamicType=false)178 static void makeSwitchCases(TestCaseGroup *group, const char *name, const char *desc, const LineStream &switchBody,
179                             const bool skipDynamicType = false)
180 {
181     static const char *switchTypeNames[] = {"static", "uniform", "dynamic"};
182     DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(switchTypeNames) == SWITCHTYPE_LAST);
183 
184     for (int type = 0; type < SWITCHTYPE_LAST; type++)
185     {
186         if (skipDynamicType && (type == SWITCHTYPE_DYNAMIC))
187             continue;
188 
189         group->addChild(makeSwitchCase(group->getContext(),
190                                        (string(name) + "_" + switchTypeNames[type] + "_vertex").c_str(), desc,
191                                        (SwitchType)type, true, switchBody));
192         group->addChild(makeSwitchCase(group->getContext(),
193                                        (string(name) + "_" + switchTypeNames[type] + "_fragment").c_str(), desc,
194                                        (SwitchType)type, false, switchBody));
195     }
196 }
197 
ShaderSwitchTests(Context & context)198 ShaderSwitchTests::ShaderSwitchTests(Context &context) : TestCaseGroup(context, "switch", "Switch statement tests")
199 {
200 }
201 
~ShaderSwitchTests(void)202 ShaderSwitchTests::~ShaderSwitchTests(void)
203 {
204 }
205 
init(void)206 void ShaderSwitchTests::init(void)
207 {
208     // Expected swizzles:
209     // 0: xyz
210     // 1: wzy
211     // 2: yzw
212     // 3: zyx
213 
214     makeSwitchCases(this, "basic", "Basic switch statement usage",
215                     LineStream(1) << "switch (${CONDITION})"
216                                   << "{"
217                                   << "    case 0: res = coords.xyz;    break;"
218                                   << "    case 1: res = coords.wzy;    break;"
219                                   << "    case 2: res = coords.yzw;    break;"
220                                   << "    case 3: res = coords.zyx;    break;"
221                                   << "}");
222 
223     makeSwitchCases(this, "const_expr_in_label", "Constant expression in label",
224                     LineStream(1) << "const int t = 2;"
225                                   << "switch (${CONDITION})"
226                                   << "{"
227                                   << "    case int(0.0): res = coords.xyz;    break;"
228                                   << "    case 2-1: res = coords.wzy;    break;"
229                                   << "    case 3&(1<<1): res = coords.yzw;    break;"
230                                   << "    case t+1: res = coords.zyx;    break;"
231                                   << "}");
232 
233     makeSwitchCases(this, "default_label", "Default label usage",
234                     LineStream(1) << "switch (${CONDITION})"
235                                   << "{"
236                                   << "    case 0: res = coords.xyz;    break;"
237                                   << "    case 1: res = coords.wzy;    break;"
238                                   << "    case 3: res = coords.zyx;    break;"
239                                   << "    default: res = coords.yzw;"
240                                   << "}");
241 
242     makeSwitchCases(this, "default_not_last", "Default label usage",
243                     LineStream(1) << "switch (${CONDITION})"
244                                   << "{"
245                                   << "    case 0: res = coords.xyz;    break;"
246                                   << "    default: res = coords.yzw;    break;"
247                                   << "    case 1: res = coords.wzy;    break;"
248                                   << "    case 3: res = coords.zyx;    break;"
249                                   << "}");
250 
251     makeSwitchCases(this, "no_default_label", "No match in switch without default label",
252                     LineStream(1) << "res = coords.yzw;\n"
253                                   << "switch (${CONDITION})"
254                                   << "{"
255                                   << "    case 0: res = coords.xyz;    break;"
256                                   << "    case 1: res = coords.wzy;    break;"
257                                   << "    case 3: res = coords.zyx;    break;"
258                                   << "}");
259 
260     makeSwitchCases(this, "default_only", "Default case only",
261                     LineStream(1) << "switch (${CONDITION})"
262                                   << "{"
263                                   << "    default:"
264                                   << "        res = coords.yzw;"
265                                   << "}",
266                     true);
267 
268     makeSwitchCases(this, "empty_case_default", "Empty case and default",
269                     LineStream(1) << "switch (${CONDITION})"
270                                   << "{"
271                                   << "    case 2:"
272                                   << "    default:"
273                                   << "        res = coords.yzw;"
274                                   << "}",
275                     true);
276 
277     makeSwitchCases(this, "fall_through", "Fall-through",
278                     LineStream(1) << "switch (${CONDITION})"
279                                   << "{"
280                                   << "    case 0: res = coords.xyz;    break;"
281                                   << "    case 1: res = coords.wzy;    break;"
282                                   << "    case 2: coords = coords.yzwx;"
283                                   << "    case 4: res = vec3(coords);    break;"
284                                   << "    case 3: res = coords.zyx;    break;"
285                                   << "}");
286 
287     makeSwitchCases(this, "fall_through_default", "Fall-through",
288                     LineStream(1) << "switch (${CONDITION})"
289                                   << "{"
290                                   << "    case 0: res = coords.xyz;    break;"
291                                   << "    case 1: res = coords.wzy;    break;"
292                                   << "    case 3: res = coords.zyx;    break;"
293                                   << "    case 2: coords = coords.yzwx;"
294                                   << "    default: res = vec3(coords);"
295                                   << "}");
296 
297     makeSwitchCases(this, "conditional_fall_through", "Fall-through",
298                     LineStream(1) << "highp vec4 tmp = coords;"
299                                   << "switch (${CONDITION})"
300                                   << "{"
301                                   << "    case 0: res = coords.xyz;    break;"
302                                   << "    case 1: res = coords.wzy;    break;"
303                                   << "    case 2:"
304                                   << "        tmp = coords.yzwx;"
305                                   << "    case 3:"
306                                   << "        res = vec3(tmp);"
307                                   << "        if (${CONDITION} != 3)"
308                                   << "            break;"
309                                   << "    default: res = tmp.zyx;        break;"
310                                   << "}");
311 
312     makeSwitchCases(this, "conditional_fall_through_2", "Fall-through",
313                     LineStream(1) << "highp vec4 tmp = coords;"
314                                   << "mediump int c = ${CONDITION};"
315                                   << "switch (c)"
316                                   << "{"
317                                   << "    case 0: res = coords.xyz;    break;"
318                                   << "    case 1: res = coords.wzy;    break;"
319                                   << "    case 2:"
320                                   << "        c += ${CONDITION};"
321                                   << "        tmp = coords.yzwx;"
322                                   << "    case 3:"
323                                   << "        res = vec3(tmp);"
324                                   << "        if (c == 4)"
325                                   << "            break;"
326                                   << "    default: res = tmp.zyx;        break;"
327                                   << "}");
328 
329     makeSwitchCases(this, "scope", "Basic switch statement usage",
330                     LineStream(1) << "switch (${CONDITION})"
331                                   << "{"
332                                   << "    case 0: res = coords.xyz;    break;"
333                                   << "    case 1: res = coords.wzy;    break;"
334                                   << "    case 2:"
335                                   << "    {"
336                                   << "        mediump vec3 t = coords.yzw;"
337                                   << "        res = t;"
338                                   << "        break;"
339                                   << "    }"
340                                   << "    case 3: res = coords.zyx;    break;"
341                                   << "}");
342 
343     makeSwitchCases(this, "switch_in_if", "Switch in for loop",
344                     LineStream(1) << "if (${CONDITION} >= 0)"
345                                   << "{"
346                                   << "    switch (${CONDITION})"
347                                   << "    {"
348                                   << "        case 0: res = coords.xyz;    break;"
349                                   << "        case 1: res = coords.wzy;    break;"
350                                   << "        case 2: res = coords.yzw;    break;"
351                                   << "        case 3: res = coords.zyx;    break;"
352                                   << "    }"
353                                   << "}");
354 
355     makeSwitchCases(this, "switch_in_for_loop", "Switch in for loop",
356                     LineStream(1) << "for (int i = 0; i <= ${CONDITION}; i++)"
357                                   << "{"
358                                   << "    switch (i)"
359                                   << "    {"
360                                   << "        case 0: res = coords.xyz;    break;"
361                                   << "        case 1: res = coords.wzy;    break;"
362                                   << "        case 2: res = coords.yzw;    break;"
363                                   << "        case 3: res = coords.zyx;    break;"
364                                   << "    }"
365                                   << "}");
366 
367     makeSwitchCases(this, "switch_in_while_loop", "Switch in while loop",
368                     LineStream(1) << "int i = 0;"
369                                   << "while (i <= ${CONDITION})"
370                                   << "{"
371                                   << "    switch (i)"
372                                   << "    {"
373                                   << "        case 0: res = coords.xyz;    break;"
374                                   << "        case 1: res = coords.wzy;    break;"
375                                   << "        case 2: res = coords.yzw;    break;"
376                                   << "        case 3: res = coords.zyx;    break;"
377                                   << "    }"
378                                   << "    i += 1;"
379                                   << "}");
380 
381     makeSwitchCases(this, "switch_in_do_while_loop", "Switch in do-while loop",
382                     LineStream(1) << "int i = 0;"
383                                   << "do"
384                                   << "{"
385                                   << "    switch (i)"
386                                   << "    {"
387                                   << "        case 0: res = coords.xyz;    break;"
388                                   << "        case 1: res = coords.wzy;    break;"
389                                   << "        case 2: res = coords.yzw;    break;"
390                                   << "        case 3: res = coords.zyx;    break;"
391                                   << "    }"
392                                   << "    i += 1;"
393                                   << "} while (i <= ${CONDITION});");
394 
395     makeSwitchCases(this, "if_in_switch", "Basic switch statement usage",
396                     LineStream(1) << "switch (${CONDITION})"
397                                   << "{"
398                                   << "    case 0: res = coords.xyz;    break;"
399                                   << "    case 1: res = coords.wzy;    break;"
400                                   << "    default:"
401                                   << "        if (${CONDITION} == 2)"
402                                   << "            res = coords.yzw;"
403                                   << "        else"
404                                   << "            res = coords.zyx;"
405                                   << "        break;"
406                                   << "}");
407 
408     makeSwitchCases(this, "for_loop_in_switch", "Basic switch statement usage",
409                     LineStream(1) << "switch (${CONDITION})"
410                                   << "{"
411                                   << "    case 0: res = coords.xyz;    break;"
412                                   << "    case 1:"
413                                   << "    case 2:"
414                                   << "    {"
415                                   << "        highp vec3 t = coords.yzw;"
416                                   << "        for (int i = 0; i < ${CONDITION}; i++)"
417                                   << "            t = t.zyx;"
418                                   << "        res = t;"
419                                   << "        break;"
420                                   << "    }"
421                                   << "    default: res = coords.zyx;    break;"
422                                   << "}");
423 
424     makeSwitchCases(this, "while_loop_in_switch", "Basic switch statement usage",
425                     LineStream(1) << "switch (${CONDITION})"
426                                   << "{"
427                                   << "    case 0: res = coords.xyz;    break;"
428                                   << "    case 1:"
429                                   << "    case 2:"
430                                   << "    {"
431                                   << "        highp vec3 t = coords.yzw;"
432                                   << "        int i = 0;"
433                                   << "        while (i < ${CONDITION})"
434                                   << "        {"
435                                   << "            t = t.zyx;"
436                                   << "            i += 1;"
437                                   << "        }"
438                                   << "        res = t;"
439                                   << "        break;"
440                                   << "    }"
441                                   << "    default: res = coords.zyx;    break;"
442                                   << "}");
443 
444     makeSwitchCases(this, "do_while_loop_in_switch", "Basic switch statement usage",
445                     LineStream(1) << "switch (${CONDITION})"
446                                   << "{"
447                                   << "    case 0: res = coords.xyz;    break;"
448                                   << "    case 1:"
449                                   << "    case 2:"
450                                   << "    {"
451                                   << "        highp vec3 t = coords.yzw;"
452                                   << "        int i = 0;"
453                                   << "        do"
454                                   << "        {"
455                                   << "            t = t.zyx;"
456                                   << "            i += 1;"
457                                   << "        } while (i < ${CONDITION});"
458                                   << "        res = t;"
459                                   << "        break;"
460                                   << "    }"
461                                   << "    default: res = coords.zyx;    break;"
462                                   << "}");
463 
464     makeSwitchCases(this, "switch_in_switch", "Basic switch statement usage",
465                     LineStream(1) << "switch (${CONDITION})"
466                                   << "{"
467                                   << "    case 0: res = coords.xyz;    break;"
468                                   << "    case 1:"
469                                   << "    case 2:"
470                                   << "        switch (${CONDITION} - 1)"
471                                   << "        {"
472                                   << "            case 0: res = coords.wzy;    break;"
473                                   << "            case 1: res = coords.yzw;    break;"
474                                   << "        }"
475                                   << "        break;"
476                                   << "    default: res = coords.zyx;    break;"
477                                   << "}");
478 
479     // Negative cases.
480     ShaderLibrary library(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
481     vector<tcu::TestNode *> negativeCases = library.loadShaderFile("shaders/switch.test");
482 
483     for (vector<tcu::TestNode *>::iterator i = negativeCases.begin(); i != negativeCases.end(); i++)
484         addChild(*i);
485 }
486 
487 } // namespace Functional
488 } // namespace gles3
489 } // namespace deqp
490