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 bool isVertexCase,
57 const string& vtxSource,
58 const string& fragSource,
59 ShaderEvalFunc evalFunc,
60 UniformSetupFunc setupUniformsFunc);
61 virtual ~ShaderSwitchCase (void);
62 };
63
ShaderSwitchCase(tcu::TestContext & testCtx,const string & name,bool isVertexCase,const string & vtxSource,const string & fragSource,ShaderEvalFunc evalFunc,UniformSetupFunc setupUniformsFunc)64 ShaderSwitchCase::ShaderSwitchCase (tcu::TestContext& testCtx,
65 const string& name,
66 bool isVertexCase,
67 const string& vtxSource,
68 const string& fragSource,
69 ShaderEvalFunc evalFunc,
70 UniformSetupFunc setupUniformsFunc)
71 : ShaderRenderCase (testCtx, name, isVertexCase, evalFunc, new UniformSetup(setupUniformsFunc), DE_NULL)
72 {
73 m_vertShaderSource = vtxSource;
74 m_fragShaderSource = fragSource;
75 }
76
~ShaderSwitchCase(void)77 ShaderSwitchCase::~ShaderSwitchCase (void)
78 {
79 }
80
81 enum SwitchType
82 {
83 SWITCHTYPE_STATIC = 0,
84 SWITCHTYPE_UNIFORM,
85 SWITCHTYPE_DYNAMIC,
86
87 SWITCHTYPE_LAST
88 };
89
evalSwitchStatic(ShaderEvalContext & evalCtx)90 static void evalSwitchStatic (ShaderEvalContext& evalCtx) { evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3); }
evalSwitchUniform(ShaderEvalContext & evalCtx)91 static void evalSwitchUniform (ShaderEvalContext& evalCtx) { evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3); }
evalSwitchDynamic(ShaderEvalContext & evalCtx)92 static void evalSwitchDynamic (ShaderEvalContext& evalCtx)
93 {
94 switch (int(deFloatFloor(evalCtx.coords.z()*1.5f + 2.0f)))
95 {
96 case 0: evalCtx.color.xyz() = evalCtx.coords.swizzle(0,1,2); break;
97 case 1: evalCtx.color.xyz() = evalCtx.coords.swizzle(3,2,1); break;
98 case 2: evalCtx.color.xyz() = evalCtx.coords.swizzle(1,2,3); break;
99 case 3: evalCtx.color.xyz() = evalCtx.coords.swizzle(2,1,0); break;
100 default: evalCtx.color.xyz() = evalCtx.coords.swizzle(0,0,0); break;
101 }
102 }
103
makeSwitchCase(tcu::TestContext & testCtx,const string & name,SwitchType type,bool isVertex,const LineStream & switchBody)104 static de::MovePtr<ShaderSwitchCase> makeSwitchCase (tcu::TestContext& testCtx, const string& name, SwitchType type, bool isVertex, const LineStream& switchBody)
105 {
106 std::ostringstream vtx;
107 std::ostringstream frag;
108 std::ostringstream& op = isVertex ? vtx : frag;
109
110 vtx << "#version 310 es\n"
111 << "layout(location = 0) in highp vec4 a_position;\n"
112 << "layout(location = 1) in highp vec4 a_coords;\n\n";
113 frag << "#version 310 es\n"
114 << "layout(location = 0) out mediump vec4 o_color;\n";
115
116 if (isVertex)
117 {
118 vtx << "layout(location = 0) out mediump vec4 v_color;\n";
119 frag << "layout(location = 0) in mediump vec4 v_color;\n";
120 }
121 else
122 {
123 vtx << "layout(location = 0) out highp vec4 v_coords;\n";
124 frag << "layout(location = 0) in highp vec4 v_coords;\n";
125 }
126
127 if (type == SWITCHTYPE_UNIFORM)
128 op << "layout (std140, set=0, binding=0) uniform buffer0 { highp int ui_two; };\n";
129
130 vtx << "\n"
131 << "void main (void)\n"
132 << "{\n"
133 << " gl_Position = a_position;\n";
134 frag << "\n"
135 << "void main (void)\n"
136 << "{\n";
137
138 // Setup.
139 op << " highp vec4 coords = " << (isVertex ? "a_coords" : "v_coords") << ";\n";
140 op << " mediump vec3 res = vec3(0.0);\n\n";
141
142 // Switch body.
143 std::map<string, string> params;
144 params["CONDITION"] = type == SWITCHTYPE_STATIC ? "2" :
145 type == SWITCHTYPE_UNIFORM ? "ui_two" :
146 type == SWITCHTYPE_DYNAMIC ? "int(floor(coords.z*1.5 + 2.0))" : "???";
147
148 op << tcu::StringTemplate(switchBody.str()).specialize(params);
149 op << "\n";
150
151 if (isVertex)
152 {
153 vtx << " v_color = vec4(res, 1.0);\n";
154 frag << " o_color = v_color;\n";
155 }
156 else
157 {
158 vtx << " v_coords = a_coords;\n";
159 frag << " o_color = vec4(res, 1.0);\n";
160 }
161
162 vtx << "}\n";
163 frag << "}\n";
164
165 return de::MovePtr<ShaderSwitchCase>(new ShaderSwitchCase(testCtx, name, isVertex, vtx.str(), frag.str(),
166 type == SWITCHTYPE_STATIC ? evalSwitchStatic :
167 type == SWITCHTYPE_UNIFORM ? evalSwitchUniform :
168 type == SWITCHTYPE_DYNAMIC ? evalSwitchDynamic : (ShaderEvalFunc)DE_NULL,
169 type == SWITCHTYPE_UNIFORM ? setUniforms : DE_NULL));
170 }
171
172 class ShaderSwitchTests : public tcu::TestCaseGroup
173 {
174 public:
175 ShaderSwitchTests (tcu::TestContext& context);
176 virtual ~ShaderSwitchTests (void);
177
178 virtual void init (void);
179
180 private:
181 ShaderSwitchTests (const ShaderSwitchTests&); // not allowed!
182 ShaderSwitchTests& operator= (const ShaderSwitchTests&); // not allowed!
183
184 void makeSwitchCases (const string& name, const LineStream& switchBody, const bool skipDynamicType = false);
185 };
186
ShaderSwitchTests(tcu::TestContext & testCtx)187 ShaderSwitchTests::ShaderSwitchTests (tcu::TestContext& testCtx)
188 : tcu::TestCaseGroup (testCtx, "switch")
189 {
190 }
191
~ShaderSwitchTests(void)192 ShaderSwitchTests::~ShaderSwitchTests (void)
193 {
194 }
195
makeSwitchCases(const string & name,const LineStream & switchBody,const bool skipDynamicType)196 void ShaderSwitchTests::makeSwitchCases (const string& name, const LineStream& switchBody, const bool skipDynamicType)
197 {
198 static const char* switchTypeNames[] = { "static", "uniform", "dynamic" };
199 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(switchTypeNames) == SWITCHTYPE_LAST);
200
201 for (int type = 0; type < SWITCHTYPE_LAST; type++)
202 {
203 if (skipDynamicType && (type == SWITCHTYPE_DYNAMIC))
204 continue;
205
206 addChild(makeSwitchCase(m_testCtx, (name + "_" + switchTypeNames[type] + "_vertex"), (SwitchType)type, true, switchBody).release());
207 addChild(makeSwitchCase(m_testCtx, (name + "_" + switchTypeNames[type] + "_fragment"), (SwitchType)type, false, switchBody).release());
208 }
209 }
210
init(void)211 void ShaderSwitchTests::init (void)
212 {
213 // Expected swizzles:
214 // 0: xyz
215 // 1: wzy
216 // 2: yzw
217 // 3: zyx
218
219 // Basic switch statement usage
220 makeSwitchCases("basic",
221 LineStream(1)
222 << "switch (${CONDITION})"
223 << "{"
224 << " case 0: res = coords.xyz; break;"
225 << " case 1: res = coords.wzy; break;"
226 << " case 2: res = coords.yzw; break;"
227 << " case 3: res = coords.zyx; break;"
228 << "}");
229
230 // Constant expression in label
231 makeSwitchCases("const_expr_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 // Default label usage
243 makeSwitchCases("default_label",
244 LineStream(1)
245 << "switch (${CONDITION})"
246 << "{"
247 << " case 0: res = coords.xyz; break;"
248 << " case 1: res = coords.wzy; break;"
249 << " case 3: res = coords.zyx; break;"
250 << " default: res = coords.yzw;"
251 << "}");
252
253 // Default label usage
254 makeSwitchCases("default_not_last",
255 LineStream(1)
256 << "switch (${CONDITION})"
257 << "{"
258 << " case 0: res = coords.xyz; break;"
259 << " default: res = coords.yzw; break;"
260 << " case 1: res = coords.wzy; break;"
261 << " case 3: res = coords.zyx; break;"
262 << "}");
263
264 // No match in switch without default label
265 makeSwitchCases("no_default_label",
266 LineStream(1)
267 << "res = coords.yzw;\n"
268 << "switch (${CONDITION})"
269 << "{"
270 << " case 0: res = coords.xyz; break;"
271 << " case 1: res = coords.wzy; break;"
272 << " case 3: res = coords.zyx; break;"
273 << "}");
274
275 // Default case only
276 makeSwitchCases("default_only",
277 LineStream(1)
278 << "switch (${CONDITION})"
279 << "{"
280 << " default:"
281 << " res = coords.yzw;"
282 << "}", true);
283
284 // Empty case and default
285 makeSwitchCases("empty_case_default",
286 LineStream(1)
287 << "switch (${CONDITION})"
288 << "{"
289 << " case 2:"
290 << " default:"
291 << " res = coords.yzw;"
292 << "}", true);
293
294 // Fall-through
295 makeSwitchCases("fall_through",
296 LineStream(1)
297 << "switch (${CONDITION})"
298 << "{"
299 << " case 0: res = coords.xyz; break;"
300 << " case 1: res = coords.wzy; break;"
301 << " case 2: coords = coords.yzwx;"
302 << " case 4: res = vec3(coords); break;"
303 << " case 3: res = coords.zyx; break;"
304 << "}");
305
306 // Fall-through
307 makeSwitchCases("fall_through_default",
308 LineStream(1)
309 << "switch (${CONDITION})"
310 << "{"
311 << " case 0: res = coords.xyz; break;"
312 << " case 1: res = coords.wzy; break;"
313 << " case 3: res = coords.zyx; break;"
314 << " case 2: coords = coords.yzwx;"
315 << " default: res = vec3(coords);"
316 << "}");
317
318 // Fall-through
319 makeSwitchCases("conditional_fall_through",
320 LineStream(1)
321 << "highp vec4 tmp = coords;"
322 << "switch (${CONDITION})"
323 << "{"
324 << " case 0: res = coords.xyz; break;"
325 << " case 1: res = coords.wzy; break;"
326 << " case 2:"
327 << " tmp = coords.yzwx;"
328 << " case 3:"
329 << " res = vec3(tmp);"
330 << " if (${CONDITION} != 3)"
331 << " break;"
332 << " default: res = tmp.zyx; break;"
333 << "}");
334
335 // Fall-through
336 makeSwitchCases("conditional_fall_through_2",
337 LineStream(1)
338 << "highp vec4 tmp = coords;"
339 << "mediump int c = ${CONDITION};"
340 << "switch (c)"
341 << "{"
342 << " case 0: res = coords.xyz; break;"
343 << " case 1: res = coords.wzy; break;"
344 << " case 2:"
345 << " c += ${CONDITION};"
346 << " tmp = coords.yzwx;"
347 << " case 3:"
348 << " res = vec3(tmp);"
349 << " if (c == 4)"
350 << " break;"
351 << " default: res = tmp.zyx; break;"
352 << "}");
353
354 // Basic switch statement usage
355 makeSwitchCases("scope",
356 LineStream(1)
357 << "switch (${CONDITION})"
358 << "{"
359 << " case 0: res = coords.xyz; break;"
360 << " case 1: res = coords.wzy; break;"
361 << " case 2:"
362 << " {"
363 << " mediump vec3 t = coords.yzw;"
364 << " res = t;"
365 << " break;"
366 << " }"
367 << " case 3: res = coords.zyx; break;"
368 << "}");
369
370 // Switch in for loop
371 makeSwitchCases("switch_in_if",
372 LineStream(1)
373 << "if (${CONDITION} >= 0)"
374 << "{"
375 << " switch (${CONDITION})"
376 << " {"
377 << " case 0: res = coords.xyz; break;"
378 << " case 1: res = coords.wzy; break;"
379 << " case 2: res = coords.yzw; break;"
380 << " case 3: res = coords.zyx; break;"
381 << " }"
382 << "}");
383
384 // Switch in for loop
385 makeSwitchCases("switch_in_for_loop",
386 LineStream(1)
387 << "for (int i = 0; i <= ${CONDITION}; i++)"
388 << "{"
389 << " switch (i)"
390 << " {"
391 << " case 0: res = coords.xyz; break;"
392 << " case 1: res = coords.wzy; break;"
393 << " case 2: res = coords.yzw; break;"
394 << " case 3: res = coords.zyx; break;"
395 << " }"
396 << "}");
397
398
399 // Switch in while loop
400 makeSwitchCases("switch_in_while_loop",
401 LineStream(1)
402 << "int i = 0;"
403 << "while (i <= ${CONDITION})"
404 << "{"
405 << " switch (i)"
406 << " {"
407 << " case 0: res = coords.xyz; break;"
408 << " case 1: res = coords.wzy; break;"
409 << " case 2: res = coords.yzw; break;"
410 << " case 3: res = coords.zyx; break;"
411 << " }"
412 << " i += 1;"
413 << "}");
414
415 // Switch in do-while loop
416 makeSwitchCases("switch_in_do_while_loop",
417 LineStream(1)
418 << "int i = 0;"
419 << "do"
420 << "{"
421 << " switch (i)"
422 << " {"
423 << " case 0: res = coords.xyz; break;"
424 << " case 1: res = coords.wzy; break;"
425 << " case 2: res = coords.yzw; break;"
426 << " case 3: res = coords.zyx; break;"
427 << " }"
428 << " i += 1;"
429 << "} while (i <= ${CONDITION});");
430
431 // Basic switch statement usage
432 makeSwitchCases("if_in_switch",
433 LineStream(1)
434 << "switch (${CONDITION})"
435 << "{"
436 << " case 0: res = coords.xyz; break;"
437 << " case 1: res = coords.wzy; break;"
438 << " default:"
439 << " if (${CONDITION} == 2)"
440 << " res = coords.yzw;"
441 << " else"
442 << " res = coords.zyx;"
443 << " break;"
444 << "}");
445
446 // Basic switch statement usage
447 makeSwitchCases("for_loop_in_switch",
448 LineStream(1)
449 << "switch (${CONDITION})"
450 << "{"
451 << " case 0: res = coords.xyz; break;"
452 << " case 1:"
453 << " case 2:"
454 << " {"
455 << " highp vec3 t = coords.yzw;"
456 << " for (int i = 0; i < ${CONDITION}; i++)"
457 << " t = t.zyx;"
458 << " res = t;"
459 << " break;"
460 << " }"
461 << " default: res = coords.zyx; break;"
462 << "}");
463
464 // Basic switch statement usage
465 makeSwitchCases("while_loop_in_switch",
466 LineStream(1)
467 << "switch (${CONDITION})"
468 << "{"
469 << " case 0: res = coords.xyz; break;"
470 << " case 1:"
471 << " case 2:"
472 << " {"
473 << " highp vec3 t = coords.yzw;"
474 << " int i = 0;"
475 << " while (i < ${CONDITION})"
476 << " {"
477 << " t = t.zyx;"
478 << " i += 1;"
479 << " }"
480 << " res = t;"
481 << " break;"
482 << " }"
483 << " default: res = coords.zyx; break;"
484 << "}");
485
486 // Basic switch statement usage
487 makeSwitchCases("do_while_loop_in_switch",
488 LineStream(1)
489 << "switch (${CONDITION})"
490 << "{"
491 << " case 0: res = coords.xyz; break;"
492 << " case 1:"
493 << " case 2:"
494 << " {"
495 << " highp vec3 t = coords.yzw;"
496 << " int i = 0;"
497 << " do"
498 << " {"
499 << " t = t.zyx;"
500 << " i += 1;"
501 << " } while (i < ${CONDITION});"
502 << " res = t;"
503 << " break;"
504 << " }"
505 << " default: res = coords.zyx; break;"
506 << "}");
507
508 // Basic switch statement usage
509 makeSwitchCases("switch_in_switch",
510 LineStream(1)
511 << "switch (${CONDITION})"
512 << "{"
513 << " case 0: res = coords.xyz; break;"
514 << " case 1:"
515 << " case 2:"
516 << " switch (${CONDITION} - 1)"
517 << " {"
518 << " case 0: res = coords.wzy; break;"
519 << " case 1: res = coords.yzw; break;"
520 << " }"
521 << " break;"
522 << " default: res = coords.zyx; break;"
523 << "}");
524 }
525
526 } // anonymous
527
createSwitchTests(tcu::TestContext & testCtx)528 tcu::TestCaseGroup* createSwitchTests (tcu::TestContext& testCtx)
529 {
530 return new ShaderSwitchTests(testCtx);
531 }
532
533 } // sr
534 } // vkt
535