1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Shader switch statement tests.
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 *//*--------------------------------------------------------------------*/
30 #include "es3fShaderSwitchTests.hpp"
31 #include "glsShaderRenderCase.hpp"
32 #include "glsShaderLibrary.hpp"
33 #include "tcuStringTemplate.hpp"
43 using namespace deqp::gls;
48 class ShaderSwitchCase : public ShaderRenderCase
51 ShaderSwitchCase (Context& context, const char* name, const char* description, bool isVertexCase, const char* vtxSource, const char* fragSource, ShaderEvalFunc evalFunc);
52 virtual ~ShaderSwitchCase (void);
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)
58 m_vertShaderSource = vtxSource;
59 m_fragShaderSource = fragSource;
62 ShaderSwitchCase::~ShaderSwitchCase (void)
68 SWITCHTYPE_STATIC = 0,
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)
79 switch (int(deFloatFloor(evalCtx.coords.z()*1.5f + 2.0f)))
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;
89 static tcu::TestCase* makeSwitchCase (Context& context, const char* name, const char* desc, SwitchType type, bool isVertex, const LineStream& switchBody)
91 std::ostringstream vtx;
92 std::ostringstream frag;
93 std::ostringstream& op = isVertex ? vtx : frag;
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";
103 vtx << "out mediump vec4 v_color;\n";
104 frag << "in mediump vec4 v_color;\n";
108 vtx << "out highp vec4 v_coords;\n";
109 frag << "in highp vec4 v_coords;\n";
112 if (type == SWITCHTYPE_UNIFORM)
113 op << "uniform highp int ui_two;\n";
116 << "void main (void)\n"
118 << " gl_Position = a_position;\n";
120 << "void main (void)\n"
124 op << " highp vec4 coords = " << (isVertex ? "a_coords" : "v_coords") << ";\n";
125 op << " mediump vec3 res = vec3(0.0);\n\n";
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))" : "???";
133 op << tcu::StringTemplate(switchBody.str()).specialize(params).c_str();
138 vtx << " v_color = vec4(res, 1.0);\n";
139 frag << " o_color = v_color;\n";
143 vtx << " v_coords = a_coords;\n";
144 frag << " o_color = vec4(res, 1.0);\n";
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);
156 static void makeSwitchCases (TestCaseGroup* group, const char* name, const char* desc, const LineStream& switchBody)
158 static const char* switchTypeNames[] = { "static", "uniform", "dynamic" };
159 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(switchTypeNames) == SWITCHTYPE_LAST);
161 for (int type = 0; type < SWITCHTYPE_LAST; type++)
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));
168 ShaderSwitchTests::ShaderSwitchTests (Context& context)
169 : TestCaseGroup(context, "switch", "Switch statement tests")
173 ShaderSwitchTests::~ShaderSwitchTests (void)
177 void ShaderSwitchTests::init (void)
179 // Expected swizzles:
185 makeSwitchCases(this, "basic", "Basic switch statement usage",
187 << "switch (${CONDITION})"
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;"
195 makeSwitchCases(this, "const_expr_in_label", "Constant expression in label",
197 << "const int t = 2;"
198 << "switch (${CONDITION})"
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;"
206 makeSwitchCases(this, "default_label", "Default label usage",
208 << "switch (${CONDITION})"
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;"
216 makeSwitchCases(this, "default_not_last", "Default label usage",
218 << "switch (${CONDITION})"
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;"
226 makeSwitchCases(this, "no_default_label", "No match in switch without default label",
228 << "res = coords.yzw;\n"
229 << "switch (${CONDITION})"
231 << " case 0: res = coords.xyz; break;"
232 << " case 1: res = coords.wzy; break;"
233 << " case 3: res = coords.zyx; break;"
236 makeSwitchCases(this, "fall_through", "Fall-through",
238 << "switch (${CONDITION})"
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;"
247 makeSwitchCases(this, "fall_through_default", "Fall-through",
249 << "switch (${CONDITION})"
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);"
258 makeSwitchCases(this, "conditional_fall_through", "Fall-through",
260 << "highp vec4 tmp = coords;"
261 << "switch (${CONDITION})"
263 << " case 0: res = coords.xyz; break;"
264 << " case 1: res = coords.wzy; break;"
266 << " tmp = coords.yzwx;"
268 << " res = vec3(tmp);"
269 << " if (${CONDITION} != 3)"
271 << " default: res = tmp.zyx; break;"
274 makeSwitchCases(this, "conditional_fall_through_2", "Fall-through",
276 << "highp vec4 tmp = coords;"
277 << "mediump int c = ${CONDITION};"
280 << " case 0: res = coords.xyz; break;"
281 << " case 1: res = coords.wzy; break;"
283 << " c += ${CONDITION};"
284 << " tmp = coords.yzwx;"
286 << " res = vec3(tmp);"
289 << " default: res = tmp.zyx; break;"
292 makeSwitchCases(this, "scope", "Basic switch statement usage",
294 << "switch (${CONDITION})"
296 << " case 0: res = coords.xyz; break;"
297 << " case 1: res = coords.wzy; break;"
300 << " mediump vec3 t = coords.yzw;"
304 << " case 3: res = coords.zyx; break;"
307 makeSwitchCases(this, "switch_in_if", "Switch in for loop",
309 << "if (${CONDITION} >= 0)"
311 << " switch (${CONDITION})"
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;"
320 makeSwitchCases(this, "switch_in_for_loop", "Switch in for loop",
322 << "for (int i = 0; i <= ${CONDITION}; i++)"
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;"
333 makeSwitchCases(this, "switch_in_while_loop", "Switch in while loop",
336 << "while (i <= ${CONDITION})"
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;"
348 makeSwitchCases(this, "switch_in_do_while_loop", "Switch in do-while loop",
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;"
361 << "} while (i <= ${CONDITION});");
363 makeSwitchCases(this, "if_in_switch", "Basic switch statement usage",
365 << "switch (${CONDITION})"
367 << " case 0: res = coords.xyz; break;"
368 << " case 1: res = coords.wzy; break;"
370 << " if (${CONDITION} == 2)"
371 << " res = coords.yzw;"
373 << " res = coords.zyx;"
377 makeSwitchCases(this, "for_loop_in_switch", "Basic switch statement usage",
379 << "switch (${CONDITION})"
381 << " case 0: res = coords.xyz; break;"
385 << " highp vec3 t = coords.yzw;"
386 << " for (int i = 0; i < ${CONDITION}; i++)"
391 << " default: res = coords.zyx; break;"
394 makeSwitchCases(this, "while_loop_in_switch", "Basic switch statement usage",
396 << "switch (${CONDITION})"
398 << " case 0: res = coords.xyz; break;"
402 << " highp vec3 t = coords.yzw;"
404 << " while (i < ${CONDITION})"
412 << " default: res = coords.zyx; break;"
415 makeSwitchCases(this, "do_while_loop_in_switch", "Basic switch statement usage",
417 << "switch (${CONDITION})"
419 << " case 0: res = coords.xyz; break;"
423 << " highp vec3 t = coords.yzw;"
429 << " } while (i < ${CONDITION});"
433 << " default: res = coords.zyx; break;"
436 makeSwitchCases(this, "switch_in_switch", "Basic switch statement usage",
438 << "switch (${CONDITION})"
440 << " case 0: res = coords.xyz; break;"
443 << " switch (${CONDITION} - 1)"
445 << " case 0: res = coords.wzy; break;"
446 << " case 1: res = coords.yzw; break;"
449 << " default: res = coords.zyx; break;"
453 ShaderLibrary library(m_testCtx, m_context.getRenderContext(), m_context.getContextInfo());
454 vector<tcu::TestNode*> negativeCases = library.loadShaderFile("shaders/switch.test");
456 for (vector<tcu::TestNode*>::iterator i = negativeCases.begin(); i != negativeCases.end(); i++)