Home | History | Annotate | Download | only in common
      1 /*-------------------------------------------------------------------------
      2  * OpenGL Conformance Test Suite
      3  * -----------------------------
      4  *
      5  * Copyright (c) 2016 Google Inc.
      6  * Copyright (c) 2016 The Khronos Group Inc.
      7  *
      8  * Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *      http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  *
     20  */ /*!
     21  * \file
     22  * \brief Shader struct tests.
     23  */ /*-------------------------------------------------------------------*/
     24 
     25 #include "glcShaderStructTests.hpp"
     26 #include "glcShaderRenderCase.hpp"
     27 #include "gluTexture.hpp"
     28 #include "glwEnums.hpp"
     29 #include "glwFunctions.hpp"
     30 #include "tcuStringTemplate.hpp"
     31 #include "tcuTextureUtil.hpp"
     32 
     33 using tcu::StringTemplate;
     34 
     35 using std::string;
     36 using std::vector;
     37 using std::ostringstream;
     38 
     39 using namespace glu;
     40 
     41 namespace deqp
     42 {
     43 
     44 enum
     45 {
     46 	TEXTURE_GRADIENT = 0 //!< Unit index for gradient texture
     47 };
     48 
     49 typedef void (*SetupUniformsFunc)(const glw::Functions& gl, deUint32 programID, const tcu::Vec4& constCoords);
     50 
     51 class ShaderStructCase : public ShaderRenderCase
     52 {
     53 public:
     54 	ShaderStructCase(Context& context, const char* name, const char* description, bool isVertexCase, bool usesTextures,
     55 					 ShaderEvalFunc evalFunc, SetupUniformsFunc setupUniformsFunc, const char* vertShaderSource,
     56 					 const char* fragShaderSource);
     57 	~ShaderStructCase(void);
     58 
     59 	void init(void);
     60 	void deinit(void);
     61 
     62 	virtual void setupUniforms(deUint32 programID, const tcu::Vec4& constCoords);
     63 
     64 private:
     65 	ShaderStructCase(const ShaderStructCase&);
     66 	ShaderStructCase& operator=(const ShaderStructCase&);
     67 
     68 	SetupUniformsFunc m_setupUniforms;
     69 	bool			  m_usesTexture;
     70 
     71 	glu::Texture2D* m_gradientTexture;
     72 };
     73 
     74 ShaderStructCase::ShaderStructCase(Context& context, const char* name, const char* description, bool isVertexCase,
     75 								   bool usesTextures, ShaderEvalFunc evalFunc, SetupUniformsFunc setupUniformsFunc,
     76 								   const char* vertShaderSource, const char* fragShaderSource)
     77 	: ShaderRenderCase(context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name,
     78 					   description, isVertexCase, evalFunc)
     79 	, m_setupUniforms(setupUniformsFunc)
     80 	, m_usesTexture(usesTextures)
     81 	, m_gradientTexture(DE_NULL)
     82 {
     83 	m_vertShaderSource = vertShaderSource;
     84 	m_fragShaderSource = fragShaderSource;
     85 }
     86 
     87 ShaderStructCase::~ShaderStructCase(void)
     88 {
     89 }
     90 
     91 void ShaderStructCase::init(void)
     92 {
     93 	if (m_usesTexture)
     94 	{
     95 		m_gradientTexture = new glu::Texture2D(m_renderCtx, GL_RGBA8, 128, 128);
     96 
     97 		m_gradientTexture->getRefTexture().allocLevel(0);
     98 		tcu::fillWithComponentGradients(m_gradientTexture->getRefTexture().getLevel(0), tcu::Vec4(0.0f),
     99 										tcu::Vec4(1.0f));
    100 		m_gradientTexture->upload();
    101 
    102 		m_textures.push_back(TextureBinding(
    103 			m_gradientTexture, tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
    104 											tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR)));
    105 		DE_ASSERT(m_textures.size() == 1);
    106 	}
    107 	ShaderRenderCase::init();
    108 }
    109 
    110 void ShaderStructCase::deinit(void)
    111 {
    112 	if (m_usesTexture)
    113 	{
    114 		delete m_gradientTexture;
    115 	}
    116 	ShaderRenderCase::deinit();
    117 }
    118 
    119 void ShaderStructCase::setupUniforms(deUint32 programID, const tcu::Vec4& constCoords)
    120 {
    121 	ShaderRenderCase::setupUniforms(programID, constCoords);
    122 	if (m_setupUniforms)
    123 		m_setupUniforms(m_renderCtx.getFunctions(), programID, constCoords);
    124 }
    125 
    126 static ShaderStructCase* createStructCase(Context& context, const char* name, const char* description,
    127 										  glu::GLSLVersion glslVersion, bool isVertexCase, bool usesTextures,
    128 										  ShaderEvalFunc evalFunc, SetupUniformsFunc setupUniforms,
    129 										  const LineStream& shaderSrc)
    130 {
    131 	const std::string versionDecl = glu::getGLSLVersionDeclaration(glslVersion);
    132 
    133 	const std::string defaultVertSrc = versionDecl + "\n"
    134 													 "in highp vec4 a_position;\n"
    135 													 "in highp vec4 a_coords;\n"
    136 													 "out mediump vec4 v_coords;\n\n"
    137 													 "void main (void)\n"
    138 													 "{\n"
    139 													 "   v_coords = a_coords;\n"
    140 													 "   gl_Position = a_position;\n"
    141 													 "}\n";
    142 	const std::string defaultFragSrc = versionDecl + "\n"
    143 													 "in mediump vec4 v_color;\n"
    144 													 "layout(location = 0) out mediump vec4 o_color;\n\n"
    145 													 "void main (void)\n"
    146 													 "{\n"
    147 													 "   o_color = v_color;\n"
    148 													 "}\n";
    149 
    150 	// Fill in specialization parameters.
    151 	std::map<std::string, std::string> spParams;
    152 	if (isVertexCase)
    153 	{
    154 		spParams["HEADER"] = versionDecl + "\n"
    155 										   "in highp vec4 a_position;\n"
    156 										   "in highp vec4 a_coords;\n"
    157 										   "out mediump vec4 v_color;";
    158 		spParams["COORDS"]	 = "a_coords";
    159 		spParams["DST"]		   = "v_color";
    160 		spParams["ASSIGN_POS"] = "gl_Position = a_position;";
    161 	}
    162 	else
    163 	{
    164 		spParams["HEADER"] = versionDecl + "\n"
    165 										   "in mediump vec4 v_coords;\n"
    166 										   "layout(location = 0) out mediump vec4 o_color;";
    167 		spParams["COORDS"]	 = "v_coords";
    168 		spParams["DST"]		   = "o_color";
    169 		spParams["ASSIGN_POS"] = "";
    170 	}
    171 
    172 	if (isVertexCase)
    173 		return new ShaderStructCase(context, name, description, isVertexCase, usesTextures, evalFunc, setupUniforms,
    174 									StringTemplate(shaderSrc.str()).specialize(spParams).c_str(),
    175 									defaultFragSrc.c_str());
    176 	else
    177 		return new ShaderStructCase(context, name, description, isVertexCase, usesTextures, evalFunc, setupUniforms,
    178 									defaultVertSrc.c_str(),
    179 									StringTemplate(shaderSrc.str()).specialize(spParams).c_str());
    180 }
    181 
    182 class LocalStructTests : public TestCaseGroup
    183 {
    184 public:
    185 	LocalStructTests(Context& context, glu::GLSLVersion glslVersion)
    186 		: TestCaseGroup(context, "local", "Local structs"), m_glslVersion(glslVersion)
    187 	{
    188 	}
    189 
    190 	~LocalStructTests(void)
    191 	{
    192 	}
    193 
    194 	virtual void init(void);
    195 
    196 private:
    197 	glu::GLSLVersion m_glslVersion;
    198 };
    199 
    200 void LocalStructTests::init(void)
    201 {
    202 #define LOCAL_STRUCT_CASE(NAME, DESCRIPTION, SHADER_SRC, EVAL_FUNC_BODY)                                  \
    203 	do                                                                                                    \
    204 	{                                                                                                     \
    205 		struct Eval_##NAME                                                                                \
    206 		{                                                                                                 \
    207 			static void eval(ShaderEvalContext& c) EVAL_FUNC_BODY                                         \
    208 		};                                                                                                \
    209 		addChild(createStructCase(m_context, #NAME "_vertex", DESCRIPTION, m_glslVersion, true, false,    \
    210 								  &Eval_##NAME::eval, DE_NULL, SHADER_SRC));                              \
    211 		addChild(createStructCase(m_context, #NAME "_fragment", DESCRIPTION, m_glslVersion, false, false, \
    212 								  &Eval_##NAME::eval, DE_NULL, SHADER_SRC));                              \
    213 	} while (deGetFalse())
    214 
    215 	LOCAL_STRUCT_CASE(basic, "Basic struct usage",
    216 					  LineStream() << "${HEADER}"
    217 								   << "uniform int ui_one;"
    218 								   << ""
    219 								   << "struct S {"
    220 								   << "    mediump float   a;"
    221 								   << "    mediump vec3    b;"
    222 								   << "    int             c;"
    223 								   << "};"
    224 								   << ""
    225 								   << "void main (void)"
    226 								   << "{"
    227 								   << "    S s = S(${COORDS}.x, vec3(0.0), ui_one);"
    228 								   << "    s.b = ${COORDS}.yzw;"
    229 								   << "    ${DST} = vec4(s.a, s.b.x, s.b.y, s.c);"
    230 								   << "    ${ASSIGN_POS}"
    231 								   << "}",
    232 					  { c.color.xyz() = c.coords.swizzle(0, 1, 2); });
    233 
    234 	LOCAL_STRUCT_CASE(nested, "Nested struct",
    235 					  LineStream() << "${HEADER}"
    236 								   << "uniform int ui_zero;"
    237 								   << "uniform int ui_one;"
    238 								   << ""
    239 								   << "struct T {"
    240 								   << "    int             a;"
    241 								   << "    mediump vec2    b;"
    242 								   << "};"
    243 								   << "struct S {"
    244 								   << "    mediump float   a;"
    245 								   << "    T               b;"
    246 								   << "    int             c;"
    247 								   << "};"
    248 								   << ""
    249 								   << "void main (void)"
    250 								   << "{"
    251 								   << "    S s = S(${COORDS}.x, T(0, vec2(0.0)), ui_one);"
    252 								   << "    s.b = T(ui_zero, ${COORDS}.yz);"
    253 								   << "    ${DST} = vec4(s.a, s.b.b, s.b.a + s.c);"
    254 								   << "    ${ASSIGN_POS}"
    255 								   << "}",
    256 					  { c.color.xyz() = c.coords.swizzle(0, 1, 2); });
    257 
    258 	LOCAL_STRUCT_CASE(array_member, "Struct with array member",
    259 					  LineStream() << "${HEADER}"
    260 								   << "uniform int ui_one;"
    261 								   << ""
    262 								   << "struct S {"
    263 								   << "    mediump float   a;"
    264 								   << "    mediump float   b[3];"
    265 								   << "    int             c;"
    266 								   << "};"
    267 								   << ""
    268 								   << "void main (void)"
    269 								   << "{"
    270 								   << "    S s;"
    271 								   << "    s.a = ${COORDS}.w;"
    272 								   << "    s.c = ui_one;"
    273 								   << "    s.b[0] = ${COORDS}.z;"
    274 								   << "    s.b[1] = ${COORDS}.y;"
    275 								   << "    s.b[2] = ${COORDS}.x;"
    276 								   << "    ${DST} = vec4(s.a, s.b[0], s.b[1], s.c);"
    277 								   << "    ${ASSIGN_POS}"
    278 								   << "}",
    279 					  { c.color.xyz() = c.coords.swizzle(3, 2, 1); });
    280 
    281 	LOCAL_STRUCT_CASE(array_member_dynamic_index, "Struct with array member, dynamic indexing",
    282 					  LineStream() << "${HEADER}"
    283 								   << "uniform int ui_zero;"
    284 								   << "uniform int ui_one;"
    285 								   << "uniform int ui_two;"
    286 								   << ""
    287 								   << "struct S {"
    288 								   << "    mediump float   a;"
    289 								   << "    mediump float   b[3];"
    290 								   << "    int             c;"
    291 								   << "};"
    292 								   << ""
    293 								   << "void main (void)"
    294 								   << "{"
    295 								   << "    S s;"
    296 								   << "    s.a = ${COORDS}.w;"
    297 								   << "    s.c = ui_one;"
    298 								   << "    s.b[0] = ${COORDS}.z;"
    299 								   << "    s.b[1] = ${COORDS}.y;"
    300 								   << "    s.b[2] = ${COORDS}.x;"
    301 								   << "    ${DST} = vec4(s.b[ui_one], s.b[ui_zero], s.b[ui_two], s.c);"
    302 								   << "    ${ASSIGN_POS}"
    303 								   << "}",
    304 					  { c.color.xyz() = c.coords.swizzle(1, 2, 0); });
    305 
    306 	LOCAL_STRUCT_CASE(struct_array, "Struct array",
    307 					  LineStream() << "${HEADER}"
    308 								   << "uniform int ui_zero;"
    309 								   << "uniform int ui_one;"
    310 								   << "uniform int ui_two;"
    311 								   << ""
    312 								   << "struct S {"
    313 								   << "    mediump float   a;"
    314 								   << "    mediump int     b;"
    315 								   << "};"
    316 								   << ""
    317 								   << "void main (void)"
    318 								   << "{"
    319 								   << "    S s[3];"
    320 								   << "    s[0] = S(${COORDS}.x, ui_zero);"
    321 								   << "    s[1].a = ${COORDS}.y;"
    322 								   << "    s[1].b = ui_one;"
    323 								   << "    s[2] = S(${COORDS}.z, ui_two);"
    324 								   << "    ${DST} = vec4(s[2].a, s[1].a, s[0].a, s[2].b - s[1].b + s[0].b);"
    325 								   << "    ${ASSIGN_POS}"
    326 								   << "}",
    327 					  { c.color.xyz() = c.coords.swizzle(2, 1, 0); });
    328 
    329 	LOCAL_STRUCT_CASE(
    330 		struct_array_dynamic_index, "Struct array with dynamic indexing",
    331 		LineStream()
    332 			<< "${HEADER}"
    333 			<< "uniform int ui_zero;"
    334 			<< "uniform int ui_one;"
    335 			<< "uniform int ui_two;"
    336 			<< ""
    337 			<< "struct S {"
    338 			<< "    mediump float   a;"
    339 			<< "    mediump int     b;"
    340 			<< "};"
    341 			<< ""
    342 			<< "void main (void)"
    343 			<< "{"
    344 			<< "    S s[3];"
    345 			<< "    s[0] = S(${COORDS}.x, ui_zero);"
    346 			<< "    s[1].a = ${COORDS}.y;"
    347 			<< "    s[1].b = ui_one;"
    348 			<< "    s[2] = S(${COORDS}.z, ui_two);"
    349 			<< "    ${DST} = vec4(s[ui_two].a, s[ui_one].a, s[ui_zero].a, s[ui_two].b - s[ui_one].b + s[ui_zero].b);"
    350 			<< "    ${ASSIGN_POS}"
    351 			<< "}",
    352 		{ c.color.xyz() = c.coords.swizzle(2, 1, 0); });
    353 
    354 	LOCAL_STRUCT_CASE(
    355 		nested_struct_array, "Nested struct array",
    356 		LineStream() << "${HEADER}"
    357 					 << "uniform int ui_zero;"
    358 					 << "uniform int ui_one;"
    359 					 << "uniform int ui_two;"
    360 					 << "uniform mediump float uf_two;"
    361 					 << "uniform mediump float uf_three;"
    362 					 << "uniform mediump float uf_four;"
    363 					 << "uniform mediump float uf_half;"
    364 					 << "uniform mediump float uf_third;"
    365 					 << "uniform mediump float uf_fourth;"
    366 					 << ""
    367 					 << "struct T {"
    368 					 << "    mediump float   a;"
    369 					 << "    mediump vec2    b[2];"
    370 					 << "};"
    371 					 << "struct S {"
    372 					 << "    mediump float   a;"
    373 					 << "    T               b[3];"
    374 					 << "    int             c;"
    375 					 << "};"
    376 					 << ""
    377 					 << "void main (void)"
    378 					 << "{"
    379 					 << "    S s[2];"
    380 					 << ""
    381 					 << "    // S[0]"
    382 					 << "    s[0].a         = ${COORDS}.x;"
    383 					 << "    s[0].b[0].a    = uf_half;"
    384 					 << "    s[0].b[0].b[0] = ${COORDS}.xy;"
    385 					 << "    s[0].b[0].b[1] = ${COORDS}.zw;"
    386 					 << "    s[0].b[1].a    = uf_third;"
    387 					 << "    s[0].b[1].b[0] = ${COORDS}.zw;"
    388 					 << "    s[0].b[1].b[1] = ${COORDS}.xy;"
    389 					 << "    s[0].b[2].a    = uf_fourth;"
    390 					 << "    s[0].b[2].b[0] = ${COORDS}.xz;"
    391 					 << "    s[0].b[2].b[1] = ${COORDS}.yw;"
    392 					 << "    s[0].c         = ui_zero;"
    393 					 << ""
    394 					 << "    // S[1]"
    395 					 << "    s[1].a         = ${COORDS}.w;"
    396 					 << "    s[1].b[0].a    = uf_two;"
    397 					 << "    s[1].b[0].b[0] = ${COORDS}.xx;"
    398 					 << "    s[1].b[0].b[1] = ${COORDS}.yy;"
    399 					 << "    s[1].b[1].a    = uf_three;"
    400 					 << "    s[1].b[1].b[0] = ${COORDS}.zz;"
    401 					 << "    s[1].b[1].b[1] = ${COORDS}.ww;"
    402 					 << "    s[1].b[2].a    = uf_four;"
    403 					 << "    s[1].b[2].b[0] = ${COORDS}.yx;"
    404 					 << "    s[1].b[2].b[1] = ${COORDS}.wz;"
    405 					 << "    s[1].c         = ui_one;"
    406 					 << ""
    407 					 << "    mediump float r = (s[0].b[1].b[0].x + s[1].b[2].b[1].y) * s[0].b[0].a; // (z + z) * 0.5"
    408 					 << "    mediump float g = s[1].b[0].b[0].y * s[0].b[2].a * s[1].b[2].a; // x * 0.25 * 4"
    409 					 << "    mediump float b = (s[0].b[2].b[1].y + s[0].b[1].b[0].y + s[1].a) * s[0].b[1].a; // (w + w "
    410 						"+ w) * 0.333"
    411 					 << "    mediump float a = float(s[0].c) + s[1].b[2].a - s[1].b[1].a; // 0 + 4.0 - 3.0"
    412 					 << "    ${DST} = vec4(r, g, b, a);"
    413 					 << "    ${ASSIGN_POS}"
    414 					 << "}",
    415 		{ c.color.xyz() = c.coords.swizzle(2, 0, 3); });
    416 
    417 	LOCAL_STRUCT_CASE(nested_struct_array_dynamic_index, "Nested struct array with dynamic indexing",
    418 					  LineStream() << "${HEADER}"
    419 								   << "uniform int ui_zero;"
    420 								   << "uniform int ui_one;"
    421 								   << "uniform int ui_two;"
    422 								   << "uniform mediump float uf_two;"
    423 								   << "uniform mediump float uf_three;"
    424 								   << "uniform mediump float uf_four;"
    425 								   << "uniform mediump float uf_half;"
    426 								   << "uniform mediump float uf_third;"
    427 								   << "uniform mediump float uf_fourth;"
    428 								   << ""
    429 								   << "struct T {"
    430 								   << "    mediump float   a;"
    431 								   << "    mediump vec2    b[2];"
    432 								   << "};"
    433 								   << "struct S {"
    434 								   << "    mediump float   a;"
    435 								   << "    T               b[3];"
    436 								   << "    int             c;"
    437 								   << "};"
    438 								   << ""
    439 								   << "void main (void)"
    440 								   << "{"
    441 								   << "    S s[2];"
    442 								   << ""
    443 								   << "    // S[0]"
    444 								   << "    s[0].a         = ${COORDS}.x;"
    445 								   << "    s[0].b[0].a    = uf_half;"
    446 								   << "    s[0].b[0].b[0] = ${COORDS}.xy;"
    447 								   << "    s[0].b[0].b[1] = ${COORDS}.zw;"
    448 								   << "    s[0].b[1].a    = uf_third;"
    449 								   << "    s[0].b[1].b[0] = ${COORDS}.zw;"
    450 								   << "    s[0].b[1].b[1] = ${COORDS}.xy;"
    451 								   << "    s[0].b[2].a    = uf_fourth;"
    452 								   << "    s[0].b[2].b[0] = ${COORDS}.xz;"
    453 								   << "    s[0].b[2].b[1] = ${COORDS}.yw;"
    454 								   << "    s[0].c         = ui_zero;"
    455 								   << ""
    456 								   << "    // S[1]"
    457 								   << "    s[1].a         = ${COORDS}.w;"
    458 								   << "    s[1].b[0].a    = uf_two;"
    459 								   << "    s[1].b[0].b[0] = ${COORDS}.xx;"
    460 								   << "    s[1].b[0].b[1] = ${COORDS}.yy;"
    461 								   << "    s[1].b[1].a    = uf_three;"
    462 								   << "    s[1].b[1].b[0] = ${COORDS}.zz;"
    463 								   << "    s[1].b[1].b[1] = ${COORDS}.ww;"
    464 								   << "    s[1].b[2].a    = uf_four;"
    465 								   << "    s[1].b[2].b[0] = ${COORDS}.yx;"
    466 								   << "    s[1].b[2].b[1] = ${COORDS}.wz;"
    467 								   << "    s[1].c         = ui_one;"
    468 								   << ""
    469 								   << "    mediump float r = (s[0].b[ui_one].b[ui_one-1].x + "
    470 									  "s[ui_one].b[ui_two].b[ui_zero+1].y) * s[0].b[0].a; // (z + z) * 0.5"
    471 								   << "    mediump float g = s[ui_two-1].b[ui_two-2].b[ui_zero].y * s[0].b[ui_two].a * "
    472 									  "s[ui_one].b[2].a; // x * 0.25 * 4"
    473 								   << "    mediump float b = (s[ui_zero].b[ui_one+1].b[1].y + "
    474 									  "s[0].b[ui_one*ui_one].b[0].y + s[ui_one].a) * s[0].b[ui_two-ui_one].a; // (w + "
    475 									  "w + w) * 0.333"
    476 								   << "    mediump float a = float(s[ui_zero].c) + s[ui_one-ui_zero].b[ui_two].a - "
    477 									  "s[ui_zero+ui_one].b[ui_two-ui_one].a; // 0 + 4.0 - 3.0"
    478 								   << "    ${DST} = vec4(r, g, b, a);"
    479 								   << "    ${ASSIGN_POS}"
    480 								   << "}",
    481 					  { c.color.xyz() = c.coords.swizzle(2, 0, 3); });
    482 
    483 	LOCAL_STRUCT_CASE(parameter, "Struct as a function parameter",
    484 					  LineStream() << "${HEADER}"
    485 								   << "uniform int ui_one;"
    486 								   << ""
    487 								   << "struct S {"
    488 								   << "    mediump float   a;"
    489 								   << "    mediump vec3    b;"
    490 								   << "    int             c;"
    491 								   << "};"
    492 								   << ""
    493 								   << "mediump vec4 myFunc (S s)"
    494 								   << "{"
    495 								   << "    return vec4(s.a, s.b.x, s.b.y, s.c);"
    496 								   << "}"
    497 								   << ""
    498 								   << "void main (void)"
    499 								   << "{"
    500 								   << "    S s = S(${COORDS}.x, vec3(0.0), ui_one);"
    501 								   << "    s.b = ${COORDS}.yzw;"
    502 								   << "    ${DST} = myFunc(s);"
    503 								   << "    ${ASSIGN_POS}"
    504 								   << "}",
    505 					  { c.color.xyz() = c.coords.swizzle(0, 1, 2); });
    506 
    507 	LOCAL_STRUCT_CASE(parameter_nested, "Nested struct as a function parameter",
    508 					  LineStream() << "${HEADER}"
    509 								   << "uniform int ui_zero;"
    510 								   << "uniform int ui_one;"
    511 								   << ""
    512 								   << "struct T {"
    513 								   << "    int             a;"
    514 								   << "    mediump vec2    b;"
    515 								   << "};"
    516 								   << "struct S {"
    517 								   << "    mediump float   a;"
    518 								   << "    T               b;"
    519 								   << "    int             c;"
    520 								   << "};"
    521 								   << ""
    522 								   << "mediump vec4 myFunc (S s)"
    523 								   << "{"
    524 								   << "    return vec4(s.a, s.b.b, s.b.a + s.c);"
    525 								   << "}"
    526 								   << ""
    527 								   << "void main (void)"
    528 								   << "{"
    529 								   << "    S s = S(${COORDS}.x, T(0, vec2(0.0)), ui_one);"
    530 								   << "    s.b = T(ui_zero, ${COORDS}.yz);"
    531 								   << "    ${DST} = myFunc(s);"
    532 								   << "    ${ASSIGN_POS}"
    533 								   << "}",
    534 					  { c.color.xyz() = c.coords.swizzle(0, 1, 2); });
    535 
    536 	LOCAL_STRUCT_CASE(return, "Struct as a return value",
    537 							LineStream() << "${HEADER}"
    538 										 << "uniform int ui_one;"
    539 										 << ""
    540 										 << "struct S {"
    541 										 << "    mediump float   a;"
    542 										 << "    mediump vec3    b;"
    543 										 << "    int             c;"
    544 										 << "};"
    545 										 << ""
    546 										 << "S myFunc (void)"
    547 										 << "{"
    548 										 << "    S s = S(${COORDS}.x, vec3(0.0), ui_one);"
    549 										 << "    s.b = ${COORDS}.yzw;"
    550 										 << "    return s;"
    551 										 << "}"
    552 										 << ""
    553 										 << "void main (void)"
    554 										 << "{"
    555 										 << "    S s = myFunc();"
    556 										 << "    ${DST} = vec4(s.a, s.b.x, s.b.y, s.c);"
    557 										 << "    ${ASSIGN_POS}"
    558 										 << "}",
    559 							{ c.color.xyz() = c.coords.swizzle(0, 1, 2); });
    560 
    561 	LOCAL_STRUCT_CASE(return_nested, "Nested struct",
    562 					  LineStream() << "${HEADER}"
    563 								   << "uniform int ui_zero;"
    564 								   << "uniform int ui_one;"
    565 								   << ""
    566 								   << "struct T {"
    567 								   << "    int             a;"
    568 								   << "    mediump vec2    b;"
    569 								   << "};"
    570 								   << "struct S {"
    571 								   << "    mediump float   a;"
    572 								   << "    T               b;"
    573 								   << "    int             c;"
    574 								   << "};"
    575 								   << ""
    576 								   << "S myFunc (void)"
    577 								   << "{"
    578 								   << "    S s = S(${COORDS}.x, T(0, vec2(0.0)), ui_one);"
    579 								   << "    s.b = T(ui_zero, ${COORDS}.yz);"
    580 								   << "    return s;"
    581 								   << "}"
    582 								   << ""
    583 								   << "void main (void)"
    584 								   << "{"
    585 								   << "    S s = myFunc();"
    586 								   << "    ${DST} = vec4(s.a, s.b.b, s.b.a + s.c);"
    587 								   << "    ${ASSIGN_POS}"
    588 								   << "}",
    589 					  { c.color.xyz() = c.coords.swizzle(0, 1, 2); });
    590 
    591 	LOCAL_STRUCT_CASE(conditional_assignment, "Conditional struct assignment",
    592 					  LineStream() << "${HEADER}"
    593 								   << "uniform int ui_zero;"
    594 								   << "uniform int ui_one;"
    595 								   << "uniform mediump float uf_one;"
    596 								   << ""
    597 								   << "struct S {"
    598 								   << "    mediump float   a;"
    599 								   << "    mediump vec3    b;"
    600 								   << "    int             c;"
    601 								   << "};"
    602 								   << ""
    603 								   << "void main (void)"
    604 								   << "{"
    605 								   << "    S s = S(${COORDS}.x, ${COORDS}.yzw, ui_zero);"
    606 								   << "    if (uf_one > 0.0)"
    607 								   << "        s = S(${COORDS}.w, ${COORDS}.zyx, ui_one);"
    608 								   << "    ${DST} = vec4(s.a, s.b.xy, s.c);"
    609 								   << "    ${ASSIGN_POS}"
    610 								   << "}",
    611 					  { c.color.xyz() = c.coords.swizzle(3, 2, 1); });
    612 
    613 	LOCAL_STRUCT_CASE(loop_assignment, "Struct assignment in loop",
    614 					  LineStream() << "${HEADER}"
    615 								   << "uniform int ui_zero;"
    616 								   << "uniform int ui_one;"
    617 								   << ""
    618 								   << "struct S {"
    619 								   << "    mediump float   a;"
    620 								   << "    mediump vec3    b;"
    621 								   << "    int             c;"
    622 								   << "};"
    623 								   << ""
    624 								   << "void main (void)"
    625 								   << "{"
    626 								   << "    S s = S(${COORDS}.x, ${COORDS}.yzw, ui_zero);"
    627 								   << "    for (int i = 0; i < 3; i++)"
    628 								   << "    {"
    629 								   << "        if (i == 1)"
    630 								   << "            s = S(${COORDS}.w, ${COORDS}.zyx, ui_one);"
    631 								   << "    }"
    632 								   << "    ${DST} = vec4(s.a, s.b.xy, s.c);"
    633 								   << "    ${ASSIGN_POS}"
    634 								   << "}",
    635 					  { c.color.xyz() = c.coords.swizzle(3, 2, 1); });
    636 
    637 	LOCAL_STRUCT_CASE(dynamic_loop_assignment, "Struct assignment in loop",
    638 					  LineStream() << "${HEADER}"
    639 								   << "uniform int ui_zero;"
    640 								   << "uniform int ui_one;"
    641 								   << "uniform int ui_three;"
    642 								   << ""
    643 								   << "struct S {"
    644 								   << "    mediump float   a;"
    645 								   << "    mediump vec3    b;"
    646 								   << "    int             c;"
    647 								   << "};"
    648 								   << ""
    649 								   << "void main (void)"
    650 								   << "{"
    651 								   << "    S s = S(${COORDS}.x, ${COORDS}.yzw, ui_zero);"
    652 								   << "    for (int i = 0; i < ui_three; i++)"
    653 								   << "    {"
    654 								   << "        if (i == ui_one)"
    655 								   << "            s = S(${COORDS}.w, ${COORDS}.zyx, ui_one);"
    656 								   << "    }"
    657 								   << "    ${DST} = vec4(s.a, s.b.xy, s.c);"
    658 								   << "    ${ASSIGN_POS}"
    659 								   << "}",
    660 					  { c.color.xyz() = c.coords.swizzle(3, 2, 1); });
    661 
    662 	LOCAL_STRUCT_CASE(nested_conditional_assignment, "Conditional assignment of nested struct",
    663 					  LineStream() << "${HEADER}"
    664 								   << "uniform int ui_zero;"
    665 								   << "uniform int ui_one;"
    666 								   << "uniform mediump float uf_one;"
    667 								   << ""
    668 								   << "struct T {"
    669 								   << "    int             a;"
    670 								   << "    mediump vec2    b;"
    671 								   << "};"
    672 								   << "struct S {"
    673 								   << "    mediump float   a;"
    674 								   << "    T               b;"
    675 								   << "    int             c;"
    676 								   << "};"
    677 								   << ""
    678 								   << "void main (void)"
    679 								   << "{"
    680 								   << "    S s = S(${COORDS}.x, T(ui_one, ${COORDS}.yz), ui_one);"
    681 								   << "    if (uf_one > 0.0)"
    682 								   << "        s.b = T(ui_zero, ${COORDS}.zw);"
    683 								   << "    ${DST} = vec4(s.a, s.b.b, s.c - s.b.a);"
    684 								   << "    ${ASSIGN_POS}"
    685 								   << "}",
    686 					  { c.color.xyz() = c.coords.swizzle(0, 2, 3); });
    687 
    688 	LOCAL_STRUCT_CASE(nested_loop_assignment, "Nested struct assignment in loop",
    689 					  LineStream() << "${HEADER}"
    690 								   << "uniform int ui_zero;"
    691 								   << "uniform int ui_one;"
    692 								   << "uniform mediump float uf_one;"
    693 								   << ""
    694 								   << "struct T {"
    695 								   << "    int             a;"
    696 								   << "    mediump vec2    b;"
    697 								   << "};"
    698 								   << "struct S {"
    699 								   << "    mediump float   a;"
    700 								   << "    T               b;"
    701 								   << "    int             c;"
    702 								   << "};"
    703 								   << ""
    704 								   << "void main (void)"
    705 								   << "{"
    706 								   << "    S s = S(${COORDS}.x, T(ui_one, ${COORDS}.yz), ui_one);"
    707 								   << "    for (int i = 0; i < 3; i++)"
    708 								   << "    {"
    709 								   << "        if (i == 1)"
    710 								   << "            s.b = T(ui_zero, ${COORDS}.zw);"
    711 								   << "    }"
    712 								   << "    ${DST} = vec4(s.a, s.b.b, s.c - s.b.a);"
    713 								   << "    ${ASSIGN_POS}"
    714 								   << "}",
    715 					  { c.color.xyz() = c.coords.swizzle(0, 2, 3); });
    716 
    717 	LOCAL_STRUCT_CASE(nested_dynamic_loop_assignment, "Nested struct assignment in dynamic loop",
    718 					  LineStream() << "${HEADER}"
    719 								   << "uniform int ui_zero;"
    720 								   << "uniform int ui_one;"
    721 								   << "uniform int ui_three;"
    722 								   << "uniform mediump float uf_one;"
    723 								   << ""
    724 								   << "struct T {"
    725 								   << "    int             a;"
    726 								   << "    mediump vec2    b;"
    727 								   << "};"
    728 								   << "struct S {"
    729 								   << "    mediump float   a;"
    730 								   << "    T               b;"
    731 								   << "    int             c;"
    732 								   << "};"
    733 								   << ""
    734 								   << "void main (void)"
    735 								   << "{"
    736 								   << "    S s = S(${COORDS}.x, T(ui_one, ${COORDS}.yz), ui_one);"
    737 								   << "    for (int i = 0; i < ui_three; i++)"
    738 								   << "    {"
    739 								   << "        if (i == ui_one)"
    740 								   << "            s.b = T(ui_zero, ${COORDS}.zw);"
    741 								   << "    }"
    742 								   << "    ${DST} = vec4(s.a, s.b.b, s.c - s.b.a);"
    743 								   << "    ${ASSIGN_POS}"
    744 								   << "}",
    745 					  { c.color.xyz() = c.coords.swizzle(0, 2, 3); });
    746 
    747 	LOCAL_STRUCT_CASE(loop_struct_array, "Struct array usage in loop",
    748 					  LineStream() << "${HEADER}"
    749 								   << "uniform int ui_zero;"
    750 								   << "uniform int ui_one;"
    751 								   << "uniform int ui_two;"
    752 								   << ""
    753 								   << "struct S {"
    754 								   << "    mediump float   a;"
    755 								   << "    mediump int     b;"
    756 								   << "};"
    757 								   << ""
    758 								   << "void main (void)"
    759 								   << "{"
    760 								   << "    S s[3];"
    761 								   << "    s[0] = S(${COORDS}.x, ui_zero);"
    762 								   << "    s[1].a = ${COORDS}.y;"
    763 								   << "    s[1].b = -ui_one;"
    764 								   << "    s[2] = S(${COORDS}.z, ui_two);"
    765 								   << ""
    766 								   << "    mediump float rgb[3];"
    767 								   << "    int alpha = 0;"
    768 								   << "    for (int i = 0; i < 3; i++)"
    769 								   << "    {"
    770 								   << "        rgb[i] = s[2-i].a;"
    771 								   << "        alpha += s[i].b;"
    772 								   << "    }"
    773 								   << "    ${DST} = vec4(rgb[0], rgb[1], rgb[2], alpha);"
    774 								   << "    ${ASSIGN_POS}"
    775 								   << "}",
    776 					  { c.color.xyz() = c.coords.swizzle(2, 1, 0); });
    777 
    778 	LOCAL_STRUCT_CASE(loop_nested_struct_array, "Nested struct array usage in loop",
    779 					  LineStream() << "${HEADER}"
    780 								   << "uniform int ui_zero;"
    781 								   << "uniform int ui_one;"
    782 								   << "uniform int ui_two;"
    783 								   << "uniform mediump float uf_two;"
    784 								   << "uniform mediump float uf_three;"
    785 								   << "uniform mediump float uf_four;"
    786 								   << "uniform mediump float uf_half;"
    787 								   << "uniform mediump float uf_third;"
    788 								   << "uniform mediump float uf_fourth;"
    789 								   << "uniform mediump float uf_sixth;"
    790 								   << ""
    791 								   << "struct T {"
    792 								   << "    mediump float   a;"
    793 								   << "    mediump vec2    b[2];"
    794 								   << "};"
    795 								   << "struct S {"
    796 								   << "    mediump float   a;"
    797 								   << "    T               b[3];"
    798 								   << "    int             c;"
    799 								   << "};"
    800 								   << ""
    801 								   << "void main (void)"
    802 								   << "{"
    803 								   << "    S s[2];"
    804 								   << ""
    805 								   << "    // S[0]"
    806 								   << "    s[0].a         = ${COORDS}.x;"
    807 								   << "    s[0].b[0].a    = uf_half;"
    808 								   << "    s[0].b[0].b[0] = ${COORDS}.yx;"
    809 								   << "    s[0].b[0].b[1] = ${COORDS}.zx;"
    810 								   << "    s[0].b[1].a    = uf_third;"
    811 								   << "    s[0].b[1].b[0] = ${COORDS}.yy;"
    812 								   << "    s[0].b[1].b[1] = ${COORDS}.wy;"
    813 								   << "    s[0].b[2].a    = uf_fourth;"
    814 								   << "    s[0].b[2].b[0] = ${COORDS}.zx;"
    815 								   << "    s[0].b[2].b[1] = ${COORDS}.zy;"
    816 								   << "    s[0].c         = ui_zero;"
    817 								   << ""
    818 								   << "    // S[1]"
    819 								   << "    s[1].a         = ${COORDS}.w;"
    820 								   << "    s[1].b[0].a    = uf_two;"
    821 								   << "    s[1].b[0].b[0] = ${COORDS}.zx;"
    822 								   << "    s[1].b[0].b[1] = ${COORDS}.zy;"
    823 								   << "    s[1].b[1].a    = uf_three;"
    824 								   << "    s[1].b[1].b[0] = ${COORDS}.zz;"
    825 								   << "    s[1].b[1].b[1] = ${COORDS}.ww;"
    826 								   << "    s[1].b[2].a    = uf_four;"
    827 								   << "    s[1].b[2].b[0] = ${COORDS}.yx;"
    828 								   << "    s[1].b[2].b[1] = ${COORDS}.wz;"
    829 								   << "    s[1].c         = ui_one;"
    830 								   << ""
    831 								   << "    mediump float r = 0.0; // (x*3 + y*3) / 6.0"
    832 								   << "    mediump float g = 0.0; // (y*3 + z*3) / 6.0"
    833 								   << "    mediump float b = 0.0; // (z*3 + w*3) / 6.0"
    834 								   << "    mediump float a = 1.0;"
    835 								   << "    for (int i = 0; i < 2; i++)"
    836 								   << "    {"
    837 								   << "        for (int j = 0; j < 3; j++)"
    838 								   << "        {"
    839 								   << "            r += s[0].b[j].b[i].y;"
    840 								   << "            g += s[i].b[j].b[0].x;"
    841 								   << "            b += s[i].b[j].b[1].x;"
    842 								   << "            a *= s[i].b[j].a;"
    843 								   << "        }"
    844 								   << "    }"
    845 								   << "    ${DST} = vec4(r*uf_sixth, g*uf_sixth, b*uf_sixth, a);"
    846 								   << "    ${ASSIGN_POS}"
    847 								   << "}",
    848 					  { c.color.xyz() = (c.coords.swizzle(0, 1, 2) + c.coords.swizzle(1, 2, 3)) * 0.5f; });
    849 
    850 	LOCAL_STRUCT_CASE(dynamic_loop_struct_array, "Struct array usage in dynamic loop",
    851 					  LineStream() << "${HEADER}"
    852 								   << "uniform int ui_zero;"
    853 								   << "uniform int ui_one;"
    854 								   << "uniform int ui_two;"
    855 								   << "uniform int ui_three;"
    856 								   << ""
    857 								   << "struct S {"
    858 								   << "    mediump float   a;"
    859 								   << "    mediump int     b;"
    860 								   << "};"
    861 								   << ""
    862 								   << "void main (void)"
    863 								   << "{"
    864 								   << "    S s[3];"
    865 								   << "    s[0] = S(${COORDS}.x, ui_zero);"
    866 								   << "    s[1].a = ${COORDS}.y;"
    867 								   << "    s[1].b = -ui_one;"
    868 								   << "    s[2] = S(${COORDS}.z, ui_two);"
    869 								   << ""
    870 								   << "    mediump float rgb[3];"
    871 								   << "    int alpha = 0;"
    872 								   << "    for (int i = 0; i < ui_three; i++)"
    873 								   << "    {"
    874 								   << "        rgb[i] = s[2-i].a;"
    875 								   << "        alpha += s[i].b;"
    876 								   << "    }"
    877 								   << "    ${DST} = vec4(rgb[0], rgb[1], rgb[2], alpha);"
    878 								   << "    ${ASSIGN_POS}"
    879 								   << "}",
    880 					  { c.color.xyz() = c.coords.swizzle(2, 1, 0); });
    881 
    882 	LOCAL_STRUCT_CASE(dynamic_loop_nested_struct_array, "Nested struct array usage in dynamic loop",
    883 					  LineStream() << "${HEADER}"
    884 								   << "uniform int ui_zero;"
    885 								   << "uniform int ui_one;"
    886 								   << "uniform int ui_two;"
    887 								   << "uniform int ui_three;"
    888 								   << "uniform mediump float uf_two;"
    889 								   << "uniform mediump float uf_three;"
    890 								   << "uniform mediump float uf_four;"
    891 								   << "uniform mediump float uf_half;"
    892 								   << "uniform mediump float uf_third;"
    893 								   << "uniform mediump float uf_fourth;"
    894 								   << "uniform mediump float uf_sixth;"
    895 								   << ""
    896 								   << "struct T {"
    897 								   << "    mediump float   a;"
    898 								   << "    mediump vec2    b[2];"
    899 								   << "};"
    900 								   << "struct S {"
    901 								   << "    mediump float   a;"
    902 								   << "    T               b[3];"
    903 								   << "    int             c;"
    904 								   << "};"
    905 								   << ""
    906 								   << "void main (void)"
    907 								   << "{"
    908 								   << "    S s[2];"
    909 								   << ""
    910 								   << "    // S[0]"
    911 								   << "    s[0].a         = ${COORDS}.x;"
    912 								   << "    s[0].b[0].a    = uf_half;"
    913 								   << "    s[0].b[0].b[0] = ${COORDS}.yx;"
    914 								   << "    s[0].b[0].b[1] = ${COORDS}.zx;"
    915 								   << "    s[0].b[1].a    = uf_third;"
    916 								   << "    s[0].b[1].b[0] = ${COORDS}.yy;"
    917 								   << "    s[0].b[1].b[1] = ${COORDS}.wy;"
    918 								   << "    s[0].b[2].a    = uf_fourth;"
    919 								   << "    s[0].b[2].b[0] = ${COORDS}.zx;"
    920 								   << "    s[0].b[2].b[1] = ${COORDS}.zy;"
    921 								   << "    s[0].c         = ui_zero;"
    922 								   << ""
    923 								   << "    // S[1]"
    924 								   << "    s[1].a         = ${COORDS}.w;"
    925 								   << "    s[1].b[0].a    = uf_two;"
    926 								   << "    s[1].b[0].b[0] = ${COORDS}.zx;"
    927 								   << "    s[1].b[0].b[1] = ${COORDS}.zy;"
    928 								   << "    s[1].b[1].a    = uf_three;"
    929 								   << "    s[1].b[1].b[0] = ${COORDS}.zz;"
    930 								   << "    s[1].b[1].b[1] = ${COORDS}.ww;"
    931 								   << "    s[1].b[2].a    = uf_four;"
    932 								   << "    s[1].b[2].b[0] = ${COORDS}.yx;"
    933 								   << "    s[1].b[2].b[1] = ${COORDS}.wz;"
    934 								   << "    s[1].c         = ui_one;"
    935 								   << ""
    936 								   << "    mediump float r = 0.0; // (x*3 + y*3) / 6.0"
    937 								   << "    mediump float g = 0.0; // (y*3 + z*3) / 6.0"
    938 								   << "    mediump float b = 0.0; // (z*3 + w*3) / 6.0"
    939 								   << "    mediump float a = 1.0;"
    940 								   << "    for (int i = 0; i < ui_two; i++)"
    941 								   << "    {"
    942 								   << "        for (int j = 0; j < ui_three; j++)"
    943 								   << "        {"
    944 								   << "            r += s[0].b[j].b[i].y;"
    945 								   << "            g += s[i].b[j].b[0].x;"
    946 								   << "            b += s[i].b[j].b[1].x;"
    947 								   << "            a *= s[i].b[j].a;"
    948 								   << "        }"
    949 								   << "    }"
    950 								   << "    ${DST} = vec4(r*uf_sixth, g*uf_sixth, b*uf_sixth, a);"
    951 								   << "    ${ASSIGN_POS}"
    952 								   << "}",
    953 					  { c.color.xyz() = (c.coords.swizzle(0, 1, 2) + c.coords.swizzle(1, 2, 3)) * 0.5f; });
    954 }
    955 
    956 class UniformStructTests : public TestCaseGroup
    957 {
    958 public:
    959 	UniformStructTests(Context& context, glu::GLSLVersion glslVersion)
    960 		: TestCaseGroup(context, "uniform", "Uniform structs"), m_glslVersion(glslVersion)
    961 	{
    962 	}
    963 
    964 	~UniformStructTests(void)
    965 	{
    966 	}
    967 
    968 	virtual void init(void);
    969 
    970 private:
    971 	glu::GLSLVersion m_glslVersion;
    972 };
    973 
    974 namespace
    975 {
    976 
    977 #define CHECK_SET_UNIFORM(NAME) GLU_EXPECT_NO_ERROR(gl.getError(), (string("Failed to set ") + NAME).c_str())
    978 
    979 #define MAKE_SET_VEC_UNIFORM(VECTYPE, SETUNIFORM)                                                            \
    980 	void setUniform(const glw::Functions& gl, deUint32 programID, const char* name, const tcu::VECTYPE& vec) \
    981 	{                                                                                                        \
    982 		int loc = gl.getUniformLocation(programID, name);                                                    \
    983 		SETUNIFORM(loc, 1, vec.getPtr());                                                                    \
    984 		CHECK_SET_UNIFORM(name);                                                                             \
    985 	}                                                                                                        \
    986 	struct SetUniform##VECTYPE##Dummy_s                                                                      \
    987 	{                                                                                                        \
    988 		int unused;                                                                                          \
    989 	}
    990 
    991 #define MAKE_SET_VEC_UNIFORM_PTR(VECTYPE, SETUNIFORM)                                                        \
    992 	void setUniform(const glw::Functions& gl, deUint32 programID, const char* name, const tcu::VECTYPE* vec, \
    993 					int arraySize)                                                                           \
    994 	{                                                                                                        \
    995 		int loc = gl.getUniformLocation(programID, name);                                                    \
    996 		SETUNIFORM(loc, arraySize, vec->getPtr());                                                           \
    997 		CHECK_SET_UNIFORM(name);                                                                             \
    998 	}                                                                                                        \
    999 	struct SetUniformPtr##VECTYPE##Dummy_s                                                                   \
   1000 	{                                                                                                        \
   1001 		int unused;                                                                                          \
   1002 	}
   1003 
   1004 MAKE_SET_VEC_UNIFORM(Vec2, gl.uniform2fv);
   1005 MAKE_SET_VEC_UNIFORM(Vec3, gl.uniform3fv);
   1006 MAKE_SET_VEC_UNIFORM_PTR(Vec2, gl.uniform2fv);
   1007 
   1008 void setUniform(const glw::Functions& gl, deUint32 programID, const char* name, float value)
   1009 {
   1010 	int loc = gl.getUniformLocation(programID, name);
   1011 	gl.uniform1f(loc, value);
   1012 	CHECK_SET_UNIFORM(name);
   1013 }
   1014 
   1015 void setUniform(const glw::Functions& gl, deUint32 programID, const char* name, int value)
   1016 {
   1017 	int loc = gl.getUniformLocation(programID, name);
   1018 	gl.uniform1i(loc, value);
   1019 	CHECK_SET_UNIFORM(name);
   1020 }
   1021 
   1022 void setUniform(const glw::Functions& gl, deUint32 programID, const char* name, const float* value, int arraySize)
   1023 {
   1024 	int loc = gl.getUniformLocation(programID, name);
   1025 	gl.uniform1fv(loc, arraySize, value);
   1026 	CHECK_SET_UNIFORM(name);
   1027 }
   1028 
   1029 } // anonymous
   1030 
   1031 void UniformStructTests::init(void)
   1032 {
   1033 #define UNIFORM_STRUCT_CASE(NAME, DESCRIPTION, TEXTURES, SHADER_SRC, SET_UNIFORMS_BODY, EVAL_FUNC_BODY)      \
   1034 	do                                                                                                       \
   1035 	{                                                                                                        \
   1036 		struct SetUniforms_##NAME                                                                            \
   1037 		{                                                                                                    \
   1038 			static void setUniforms(const glw::Functions& gl, deUint32 programID,                            \
   1039 									const tcu::Vec4& constCoords) SET_UNIFORMS_BODY                          \
   1040 		};                                                                                                   \
   1041 		struct Eval_##NAME                                                                                   \
   1042 		{                                                                                                    \
   1043 			static void eval(ShaderEvalContext& c) EVAL_FUNC_BODY                                            \
   1044 		};                                                                                                   \
   1045 		addChild(createStructCase(m_context, #NAME "_vertex", DESCRIPTION, m_glslVersion, true, TEXTURES,    \
   1046 								  Eval_##NAME::eval, SetUniforms_##NAME::setUniforms, SHADER_SRC));          \
   1047 		addChild(createStructCase(m_context, #NAME "_fragment", DESCRIPTION, m_glslVersion, false, TEXTURES, \
   1048 								  Eval_##NAME::eval, SetUniforms_##NAME::setUniforms, SHADER_SRC));          \
   1049 	} while (deGetFalse())
   1050 
   1051 	UNIFORM_STRUCT_CASE(basic, "Basic struct usage", false,
   1052 						LineStream() << "${HEADER}"
   1053 									 << "uniform int ui_one;"
   1054 									 << ""
   1055 									 << "struct S {"
   1056 									 << "    mediump float   a;"
   1057 									 << "    mediump vec3    b;"
   1058 									 << "    int             c;"
   1059 									 << "};"
   1060 									 << "uniform S s;"
   1061 									 << ""
   1062 									 << "void main (void)"
   1063 									 << "{"
   1064 									 << "    ${DST} = vec4(s.a, s.b.x, s.b.y, s.c);"
   1065 									 << "    ${ASSIGN_POS}"
   1066 									 << "}",
   1067 						{
   1068 							setUniform(gl, programID, "s.a", constCoords.x());
   1069 							setUniform(gl, programID, "s.b", constCoords.swizzle(1, 2, 3));
   1070 							setUniform(gl, programID, "s.c", 1);
   1071 						},
   1072 						{ c.color.xyz() = c.constCoords.swizzle(0, 1, 2); });
   1073 
   1074 	UNIFORM_STRUCT_CASE(nested, "Nested struct", false,
   1075 						LineStream() << "${HEADER}"
   1076 									 << "uniform int ui_zero;"
   1077 									 << "uniform int ui_one;"
   1078 									 << ""
   1079 									 << "struct T {"
   1080 									 << "    int             a;"
   1081 									 << "    mediump vec2    b;"
   1082 									 << "};"
   1083 									 << "struct S {"
   1084 									 << "    mediump float   a;"
   1085 									 << "    T               b;"
   1086 									 << "    int             c;"
   1087 									 << "};"
   1088 									 << "uniform S s;"
   1089 									 << ""
   1090 									 << "void main (void)"
   1091 									 << "{"
   1092 									 << "    ${DST} = vec4(s.a, s.b.b, s.b.a + s.c);"
   1093 									 << "    ${ASSIGN_POS}"
   1094 									 << "}",
   1095 						{
   1096 							setUniform(gl, programID, "s.a", constCoords.x());
   1097 							setUniform(gl, programID, "s.b.a", 0);
   1098 							setUniform(gl, programID, "s.b.b", constCoords.swizzle(1, 2));
   1099 							setUniform(gl, programID, "s.c", 1);
   1100 						},
   1101 						{ c.color.xyz() = c.constCoords.swizzle(0, 1, 2); });
   1102 
   1103 	UNIFORM_STRUCT_CASE(array_member, "Struct with array member", false,
   1104 						LineStream() << "${HEADER}"
   1105 									 << "uniform int ui_one;"
   1106 									 << ""
   1107 									 << "struct S {"
   1108 									 << "    mediump float   a;"
   1109 									 << "    mediump float   b[3];"
   1110 									 << "    int             c;"
   1111 									 << "};"
   1112 									 << "uniform S s;"
   1113 									 << ""
   1114 									 << "void main (void)"
   1115 									 << "{"
   1116 									 << "    ${DST} = vec4(s.a, s.b[0], s.b[1], s.c);"
   1117 									 << "    ${ASSIGN_POS}"
   1118 									 << "}",
   1119 						{
   1120 							setUniform(gl, programID, "s.a", constCoords.w());
   1121 							setUniform(gl, programID, "s.c", 1);
   1122 
   1123 							float b[3];
   1124 							b[0] = constCoords.z();
   1125 							b[1] = constCoords.y();
   1126 							b[2] = constCoords.x();
   1127 							setUniform(gl, programID, "s.b", b, DE_LENGTH_OF_ARRAY(b));
   1128 						},
   1129 						{ c.color.xyz() = c.constCoords.swizzle(3, 2, 1); });
   1130 
   1131 	UNIFORM_STRUCT_CASE(array_member_dynamic_index, "Struct with array member, dynamic indexing", false,
   1132 						LineStream() << "${HEADER}"
   1133 									 << "uniform int ui_zero;"
   1134 									 << "uniform int ui_one;"
   1135 									 << "uniform int ui_two;"
   1136 									 << ""
   1137 									 << "struct S {"
   1138 									 << "    mediump float   a;"
   1139 									 << "    mediump float   b[3];"
   1140 									 << "    int             c;"
   1141 									 << "};"
   1142 									 << "uniform S s;"
   1143 									 << ""
   1144 									 << "void main (void)"
   1145 									 << "{"
   1146 									 << "    ${DST} = vec4(s.b[ui_one], s.b[ui_zero], s.b[ui_two], s.c);"
   1147 									 << "    ${ASSIGN_POS}"
   1148 									 << "}",
   1149 						{
   1150 							setUniform(gl, programID, "s.a", constCoords.w());
   1151 							setUniform(gl, programID, "s.c", 1);
   1152 
   1153 							float b[3];
   1154 							b[0] = constCoords.z();
   1155 							b[1] = constCoords.y();
   1156 							b[2] = constCoords.x();
   1157 							setUniform(gl, programID, "s.b", b, DE_LENGTH_OF_ARRAY(b));
   1158 						},
   1159 						{ c.color.xyz() = c.constCoords.swizzle(1, 2, 0); });
   1160 
   1161 	UNIFORM_STRUCT_CASE(struct_array, "Struct array", false,
   1162 						LineStream() << "${HEADER}"
   1163 									 << "uniform int ui_zero;"
   1164 									 << "uniform int ui_one;"
   1165 									 << "uniform int ui_two;"
   1166 									 << ""
   1167 									 << "struct S {"
   1168 									 << "    mediump float   a;"
   1169 									 << "    mediump int     b;"
   1170 									 << "};"
   1171 									 << "uniform S s[3];"
   1172 									 << ""
   1173 									 << "void main (void)"
   1174 									 << "{"
   1175 									 << "    ${DST} = vec4(s[2].a, s[1].a, s[0].a, s[2].b - s[1].b + s[0].b);"
   1176 									 << "    ${ASSIGN_POS}"
   1177 									 << "}",
   1178 						{
   1179 							setUniform(gl, programID, "s[0].a", constCoords.x());
   1180 							setUniform(gl, programID, "s[0].b", 0);
   1181 							setUniform(gl, programID, "s[1].a", constCoords.y());
   1182 							setUniform(gl, programID, "s[1].b", 1);
   1183 							setUniform(gl, programID, "s[2].a", constCoords.z());
   1184 							setUniform(gl, programID, "s[2].b", 2);
   1185 						},
   1186 						{ c.color.xyz() = c.constCoords.swizzle(2, 1, 0); });
   1187 
   1188 	UNIFORM_STRUCT_CASE(
   1189 		struct_array_dynamic_index, "Struct array with dynamic indexing", false,
   1190 		LineStream()
   1191 			<< "${HEADER}"
   1192 			<< "uniform int ui_zero;"
   1193 			<< "uniform int ui_one;"
   1194 			<< "uniform int ui_two;"
   1195 			<< ""
   1196 			<< "struct S {"
   1197 			<< "    mediump float   a;"
   1198 			<< "    mediump int     b;"
   1199 			<< "};"
   1200 			<< "uniform S s[3];"
   1201 			<< ""
   1202 			<< "void main (void)"
   1203 			<< "{"
   1204 			<< "    ${DST} = vec4(s[ui_two].a, s[ui_one].a, s[ui_zero].a, s[ui_two].b - s[ui_one].b + s[ui_zero].b);"
   1205 			<< "    ${ASSIGN_POS}"
   1206 			<< "}",
   1207 		{
   1208 			setUniform(gl, programID, "s[0].a", constCoords.x());
   1209 			setUniform(gl, programID, "s[0].b", 0);
   1210 			setUniform(gl, programID, "s[1].a", constCoords.y());
   1211 			setUniform(gl, programID, "s[1].b", 1);
   1212 			setUniform(gl, programID, "s[2].a", constCoords.z());
   1213 			setUniform(gl, programID, "s[2].b", 2);
   1214 		},
   1215 		{ c.color.xyz() = c.constCoords.swizzle(2, 1, 0); });
   1216 
   1217 	UNIFORM_STRUCT_CASE(
   1218 		nested_struct_array, "Nested struct array", false,
   1219 		LineStream() << "${HEADER}"
   1220 					 << "struct T {"
   1221 					 << "    mediump float   a;"
   1222 					 << "    mediump vec2    b[2];"
   1223 					 << "};"
   1224 					 << "struct S {"
   1225 					 << "    mediump float   a;"
   1226 					 << "    T               b[3];"
   1227 					 << "    int             c;"
   1228 					 << "};"
   1229 					 << "uniform S s[2];"
   1230 					 << ""
   1231 					 << "void main (void)"
   1232 					 << "{"
   1233 					 << "    mediump float r = (s[0].b[1].b[0].x + s[1].b[2].b[1].y) * s[0].b[0].a; // (z + z) * 0.5"
   1234 					 << "    mediump float g = s[1].b[0].b[0].y * s[0].b[2].a * s[1].b[2].a; // x * 0.25 * 4"
   1235 					 << "    mediump float b = (s[0].b[2].b[1].y + s[0].b[1].b[0].y + s[1].a) * s[0].b[1].a; // (w + w "
   1236 						"+ w) * 0.333"
   1237 					 << "    mediump float a = float(s[0].c) + s[1].b[2].a - s[1].b[1].a; // 0 + 4.0 - 3.0"
   1238 					 << "    ${DST} = vec4(r, g, b, a);"
   1239 					 << "    ${ASSIGN_POS}"
   1240 					 << "}",
   1241 		{
   1242 			tcu::Vec2 arr[2];
   1243 
   1244 			setUniform(gl, programID, "s[0].a", constCoords.x());
   1245 			arr[0] = constCoords.swizzle(0, 1);
   1246 			arr[1] = constCoords.swizzle(2, 3);
   1247 			setUniform(gl, programID, "s[0].b[0].a", 0.5f);
   1248 			setUniform(gl, programID, "s[0].b[0].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1249 			arr[0] = constCoords.swizzle(2, 3);
   1250 			arr[1] = constCoords.swizzle(0, 1);
   1251 			setUniform(gl, programID, "s[0].b[1].a", 1.0f / 3.0f);
   1252 			setUniform(gl, programID, "s[0].b[1].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1253 			arr[0] = constCoords.swizzle(0, 2);
   1254 			arr[1] = constCoords.swizzle(1, 3);
   1255 			setUniform(gl, programID, "s[0].b[2].a", 1.0f / 4.0f);
   1256 			setUniform(gl, programID, "s[0].b[2].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1257 			setUniform(gl, programID, "s[0].c", 0);
   1258 
   1259 			setUniform(gl, programID, "s[1].a", constCoords.w());
   1260 			arr[0] = constCoords.swizzle(0, 0);
   1261 			arr[1] = constCoords.swizzle(1, 1);
   1262 			setUniform(gl, programID, "s[1].b[0].a", 2.0f);
   1263 			setUniform(gl, programID, "s[1].b[0].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1264 			arr[0] = constCoords.swizzle(2, 2);
   1265 			arr[1] = constCoords.swizzle(3, 3);
   1266 			setUniform(gl, programID, "s[1].b[1].a", 3.0f);
   1267 			setUniform(gl, programID, "s[1].b[1].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1268 			arr[0] = constCoords.swizzle(1, 0);
   1269 			arr[1] = constCoords.swizzle(3, 2);
   1270 			setUniform(gl, programID, "s[1].b[2].a", 4.0f);
   1271 			setUniform(gl, programID, "s[1].b[2].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1272 			setUniform(gl, programID, "s[1].c", 1);
   1273 		},
   1274 		{ c.color.xyz() = c.constCoords.swizzle(2, 0, 3); });
   1275 
   1276 	UNIFORM_STRUCT_CASE(nested_struct_array_dynamic_index, "Nested struct array with dynamic indexing", false,
   1277 						LineStream() << "${HEADER}"
   1278 									 << "uniform int ui_zero;"
   1279 									 << "uniform int ui_one;"
   1280 									 << "uniform int ui_two;"
   1281 									 << ""
   1282 									 << "struct T {"
   1283 									 << "    mediump float   a;"
   1284 									 << "    mediump vec2    b[2];"
   1285 									 << "};"
   1286 									 << "struct S {"
   1287 									 << "    mediump float   a;"
   1288 									 << "    T               b[3];"
   1289 									 << "    int             c;"
   1290 									 << "};"
   1291 									 << "uniform S s[2];"
   1292 									 << ""
   1293 									 << "void main (void)"
   1294 									 << "{"
   1295 									 << "    mediump float r = (s[0].b[ui_one].b[ui_one-1].x + "
   1296 										"s[ui_one].b[ui_two].b[ui_zero+1].y) * s[0].b[0].a; // (z + z) * 0.5"
   1297 									 << "    mediump float g = s[ui_two-1].b[ui_two-2].b[ui_zero].y * s[0].b[ui_two].a "
   1298 										"* s[ui_one].b[2].a; // x * 0.25 * 4"
   1299 									 << "    mediump float b = (s[ui_zero].b[ui_one+1].b[1].y + "
   1300 										"s[0].b[ui_one*ui_one].b[0].y + s[ui_one].a) * s[0].b[ui_two-ui_one].a; // (w "
   1301 										"+ w + w) * 0.333"
   1302 									 << "    mediump float a = float(s[ui_zero].c) + s[ui_one-ui_zero].b[ui_two].a - "
   1303 										"s[ui_zero+ui_one].b[ui_two-ui_one].a; // 0 + 4.0 - 3.0"
   1304 									 << "    ${DST} = vec4(r, g, b, a);"
   1305 									 << "    ${ASSIGN_POS}"
   1306 									 << "}",
   1307 						{
   1308 							tcu::Vec2 arr[2];
   1309 
   1310 							setUniform(gl, programID, "s[0].a", constCoords.x());
   1311 							arr[0] = constCoords.swizzle(0, 1);
   1312 							arr[1] = constCoords.swizzle(2, 3);
   1313 							setUniform(gl, programID, "s[0].b[0].a", 0.5f);
   1314 							setUniform(gl, programID, "s[0].b[0].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1315 							arr[0] = constCoords.swizzle(2, 3);
   1316 							arr[1] = constCoords.swizzle(0, 1);
   1317 							setUniform(gl, programID, "s[0].b[1].a", 1.0f / 3.0f);
   1318 							setUniform(gl, programID, "s[0].b[1].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1319 							arr[0] = constCoords.swizzle(0, 2);
   1320 							arr[1] = constCoords.swizzle(1, 3);
   1321 							setUniform(gl, programID, "s[0].b[2].a", 1.0f / 4.0f);
   1322 							setUniform(gl, programID, "s[0].b[2].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1323 							setUniform(gl, programID, "s[0].c", 0);
   1324 
   1325 							setUniform(gl, programID, "s[1].a", constCoords.w());
   1326 							arr[0] = constCoords.swizzle(0, 0);
   1327 							arr[1] = constCoords.swizzle(1, 1);
   1328 							setUniform(gl, programID, "s[1].b[0].a", 2.0f);
   1329 							setUniform(gl, programID, "s[1].b[0].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1330 							arr[0] = constCoords.swizzle(2, 2);
   1331 							arr[1] = constCoords.swizzle(3, 3);
   1332 							setUniform(gl, programID, "s[1].b[1].a", 3.0f);
   1333 							setUniform(gl, programID, "s[1].b[1].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1334 							arr[0] = constCoords.swizzle(1, 0);
   1335 							arr[1] = constCoords.swizzle(3, 2);
   1336 							setUniform(gl, programID, "s[1].b[2].a", 4.0f);
   1337 							setUniform(gl, programID, "s[1].b[2].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1338 							setUniform(gl, programID, "s[1].c", 1);
   1339 						},
   1340 						{ c.color.xyz() = c.constCoords.swizzle(2, 0, 3); });
   1341 
   1342 	UNIFORM_STRUCT_CASE(loop_struct_array, "Struct array usage in loop", false,
   1343 						LineStream() << "${HEADER}"
   1344 									 << "uniform int ui_zero;"
   1345 									 << "uniform int ui_one;"
   1346 									 << "uniform int ui_two;"
   1347 									 << ""
   1348 									 << "struct S {"
   1349 									 << "    mediump float   a;"
   1350 									 << "    mediump int     b;"
   1351 									 << "};"
   1352 									 << "uniform S s[3];"
   1353 									 << ""
   1354 									 << "void main (void)"
   1355 									 << "{"
   1356 									 << "    mediump float rgb[3];"
   1357 									 << "    int alpha = 0;"
   1358 									 << "    for (int i = 0; i < 3; i++)"
   1359 									 << "    {"
   1360 									 << "        rgb[i] = s[2-i].a;"
   1361 									 << "        alpha += s[i].b;"
   1362 									 << "    }"
   1363 									 << "    ${DST} = vec4(rgb[0], rgb[1], rgb[2], alpha);"
   1364 									 << "    ${ASSIGN_POS}"
   1365 									 << "}",
   1366 						{
   1367 							setUniform(gl, programID, "s[0].a", constCoords.x());
   1368 							setUniform(gl, programID, "s[0].b", 0);
   1369 							setUniform(gl, programID, "s[1].a", constCoords.y());
   1370 							setUniform(gl, programID, "s[1].b", -1);
   1371 							setUniform(gl, programID, "s[2].a", constCoords.z());
   1372 							setUniform(gl, programID, "s[2].b", 2);
   1373 						},
   1374 						{ c.color.xyz() = c.constCoords.swizzle(2, 1, 0); });
   1375 
   1376 	UNIFORM_STRUCT_CASE(loop_nested_struct_array, "Nested struct array usage in loop", false,
   1377 						LineStream() << "${HEADER}"
   1378 									 << "uniform int ui_zero;"
   1379 									 << "uniform int ui_one;"
   1380 									 << "uniform int ui_two;"
   1381 									 << "uniform mediump float uf_two;"
   1382 									 << "uniform mediump float uf_three;"
   1383 									 << "uniform mediump float uf_four;"
   1384 									 << "uniform mediump float uf_half;"
   1385 									 << "uniform mediump float uf_third;"
   1386 									 << "uniform mediump float uf_fourth;"
   1387 									 << "uniform mediump float uf_sixth;"
   1388 									 << ""
   1389 									 << "struct T {"
   1390 									 << "    mediump float   a;"
   1391 									 << "    mediump vec2    b[2];"
   1392 									 << "};"
   1393 									 << "struct S {"
   1394 									 << "    mediump float   a;"
   1395 									 << "    T               b[3];"
   1396 									 << "    int             c;"
   1397 									 << "};"
   1398 									 << "uniform S s[2];"
   1399 									 << ""
   1400 									 << "void main (void)"
   1401 									 << "{"
   1402 									 << "    mediump float r = 0.0; // (x*3 + y*3) / 6.0"
   1403 									 << "    mediump float g = 0.0; // (y*3 + z*3) / 6.0"
   1404 									 << "    mediump float b = 0.0; // (z*3 + w*3) / 6.0"
   1405 									 << "    mediump float a = 1.0;"
   1406 									 << "    for (int i = 0; i < 2; i++)"
   1407 									 << "    {"
   1408 									 << "        for (int j = 0; j < 3; j++)"
   1409 									 << "        {"
   1410 									 << "            r += s[0].b[j].b[i].y;"
   1411 									 << "            g += s[i].b[j].b[0].x;"
   1412 									 << "            b += s[i].b[j].b[1].x;"
   1413 									 << "            a *= s[i].b[j].a;"
   1414 									 << "        }"
   1415 									 << "    }"
   1416 									 << "    ${DST} = vec4(r*uf_sixth, g*uf_sixth, b*uf_sixth, a);"
   1417 									 << "    ${ASSIGN_POS}"
   1418 									 << "}",
   1419 						{
   1420 							tcu::Vec2 arr[2];
   1421 
   1422 							setUniform(gl, programID, "s[0].a", constCoords.x());
   1423 							arr[0] = constCoords.swizzle(1, 0);
   1424 							arr[1] = constCoords.swizzle(2, 0);
   1425 							setUniform(gl, programID, "s[0].b[0].a", 0.5f);
   1426 							setUniform(gl, programID, "s[0].b[0].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1427 							arr[0] = constCoords.swizzle(1, 1);
   1428 							arr[1] = constCoords.swizzle(3, 1);
   1429 							setUniform(gl, programID, "s[0].b[1].a", 1.0f / 3.0f);
   1430 							setUniform(gl, programID, "s[0].b[1].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1431 							arr[0] = constCoords.swizzle(2, 1);
   1432 							arr[1] = constCoords.swizzle(2, 1);
   1433 							setUniform(gl, programID, "s[0].b[2].a", 1.0f / 4.0f);
   1434 							setUniform(gl, programID, "s[0].b[2].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1435 							setUniform(gl, programID, "s[0].c", 0);
   1436 
   1437 							setUniform(gl, programID, "s[1].a", constCoords.w());
   1438 							arr[0] = constCoords.swizzle(2, 0);
   1439 							arr[1] = constCoords.swizzle(2, 1);
   1440 							setUniform(gl, programID, "s[1].b[0].a", 2.0f);
   1441 							setUniform(gl, programID, "s[1].b[0].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1442 							arr[0] = constCoords.swizzle(2, 2);
   1443 							arr[1] = constCoords.swizzle(3, 3);
   1444 							setUniform(gl, programID, "s[1].b[1].a", 3.0f);
   1445 							setUniform(gl, programID, "s[1].b[1].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1446 							arr[0] = constCoords.swizzle(1, 0);
   1447 							arr[1] = constCoords.swizzle(3, 2);
   1448 							setUniform(gl, programID, "s[1].b[2].a", 4.0f);
   1449 							setUniform(gl, programID, "s[1].b[2].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1450 							setUniform(gl, programID, "s[1].c", 1);
   1451 						},
   1452 						{ c.color.xyz() = (c.constCoords.swizzle(0, 1, 2) + c.constCoords.swizzle(1, 2, 3)) * 0.5f; });
   1453 
   1454 	UNIFORM_STRUCT_CASE(dynamic_loop_struct_array, "Struct array usage in dynamic loop", false,
   1455 						LineStream() << "${HEADER}"
   1456 									 << "uniform int ui_zero;"
   1457 									 << "uniform int ui_one;"
   1458 									 << "uniform int ui_two;"
   1459 									 << "uniform int ui_three;"
   1460 									 << ""
   1461 									 << "struct S {"
   1462 									 << "    mediump float   a;"
   1463 									 << "    mediump int     b;"
   1464 									 << "};"
   1465 									 << "uniform S s[3];"
   1466 									 << ""
   1467 									 << "void main (void)"
   1468 									 << "{"
   1469 									 << "    mediump float rgb[3];"
   1470 									 << "    int alpha = 0;"
   1471 									 << "    for (int i = 0; i < ui_three; i++)"
   1472 									 << "    {"
   1473 									 << "        rgb[i] = s[2-i].a;"
   1474 									 << "        alpha += s[i].b;"
   1475 									 << "    }"
   1476 									 << "    ${DST} = vec4(rgb[0], rgb[1], rgb[2], alpha);"
   1477 									 << "    ${ASSIGN_POS}"
   1478 									 << "}",
   1479 						{
   1480 							setUniform(gl, programID, "s[0].a", constCoords.x());
   1481 							setUniform(gl, programID, "s[0].b", 0);
   1482 							setUniform(gl, programID, "s[1].a", constCoords.y());
   1483 							setUniform(gl, programID, "s[1].b", -1);
   1484 							setUniform(gl, programID, "s[2].a", constCoords.z());
   1485 							setUniform(gl, programID, "s[2].b", 2);
   1486 						},
   1487 						{ c.color.xyz() = c.constCoords.swizzle(2, 1, 0); });
   1488 
   1489 	UNIFORM_STRUCT_CASE(dynamic_loop_nested_struct_array, "Nested struct array usage in dynamic loop", false,
   1490 						LineStream() << "${HEADER}"
   1491 									 << "uniform int ui_zero;"
   1492 									 << "uniform int ui_one;"
   1493 									 << "uniform int ui_two;"
   1494 									 << "uniform int ui_three;"
   1495 									 << "uniform mediump float uf_two;"
   1496 									 << "uniform mediump float uf_three;"
   1497 									 << "uniform mediump float uf_four;"
   1498 									 << "uniform mediump float uf_half;"
   1499 									 << "uniform mediump float uf_third;"
   1500 									 << "uniform mediump float uf_fourth;"
   1501 									 << "uniform mediump float uf_sixth;"
   1502 									 << ""
   1503 									 << "struct T {"
   1504 									 << "    mediump float   a;"
   1505 									 << "    mediump vec2    b[2];"
   1506 									 << "};"
   1507 									 << "struct S {"
   1508 									 << "    mediump float   a;"
   1509 									 << "    T               b[3];"
   1510 									 << "    int             c;"
   1511 									 << "};"
   1512 									 << "uniform S s[2];"
   1513 									 << ""
   1514 									 << "void main (void)"
   1515 									 << "{"
   1516 									 << "    mediump float r = 0.0; // (x*3 + y*3) / 6.0"
   1517 									 << "    mediump float g = 0.0; // (y*3 + z*3) / 6.0"
   1518 									 << "    mediump float b = 0.0; // (z*3 + w*3) / 6.0"
   1519 									 << "    mediump float a = 1.0;"
   1520 									 << "    for (int i = 0; i < ui_two; i++)"
   1521 									 << "    {"
   1522 									 << "        for (int j = 0; j < ui_three; j++)"
   1523 									 << "        {"
   1524 									 << "            r += s[0].b[j].b[i].y;"
   1525 									 << "            g += s[i].b[j].b[0].x;"
   1526 									 << "            b += s[i].b[j].b[1].x;"
   1527 									 << "            a *= s[i].b[j].a;"
   1528 									 << "        }"
   1529 									 << "    }"
   1530 									 << "    ${DST} = vec4(r*uf_sixth, g*uf_sixth, b*uf_sixth, a);"
   1531 									 << "    ${ASSIGN_POS}"
   1532 									 << "}",
   1533 						{
   1534 							tcu::Vec2 arr[2];
   1535 
   1536 							setUniform(gl, programID, "s[0].a", constCoords.x());
   1537 							arr[0] = constCoords.swizzle(1, 0);
   1538 							arr[1] = constCoords.swizzle(2, 0);
   1539 							setUniform(gl, programID, "s[0].b[0].a", 0.5f);
   1540 							setUniform(gl, programID, "s[0].b[0].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1541 							arr[0] = constCoords.swizzle(1, 1);
   1542 							arr[1] = constCoords.swizzle(3, 1);
   1543 							setUniform(gl, programID, "s[0].b[1].a", 1.0f / 3.0f);
   1544 							setUniform(gl, programID, "s[0].b[1].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1545 							arr[0] = constCoords.swizzle(2, 1);
   1546 							arr[1] = constCoords.swizzle(2, 1);
   1547 							setUniform(gl, programID, "s[0].b[2].a", 1.0f / 4.0f);
   1548 							setUniform(gl, programID, "s[0].b[2].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1549 							setUniform(gl, programID, "s[0].c", 0);
   1550 
   1551 							setUniform(gl, programID, "s[1].a", constCoords.w());
   1552 							arr[0] = constCoords.swizzle(2, 0);
   1553 							arr[1] = constCoords.swizzle(2, 1);
   1554 							setUniform(gl, programID, "s[1].b[0].a", 2.0f);
   1555 							setUniform(gl, programID, "s[1].b[0].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1556 							arr[0] = constCoords.swizzle(2, 2);
   1557 							arr[1] = constCoords.swizzle(3, 3);
   1558 							setUniform(gl, programID, "s[1].b[1].a", 3.0f);
   1559 							setUniform(gl, programID, "s[1].b[1].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1560 							arr[0] = constCoords.swizzle(1, 0);
   1561 							arr[1] = constCoords.swizzle(3, 2);
   1562 							setUniform(gl, programID, "s[1].b[2].a", 4.0f);
   1563 							setUniform(gl, programID, "s[1].b[2].b", &arr[0], DE_LENGTH_OF_ARRAY(arr));
   1564 							setUniform(gl, programID, "s[1].c", 1);
   1565 						},
   1566 						{ c.color.xyz() = (c.constCoords.swizzle(0, 1, 2) + c.constCoords.swizzle(1, 2, 3)) * 0.5f; });
   1567 
   1568 	UNIFORM_STRUCT_CASE(
   1569 		sampler, "Sampler in struct", true,
   1570 		LineStream() << "${HEADER}"
   1571 					 << "uniform int ui_one;"
   1572 					 << ""
   1573 					 << "struct S {"
   1574 					 << "    mediump float   a;"
   1575 					 << "    mediump vec3    b;"
   1576 					 << "    sampler2D       c;"
   1577 					 << "};"
   1578 					 << "uniform S s;"
   1579 					 << ""
   1580 					 << "void main (void)"
   1581 					 << "{"
   1582 					 << "    ${DST} = vec4(texture(s.c, ${COORDS}.xy * s.b.xy + s.b.z).rgb, s.a);"
   1583 					 << "    ${ASSIGN_POS}"
   1584 					 << "}",
   1585 		{
   1586 			DE_UNREF(constCoords);
   1587 			setUniform(gl, programID, "s.a", 1.0f);
   1588 			setUniform(gl, programID, "s.b", tcu::Vec3(0.75f, 0.75f, 0.1f));
   1589 			setUniform(gl, programID, "s.c", TEXTURE_GRADIENT);
   1590 		},
   1591 		{ c.color.xyz() = c.texture2D(TEXTURE_GRADIENT, c.coords.swizzle(0, 1) * 0.75f + 0.1f).swizzle(0, 1, 2); });
   1592 
   1593 	UNIFORM_STRUCT_CASE(
   1594 		sampler_nested, "Sampler in nested struct", true,
   1595 		LineStream() << "${HEADER}"
   1596 					 << "uniform int ui_zero;"
   1597 					 << "uniform int ui_one;"
   1598 					 << ""
   1599 					 << "struct T {"
   1600 					 << "    sampler2D       a;"
   1601 					 << "    mediump vec2    b;"
   1602 					 << "};"
   1603 					 << "struct S {"
   1604 					 << "    mediump float   a;"
   1605 					 << "    T               b;"
   1606 					 << "    int             c;"
   1607 					 << "};"
   1608 					 << "uniform S s;"
   1609 					 << ""
   1610 					 << "void main (void)"
   1611 					 << "{"
   1612 					 << "    ${DST} = vec4(texture(s.b.a, ${COORDS}.xy * s.b.b + s.a).rgb, s.c);"
   1613 					 << "    ${ASSIGN_POS}"
   1614 					 << "}",
   1615 		{
   1616 			DE_UNREF(constCoords);
   1617 			setUniform(gl, programID, "s.a", 0.1f);
   1618 			setUniform(gl, programID, "s.b.a", TEXTURE_GRADIENT);
   1619 			setUniform(gl, programID, "s.b.b", tcu::Vec2(0.75f, 0.75f));
   1620 			setUniform(gl, programID, "s.c", 1);
   1621 		},
   1622 		{ c.color.xyz() = c.texture2D(TEXTURE_GRADIENT, c.coords.swizzle(0, 1) * 0.75f + 0.1f).swizzle(0, 1, 2); });
   1623 
   1624 	UNIFORM_STRUCT_CASE(
   1625 		sampler_array, "Sampler in struct array", true,
   1626 		LineStream() << "${HEADER}"
   1627 					 << "uniform int ui_one;"
   1628 					 << ""
   1629 					 << "struct S {"
   1630 					 << "    mediump float   a;"
   1631 					 << "    mediump vec3    b;"
   1632 					 << "    sampler2D       c;"
   1633 					 << "};"
   1634 					 << "uniform S s[2];"
   1635 					 << ""
   1636 					 << "void main (void)"
   1637 					 << "{"
   1638 					 << "    ${DST} = vec4(texture(s[1].c, ${COORDS}.xy * s[0].b.xy + s[1].b.z).rgb, s[0].a);"
   1639 					 << "    ${ASSIGN_POS}"
   1640 					 << "}",
   1641 		{
   1642 			DE_UNREF(constCoords);
   1643 			setUniform(gl, programID, "s[0].a", 1.0f);
   1644 			setUniform(gl, programID, "s[0].b", tcu::Vec3(0.75f, 0.75f, 0.25f));
   1645 			setUniform(gl, programID, "s[0].c", 1);
   1646 			setUniform(gl, programID, "s[1].a", 0.0f);
   1647 			setUniform(gl, programID, "s[1].b", tcu::Vec3(0.5f, 0.5f, 0.1f));
   1648 			setUniform(gl, programID, "s[1].c", TEXTURE_GRADIENT);
   1649 		},
   1650 		{ c.color.xyz() = c.texture2D(TEXTURE_GRADIENT, c.coords.swizzle(0, 1) * 0.75f + 0.1f).swizzle(0, 1, 2); });
   1651 }
   1652 
   1653 ShaderStructTests::ShaderStructTests(Context& context, glu::GLSLVersion glslVersion)
   1654 	: TestCaseGroup(context, "struct", "Struct Tests"), m_glslVersion(glslVersion)
   1655 {
   1656 }
   1657 
   1658 ShaderStructTests::~ShaderStructTests(void)
   1659 {
   1660 }
   1661 
   1662 void ShaderStructTests::init(void)
   1663 {
   1664 	addChild(new LocalStructTests(m_context, m_glslVersion));
   1665 	addChild(new UniformStructTests(m_context, m_glslVersion));
   1666 }
   1667 
   1668 } // deqp
   1669