• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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