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