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