Home | History | Annotate | Download | only in functional
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES 3.0 Module
      3  * -------------------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *      http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  *//*!
     20  * \file
     21  * \brief Shader return statement tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "es3fShaderReturnTests.hpp"
     25 #include "glsShaderRenderCase.hpp"
     26 #include "tcuStringTemplate.hpp"
     27 
     28 #include <map>
     29 #include <sstream>
     30 #include <string>
     31 
     32 using tcu::StringTemplate;
     33 
     34 using std::map;
     35 using std::string;
     36 using std::ostringstream;
     37 
     38 using namespace glu;
     39 using namespace deqp::gls;
     40 
     41 namespace deqp
     42 {
     43 namespace gles3
     44 {
     45 namespace Functional
     46 {
     47 
     48 enum ReturnMode
     49 {
     50 	RETURNMODE_ALWAYS = 0,
     51 	RETURNMODE_NEVER,
     52 	RETURNMODE_DYNAMIC,
     53 
     54 	RETURNMODE_LAST
     55 };
     56 
     57 // Evaluation functions
     58 inline void evalReturnAlways	(ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(0,1,2); }
     59 inline void evalReturnNever		(ShaderEvalContext& c) { c.color.xyz() = c.coords.swizzle(3,2,1); }
     60 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); }
     61 
     62 static ShaderEvalFunc getEvalFunc (ReturnMode mode)
     63 {
     64 	switch (mode)
     65 	{
     66 		case RETURNMODE_ALWAYS:		return evalReturnAlways;
     67 		case RETURNMODE_NEVER:		return evalReturnNever;
     68 		case RETURNMODE_DYNAMIC:	return evalReturnDynamic;
     69 		default:
     70 			DE_ASSERT(DE_FALSE);
     71 			return (ShaderEvalFunc)DE_NULL;
     72 	}
     73 }
     74 
     75 class ShaderReturnCase : public ShaderRenderCase
     76 {
     77 public:
     78 						ShaderReturnCase			(Context& context, const char* name, const char* description, bool isVertexCase, const char* shaderSource, ShaderEvalFunc evalFunc);
     79 	virtual				~ShaderReturnCase			(void);
     80 };
     81 
     82 ShaderReturnCase::ShaderReturnCase (Context& context, const char* name, const char* description, bool isVertexCase, const char* shaderSource, ShaderEvalFunc evalFunc)
     83 	: ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, description, isVertexCase, evalFunc)
     84 {
     85 	if (isVertexCase)
     86 	{
     87 		m_vertShaderSource = shaderSource;
     88 		m_fragShaderSource =
     89 			"#version 300 es\n"
     90 			"in mediump vec4 v_color;\n"
     91 			"layout(location = 0) out mediump vec4 o_color;\n\n"
     92 			"void main (void)\n"
     93 			"{\n"
     94 			"    o_color = v_color;\n"
     95 			"}\n";
     96 	}
     97 	else
     98 	{
     99 		m_fragShaderSource = shaderSource;
    100 		m_vertShaderSource =
    101 			"#version 300 es\n"
    102 			"in  highp   vec4 a_position;\n"
    103 			"in  highp   vec4 a_coords;\n"
    104 			"out mediump vec4 v_coords;\n\n"
    105 			"void main (void)\n"
    106 			"{\n"
    107 			"    gl_Position = a_position;\n"
    108 			"    v_coords = a_coords;\n"
    109 			"}\n";
    110 	}
    111 }
    112 
    113 ShaderReturnCase::~ShaderReturnCase (void)
    114 {
    115 }
    116 
    117 ShaderReturnTests::ShaderReturnTests (Context& context)
    118 	: TestCaseGroup(context, "return", "Return Statement Tests")
    119 {
    120 }
    121 
    122 ShaderReturnTests::~ShaderReturnTests (void)
    123 {
    124 }
    125 
    126 ShaderReturnCase* makeConditionalReturnInFuncCase (Context& context, const char* name, const char* description, ReturnMode returnMode, bool isVertex)
    127 {
    128 	// Template
    129 	StringTemplate tmpl(
    130 		"#version 300 es\n"
    131 		"in ${COORDPREC} vec4 ${COORDS};\n"
    132 		"${EXTRADECL}\n"
    133 		"${COORDPREC} vec4 getColor (void)\n"
    134 		"{\n"
    135 		"    if (${RETURNCOND})\n"
    136 		"        return vec4(${COORDS}.xyz, 1.0);\n"
    137 		"    return vec4(${COORDS}.wzy, 1.0);\n"
    138 		"}\n\n"
    139 		"void main (void)\n"
    140 		"{\n"
    141 		"${POSITIONWRITE}"
    142 		"    ${OUTPUT} = getColor();\n"
    143 		"}\n");
    144 
    145 	const char* coords = isVertex ? "a_coords" : "v_coords";
    146 
    147 	map<string, string> params;
    148 
    149 	params["COORDPREC"]		= isVertex ? "highp"		: "mediump";
    150 	params["OUTPUT"]		= isVertex ? "v_color"		: "o_color";
    151 	params["COORDS"]		= coords;
    152 	params["EXTRADECL"]		= isVertex ? "in highp vec4 a_position;\nout mediump vec4 v_color;\n" : "layout(location = 0) out mediump vec4 o_color;\n";
    153 	params["POSITIONWRITE"]	= isVertex ? "    gl_Position = a_position;\n" : "";
    154 
    155 	switch (returnMode)
    156 	{
    157 		case RETURNMODE_ALWAYS:		params["RETURNCOND"] = "true";											break;
    158 		case RETURNMODE_NEVER:		params["RETURNCOND"] = "false";											break;
    159 		case RETURNMODE_DYNAMIC:	params["RETURNCOND"] = string(coords) + ".x+" + coords + ".y >= 0.0";	break;
    160 		default:					DE_ASSERT(DE_FALSE);
    161 	}
    162 
    163 	return new ShaderReturnCase(context, name, description, isVertex, tmpl.specialize(params).c_str(), getEvalFunc(returnMode));
    164 }
    165 
    166 ShaderReturnCase* makeOutputWriteReturnCase (Context& context, const char* name, const char* description, bool inFunction, ReturnMode returnMode, bool isVertex)
    167 {
    168 	// Template
    169 	StringTemplate tmpl(
    170 		inFunction
    171 		?
    172 			"#version 300 es\n"
    173 			"in ${COORDPREC} vec4 ${COORDS};\n"
    174 			"${EXTRADECL}\n"
    175 			"void myfunc (void)\n"
    176 			"{\n"
    177 			"    ${OUTPUT} = vec4(${COORDS}.xyz, 1.0);\n"
    178 			"    if (${RETURNCOND})\n"
    179 			"        return;\n"
    180 			"    ${OUTPUT} = vec4(${COORDS}.wzy, 1.0);\n"
    181 			"}\n\n"
    182 			"void main (void)\n"
    183 			"{\n"
    184 			"${POSITIONWRITE}"
    185 			"    myfunc();\n"
    186 			"}\n"
    187 		:
    188 			"#version 300 es\n"
    189 			"in ${COORDPREC} vec4 ${COORDS};\n"
    190 			"uniform mediump int ui_one;\n"
    191 			"${EXTRADECL}\n"
    192 			"void main ()\n"
    193 			"{\n"
    194 			"${POSITIONWRITE}"
    195 			"    ${OUTPUT} = vec4(${COORDS}.xyz, 1.0);\n"
    196 			"    if (${RETURNCOND})\n"
    197 			"        return;\n"
    198 			"    ${OUTPUT} = vec4(${COORDS}.wzy, 1.0);\n"
    199 			"}\n");
    200 
    201 	const char* coords = isVertex ? "a_coords" : "v_coords";
    202 
    203 	map<string, string> params;
    204 
    205 	params["COORDPREC"]		= isVertex ? "highp"		: "mediump";
    206 	params["COORDS"]		= coords;
    207 	params["OUTPUT"]		= isVertex ? "v_color"			: "o_color";
    208 	params["EXTRADECL"]		= isVertex ? "in highp vec4 a_position;\nout mediump vec4 v_color;\n" : "layout(location = 0) out mediump vec4 o_color;\n";
    209 	params["POSITIONWRITE"]	= isVertex ? "    gl_Position = a_position;\n" : "";
    210 
    211 	switch (returnMode)
    212 	{
    213 		case RETURNMODE_ALWAYS:		params["RETURNCOND"] = "true";											break;
    214 		case RETURNMODE_NEVER:		params["RETURNCOND"] = "false";											break;
    215 		case RETURNMODE_DYNAMIC:	params["RETURNCOND"] = string(coords) + ".x+" + coords + ".y >= 0.0";	break;
    216 		default:					DE_ASSERT(DE_FALSE);
    217 	}
    218 
    219 	return new ShaderReturnCase(context, name, description, isVertex, tmpl.specialize(params).c_str(), getEvalFunc(returnMode));
    220 }
    221 
    222 ShaderReturnCase* makeReturnInLoopCase (Context& context, const char* name, const char* description, bool isDynamicLoop, ReturnMode returnMode, bool isVertex)
    223 {
    224 	// Template
    225 	StringTemplate tmpl(
    226 		"#version 300 es\n"
    227 		"in ${COORDPREC} vec4 ${COORDS};\n"
    228 		"uniform mediump int ui_one;\n"
    229 		"${EXTRADECL}\n"
    230 		"${COORDPREC} vec4 getCoords (void)\n"
    231 		"{\n"
    232 		"    ${COORDPREC} vec4 coords = ${COORDS};\n"
    233 		"    for (int i = 0; i < ${ITERLIMIT}; i++)\n"
    234 		"    {\n"
    235 		"        if (${RETURNCOND})\n"
    236 		"            return coords;\n"
    237 		"        coords = coords.wzyx;\n"
    238 		"    }\n"
    239 		"    return coords;\n"
    240 		"}\n\n"
    241 		"void main (void)\n"
    242 		"{\n"
    243 		"${POSITIONWRITE}"
    244 		"    ${OUTPUT} = vec4(getCoords().xyz, 1.0);\n"
    245 		"}\n");
    246 
    247 	const char* coords = isVertex ? "a_coords" : "v_coords";
    248 
    249 	map<string, string> params;
    250 
    251 	params["COORDPREC"]		= isVertex ? "highp"		: "mediump";
    252 	params["OUTPUT"]		= isVertex ? "v_color"		: "o_color";
    253 	params["COORDS"]		= coords;
    254 	params["EXTRADECL"]		= isVertex ? "in highp vec4 a_position;\nout mediump vec4 v_color;\n" : "layout(location = 0) out mediump vec4 o_color;\n";
    255 	params["POSITIONWRITE"]	= isVertex ? "    gl_Position = a_position;\n" : "";
    256 	params["ITERLIMIT"]		= isDynamicLoop ? "ui_one" : "1";
    257 
    258 	switch (returnMode)
    259 	{
    260 		case RETURNMODE_ALWAYS:		params["RETURNCOND"] = "true";											break;
    261 		case RETURNMODE_NEVER:		params["RETURNCOND"] = "false";											break;
    262 		case RETURNMODE_DYNAMIC:	params["RETURNCOND"] = string(coords) + ".x+" + coords + ".y >= 0.0";	break;
    263 		default:					DE_ASSERT(DE_FALSE);
    264 	}
    265 
    266 	return new ShaderReturnCase(context, name, description, isVertex, tmpl.specialize(params).c_str(), getEvalFunc(returnMode));
    267 }
    268 
    269 static const char* getReturnModeName (ReturnMode mode)
    270 {
    271 	switch (mode)
    272 	{
    273 		case RETURNMODE_ALWAYS:		return "always";
    274 		case RETURNMODE_NEVER:		return "never";
    275 		case RETURNMODE_DYNAMIC:	return "dynamic";
    276 		default:
    277 			DE_ASSERT(DE_FALSE);
    278 			return DE_NULL;
    279 	}
    280 }
    281 
    282 static const char* getReturnModeDesc (ReturnMode mode)
    283 {
    284 	switch (mode)
    285 	{
    286 		case RETURNMODE_ALWAYS:		return "Always return";
    287 		case RETURNMODE_NEVER:		return "Never return";
    288 		case RETURNMODE_DYNAMIC:	return "Return based on coords";
    289 		default:
    290 			DE_ASSERT(DE_FALSE);
    291 			return DE_NULL;
    292 	}
    293 }
    294 
    295 void ShaderReturnTests::init (void)
    296 {
    297 	// Single return statement in function.
    298 	addChild(new ShaderReturnCase(m_context, "single_return_vertex", "Single return statement in function", true,
    299 		"#version 300 es\n"
    300 		"in highp vec4 a_position;\n"
    301 		"in highp vec4 a_coords;\n"
    302 		"out highp vec4 v_color;\n\n"
    303 		"vec4 getColor (void)\n"
    304 		"{\n"
    305 		"    return vec4(a_coords.xyz, 1.0);\n"
    306 		"}\n\n"
    307 		"void main (void)\n"
    308 		"{\n"
    309 		"    gl_Position = a_position;\n"
    310 		"    v_color = getColor();\n"
    311 		"}\n", evalReturnAlways));
    312 	addChild(new ShaderReturnCase(m_context, "single_return_fragment", "Single return statement in function", false,
    313 		"#version 300 es\n"
    314 		"in mediump vec4 v_coords;\n"
    315 		"layout(location = 0) out mediump vec4 o_color;\n"
    316 		"mediump vec4 getColor (void)\n"
    317 		"{\n"
    318 		"    return vec4(v_coords.xyz, 1.0);\n"
    319 		"}\n\n"
    320 		"void main (void)\n"
    321 		"{\n"
    322 		"    o_color = getColor();\n"
    323 		"}\n", evalReturnAlways));
    324 
    325 	// Conditional return statement in function.
    326 	for (int returnMode = 0; returnMode < RETURNMODE_LAST; returnMode++)
    327 	{
    328 		for (int isFragment = 0; isFragment < 2; isFragment++)
    329 		{
    330 			string name			= string("conditional_return_") + getReturnModeName((ReturnMode)returnMode) + (isFragment ? "_fragment" : "_vertex");
    331 			string description	= string(getReturnModeDesc((ReturnMode)returnMode)) + " in function";
    332 			addChild(makeConditionalReturnInFuncCase(m_context, name.c_str(), description.c_str(), (ReturnMode)returnMode, isFragment == 0));
    333 		}
    334 	}
    335 
    336 	// Unconditional double return in function.
    337 	addChild(new ShaderReturnCase(m_context, "double_return_vertex", "Unconditional double return in function", true,
    338 		"#version 300 es\n"
    339 		"in highp vec4 a_position;\n"
    340 		"in highp vec4 a_coords;\n"
    341 		"out highp vec4 v_color;\n\n"
    342 		"vec4 getColor (void)\n"
    343 		"{\n"
    344 		"    return vec4(a_coords.xyz, 1.0);\n"
    345 		"    return vec4(a_coords.wzy, 1.0);\n"
    346 		"}\n\n"
    347 		"void main (void)\n"
    348 		"{\n"
    349 		"    gl_Position = a_position;\n"
    350 		"    v_color = getColor();\n"
    351 		"}\n", evalReturnAlways));
    352 	addChild(new ShaderReturnCase(m_context, "double_return_fragment", "Unconditional double return in function", false,
    353 		"#version 300 es\n"
    354 		"in mediump vec4 v_coords;\n"
    355 		"layout(location = 0) out mediump vec4 o_color;\n\n"
    356 		"mediump vec4 getColor (void)\n"
    357 		"{\n"
    358 		"    return vec4(v_coords.xyz, 1.0);\n"
    359 		"    return vec4(v_coords.wzy, 1.0);\n"
    360 		"}\n\n"
    361 		"void main (void)\n"
    362 		"{\n"
    363 		"    o_color = getColor();\n"
    364 		"}\n", evalReturnAlways));
    365 
    366 	// Last statement in main.
    367 	addChild(new ShaderReturnCase(m_context, "last_statement_in_main_vertex", "Return as a final statement in main()", true,
    368 		"#version 300 es\n"
    369 		"in highp vec4 a_position;\n"
    370 		"in highp vec4 a_coords;\n"
    371 		"out highp vec4 v_color;\n\n"
    372 		"void main (void)\n"
    373 		"{\n"
    374 		"    gl_Position = a_position;\n"
    375 		"    v_color = vec4(a_coords.xyz, 1.0);\n"
    376 		"    return;\n"
    377 		"}\n", evalReturnAlways));
    378 	addChild(new ShaderReturnCase(m_context, "last_statement_in_main_fragment", "Return as a final statement in main()", false,
    379 		"#version 300 es\n"
    380 		"in mediump vec4 v_coords;\n"
    381 		"layout(location = 0) out mediump vec4 o_color;\n\n"
    382 		"void main (void)\n"
    383 		"{\n"
    384 		"    o_color = vec4(v_coords.xyz, 1.0);\n"
    385 		"    return;\n"
    386 		"}\n", evalReturnAlways));
    387 
    388 	// Return between output variable writes.
    389 	for (int inFunc = 0; inFunc < 2; inFunc++)
    390 	{
    391 		for (int returnMode = 0; returnMode < RETURNMODE_LAST; returnMode++)
    392 		{
    393 			for (int isFragment = 0; isFragment < 2; isFragment++)
    394 			{
    395 				string name = string("output_write_") + (inFunc ? "in_func_" : "") + getReturnModeName((ReturnMode)returnMode) + (isFragment ? "_fragment" : "_vertex");
    396 				string desc = string(getReturnModeDesc((ReturnMode)returnMode)) + (inFunc ? " in user-defined function" : " in main()") + " between output writes";
    397 
    398 				addChild(makeOutputWriteReturnCase(m_context, name.c_str(), desc.c_str(), inFunc != 0, (ReturnMode)returnMode, isFragment == 0));
    399 			}
    400 		}
    401 	}
    402 
    403 	// Conditional return statement in loop.
    404 	for (int isDynamicLoop = 0; isDynamicLoop < 2; isDynamicLoop++)
    405 	{
    406 		for (int returnMode = 0; returnMode < RETURNMODE_LAST; returnMode++)
    407 		{
    408 			for (int isFragment = 0; isFragment < 2; isFragment++)
    409 			{
    410 				string name			= string("return_in_") + (isDynamicLoop ? "dynamic" : "static") + "_loop_" + getReturnModeName((ReturnMode)returnMode) + (isFragment ? "_fragment" : "_vertex");
    411 				string description	= string(getReturnModeDesc((ReturnMode)returnMode)) + " in loop";
    412 				addChild(makeReturnInLoopCase(m_context, name.c_str(), description.c_str(), isDynamicLoop != 0, (ReturnMode)returnMode, isFragment == 0));
    413 			}
    414 		}
    415 	}
    416 
    417 	// Unconditional return in infinite loop.
    418 	addChild(new ShaderReturnCase(m_context, "return_in_infinite_loop_vertex", "Return in infinite loop", true,
    419 		"#version 300 es\n"
    420 		"in highp vec4 a_position;\n"
    421 		"in highp vec4 a_coords;\n"
    422 		"out highp vec4 v_color;\n"
    423 		"uniform int ui_zero;\n\n"
    424 		"highp vec4 getCoords (void)\n"
    425 		"{\n"
    426 		"	for (int i = 1; i < 10; i += ui_zero)\n"
    427 		"		return a_coords;\n"
    428 		"	return a_coords.wzyx;\n"
    429 		"}\n\n"
    430 		"void main (void)\n"
    431 		"{\n"
    432 		"    gl_Position = a_position;\n"
    433 		"    v_color = vec4(getCoords().xyz, 1.0);\n"
    434 		"    return;\n"
    435 		"}\n", evalReturnAlways));
    436 	addChild(new ShaderReturnCase(m_context, "return_in_infinite_loop_fragment", "Return in infinite loop", false,
    437 		"#version 300 es\n"
    438 		"in mediump vec4 v_coords;\n"
    439 		"layout(location = 0) out mediump vec4 o_color;\n"
    440 		"uniform int ui_zero;\n\n"
    441 		"mediump vec4 getCoords (void)\n"
    442 		"{\n"
    443 		"	for (int i = 1; i < 10; i += ui_zero)\n"
    444 		"		return v_coords;\n"
    445 		"	return v_coords.wzyx;\n"
    446 		"}\n\n"
    447 		"void main (void)\n"
    448 		"{\n"
    449 		"    o_color = vec4(getCoords().xyz, 1.0);\n"
    450 		"    return;\n"
    451 		"}\n", evalReturnAlways));
    452 }
    453 
    454 } // Functional
    455 } // gles3
    456 } // deqp
    457