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