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 };	/* 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
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 {																																	\
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
1921ShaderStructTests::ShaderStructTests (Context& context)
1922	: TestCaseGroup(context, "struct", "Struct Tests")
1923{
1924}
1925
1926ShaderStructTests::~ShaderStructTests (void)
1927{
1928}
1929
1930void 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