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