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
33using tcu::StringTemplate;
34
35using std::string;
36using std::vector;
37using std::ostringstream;
38
39using namespace glu;
40using namespace deqp::gls;
41
42namespace deqp
43{
44namespace gles3
45{
46namespace Functional
47{
48
49enum
50{
51	TEXTURE_BRICK = 0 //!< Unit index for brick texture
52};
53
54typedef void (*SetupUniformsFunc) (const glw::Functions& gl, deUint32 programID, const tcu::Vec4& constCoords);
55
56class ShaderStructCase : public ShaderRenderCase
57{
58public:
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
67private:
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
77ShaderStructCase::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
87ShaderStructCase::~ShaderStructCase (void)
88{
89	delete m_brickTexture;
90}
91
92void 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
104void ShaderStructCase::deinit (void)
105{
106	gls::ShaderRenderCase::deinit();
107	delete m_brickTexture;
108	m_brickTexture = DE_NULL;
109}
110
111void 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
118static 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
169class LocalStructTests : public TestCaseGroup
170{
171public:
172	LocalStructTests (Context& context)
173		: TestCaseGroup(context, "local", "Local structs")
174	{
175	}
176
177	~LocalStructTests (void)
178	{
179	}
180
181	virtual void init (void);
182};
183
184void 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
1125class UniformStructTests : public TestCaseGroup
1126{
1127public:
1128	UniformStructTests (Context& context)
1129		: TestCaseGroup(context, "uniform", "Uniform structs")
1130	{
1131	}
1132
1133	~UniformStructTests (void)
1134	{
1135	}
1136
1137	virtual void init (void);
1138};
1139
1140namespace
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)															\
1146void 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}																											\
1152struct SetUniform##VECTYPE##Dummy_s { int unused; }
1153
1154#define MAKE_SET_VEC_UNIFORM_PTR(VECTYPE, SETUNIFORM)																		\
1155void 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}																															\
1161struct SetUniformPtr##VECTYPE##Dummy_s { int unused; }
1162
1163MAKE_SET_VEC_UNIFORM	(Vec2,	gl.uniform2fv);
1164MAKE_SET_VEC_UNIFORM	(Vec3,	gl.uniform3fv);
1165MAKE_SET_VEC_UNIFORM_PTR(Vec2,	gl.uniform2fv);
1166
1167void 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
1174void 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
1181void 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
1190void 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
1919ShaderStructTests::ShaderStructTests (Context& context)
1920	: TestCaseGroup(context, "struct", "Struct Tests")
1921{
1922}
1923
1924ShaderStructTests::~ShaderStructTests (void)
1925{
1926}
1927
1928void 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