Merge "Fix extension support checks in negative api tests" into nougat-cts-dev am...
[platform/upstream/VK-GL-CTS.git] / modules / gles3 / functional / es3fShaderSwitchTests.cpp
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::string;
45 using std::map;
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, const char* vtxSource, const char* fragSource, ShaderEvalFunc evalFunc);
52         virtual                         ~ShaderSwitchCase                       (void);
53 };
54
55 ShaderSwitchCase::ShaderSwitchCase (Context& context, const char* name, const char* description, bool isVertexCase, const char* vtxSource, const char* fragSource, ShaderEvalFunc evalFunc)
56         : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, description, isVertexCase, evalFunc)
57 {
58         m_vertShaderSource      = vtxSource;
59         m_fragShaderSource      = fragSource;
60 }
61
62 ShaderSwitchCase::~ShaderSwitchCase (void)
63 {
64 }
65
66 enum SwitchType
67 {
68         SWITCHTYPE_STATIC = 0,
69         SWITCHTYPE_UNIFORM,
70         SWITCHTYPE_DYNAMIC,
71
72         SWITCHTYPE_LAST
73 };
74
75 static void evalSwitchStatic    (ShaderEvalContext& evalCtx)    { evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3);  }
76 static void evalSwitchUniform   (ShaderEvalContext& evalCtx)    { evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3);  }
77 static void evalSwitchDynamic   (ShaderEvalContext& evalCtx)
78 {
79         switch (int(deFloatFloor(evalCtx.coords.z()*1.5f + 2.0f)))
80         {
81                 case 0:         evalCtx.color.xyz() = evalCtx.coords.swizzle(0,1,2);    break;
82                 case 1:         evalCtx.color.xyz() = evalCtx.coords.swizzle(3,2,1);    break;
83                 case 2:         evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3);    break;
84                 case 3:         evalCtx.color.xyz() = evalCtx.coords.swizzle(2,1,0);    break;
85                 default:        evalCtx.color.xyz() = evalCtx.coords.swizzle(0,0,0);    break;
86         }
87 }
88
89 static tcu::TestCase* makeSwitchCase (Context& context, const char* name, const char* desc, SwitchType type, bool isVertex, const LineStream& switchBody)
90 {
91         std::ostringstream      vtx;
92         std::ostringstream      frag;
93         std::ostringstream&     op              = isVertex ? vtx : frag;
94
95         vtx << "#version 300 es\n"
96                 << "in highp vec4 a_position;\n"
97                 << "in highp vec4 a_coords;\n";
98         frag << "#version 300 es\n"
99                  << "layout(location = 0) out mediump vec4 o_color;\n";
100
101         if (isVertex)
102         {
103                 vtx << "out mediump vec4 v_color;\n";
104                 frag << "in mediump vec4 v_color;\n";
105         }
106         else
107         {
108                 vtx << "out highp vec4 v_coords;\n";
109                 frag << "in highp vec4 v_coords;\n";
110         }
111
112         if (type == SWITCHTYPE_UNIFORM)
113                 op << "uniform highp int ui_two;\n";
114
115         vtx << "\n"
116                 << "void main (void)\n"
117                 << "{\n"
118                 << "    gl_Position = a_position;\n";
119         frag << "\n"
120                  << "void main (void)\n"
121                  << "{\n";
122
123         // Setup.
124         op << " highp vec4 coords = " << (isVertex ? "a_coords" : "v_coords") << ";\n";
125         op << " mediump vec3 res = vec3(0.0);\n\n";
126
127         // Switch body.
128         map<string, string> params;
129         params["CONDITION"] = type == SWITCHTYPE_STATIC         ? "2"                                                           :
130                                                   type == SWITCHTYPE_UNIFORM    ? "ui_two"                                                      :
131                                                   type == SWITCHTYPE_DYNAMIC    ? "int(floor(coords.z*1.5 + 2.0))"      : "???";
132
133         op << tcu::StringTemplate(switchBody.str()).specialize(params).c_str();
134         op << "\n";
135
136         if (isVertex)
137         {
138                 vtx << "        v_color = vec4(res, 1.0);\n";
139                 frag << "       o_color = v_color;\n";
140         }
141         else
142         {
143                 vtx << "        v_coords = a_coords;\n";
144                 frag << "       o_color = vec4(res, 1.0);\n";
145         }
146
147         vtx << "}\n";
148         frag << "}\n";
149
150         return new ShaderSwitchCase(context, name, desc, isVertex, vtx.str().c_str(), frag.str().c_str(),
151                                                                 type == SWITCHTYPE_STATIC       ? evalSwitchStatic      :
152                                                                 type == SWITCHTYPE_UNIFORM      ? evalSwitchUniform     :
153                                                                 type == SWITCHTYPE_DYNAMIC      ? evalSwitchDynamic     : (ShaderEvalFunc)DE_NULL);
154 }
155
156 static void makeSwitchCases (TestCaseGroup* group, const char* name, const char* desc, const LineStream& switchBody)
157 {
158         static const char* switchTypeNames[] = { "static", "uniform", "dynamic" };
159         DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(switchTypeNames) == SWITCHTYPE_LAST);
160
161         for (int type = 0; type < SWITCHTYPE_LAST; type++)
162         {
163                 group->addChild(makeSwitchCase(group->getContext(), (string(name) + "_" + switchTypeNames[type] + "_vertex").c_str(),   desc, (SwitchType)type, true,   switchBody));
164                 group->addChild(makeSwitchCase(group->getContext(), (string(name) + "_" + switchTypeNames[type] + "_fragment").c_str(), desc, (SwitchType)type, false,  switchBody));
165         }
166 }
167
168 ShaderSwitchTests::ShaderSwitchTests (Context& context)
169         : TestCaseGroup(context, "switch", "Switch statement tests")
170 {
171 }
172
173 ShaderSwitchTests::~ShaderSwitchTests (void)
174 {
175 }
176
177 void ShaderSwitchTests::init (void)
178 {
179         // Expected swizzles:
180         // 0: xyz
181         // 1: wzy
182         // 2: yzw
183         // 3: zyx
184
185         makeSwitchCases(this, "basic", "Basic switch statement usage",
186                 LineStream(1)
187                 << "switch (${CONDITION})"
188                 << "{"
189                 << "    case 0:         res = coords.xyz;       break;"
190                 << "    case 1:         res = coords.wzy;       break;"
191                 << "    case 2:         res = coords.yzw;       break;"
192                 << "    case 3:         res = coords.zyx;       break;"
193                 << "}");
194
195         makeSwitchCases(this, "const_expr_in_label", "Constant expression in label",
196                 LineStream(1)
197                 << "const int t = 2;"
198                 << "switch (${CONDITION})"
199                 << "{"
200                 << "    case int(0.0):  res = coords.xyz;       break;"
201                 << "    case 2-1:               res = coords.wzy;       break;"
202                 << "    case 3&(1<<1):  res = coords.yzw;       break;"
203                 << "    case t+1:               res = coords.zyx;       break;"
204                 << "}");
205
206         makeSwitchCases(this, "default_label", "Default label usage",
207                 LineStream(1)
208                 << "switch (${CONDITION})"
209                 << "{"
210                 << "    case 0:         res = coords.xyz;       break;"
211                 << "    case 1:         res = coords.wzy;       break;"
212                 << "    case 3:         res = coords.zyx;       break;"
213                 << "    default:        res = coords.yzw;"
214                 << "}");
215
216         makeSwitchCases(this, "default_not_last", "Default label usage",
217                 LineStream(1)
218                 << "switch (${CONDITION})"
219                 << "{"
220                 << "    case 0:         res = coords.xyz;       break;"
221                 << "    default:        res = coords.yzw;       break;"
222                 << "    case 1:         res = coords.wzy;       break;"
223                 << "    case 3:         res = coords.zyx;       break;"
224                 << "}");
225
226         makeSwitchCases(this, "no_default_label", "No match in switch without default label",
227                 LineStream(1)
228                 << "res = coords.yzw;\n"
229                 << "switch (${CONDITION})"
230                 << "{"
231                 << "    case 0:         res = coords.xyz;       break;"
232                 << "    case 1:         res = coords.wzy;       break;"
233                 << "    case 3:         res = coords.zyx;       break;"
234                 << "}");
235
236         makeSwitchCases(this, "fall_through", "Fall-through",
237                 LineStream(1)
238                 << "switch (${CONDITION})"
239                 << "{"
240                 << "    case 0:         res = coords.xyz;       break;"
241                 << "    case 1:         res = coords.wzy;       break;"
242                 << "    case 2:         coords = coords.yzwx;"
243                 << "    case 4:         res = vec3(coords);     break;"
244                 << "    case 3:         res = coords.zyx;       break;"
245                 << "}");
246
247         makeSwitchCases(this, "fall_through_default", "Fall-through",
248                 LineStream(1)
249                 << "switch (${CONDITION})"
250                 << "{"
251                 << "    case 0:         res = coords.xyz;       break;"
252                 << "    case 1:         res = coords.wzy;       break;"
253                 << "    case 3:         res = coords.zyx;       break;"
254                 << "    case 2:         coords = coords.yzwx;"
255                 << "    default:        res = vec3(coords);"
256                 << "}");
257
258         makeSwitchCases(this, "conditional_fall_through", "Fall-through",
259                 LineStream(1)
260                 << "highp vec4 tmp = coords;"
261                 << "switch (${CONDITION})"
262                 << "{"
263                 << "    case 0:         res = coords.xyz;       break;"
264                 << "    case 1:         res = coords.wzy;       break;"
265                 << "    case 2:"
266                 << "            tmp = coords.yzwx;"
267                 << "    case 3:"
268                 << "            res = vec3(tmp);"
269                 << "            if (${CONDITION} != 3)"
270                 << "                    break;"
271                 << "    default:        res = tmp.zyx;          break;"
272                 << "}");
273
274         makeSwitchCases(this, "conditional_fall_through_2", "Fall-through",
275                 LineStream(1)
276                 << "highp vec4 tmp = coords;"
277                 << "mediump int c = ${CONDITION};"
278                 << "switch (c)"
279                 << "{"
280                 << "    case 0:         res = coords.xyz;       break;"
281                 << "    case 1:         res = coords.wzy;       break;"
282                 << "    case 2:"
283                 << "            c += ${CONDITION};"
284                 << "            tmp = coords.yzwx;"
285                 << "    case 3:"
286                 << "            res = vec3(tmp);"
287                 << "            if (c == 4)"
288                 << "                    break;"
289                 << "    default:        res = tmp.zyx;          break;"
290                 << "}");
291
292         makeSwitchCases(this, "scope", "Basic switch statement usage",
293                 LineStream(1)
294                 << "switch (${CONDITION})"
295                 << "{"
296                 << "    case 0:         res = coords.xyz;       break;"
297                 << "    case 1:         res = coords.wzy;       break;"
298                 << "    case 2:"
299                 << "    {"
300                 << "            mediump vec3 t = coords.yzw;"
301                 << "            res = t;"
302                 << "            break;"
303                 << "    }"
304                 << "    case 3:         res = coords.zyx;       break;"
305                 << "}");
306
307         makeSwitchCases(this, "switch_in_if", "Switch in for loop",
308                 LineStream(1)
309                 << "if (${CONDITION} >= 0)"
310                 << "{"
311                 << "    switch (${CONDITION})"
312                 << "    {"
313                 << "            case 0:         res = coords.xyz;       break;"
314                 << "            case 1:         res = coords.wzy;       break;"
315                 << "            case 2:         res = coords.yzw;       break;"
316                 << "            case 3:         res = coords.zyx;       break;"
317                 << "    }"
318                 << "}");
319
320         makeSwitchCases(this, "switch_in_for_loop", "Switch in for loop",
321                 LineStream(1)
322                 << "for (int i = 0; i <= ${CONDITION}; i++)"
323                 << "{"
324                 << "    switch (i)"
325                 << "    {"
326                 << "            case 0:         res = coords.xyz;       break;"
327                 << "            case 1:         res = coords.wzy;       break;"
328                 << "            case 2:         res = coords.yzw;       break;"
329                 << "            case 3:         res = coords.zyx;       break;"
330                 << "    }"
331                 << "}");
332
333         makeSwitchCases(this, "switch_in_while_loop", "Switch in while loop",
334                 LineStream(1)
335                 << "int i = 0;"
336                 << "while (i <= ${CONDITION})"
337                 << "{"
338                 << "    switch (i)"
339                 << "    {"
340                 << "            case 0:         res = coords.xyz;       break;"
341                 << "            case 1:         res = coords.wzy;       break;"
342                 << "            case 2:         res = coords.yzw;       break;"
343                 << "            case 3:         res = coords.zyx;       break;"
344                 << "    }"
345                 << "    i += 1;"
346                 << "}");
347
348         makeSwitchCases(this, "switch_in_do_while_loop", "Switch in do-while loop",
349                 LineStream(1)
350                 << "int i = 0;"
351                 << "do"
352                 << "{"
353                 << "    switch (i)"
354                 << "    {"
355                 << "            case 0:         res = coords.xyz;       break;"
356                 << "            case 1:         res = coords.wzy;       break;"
357                 << "            case 2:         res = coords.yzw;       break;"
358                 << "            case 3:         res = coords.zyx;       break;"
359                 << "    }"
360                 << "    i += 1;"
361                 << "} while (i <= ${CONDITION});");
362
363         makeSwitchCases(this, "if_in_switch", "Basic switch statement usage",
364                 LineStream(1)
365                 << "switch (${CONDITION})"
366                 << "{"
367                 << "    case 0:         res = coords.xyz;       break;"
368                 << "    case 1:         res = coords.wzy;       break;"
369                 << "    default:"
370                 << "            if (${CONDITION} == 2)"
371                 << "                    res = coords.yzw;"
372                 << "            else"
373                 << "                    res = coords.zyx;"
374                 << "            break;"
375                 << "}");
376
377         makeSwitchCases(this, "for_loop_in_switch", "Basic switch statement usage",
378                 LineStream(1)
379                 << "switch (${CONDITION})"
380                 << "{"
381                 << "    case 0:         res = coords.xyz;       break;"
382                 << "    case 1:"
383                 << "    case 2:"
384                 << "    {"
385                 << "            highp vec3 t = coords.yzw;"
386                 << "            for (int i = 0; i < ${CONDITION}; i++)"
387                 << "                    t = t.zyx;"
388                 << "            res = t;"
389                 << "            break;"
390                 << "    }"
391                 << "    default:        res = coords.zyx;       break;"
392                 << "}");
393
394         makeSwitchCases(this, "while_loop_in_switch", "Basic switch statement usage",
395                 LineStream(1)
396                 << "switch (${CONDITION})"
397                 << "{"
398                 << "    case 0:         res = coords.xyz;       break;"
399                 << "    case 1:"
400                 << "    case 2:"
401                 << "    {"
402                 << "            highp vec3 t = coords.yzw;"
403                 << "            int i = 0;"
404                 << "            while (i < ${CONDITION})"
405                 << "            {"
406                 << "                    t = t.zyx;"
407                 << "                    i += 1;"
408                 << "            }"
409                 << "            res = t;"
410                 << "            break;"
411                 << "    }"
412                 << "    default:        res = coords.zyx;       break;"
413                 << "}");
414
415         makeSwitchCases(this, "do_while_loop_in_switch", "Basic switch statement usage",
416                 LineStream(1)
417                 << "switch (${CONDITION})"
418                 << "{"
419                 << "    case 0:         res = coords.xyz;       break;"
420                 << "    case 1:"
421                 << "    case 2:"
422                 << "    {"
423                 << "            highp vec3 t = coords.yzw;"
424                 << "            int i = 0;"
425                 << "            do"
426                 << "            {"
427                 << "                    t = t.zyx;"
428                 << "                    i += 1;"
429                 << "            } while (i < ${CONDITION});"
430                 << "            res = t;"
431                 << "            break;"
432                 << "    }"
433                 << "    default:        res = coords.zyx;       break;"
434                 << "}");
435
436         makeSwitchCases(this, "switch_in_switch", "Basic switch statement usage",
437                 LineStream(1)
438                 << "switch (${CONDITION})"
439                 << "{"
440                 << "    case 0:         res = coords.xyz;       break;"
441                 << "    case 1:"
442                 << "    case 2:"
443                 << "            switch (${CONDITION} - 1)"
444                 << "            {"
445                 << "                    case 0:         res = coords.wzy;       break;"
446                 << "                    case 1:         res = coords.yzw;       break;"
447                 << "            }"
448                 << "            break;"
449                 << "    default:        res = coords.zyx;       break;"
450                 << "}");
451
452         // Negative cases.
453         ShaderLibrary library(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
454         vector<tcu::TestNode*> negativeCases = library.loadShaderFile("shaders/switch.test");
455
456         for (vector<tcu::TestNode*>::iterator i = negativeCases.begin(); i != negativeCases.end(); i++)
457                 addChild(*i);
458 }
459
460 } // Functional
461 } // gles3
462 } // deqp