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