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