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 return statement tests.
24 *//*--------------------------------------------------------------------*/
25
26 #include "vktShaderRenderReturnTests.hpp"
27 #include "vktShaderRender.hpp"
28 #include "tcuStringTemplate.hpp"
29
30 #include <map>
31 #include <string>
32
33 namespace vkt
34 {
35 namespace sr
36 {
37 namespace
38 {
39
40 enum ReturnMode
41 {
42 RETURNMODE_ALWAYS = 0,
43 RETURNMODE_NEVER,
44 RETURNMODE_DYNAMIC,
45
46 RETURNMODE_LAST
47 };
48
49 // Evaluation functions
evalReturnAlways(ShaderEvalContext & c)50 inline void evalReturnAlways (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(0,1,2); }
evalReturnNever(ShaderEvalContext & c)51 inline void evalReturnNever (ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(3,2,1); }
evalReturnDynamic(ShaderEvalContext & c)52 inline void evalReturnDynamic (ShaderEvalContext& c) { c.color.xyz() = (c.coords.x()+c.coords.y() >= 0.0f) ? c.coords.swizzle(0,1,2) : c.coords.swizzle(3,2,1); }
53
getEvalFunc(ReturnMode mode)54 static ShaderEvalFunc getEvalFunc (ReturnMode mode)
55 {
56 switch (mode)
57 {
58 case RETURNMODE_ALWAYS: return evalReturnAlways;
59 case RETURNMODE_NEVER: return evalReturnNever;
60 case RETURNMODE_DYNAMIC: return evalReturnDynamic;
61 default:
62 DE_ASSERT(DE_FALSE);
63 return (ShaderEvalFunc)DE_NULL;
64 }
65 }
66
67 class ShaderReturnCase : public ShaderRenderCase
68 {
69 public:
70 ShaderReturnCase (tcu::TestContext& testCtx,
71 const std::string& name,
72 bool isVertexCase,
73 const std::string& shaderSource,
74 const ShaderEvalFunc evalFunc,
75 const UniformSetup* uniformFunc);
76 virtual ~ShaderReturnCase (void);
77 };
78
ShaderReturnCase(tcu::TestContext & testCtx,const std::string & name,bool isVertexCase,const std::string & shaderSource,const ShaderEvalFunc evalFunc,const UniformSetup * uniformFunc)79 ShaderReturnCase::ShaderReturnCase (tcu::TestContext& testCtx,
80 const std::string& name,
81 bool isVertexCase,
82 const std::string& shaderSource,
83 const ShaderEvalFunc evalFunc,
84 const UniformSetup* uniformFunc)
85 : ShaderRenderCase(testCtx, name, isVertexCase, evalFunc, uniformFunc, DE_NULL)
86 {
87 if (isVertexCase)
88 {
89 m_vertShaderSource = shaderSource;
90 m_fragShaderSource =
91 "#version 310 es\n"
92 "layout(location = 0) in mediump vec4 v_color;\n"
93 "layout(location = 0) out mediump vec4 o_color;\n\n"
94 "void main (void)\n"
95 "{\n"
96 " o_color = v_color;\n"
97 "}\n";
98 }
99 else
100 {
101 m_fragShaderSource = shaderSource;
102 m_vertShaderSource =
103 "#version 310 es\n"
104 "layout(location = 0) in highp vec4 a_position;\n"
105 "layout(location = 1) in highp vec4 a_coords;\n"
106 "layout(location = 0) out mediump vec4 v_coords;\n\n"
107 "void main (void)\n"
108 "{\n"
109 " gl_Position = a_position;\n"
110 " v_coords = a_coords;\n"
111 "}\n";
112 }
113 }
114
~ShaderReturnCase(void)115 ShaderReturnCase::~ShaderReturnCase (void)
116 {
117 }
118
119 class ReturnTestUniformSetup : public UniformSetup
120 {
121 public:
ReturnTestUniformSetup(const BaseUniformType uniformType)122 ReturnTestUniformSetup (const BaseUniformType uniformType)
123 : m_uniformType(uniformType)
124 {}
setup(ShaderRenderCaseInstance & instance,const tcu::Vec4 &) const125 virtual void setup (ShaderRenderCaseInstance& instance, const tcu::Vec4&) const
126 {
127 instance.useUniform(0u, m_uniformType);
128 }
129
130 private:
131 const BaseUniformType m_uniformType;
132 };
133
134 // Test case builders.
135
makeConditionalReturnInFuncCase(tcu::TestContext & context,const std::string & name,ReturnMode returnMode,bool isVertex)136 de::MovePtr<ShaderReturnCase> makeConditionalReturnInFuncCase (tcu::TestContext& context, const std::string& name, ReturnMode returnMode, bool isVertex)
137 {
138 tcu::StringTemplate tmpl(
139 "#version 310 es\n"
140 "layout(location = ${COORDLOC}) in ${COORDPREC} vec4 ${COORDS};\n"
141 "${EXTRADECL}\n"
142 "${COORDPREC} vec4 getColor (void)\n"
143 "{\n"
144 " if (${RETURNCOND})\n"
145 " return vec4(${COORDS}.xyz, 1.0);\n"
146 " return vec4(${COORDS}.wzy, 1.0);\n"
147 "}\n\n"
148 "void main (void)\n"
149 "{\n"
150 "${POSITIONWRITE}"
151 " ${OUTPUT} = getColor();\n"
152 "}\n");
153
154 const char* coords = isVertex ? "a_coords" : "v_coords";
155
156 std::map<std::string, std::string> params;
157
158 params["COORDLOC"] = isVertex ? "1" : "0";
159 params["COORDPREC"] = isVertex ? "highp" : "mediump";
160 params["OUTPUT"] = isVertex ? "v_color" : "o_color";
161 params["COORDS"] = coords;
162 params["EXTRADECL"] = isVertex ? "layout(location = 0) in highp vec4 a_position;\nlayout(location = 0) out mediump vec4 v_color;\n" : "layout(location = 0) out mediump vec4 o_color;\n";
163 params["POSITIONWRITE"] = isVertex ? " gl_Position = a_position;\n" : "";
164
165 switch (returnMode)
166 {
167 case RETURNMODE_ALWAYS: params["RETURNCOND"] = "true"; break;
168 case RETURNMODE_NEVER: params["RETURNCOND"] = "false"; break;
169 case RETURNMODE_DYNAMIC: params["RETURNCOND"] = std::string(coords) + ".x+" + coords + ".y >= 0.0"; break;
170 default: DE_ASSERT(DE_FALSE);
171 }
172
173 return de::MovePtr<ShaderReturnCase>(new ShaderReturnCase(context, name, isVertex, tmpl.specialize(params), getEvalFunc(returnMode), DE_NULL));
174 }
175
makeOutputWriteReturnCase(tcu::TestContext & context,const std::string & name,bool inFunction,ReturnMode returnMode,bool isVertex)176 de::MovePtr<ShaderReturnCase> makeOutputWriteReturnCase (tcu::TestContext& context, const std::string& name, bool inFunction, ReturnMode returnMode, bool isVertex)
177 {
178 tcu::StringTemplate tmpl(
179 inFunction
180 ?
181 "#version 310 es\n"
182 "layout(location = ${COORDLOC}) in ${COORDPREC} vec4 ${COORDS};\n"
183 "${EXTRADECL}\n"
184 "void myfunc (void)\n"
185 "{\n"
186 " ${OUTPUT} = vec4(${COORDS}.xyz, 1.0);\n"
187 " if (${RETURNCOND})\n"
188 " return;\n"
189 " ${OUTPUT} = vec4(${COORDS}.wzy, 1.0);\n"
190 "}\n\n"
191 "void main (void)\n"
192 "{\n"
193 "${POSITIONWRITE}"
194 " myfunc();\n"
195 "}\n"
196 :
197 "#version 310 es\n"
198 "layout(location = ${COORDLOC}) in ${COORDPREC} vec4 ${COORDS};\n"
199 "${EXTRADECL}\n"
200 "void main ()\n"
201 "{\n"
202 "${POSITIONWRITE}"
203 " ${OUTPUT} = vec4(${COORDS}.xyz, 1.0);\n"
204 " if (${RETURNCOND})\n"
205 " return;\n"
206 " ${OUTPUT} = vec4(${COORDS}.wzy, 1.0);\n"
207 "}\n");
208
209 const char* coords = isVertex ? "a_coords" : "v_coords";
210
211 std::map<std::string, std::string> params;
212
213 params["COORDLOC"] = isVertex ? "1" : "0";
214 params["COORDPREC"] = isVertex ? "highp" : "mediump";
215 params["COORDS"] = coords;
216 params["OUTPUT"] = isVertex ? "v_color" : "o_color";
217 params["EXTRADECL"] = isVertex ? "layout(location = 0) in highp vec4 a_position;\nlayout(location = 0) out mediump vec4 v_color;\n" : "layout(location = 0) out mediump vec4 o_color;\n";
218 params["POSITIONWRITE"] = isVertex ? " gl_Position = a_position;\n" : "";
219
220 switch (returnMode)
221 {
222 case RETURNMODE_ALWAYS: params["RETURNCOND"] = "true"; break;
223 case RETURNMODE_NEVER: params["RETURNCOND"] = "false"; break;
224 case RETURNMODE_DYNAMIC: params["RETURNCOND"] = std::string(coords) + ".x+" + coords + ".y >= 0.0"; break;
225 default: DE_ASSERT(DE_FALSE);
226 }
227
228 return de::MovePtr<ShaderReturnCase>(new ShaderReturnCase(context, name, isVertex, tmpl.specialize(params), getEvalFunc(returnMode), DE_NULL));
229 }
230
makeReturnInLoopCase(tcu::TestContext & context,const std::string & name,bool isDynamicLoop,ReturnMode returnMode,bool isVertex)231 de::MovePtr<ShaderReturnCase> makeReturnInLoopCase (tcu::TestContext& context, const std::string& name, bool isDynamicLoop, ReturnMode returnMode, bool isVertex)
232 {
233 tcu::StringTemplate tmpl(
234 "#version 310 es\n"
235 "layout(location = ${COORDLOC}) in ${COORDPREC} vec4 ${COORDS};\n"
236 "layout(binding = 0, std140) uniform something { mediump int ui_one; };\n"
237 "${EXTRADECL}\n"
238 "${COORDPREC} vec4 getCoords (void)\n"
239 "{\n"
240 " ${COORDPREC} vec4 coords = ${COORDS};\n"
241 " for (int i = 0; i < ${ITERLIMIT}; i++)\n"
242 " {\n"
243 " if (${RETURNCOND})\n"
244 " return coords;\n"
245 " coords = coords.wzyx;\n"
246 " }\n"
247 " return coords;\n"
248 "}\n\n"
249 "void main (void)\n"
250 "{\n"
251 "${POSITIONWRITE}"
252 " ${OUTPUT} = vec4(getCoords().xyz, 1.0);\n"
253 "}\n");
254
255 const char* coords = isVertex ? "a_coords" : "v_coords";
256
257 std::map<std::string, std::string> params;
258
259 params["COORDLOC"] = isVertex ? "1" : "0";
260 params["COORDPREC"] = isVertex ? "highp" : "mediump";
261 params["OUTPUT"] = isVertex ? "v_color" : "o_color";
262 params["COORDS"] = coords;
263 params["EXTRADECL"] = isVertex ? "layout(location = 0) in highp vec4 a_position;\nlayout(location = 0) out mediump vec4 v_color;\n" : "layout(location = 0) out mediump vec4 o_color;\n";
264 params["POSITIONWRITE"] = isVertex ? " gl_Position = a_position;\n" : "";
265 params["ITERLIMIT"] = isDynamicLoop ? "ui_one" : "1";
266
267 switch (returnMode)
268 {
269 case RETURNMODE_ALWAYS: params["RETURNCOND"] = "true"; break;
270 case RETURNMODE_NEVER: params["RETURNCOND"] = "false"; break;
271 case RETURNMODE_DYNAMIC: params["RETURNCOND"] = std::string(coords) + ".x+" + coords + ".y >= 0.0"; break;
272 default: DE_ASSERT(DE_FALSE);
273 }
274
275 return de::MovePtr<ShaderReturnCase>(new ShaderReturnCase(context, name, isVertex, tmpl.specialize(params), getEvalFunc(returnMode), new ReturnTestUniformSetup(UI_ONE)));
276 }
277
getReturnModeName(ReturnMode mode)278 static const char* getReturnModeName (ReturnMode mode)
279 {
280 switch (mode)
281 {
282 case RETURNMODE_ALWAYS: return "always";
283 case RETURNMODE_NEVER: return "never";
284 case RETURNMODE_DYNAMIC: return "dynamic";
285 default:
286 DE_ASSERT(DE_FALSE);
287 return DE_NULL;
288 }
289 }
290
291 class ShaderReturnTests : public tcu::TestCaseGroup
292 {
293 public:
294 ShaderReturnTests (tcu::TestContext& context);
295 virtual ~ShaderReturnTests (void);
296 virtual void init (void);
297
298 private:
299 ShaderReturnTests (const ShaderReturnTests&); // not allowed!
300 ShaderReturnTests& operator= (const ShaderReturnTests&); // not allowed!
301 };
302
ShaderReturnTests(tcu::TestContext & context)303 ShaderReturnTests::ShaderReturnTests (tcu::TestContext& context)
304 : TestCaseGroup(context, "return")
305 {
306 }
307
~ShaderReturnTests(void)308 ShaderReturnTests::~ShaderReturnTests (void)
309 {
310 }
311
init(void)312 void ShaderReturnTests::init (void)
313 {
314 // Single return statement in function
315 addChild(new ShaderReturnCase(m_testCtx, "single_return_vertex", true,
316 "#version 310 es\n"
317 "layout(location = 0) in highp vec4 a_position;\n"
318 "layout(location = 1) in highp vec4 a_coords;\n"
319 "layout(location = 0) out mediump vec4 v_color;\n\n"
320 "vec4 getColor (void)\n"
321 "{\n"
322 " return vec4(a_coords.xyz, 1.0);\n"
323 "}\n\n"
324 "void main (void)\n"
325 "{\n"
326 " gl_Position = a_position;\n"
327 " v_color = getColor();\n"
328 "}\n", evalReturnAlways, DE_NULL));
329 // Single return statement in function
330 addChild(new ShaderReturnCase(m_testCtx, "single_return_fragment", false,
331 "#version 310 es\n"
332 "layout(location = 0) in mediump vec4 v_coords;\n"
333 "layout(location = 0) out mediump vec4 o_color;\n"
334 "mediump vec4 getColor (void)\n"
335 "{\n"
336 " return vec4(v_coords.xyz, 1.0);\n"
337 "}\n\n"
338 "void main (void)\n"
339 "{\n"
340 " o_color = getColor();\n"
341 "}\n", evalReturnAlways, DE_NULL));
342
343 // Conditional return statement in function.
344 for (int returnMode = 0; returnMode < RETURNMODE_LAST; returnMode++)
345 {
346 for (int isFragment = 0; isFragment < 2; isFragment++)
347 {
348 std::string name = std::string("conditional_return_") + getReturnModeName((ReturnMode)returnMode) + (isFragment ? "_fragment" : "_vertex");
349 de::MovePtr<ShaderReturnCase> testCase (makeConditionalReturnInFuncCase(m_testCtx, name, (ReturnMode)returnMode, isFragment == 0));
350 addChild(testCase.release());
351 }
352 }
353
354 // Unconditional double return in function.
355 addChild(new ShaderReturnCase(m_testCtx, "double_return_vertex", true,
356 "#version 310 es\n"
357 "layout(location = 0) in highp vec4 a_position;\n"
358 "layout(location = 1) in highp vec4 a_coords;\n"
359 "layout(location = 0) out mediump vec4 v_color;\n\n"
360 "vec4 getColor (void)\n"
361 "{\n"
362 " return vec4(a_coords.xyz, 1.0);\n"
363 " return vec4(a_coords.wzy, 1.0);\n"
364 "}\n\n"
365 "void main (void)\n"
366 "{\n"
367 " gl_Position = a_position;\n"
368 " v_color = getColor();\n"
369 "}\n", evalReturnAlways, DE_NULL));
370 // Unconditional double return in function
371 addChild(new ShaderReturnCase(m_testCtx, "double_return_fragment", false,
372 "#version 310 es\n"
373 "layout(location = 0) in mediump vec4 v_coords;\n"
374 "layout(location = 0) out mediump vec4 o_color;\n\n"
375 "mediump vec4 getColor (void)\n"
376 "{\n"
377 " return vec4(v_coords.xyz, 1.0);\n"
378 " return vec4(v_coords.wzy, 1.0);\n"
379 "}\n\n"
380 "void main (void)\n"
381 "{\n"
382 " o_color = getColor();\n"
383 "}\n", evalReturnAlways, DE_NULL));
384
385 // Last statement in main.
386 // Return as a final statement in main()
387 addChild(new ShaderReturnCase(m_testCtx, "last_statement_in_main_vertex", true,
388 "#version 310 es\n"
389 "layout(location = 0) in highp vec4 a_position;\n"
390 "layout(location = 1) in highp vec4 a_coords;\n"
391 "layout(location = 0) out mediump vec4 v_color;\n\n"
392 "void main (void)\n"
393 "{\n"
394 " gl_Position = a_position;\n"
395 " v_color = vec4(a_coords.xyz, 1.0);\n"
396 " return;\n"
397 "}\n", evalReturnAlways, DE_NULL));
398 // Return as a final statement in main()
399 addChild(new ShaderReturnCase(m_testCtx, "last_statement_in_main_fragment", false,
400 "#version 310 es\n"
401 "layout(location = 0) in mediump vec4 v_coords;\n"
402 "layout(location = 0) out mediump vec4 o_color;\n\n"
403 "void main (void)\n"
404 "{\n"
405 " o_color = vec4(v_coords.xyz, 1.0);\n"
406 " return;\n"
407 "}\n", evalReturnAlways, DE_NULL));
408
409 // Return between output variable writes.
410 for (int inFunc = 0; inFunc < 2; inFunc++)
411 {
412 for (int returnMode = 0; returnMode < RETURNMODE_LAST; returnMode++)
413 {
414 for (int isFragment = 0; isFragment < 2; isFragment++)
415 {
416 std::string name = std::string("output_write_") + (inFunc ? "in_func_" : "") + getReturnModeName((ReturnMode)returnMode) + (isFragment ? "_fragment" : "_vertex");
417 de::MovePtr<ShaderReturnCase> testCase = (makeOutputWriteReturnCase(m_testCtx, name, inFunc != 0, (ReturnMode)returnMode, isFragment == 0));
418 addChild(testCase.release());
419 }
420 }
421 }
422
423 // Conditional return statement in loop.
424 for (int isDynamicLoop = 0; isDynamicLoop < 2; isDynamicLoop++)
425 {
426 for (int returnMode = 0; returnMode < RETURNMODE_LAST; returnMode++)
427 {
428 for (int isFragment = 0; isFragment < 2; isFragment++)
429 {
430 std::string name = std::string("return_in_") + (isDynamicLoop ? "dynamic" : "static") + "_loop_" + getReturnModeName((ReturnMode)returnMode) + (isFragment ? "_fragment" : "_vertex");
431 de::MovePtr<ShaderReturnCase> testCase (makeReturnInLoopCase(m_testCtx, name, isDynamicLoop != 0, (ReturnMode)returnMode, isFragment == 0));
432 addChild(testCase.release());
433 }
434 }
435 }
436
437 // Unconditional return in infinite loop.
438 addChild(new ShaderReturnCase(m_testCtx, "return_in_infinite_loop_vertex", true,
439 "#version 310 es\n"
440 "layout(location = 0) in highp vec4 a_position;\n"
441 "layout(location = 1) in highp vec4 a_coords;\n"
442 "layout(location = 0) out mediump vec4 v_color;\n"
443 "layout(binding = 0, std140) uniform something { int ui_zero; };\n"
444 "highp vec4 getCoords (void)\n"
445 "{\n"
446 " for (int i = 1; i < 10; i += ui_zero)\n"
447 " return a_coords;\n"
448 " return a_coords.wzyx;\n"
449 "}\n\n"
450 "void main (void)\n"
451 "{\n"
452 " gl_Position = a_position;\n"
453 " v_color = vec4(getCoords().xyz, 1.0);\n"
454 " return;\n"
455 "}\n", evalReturnAlways, new ReturnTestUniformSetup(UI_ZERO)));
456 // Return in infinite loop
457 addChild(new ShaderReturnCase(m_testCtx, "return_in_infinite_loop_fragment", false,
458 "#version 310 es\n"
459 "layout(location = 0) in mediump vec4 v_coords;\n"
460 "layout(location = 0) out mediump vec4 o_color;\n"
461 "layout(binding = 0, std140) uniform something { int ui_zero; };\n\n"
462 "mediump vec4 getCoords (void)\n"
463 "{\n"
464 " for (int i = 1; i < 10; i += ui_zero)\n"
465 " return v_coords;\n"
466 " return v_coords.wzyx;\n"
467 "}\n\n"
468 "void main (void)\n"
469 "{\n"
470 " o_color = vec4(getCoords().xyz, 1.0);\n"
471 " return;\n"
472 "}\n", evalReturnAlways, new ReturnTestUniformSetup(UI_ZERO)));
473 }
474
475 } // anonymous
476
createReturnTests(tcu::TestContext & testCtx)477 tcu::TestCaseGroup* createReturnTests (tcu::TestContext& testCtx)
478 {
479 return new ShaderReturnTests(testCtx);
480 }
481
482 } // sr
483 } // vkt
484