• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 };	/* NOLINT(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 {																																	\
1195 				 static void setUniforms (const glw::Functions& gl, deUint32 programID, const tcu::Vec4& constCoords) SET_UNIFORMS_BODY /* NOLINT(SET_UNIFORMS_BODY) */ \
1196 			};																																							\
1197 			struct Eval_##NAME { static void eval (ShaderEvalContext& c) EVAL_FUNC_BODY };	/* NOLINT(EVAL_FUNC_BODY) */												\
1198 			addChild(createStructCase(m_context, #NAME "_vertex", DESCRIPTION, true, TEXTURES, Eval_##NAME::eval, SetUniforms_##NAME::setUniforms, SHADER_SRC));		\
1199 			addChild(createStructCase(m_context, #NAME "_fragment", DESCRIPTION, false, TEXTURES, Eval_##NAME::eval, SetUniforms_##NAME::setUniforms, SHADER_SRC));		\
1200 		} while (deGetFalse())
1201 
1202 	UNIFORM_STRUCT_CASE(basic, "Basic struct usage", false,
1203 		LineStream()
1204 		<< "${HEADER}"
1205 		<< "uniform int ui_one;"
1206 		<< ""
1207 		<< "struct S {"
1208 		<< "	mediump float	a;"
1209 		<< "	mediump vec3	b;"
1210 		<< "	int				c;"
1211 		<< "};"
1212 		<< "uniform S s;"
1213 		<< ""
1214 		<< "void main (void)"
1215 		<< "{"
1216 		<< "	${DST} = vec4(s.a, s.b.x, s.b.y, s.c);"
1217 		<< "	${ASSIGN_POS}"
1218 		<< "}",
1219 		{
1220 			setUniform(gl, programID, "s.a", constCoords.x());
1221 			setUniform(gl, programID, "s.b", constCoords.swizzle(1, 2, 3));
1222 			setUniform(gl, programID, "s.c", 1);
1223 		},
1224 		{
1225 			c.color.xyz() = c.constCoords.swizzle(0,1,2);
1226 		});
1227 
1228 	UNIFORM_STRUCT_CASE(nested, "Nested struct", false,
1229 		LineStream()
1230 		<< "${HEADER}"
1231 		<< "uniform int ui_zero;"
1232 		<< "uniform int ui_one;"
1233 		<< ""
1234 		<< "struct T {"
1235 		<< "	int				a;"
1236 		<< "	mediump vec2	b;"
1237 		<< "};"
1238 		<< "struct S {"
1239 		<< "	mediump float	a;"
1240 		<< "	T				b;"
1241 		<< "	int				c;"
1242 		<< "};"
1243 		<< "uniform S s;"
1244 		<< ""
1245 		<< "void main (void)"
1246 		<< "{"
1247 		<< "	${DST} = vec4(s.a, s.b.b, s.b.a + s.c);"
1248 		<< "	${ASSIGN_POS}"
1249 		<< "}",
1250 		{
1251 			setUniform(gl, programID, "s.a",	constCoords.x());
1252 			setUniform(gl, programID, "s.b.a",	0);
1253 			setUniform(gl, programID, "s.b.b",	constCoords.swizzle(1,2));
1254 			setUniform(gl, programID, "s.c",	1);
1255 		},
1256 		{
1257 			c.color.xyz() = c.constCoords.swizzle(0,1,2);
1258 		});
1259 
1260 	UNIFORM_STRUCT_CASE(array_member, "Struct with array member", false,
1261 		LineStream()
1262 		<< "${HEADER}"
1263 		<< "uniform int ui_one;"
1264 		<< ""
1265 		<< "struct S {"
1266 		<< "	mediump float	a;"
1267 		<< "	mediump float	b[3];"
1268 		<< "	int				c;"
1269 		<< "};"
1270 		<< "uniform S s;"
1271 		<< ""
1272 		<< "void main (void)"
1273 		<< "{"
1274 		<< "	${DST} = vec4(s.a, s.b[0], s.b[1], s.c);"
1275 		<< "	${ASSIGN_POS}"
1276 		<< "}",
1277 		{
1278 			setUniform(gl, programID, "s.a",	constCoords.w());
1279 			setUniform(gl, programID, "s.c",	1);
1280 
1281 			float b[3];
1282 			b[0] = constCoords.z();
1283 			b[1] = constCoords.y();
1284 			b[2] = constCoords.x();
1285 			setUniform(gl, programID, "s.b", b, DE_LENGTH_OF_ARRAY(b));
1286 		},
1287 		{
1288 			c.color.xyz() = c.constCoords.swizzle(3,2,1);
1289 		});
1290 
1291 	UNIFORM_STRUCT_CASE(array_member_dynamic_index, "Struct with array member, dynamic indexing", false,
1292 		LineStream()
1293 		<< "${HEADER}"
1294 		<< "uniform int ui_zero;"
1295 		<< "uniform int ui_one;"
1296 		<< "uniform int ui_two;"
1297 		<< ""
1298 		<< "struct S {"
1299 		<< "	mediump float	a;"
1300 		<< "	mediump float	b[3];"
1301 		<< "	int				c;"
1302 		<< "};"
1303 		<< "uniform S s;"
1304 		<< ""
1305 		<< "void main (void)"
1306 		<< "{"
1307 		<< "	${DST} = vec4(s.b[ui_one], s.b[ui_zero], s.b[ui_two], s.c);"
1308 		<< "	${ASSIGN_POS}"
1309 		<< "}",
1310 		{
1311 			setUniform(gl, programID, "s.a",	constCoords.w());
1312 			setUniform(gl, programID, "s.c",	1);
1313 
1314 			float b[3];
1315 			b[0] = constCoords.z();
1316 			b[1] = constCoords.y();
1317 			b[2] = constCoords.x();
1318 			setUniform(gl, programID, "s.b", b, DE_LENGTH_OF_ARRAY(b));
1319 		},
1320 		{
1321 			c.color.xyz() = c.constCoords.swizzle(1,2,0);
1322 		});
1323 
1324 	UNIFORM_STRUCT_CASE(struct_array, "Struct array", false,
1325 		LineStream()
1326 		<< "${HEADER}"
1327 		<< "uniform int ui_zero;"
1328 		<< "uniform int ui_one;"
1329 		<< "uniform int ui_two;"
1330 		<< ""
1331 		<< "struct S {"
1332 		<< "	mediump float	a;"
1333 		<< "	mediump int		b;"
1334 		<< "};"
1335 		<< "uniform S s[3];"
1336 		<< ""
1337 		<< "void main (void)"
1338 		<< "{"
1339 		<< "	${DST} = vec4(s[2].a, s[1].a, s[0].a, s[2].b - s[1].b + s[0].b);"
1340 		<< "	${ASSIGN_POS}"
1341 		<< "}",
1342 		{
1343 			setUniform(gl, programID, "s[0].a",	constCoords.x());
1344 			setUniform(gl, programID, "s[0].b",	0);
1345 			setUniform(gl, programID, "s[1].a",	constCoords.y());
1346 			setUniform(gl, programID, "s[1].b",	1);
1347 			setUniform(gl, programID, "s[2].a",	constCoords.z());
1348 			setUniform(gl, programID, "s[2].b",	2);
1349 		},
1350 		{
1351 			c.color.xyz() = c.constCoords.swizzle(2,1,0);
1352 		});
1353 
1354 	UNIFORM_STRUCT_CASE(struct_array_dynamic_index, "Struct array with dynamic indexing", false,
1355 		LineStream()
1356 		<< "${HEADER}"
1357 		<< "uniform int ui_zero;"
1358 		<< "uniform int ui_one;"
1359 		<< "uniform int ui_two;"
1360 		<< ""
1361 		<< "struct S {"
1362 		<< "	mediump float	a;"
1363 		<< "	mediump int		b;"
1364 		<< "};"
1365 		<< "uniform S s[3];"
1366 		<< ""
1367 		<< "void main (void)"
1368 		<< "{"
1369 		<< "	${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);"
1370 		<< "	${ASSIGN_POS}"
1371 		<< "}",
1372 		{
1373 			setUniform(gl, programID, "s[0].a",	constCoords.x());
1374 			setUniform(gl, programID, "s[0].b",	0);
1375 			setUniform(gl, programID, "s[1].a",	constCoords.y());
1376 			setUniform(gl, programID, "s[1].b",	1);
1377 			setUniform(gl, programID, "s[2].a",	constCoords.z());
1378 			setUniform(gl, programID, "s[2].b",	2);
1379 		},
1380 		{
1381 			c.color.xyz() = c.constCoords.swizzle(2,1,0);
1382 		});
1383 
1384 	UNIFORM_STRUCT_CASE(nested_struct_array, "Nested struct array", false,
1385 		LineStream()
1386 		<< "${HEADER}"
1387 		<< "struct T {"
1388 		<< "	mediump float	a;"
1389 		<< "	mediump vec2	b[2];"
1390 		<< "};"
1391 		<< "struct S {"
1392 		<< "	mediump float	a;"
1393 		<< "	T				b[3];"
1394 		<< "	int				c;"
1395 		<< "};"
1396 		<< "uniform S s[2];"
1397 		<< ""
1398 		<< "void main (void)"
1399 		<< "{"
1400 		<< "	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"
1401 		<< "	mediump float g = s[1].b[0].b[0].y * s[0].b[2].a * s[1].b[2].a; // x * 0.25 * 4"
1402 		<< "	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"
1403 		<< "	mediump float a = float(s[0].c) + s[1].b[2].a - s[1].b[1].a; // 0 + 4.0 - 3.0"
1404 		<< "	${DST} = vec4(r, g, b, a);"
1405 		<< "	${ASSIGN_POS}"
1406 		<< "}",
1407 		{
1408 			tcu::Vec2 arr[2];
1409 
1410 			setUniform(gl, programID, "s[0].a",			constCoords.x());
1411 			arr[0] = constCoords.swizzle(0,1);
1412 			arr[1] = constCoords.swizzle(2,3);
1413 			setUniform(gl, programID, "s[0].b[0].a",	0.5f);
1414 			setUniform(gl, programID, "s[0].b[0].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1415 			arr[0] = constCoords.swizzle(2,3);
1416 			arr[1] = constCoords.swizzle(0,1);
1417 			setUniform(gl, programID, "s[0].b[1].a",	1.0f/3.0f);
1418 			setUniform(gl, programID, "s[0].b[1].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1419 			arr[0] = constCoords.swizzle(0,2);
1420 			arr[1] = constCoords.swizzle(1,3);
1421 			setUniform(gl, programID, "s[0].b[2].a",	1.0f/4.0f);
1422 			setUniform(gl, programID, "s[0].b[2].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1423 			setUniform(gl, programID, "s[0].c",			0);
1424 
1425 			setUniform(gl, programID, "s[1].a",			constCoords.w());
1426 			arr[0] = constCoords.swizzle(0,0);
1427 			arr[1] = constCoords.swizzle(1,1);
1428 			setUniform(gl, programID, "s[1].b[0].a",	2.0f);
1429 			setUniform(gl, programID, "s[1].b[0].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1430 			arr[0] = constCoords.swizzle(2,2);
1431 			arr[1] = constCoords.swizzle(3,3);
1432 			setUniform(gl, programID, "s[1].b[1].a",	3.0f);
1433 			setUniform(gl, programID, "s[1].b[1].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1434 			arr[0] = constCoords.swizzle(1,0);
1435 			arr[1] = constCoords.swizzle(3,2);
1436 			setUniform(gl, programID, "s[1].b[2].a",	4.0f);
1437 			setUniform(gl, programID, "s[1].b[2].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1438 			setUniform(gl, programID, "s[1].c",			1);
1439 		},
1440 		{
1441 			c.color.xyz() = c.constCoords.swizzle(2,0,3);
1442 		});
1443 
1444 	UNIFORM_STRUCT_CASE(nested_struct_array_dynamic_index, "Nested struct array with dynamic indexing", false,
1445 		LineStream()
1446 		<< "${HEADER}"
1447 		<< "uniform int ui_zero;"
1448 		<< "uniform int ui_one;"
1449 		<< "uniform int ui_two;"
1450 		<< ""
1451 		<< "struct T {"
1452 		<< "	mediump float	a;"
1453 		<< "	mediump vec2	b[2];"
1454 		<< "};"
1455 		<< "struct S {"
1456 		<< "	mediump float	a;"
1457 		<< "	T				b[3];"
1458 		<< "	int				c;"
1459 		<< "};"
1460 		<< "uniform S s[2];"
1461 		<< ""
1462 		<< "void main (void)"
1463 		<< "{"
1464 		<< "	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"
1465 		<< "	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"
1466 		<< "	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"
1467 		<< "	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"
1468 		<< "	${DST} = vec4(r, g, b, a);"
1469 		<< "	${ASSIGN_POS}"
1470 		<< "}",
1471 		{
1472 			tcu::Vec2 arr[2];
1473 
1474 			setUniform(gl, programID, "s[0].a",			constCoords.x());
1475 			arr[0] = constCoords.swizzle(0,1);
1476 			arr[1] = constCoords.swizzle(2,3);
1477 			setUniform(gl, programID, "s[0].b[0].a",	0.5f);
1478 			setUniform(gl, programID, "s[0].b[0].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1479 			arr[0] = constCoords.swizzle(2,3);
1480 			arr[1] = constCoords.swizzle(0,1);
1481 			setUniform(gl, programID, "s[0].b[1].a",	1.0f/3.0f);
1482 			setUniform(gl, programID, "s[0].b[1].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1483 			arr[0] = constCoords.swizzle(0,2);
1484 			arr[1] = constCoords.swizzle(1,3);
1485 			setUniform(gl, programID, "s[0].b[2].a",	1.0f/4.0f);
1486 			setUniform(gl, programID, "s[0].b[2].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1487 			setUniform(gl, programID, "s[0].c",			0);
1488 
1489 			setUniform(gl, programID, "s[1].a",			constCoords.w());
1490 			arr[0] = constCoords.swizzle(0,0);
1491 			arr[1] = constCoords.swizzle(1,1);
1492 			setUniform(gl, programID, "s[1].b[0].a",	2.0f);
1493 			setUniform(gl, programID, "s[1].b[0].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1494 			arr[0] = constCoords.swizzle(2,2);
1495 			arr[1] = constCoords.swizzle(3,3);
1496 			setUniform(gl, programID, "s[1].b[1].a",	3.0f);
1497 			setUniform(gl, programID, "s[1].b[1].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1498 			arr[0] = constCoords.swizzle(1,0);
1499 			arr[1] = constCoords.swizzle(3,2);
1500 			setUniform(gl, programID, "s[1].b[2].a",	4.0f);
1501 			setUniform(gl, programID, "s[1].b[2].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1502 			setUniform(gl, programID, "s[1].c",			1);
1503 		},
1504 		{
1505 			c.color.xyz() = c.constCoords.swizzle(2,0,3);
1506 		});
1507 
1508 	UNIFORM_STRUCT_CASE(loop_struct_array, "Struct array usage in loop", false,
1509 		LineStream()
1510 		<< "${HEADER}"
1511 		<< "uniform int ui_zero;"
1512 		<< "uniform int ui_one;"
1513 		<< "uniform int ui_two;"
1514 		<< ""
1515 		<< "struct S {"
1516 		<< "	mediump float	a;"
1517 		<< "	mediump int		b;"
1518 		<< "};"
1519 		<< "uniform S s[3];"
1520 		<< ""
1521 		<< "void main (void)"
1522 		<< "{"
1523 		<< "	mediump float rgb[3];"
1524 		<< "	int alpha = 0;"
1525 		<< "	for (int i = 0; i < 3; i++)"
1526 		<< "	{"
1527 		<< "		rgb[i] = s[2-i].a;"
1528 		<< "		alpha += s[i].b;"
1529 		<< "	}"
1530 		<< "	${DST} = vec4(rgb[0], rgb[1], rgb[2], alpha);"
1531 		<< "	${ASSIGN_POS}"
1532 		<< "}",
1533 		{
1534 			setUniform(gl, programID, "s[0].a",	constCoords.x());
1535 			setUniform(gl, programID, "s[0].b",	0);
1536 			setUniform(gl, programID, "s[1].a",	constCoords.y());
1537 			setUniform(gl, programID, "s[1].b",	-1);
1538 			setUniform(gl, programID, "s[2].a",	constCoords.z());
1539 			setUniform(gl, programID, "s[2].b",	2);
1540 		},
1541 		{
1542 			c.color.xyz() = c.constCoords.swizzle(2,1,0);
1543 		});
1544 
1545 	UNIFORM_STRUCT_CASE(loop_nested_struct_array, "Nested struct array usage in loop", false,
1546 		LineStream()
1547 		<< "${HEADER}"
1548 		<< "uniform int ui_zero;"
1549 		<< "uniform int ui_one;"
1550 		<< "uniform int ui_two;"
1551 		<< "uniform mediump float uf_two;"
1552 		<< "uniform mediump float uf_three;"
1553 		<< "uniform mediump float uf_four;"
1554 		<< "uniform mediump float uf_half;"
1555 		<< "uniform mediump float uf_third;"
1556 		<< "uniform mediump float uf_fourth;"
1557 		<< "uniform mediump float uf_sixth;"
1558 		<< ""
1559 		<< "struct T {"
1560 		<< "	mediump float	a;"
1561 		<< "	mediump vec2	b[2];"
1562 		<< "};"
1563 		<< "struct S {"
1564 		<< "	mediump float	a;"
1565 		<< "	T				b[3];"
1566 		<< "	int				c;"
1567 		<< "};"
1568 		<< "uniform S s[2];"
1569 		<< ""
1570 		<< "void main (void)"
1571 		<< "{"
1572 		<< "	mediump float r = 0.0; // (x*3 + y*3) / 6.0"
1573 		<< "	mediump float g = 0.0; // (y*3 + z*3) / 6.0"
1574 		<< "	mediump float b = 0.0; // (z*3 + w*3) / 6.0"
1575 		<< "	mediump float a = 1.0;"
1576 		<< "	for (int i = 0; i < 2; i++)"
1577 		<< "	{"
1578 		<< "		for (int j = 0; j < 3; j++)"
1579 		<< "		{"
1580 		<< "			r += s[0].b[j].b[i].y;"
1581 		<< "			g += s[i].b[j].b[0].x;"
1582 		<< "			b += s[i].b[j].b[1].x;"
1583 		<< "			a *= s[i].b[j].a;"
1584 		<< "		}"
1585 		<< "	}"
1586 		<< "	${DST} = vec4(r*uf_sixth, g*uf_sixth, b*uf_sixth, a);"
1587 		<< "	${ASSIGN_POS}"
1588 		<< "}",
1589 		{
1590 			tcu::Vec2 arr[2];
1591 
1592 			setUniform(gl, programID, "s[0].a",			constCoords.x());
1593 			arr[0] = constCoords.swizzle(1,0);
1594 			arr[1] = constCoords.swizzle(2,0);
1595 			setUniform(gl, programID, "s[0].b[0].a",	0.5f);
1596 			setUniform(gl, programID, "s[0].b[0].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1597 			arr[0] = constCoords.swizzle(1,1);
1598 			arr[1] = constCoords.swizzle(3,1);
1599 			setUniform(gl, programID, "s[0].b[1].a",	1.0f/3.0f);
1600 			setUniform(gl, programID, "s[0].b[1].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1601 			arr[0] = constCoords.swizzle(2,1);
1602 			arr[1] = constCoords.swizzle(2,1);
1603 			setUniform(gl, programID, "s[0].b[2].a",	1.0f/4.0f);
1604 			setUniform(gl, programID, "s[0].b[2].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1605 			setUniform(gl, programID, "s[0].c",			0);
1606 
1607 			setUniform(gl, programID, "s[1].a",			constCoords.w());
1608 			arr[0] = constCoords.swizzle(2,0);
1609 			arr[1] = constCoords.swizzle(2,1);
1610 			setUniform(gl, programID, "s[1].b[0].a",	2.0f);
1611 			setUniform(gl, programID, "s[1].b[0].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1612 			arr[0] = constCoords.swizzle(2,2);
1613 			arr[1] = constCoords.swizzle(3,3);
1614 			setUniform(gl, programID, "s[1].b[1].a",	3.0f);
1615 			setUniform(gl, programID, "s[1].b[1].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1616 			arr[0] = constCoords.swizzle(1,0);
1617 			arr[1] = constCoords.swizzle(3,2);
1618 			setUniform(gl, programID, "s[1].b[2].a",	4.0f);
1619 			setUniform(gl, programID, "s[1].b[2].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1620 			setUniform(gl, programID, "s[1].c",			1);
1621 		},
1622 		{
1623 			c.color.xyz() = (c.constCoords.swizzle(0,1,2) + c.constCoords.swizzle(1,2,3)) * 0.5f;
1624 		});
1625 
1626 	UNIFORM_STRUCT_CASE(dynamic_loop_struct_array, "Struct array usage in dynamic loop", false,
1627 		LineStream()
1628 		<< "${HEADER}"
1629 		<< "uniform int ui_zero;"
1630 		<< "uniform int ui_one;"
1631 		<< "uniform int ui_two;"
1632 		<< "uniform int ui_three;"
1633 		<< ""
1634 		<< "struct S {"
1635 		<< "	mediump float	a;"
1636 		<< "	mediump int		b;"
1637 		<< "};"
1638 		<< "uniform S s[3];"
1639 		<< ""
1640 		<< "void main (void)"
1641 		<< "{"
1642 		<< "	mediump float rgb[3];"
1643 		<< "	int alpha = 0;"
1644 		<< "	for (int i = 0; i < ui_three; i++)"
1645 		<< "	{"
1646 		<< "		rgb[i] = s[2-i].a;"
1647 		<< "		alpha += s[i].b;"
1648 		<< "	}"
1649 		<< "	${DST} = vec4(rgb[0], rgb[1], rgb[2], alpha);"
1650 		<< "	${ASSIGN_POS}"
1651 		<< "}",
1652 		{
1653 			setUniform(gl, programID, "s[0].a",	constCoords.x());
1654 			setUniform(gl, programID, "s[0].b",	0);
1655 			setUniform(gl, programID, "s[1].a",	constCoords.y());
1656 			setUniform(gl, programID, "s[1].b",	-1);
1657 			setUniform(gl, programID, "s[2].a",	constCoords.z());
1658 			setUniform(gl, programID, "s[2].b",	2);
1659 		},
1660 		{
1661 			c.color.xyz() = c.constCoords.swizzle(2,1,0);
1662 		});
1663 
1664 	UNIFORM_STRUCT_CASE(dynamic_loop_nested_struct_array, "Nested struct array usage in dynamic loop", false,
1665 		LineStream()
1666 		<< "${HEADER}"
1667 		<< "uniform int ui_zero;"
1668 		<< "uniform int ui_one;"
1669 		<< "uniform int ui_two;"
1670 		<< "uniform int ui_three;"
1671 		<< "uniform mediump float uf_two;"
1672 		<< "uniform mediump float uf_three;"
1673 		<< "uniform mediump float uf_four;"
1674 		<< "uniform mediump float uf_half;"
1675 		<< "uniform mediump float uf_third;"
1676 		<< "uniform mediump float uf_fourth;"
1677 		<< "uniform mediump float uf_sixth;"
1678 		<< ""
1679 		<< "struct T {"
1680 		<< "	mediump float	a;"
1681 		<< "	mediump vec2	b[2];"
1682 		<< "};"
1683 		<< "struct S {"
1684 		<< "	mediump float	a;"
1685 		<< "	T				b[3];"
1686 		<< "	int				c;"
1687 		<< "};"
1688 		<< "uniform S s[2];"
1689 		<< ""
1690 		<< "void main (void)"
1691 		<< "{"
1692 		<< "	mediump float r = 0.0; // (x*3 + y*3) / 6.0"
1693 		<< "	mediump float g = 0.0; // (y*3 + z*3) / 6.0"
1694 		<< "	mediump float b = 0.0; // (z*3 + w*3) / 6.0"
1695 		<< "	mediump float a = 1.0;"
1696 		<< "	for (int i = 0; i < ui_two; i++)"
1697 		<< "	{"
1698 		<< "		for (int j = 0; j < ui_three; j++)"
1699 		<< "		{"
1700 		<< "			r += s[0].b[j].b[i].y;"
1701 		<< "			g += s[i].b[j].b[0].x;"
1702 		<< "			b += s[i].b[j].b[1].x;"
1703 		<< "			a *= s[i].b[j].a;"
1704 		<< "		}"
1705 		<< "	}"
1706 		<< "	${DST} = vec4(r*uf_sixth, g*uf_sixth, b*uf_sixth, a);"
1707 		<< "	${ASSIGN_POS}"
1708 		<< "}",
1709 		{
1710 			tcu::Vec2 arr[2];
1711 
1712 			setUniform(gl, programID, "s[0].a",			constCoords.x());
1713 			arr[0] = constCoords.swizzle(1,0);
1714 			arr[1] = constCoords.swizzle(2,0);
1715 			setUniform(gl, programID, "s[0].b[0].a",	0.5f);
1716 			setUniform(gl, programID, "s[0].b[0].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1717 			arr[0] = constCoords.swizzle(1,1);
1718 			arr[1] = constCoords.swizzle(3,1);
1719 			setUniform(gl, programID, "s[0].b[1].a",	1.0f/3.0f);
1720 			setUniform(gl, programID, "s[0].b[1].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1721 			arr[0] = constCoords.swizzle(2,1);
1722 			arr[1] = constCoords.swizzle(2,1);
1723 			setUniform(gl, programID, "s[0].b[2].a",	1.0f/4.0f);
1724 			setUniform(gl, programID, "s[0].b[2].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1725 			setUniform(gl, programID, "s[0].c",			0);
1726 
1727 			setUniform(gl, programID, "s[1].a",			constCoords.w());
1728 			arr[0] = constCoords.swizzle(2,0);
1729 			arr[1] = constCoords.swizzle(2,1);
1730 			setUniform(gl, programID, "s[1].b[0].a",	2.0f);
1731 			setUniform(gl, programID, "s[1].b[0].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1732 			arr[0] = constCoords.swizzle(2,2);
1733 			arr[1] = constCoords.swizzle(3,3);
1734 			setUniform(gl, programID, "s[1].b[1].a",	3.0f);
1735 			setUniform(gl, programID, "s[1].b[1].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1736 			arr[0] = constCoords.swizzle(1,0);
1737 			arr[1] = constCoords.swizzle(3,2);
1738 			setUniform(gl, programID, "s[1].b[2].a",	4.0f);
1739 			setUniform(gl, programID, "s[1].b[2].b",	&arr[0], DE_LENGTH_OF_ARRAY(arr));
1740 			setUniform(gl, programID, "s[1].c",			1);
1741 		},
1742 		{
1743 			c.color.xyz() = (c.constCoords.swizzle(0,1,2) + c.constCoords.swizzle(1,2,3)) * 0.5f;
1744 		});
1745 
1746 	UNIFORM_STRUCT_CASE(sampler, "Sampler in struct", true,
1747 		LineStream()
1748 		<< "${HEADER}"
1749 		<< "uniform int ui_one;"
1750 		<< ""
1751 		<< "struct S {"
1752 		<< "	mediump float	a;"
1753 		<< "	mediump vec3	b;"
1754 		<< "	sampler2D		c;"
1755 		<< "};"
1756 		<< "uniform S s;"
1757 		<< ""
1758 		<< "void main (void)"
1759 		<< "{"
1760 		<< "	${DST} = vec4(texture(s.c, ${COORDS}.xy * s.b.xy + s.b.z).rgb, s.a);"
1761 		<< "	${ASSIGN_POS}"
1762 		<< "}",
1763 		{
1764 			DE_UNREF(constCoords);
1765 			setUniform(gl, programID, "s.a", 1.0f);
1766 			setUniform(gl, programID, "s.b", tcu::Vec3(0.25f, 0.25f, 0.5f));
1767 			setUniform(gl, programID, "s.c", 0);
1768 		},
1769 		{
1770 			c.color.xyz() = c.texture2D(TEXTURE_BRICK, c.coords.swizzle(0,1) * 0.25f + 0.5f).swizzle(0,1,2);
1771 		});
1772 
1773 	UNIFORM_STRUCT_CASE(sampler_nested, "Sampler in nested struct", true,
1774 		LineStream()
1775 		<< "${HEADER}"
1776 		<< "uniform int ui_zero;"
1777 		<< "uniform int ui_one;"
1778 		<< ""
1779 		<< "struct T {"
1780 		<< "	sampler2D		a;"
1781 		<< "	mediump vec2	b;"
1782 		<< "};"
1783 		<< "struct S {"
1784 		<< "	mediump float	a;"
1785 		<< "	T				b;"
1786 		<< "	int				c;"
1787 		<< "};"
1788 		<< "uniform S s;"
1789 		<< ""
1790 		<< "void main (void)"
1791 		<< "{"
1792 		<< "	${DST} = vec4(texture(s.b.a, ${COORDS}.xy * s.b.b + s.a).rgb, s.c);"
1793 		<< "	${ASSIGN_POS}"
1794 		<< "}",
1795 		{
1796 			DE_UNREF(constCoords);
1797 			setUniform(gl, programID, "s.a",	0.5f);
1798 			setUniform(gl, programID, "s.b.a",	0);
1799 			setUniform(gl, programID, "s.b.b",	tcu::Vec2(0.25f, 0.25f));
1800 			setUniform(gl, programID, "s.c",	1);
1801 		},
1802 		{
1803 			c.color.xyz() = c.texture2D(TEXTURE_BRICK, c.coords.swizzle(0,1) * 0.25f + 0.5f).swizzle(0,1,2);
1804 		});
1805 
1806 	UNIFORM_STRUCT_CASE(sampler_array, "Sampler in struct array", true,
1807 		LineStream()
1808 		<< "${HEADER}"
1809 		<< "uniform int ui_one;"
1810 		<< ""
1811 		<< "struct S {"
1812 		<< "	mediump float	a;"
1813 		<< "	mediump vec3	b;"
1814 		<< "	sampler2D		c;"
1815 		<< "};"
1816 		<< "uniform S s[2];"
1817 		<< ""
1818 		<< "void main (void)"
1819 		<< "{"
1820 		<< "	${DST} = vec4(texture(s[1].c, ${COORDS}.xy * s[0].b.xy + s[1].b.z).rgb, s[0].a);"
1821 		<< "	${ASSIGN_POS}"
1822 		<< "}",
1823 		{
1824 			DE_UNREF(constCoords);
1825 			setUniform(gl, programID, "s[0].a", 1.0f);
1826 			setUniform(gl, programID, "s[0].b", tcu::Vec3(0.25f, 0.25f, 0.25f));
1827 			setUniform(gl, programID, "s[0].c", 1);
1828 			setUniform(gl, programID, "s[1].a", 0.0f);
1829 			setUniform(gl, programID, "s[1].b", tcu::Vec3(0.5f, 0.5f, 0.5f));
1830 			setUniform(gl, programID, "s[1].c", 0);
1831 		},
1832 		{
1833 			c.color.xyz() = c.texture2D(TEXTURE_BRICK, c.coords.swizzle(0,1) * 0.25f + 0.5f).swizzle(0,1,2);
1834 		});
1835 
1836 	UNIFORM_STRUCT_CASE(equal, "Struct equality", false,
1837 		LineStream()
1838 		<< "${HEADER}"
1839 		<< "uniform mediump float uf_one;"
1840 		<< "uniform int ui_two;"
1841 		<< ""
1842 		<< "struct S {"
1843 		<< "	mediump float	a;"
1844 		<< "	mediump vec3	b;"
1845 		<< "	int				c;"
1846 		<< "};"
1847 		<< "uniform S a;"
1848 		<< "uniform S b;"
1849 		<< "uniform S c;"
1850 		<< ""
1851 		<< "void main (void)"
1852 		<< "{"
1853 		<< "	S d = S(uf_one, vec3(0.0, floor(${COORDS}.y+1.0), 2.0), ui_two);"
1854 		<< "	${DST} = vec4(0.0, 0.0, 0.0, 1.0);"
1855 		<< "	if (a == b) ${DST}.x = 1.0;"
1856 		<< "	if (a == c) ${DST}.y = 1.0;"
1857 		<< "	if (a == d) ${DST}.z = 1.0;"
1858 		<< "	${ASSIGN_POS}"
1859 		<< "}",
1860 		{
1861 			DE_UNREF(constCoords);
1862 			setUniform(gl, programID, "a.a", 1.0f);
1863 			setUniform(gl, programID, "a.b", tcu::Vec3(0.0f, 1.0f, 2.0f));
1864 			setUniform(gl, programID, "a.c", 2);
1865 			setUniform(gl, programID, "b.a", 1.0f);
1866 			setUniform(gl, programID, "b.b", tcu::Vec3(0.0f, 1.0f, 2.0f));
1867 			setUniform(gl, programID, "b.c", 2);
1868 			setUniform(gl, programID, "c.a", 1.0f);
1869 			setUniform(gl, programID, "c.b", tcu::Vec3(0.0f, 1.1f, 2.0f));
1870 			setUniform(gl, programID, "c.c", 2);
1871 		},
1872 		{
1873 			c.color.xy() = tcu::Vec2(1.0f, 0.0f);
1874 			if (deFloatFloor(c.coords[1]+1.0f) == deFloatFloor(1.1f))
1875 				c.color.z() = 1.0f;
1876 		});
1877 
1878 	UNIFORM_STRUCT_CASE(not_equal, "Struct equality", false,
1879 		LineStream()
1880 		<< "${HEADER}"
1881 		<< "uniform mediump float uf_one;"
1882 		<< "uniform int ui_two;"
1883 		<< ""
1884 		<< "struct S {"
1885 		<< "	mediump float	a;"
1886 		<< "	mediump vec3	b;"
1887 		<< "	int				c;"
1888 		<< "};"
1889 		<< "uniform S a;"
1890 		<< "uniform S b;"
1891 		<< "uniform S c;"
1892 		<< ""
1893 		<< "void main (void)"
1894 		<< "{"
1895 		<< "	S d = S(uf_one, vec3(0.0, floor(${COORDS}.y+1.0), 2.0), ui_two);"
1896 		<< "	${DST} = vec4(0.0, 0.0, 0.0, 1.0);"
1897 		<< "	if (a != b) ${DST}.x = 1.0;"
1898 		<< "	if (a != c) ${DST}.y = 1.0;"
1899 		<< "	if (a != d) ${DST}.z = 1.0;"
1900 		<< "	${ASSIGN_POS}"
1901 		<< "}",
1902 		{
1903 			DE_UNREF(constCoords);
1904 			setUniform(gl, programID, "a.a", 1.0f);
1905 			setUniform(gl, programID, "a.b", tcu::Vec3(0.0f, 1.0f, 2.0f));
1906 			setUniform(gl, programID, "a.c", 2);
1907 			setUniform(gl, programID, "b.a", 1.0f);
1908 			setUniform(gl, programID, "b.b", tcu::Vec3(0.0f, 1.0f, 2.0f));
1909 			setUniform(gl, programID, "b.c", 2);
1910 			setUniform(gl, programID, "c.a", 1.0f);
1911 			setUniform(gl, programID, "c.b", tcu::Vec3(0.0f, 1.1f, 2.0f));
1912 			setUniform(gl, programID, "c.c", 2);
1913 		},
1914 		{
1915 			c.color.xy() = tcu::Vec2(0.0f, 1.0f);
1916 			if (deFloatFloor(c.coords[1]+1.0f) != deFloatFloor(1.1f))
1917 				c.color.z() = 1.0f;
1918 		});
1919 }
1920 
ShaderStructTests(Context & context)1921 ShaderStructTests::ShaderStructTests (Context& context)
1922 	: TestCaseGroup(context, "struct", "Struct Tests")
1923 {
1924 }
1925 
~ShaderStructTests(void)1926 ShaderStructTests::~ShaderStructTests (void)
1927 {
1928 }
1929 
init(void)1930 void ShaderStructTests::init (void)
1931 {
1932 	addChild(new LocalStructTests(m_context));
1933 	addChild(new UniformStructTests(m_context));
1934 }
1935 
1936 } // Functional
1937 } // gles3
1938 } // deqp
1939