1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
5 * Copyright (c) 2016 Google Inc.
6 * Copyright (c) 2016 The Khronos Group Inc.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 * \brief Shader switch statement tests.
23 */ /*-------------------------------------------------------------------*/
25 #include "glcShaderSwitchTests.hpp"
27 #include "glcShaderLibrary.hpp"
28 #include "glcShaderRenderCase.hpp"
29 #include "tcuStringTemplate.hpp"
38 class ShaderSwitchCase : public ShaderRenderCase
41 ShaderSwitchCase(Context& context, const char* name, const char* description, bool isVertexCase,
42 const char* vtxSource, const char* fragSource, ShaderEvalFunc evalFunc);
43 virtual ~ShaderSwitchCase(void);
46 ShaderSwitchCase::ShaderSwitchCase(Context& context, const char* name, const char* description, bool isVertexCase,
47 const char* vtxSource, const char* fragSource, ShaderEvalFunc evalFunc)
48 : ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name,
49 description, isVertexCase, evalFunc)
51 m_vertShaderSource = vtxSource;
52 m_fragShaderSource = fragSource;
55 ShaderSwitchCase::~ShaderSwitchCase(void)
61 SWITCHTYPE_STATIC = 0,
68 static void evalSwitchStatic(ShaderEvalContext& evalCtx)
70 evalCtx.color.xyz() = evalCtx.coords.swizzle(1, 2, 3);
72 static void evalSwitchUniform(ShaderEvalContext& evalCtx)
74 evalCtx.color.xyz() = evalCtx.coords.swizzle(1, 2, 3);
76 static void evalSwitchDynamic(ShaderEvalContext& evalCtx)
78 switch (int(deFloatFloor(evalCtx.coords.z() * 1.5f + 2.0f)))
81 evalCtx.color.xyz() = evalCtx.coords.swizzle(0, 1, 2);
84 evalCtx.color.xyz() = evalCtx.coords.swizzle(3, 2, 1);
87 evalCtx.color.xyz() = evalCtx.coords.swizzle(1, 2, 3);
90 evalCtx.color.xyz() = evalCtx.coords.swizzle(2, 1, 0);
93 evalCtx.color.xyz() = evalCtx.coords.swizzle(0, 0, 0);
98 static tcu::TestCase* makeSwitchCase(Context& context, glu::GLSLVersion glslVersion, const char* name, const char* desc,
99 SwitchType type, bool isVertex, const LineStream& switchBody)
101 std::ostringstream vtx;
102 std::ostringstream frag;
103 std::ostringstream& op = isVertex ? vtx : frag;
105 vtx << glu::getGLSLVersionDeclaration(glslVersion) << "\n"
106 << "in highp vec4 a_position;\n"
107 << "in highp vec4 a_coords;\n";
108 frag << glu::getGLSLVersionDeclaration(glslVersion) << "\n"
109 << "layout(location = 0) out mediump vec4 o_color;\n";
113 vtx << "out mediump vec4 v_color;\n";
114 frag << "in mediump vec4 v_color;\n";
118 vtx << "out highp vec4 v_coords;\n";
119 frag << "in highp vec4 v_coords;\n";
122 if (type == SWITCHTYPE_UNIFORM)
123 op << "uniform highp int ui_two;\n";
126 << "void main (void)\n"
128 << " gl_Position = a_position;\n";
130 << "void main (void)\n"
134 op << " highp vec4 coords = " << (isVertex ? "a_coords" : "v_coords") << ";\n";
135 op << " mediump vec3 res = vec3(0.0);\n\n";
138 map<string, string> params;
139 params["CONDITION"] = type == SWITCHTYPE_STATIC ?
141 type == SWITCHTYPE_UNIFORM ?
143 type == SWITCHTYPE_DYNAMIC ? "int(floor(coords.z*1.5 + 2.0))" : "???";
145 op << tcu::StringTemplate(switchBody.str()).specialize(params).c_str();
150 vtx << " v_color = vec4(res, 1.0);\n";
151 frag << " o_color = v_color;\n";
155 vtx << " v_coords = a_coords;\n";
156 frag << " o_color = vec4(res, 1.0);\n";
162 return new ShaderSwitchCase(context, name, desc, isVertex, vtx.str().c_str(), frag.str().c_str(),
163 type == SWITCHTYPE_STATIC ?
165 type == SWITCHTYPE_UNIFORM ?
167 type == SWITCHTYPE_DYNAMIC ? evalSwitchDynamic : (ShaderEvalFunc)DE_NULL);
170 static void makeSwitchCases(TestCaseGroup* group, glu::GLSLVersion glslVersion, const char* name, const char* desc,
171 const LineStream& switchBody)
173 static const char* switchTypeNames[] = { "static", "uniform", "dynamic" };
174 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(switchTypeNames) == SWITCHTYPE_LAST);
176 for (int type = 0; type < SWITCHTYPE_LAST; type++)
178 group->addChild(makeSwitchCase(group->getContext(), glslVersion,
179 (string(name) + "_" + switchTypeNames[type] + "_vertex").c_str(), desc,
180 (SwitchType)type, true, switchBody));
181 group->addChild(makeSwitchCase(group->getContext(), glslVersion,
182 (string(name) + "_" + switchTypeNames[type] + "_fragment").c_str(), desc,
183 (SwitchType)type, false, switchBody));
187 ShaderSwitchTests::ShaderSwitchTests(Context& context, glu::GLSLVersion glslVersion)
188 : TestCaseGroup(context, "switch", "Switch statement tests"), m_glslVersion(glslVersion)
190 DE_ASSERT(glslVersion == glu::GLSL_VERSION_300_ES || glslVersion == glu::GLSL_VERSION_310_ES ||
191 glslVersion == glu::GLSL_VERSION_330);
194 ShaderSwitchTests::~ShaderSwitchTests(void)
198 void ShaderSwitchTests::init(void)
200 // Expected swizzles:
206 makeSwitchCases(this, m_glslVersion, "basic", "Basic switch statement usage",
207 LineStream(1) << "switch (${CONDITION})"
209 << " case 0: res = coords.xyz; break;"
210 << " case 1: res = coords.wzy; break;"
211 << " case 2: res = coords.yzw; break;"
212 << " case 3: res = coords.zyx; break;"
215 makeSwitchCases(this, m_glslVersion, "const_expr_in_label", "Constant expression in label",
216 LineStream(1) << "const int t = 2;"
217 << "switch (${CONDITION})"
219 << " case int(0.0): res = coords.xyz; break;"
220 << " case 2-1: res = coords.wzy; break;"
221 << " case 3&(1<<1): res = coords.yzw; break;"
222 << " case t+1: res = coords.zyx; break;"
225 makeSwitchCases(this, m_glslVersion, "default_label", "Default label usage",
226 LineStream(1) << "switch (${CONDITION})"
228 << " case 0: res = coords.xyz; break;"
229 << " case 1: res = coords.wzy; break;"
230 << " case 3: res = coords.zyx; break;"
231 << " default: res = coords.yzw;"
234 makeSwitchCases(this, m_glslVersion, "default_not_last", "Default label usage",
235 LineStream(1) << "switch (${CONDITION})"
237 << " case 0: res = coords.xyz; break;"
238 << " default: res = coords.yzw; break;"
239 << " case 1: res = coords.wzy; break;"
240 << " case 3: res = coords.zyx; break;"
243 makeSwitchCases(this, m_glslVersion, "no_default_label", "No match in switch without default label",
244 LineStream(1) << "res = coords.yzw;\n"
245 << "switch (${CONDITION})"
247 << " case 0: res = coords.xyz; break;"
248 << " case 1: res = coords.wzy; break;"
249 << " case 3: res = coords.zyx; break;"
252 makeSwitchCases(this, m_glslVersion, "fall_through", "Fall-through",
253 LineStream(1) << "switch (${CONDITION})"
255 << " case 0: res = coords.xyz; break;"
256 << " case 1: res = coords.wzy; break;"
257 << " case 2: coords = coords.yzwx;"
258 << " case 4: res = vec3(coords); break;"
259 << " case 3: res = coords.zyx; break;"
262 makeSwitchCases(this, m_glslVersion, "fall_through_default", "Fall-through",
263 LineStream(1) << "switch (${CONDITION})"
265 << " case 0: res = coords.xyz; break;"
266 << " case 1: res = coords.wzy; break;"
267 << " case 3: res = coords.zyx; break;"
268 << " case 2: coords = coords.yzwx;"
269 << " default: res = vec3(coords);"
272 makeSwitchCases(this, m_glslVersion, "conditional_fall_through", "Fall-through",
273 LineStream(1) << "highp vec4 tmp = coords;"
274 << "switch (${CONDITION})"
276 << " case 0: res = coords.xyz; break;"
277 << " case 1: res = coords.wzy; break;"
279 << " tmp = coords.yzwx;"
281 << " res = vec3(tmp);"
282 << " if (${CONDITION} != 3)"
284 << " default: res = tmp.zyx; break;"
287 makeSwitchCases(this, m_glslVersion, "conditional_fall_through_2", "Fall-through",
288 LineStream(1) << "highp vec4 tmp = coords;"
289 << "mediump int c = ${CONDITION};"
292 << " case 0: res = coords.xyz; break;"
293 << " case 1: res = coords.wzy; break;"
295 << " c += ${CONDITION};"
296 << " tmp = coords.yzwx;"
298 << " res = vec3(tmp);"
301 << " default: res = tmp.zyx; break;"
304 makeSwitchCases(this, m_glslVersion, "scope", "Basic switch statement usage",
305 LineStream(1) << "switch (${CONDITION})"
307 << " case 0: res = coords.xyz; break;"
308 << " case 1: res = coords.wzy; break;"
311 << " mediump vec3 t = coords.yzw;"
315 << " case 3: res = coords.zyx; break;"
318 makeSwitchCases(this, m_glslVersion, "switch_in_if", "Switch in for loop",
319 LineStream(1) << "if (${CONDITION} >= 0)"
321 << " switch (${CONDITION})"
323 << " case 0: res = coords.xyz; break;"
324 << " case 1: res = coords.wzy; break;"
325 << " case 2: res = coords.yzw; break;"
326 << " case 3: res = coords.zyx; break;"
330 makeSwitchCases(this, m_glslVersion, "switch_in_for_loop", "Switch in for loop",
331 LineStream(1) << "for (int i = 0; i <= ${CONDITION}; i++)"
335 << " case 0: res = coords.xyz; break;"
336 << " case 1: res = coords.wzy; break;"
337 << " case 2: res = coords.yzw; break;"
338 << " case 3: res = coords.zyx; break;"
342 makeSwitchCases(this, m_glslVersion, "switch_in_while_loop", "Switch in while loop",
343 LineStream(1) << "int i = 0;"
344 << "while (i <= ${CONDITION})"
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;"
356 makeSwitchCases(this, m_glslVersion, "switch_in_do_while_loop", "Switch in do-while loop",
357 LineStream(1) << "int i = 0;"
362 << " case 0: res = coords.xyz; break;"
363 << " case 1: res = coords.wzy; break;"
364 << " case 2: res = coords.yzw; break;"
365 << " case 3: res = coords.zyx; break;"
368 << "} while (i <= ${CONDITION});");
370 makeSwitchCases(this, m_glslVersion, "if_in_switch", "Basic switch statement usage",
371 LineStream(1) << "switch (${CONDITION})"
373 << " case 0: res = coords.xyz; break;"
374 << " case 1: res = coords.wzy; break;"
376 << " if (${CONDITION} == 2)"
377 << " res = coords.yzw;"
379 << " res = coords.zyx;"
383 makeSwitchCases(this, m_glslVersion, "for_loop_in_switch", "Basic switch statement usage",
384 LineStream(1) << "switch (${CONDITION})"
386 << " case 0: res = coords.xyz; break;"
390 << " highp vec3 t = coords.yzw;"
391 << " for (int i = 0; i < ${CONDITION}; i++)"
396 << " default: res = coords.zyx; break;"
399 makeSwitchCases(this, m_glslVersion, "while_loop_in_switch", "Basic switch statement usage",
400 LineStream(1) << "switch (${CONDITION})"
402 << " case 0: res = coords.xyz; break;"
406 << " highp vec3 t = coords.yzw;"
408 << " while (i < ${CONDITION})"
416 << " default: res = coords.zyx; break;"
419 makeSwitchCases(this, m_glslVersion, "do_while_loop_in_switch", "Basic switch statement usage",
420 LineStream(1) << "switch (${CONDITION})"
422 << " case 0: res = coords.xyz; break;"
426 << " highp vec3 t = coords.yzw;"
432 << " } while (i < ${CONDITION});"
436 << " default: res = coords.zyx; break;"
439 makeSwitchCases(this, m_glslVersion, "switch_in_switch", "Basic switch statement usage",
440 LineStream(1) << "switch (${CONDITION})"
442 << " case 0: res = coords.xyz; break;"
445 << " switch (${CONDITION} - 1)"
447 << " case 0: res = coords.wzy; break;"
448 << " case 1: res = coords.yzw; break;"
451 << " default: res = coords.zyx; break;"
456 ShaderLibrary library(m_testCtx, m_context.getRenderContext());
457 bool isES3 = m_glslVersion == glu::GLSL_VERSION_300_ES || m_glslVersion == glu::GLSL_VERSION_310_ES;
458 std::string path = "";
464 path += "switch.test";
465 vector<tcu::TestNode*> negativeCases = library.loadShaderFile(path.c_str());
467 for (vector<tcu::TestNode*>::iterator i = negativeCases.begin(); i != negativeCases.end(); i++)