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