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