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