• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
31 namespace vkt
32 {
33 namespace sr
34 {
35 namespace
36 {
37 
38 class ShaderStructCase : public ShaderRenderCase
39 {
40 public:
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 
51 private:
52 						ShaderStructCase		(const ShaderStructCase&);
53 	ShaderStructCase&	operator=				(const ShaderStructCase&);
54 };
55 
ShaderStructCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,bool isVertexCase,ShaderEvalFunc evalFunc,UniformSetupFunc setupUniformsFunc,const std::string & vertShaderSource,const std::string & fragShaderSource)56 ShaderStructCase::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 
~ShaderStructCase(void)70 ShaderStructCase::~ShaderStructCase (void)
71 {
72 }
73 
createStructCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,bool isVertexCase,ShaderEvalFunc evalFunc,UniformSetupFunc uniformFunc,const LineStream & shaderSrc)74 static 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 
131 class LocalStructTests : public tcu::TestCaseGroup
132 {
133 public:
LocalStructTests(tcu::TestContext & testCtx)134 	LocalStructTests (tcu::TestContext& testCtx)
135 		: TestCaseGroup(testCtx, "local", "Local structs")
136 	{
137 	}
138 
~LocalStructTests(void)139 	~LocalStructTests (void)
140 	{
141 	}
142 
143 	virtual void init (void);
144 };
145 
init(void)146 void 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 }; /* NOLINT(SET_UNIFORMS_BODY) */ \
151 			struct Eval_##NAME { static void eval (ShaderEvalContext& c) EVAL_FUNC_BODY };	/* NOLINT(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 
1229 class UniformStructTests : public tcu::TestCaseGroup
1230 {
1231 public:
UniformStructTests(tcu::TestContext & testCtx)1232 	UniformStructTests (tcu::TestContext& testCtx)
1233 		: TestCaseGroup(testCtx, "uniform", "Uniform structs")
1234 	{
1235 	}
1236 
~UniformStructTests(void)1237 	~UniformStructTests (void)
1238 	{
1239 	}
1240 
1241 	virtual void init (void);
1242 };
1243 
init(void)1244 void 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 {																																	\
1249 				 static void setUniforms (ShaderRenderCaseInstance& instance, const tcu::Vec4& constCoords) SET_UNIFORMS_BODY  /* NOLINT(SET_UNIFORMS_BODY) */			\
1250 			};																																							\
1251 			struct Eval_##NAME { static void eval (ShaderEvalContext& c) EVAL_FUNC_BODY };  /* NOLINT(EVAL_FUNC_BODY) */												\
1252 			addChild(createStructCase(m_testCtx, #NAME "_vertex", DESCRIPTION, true, Eval_##NAME::eval, SetUniforms_##NAME::setUniforms, SHADER_SRC).release());		\
1253 			addChild(createStructCase(m_testCtx, #NAME "_fragment", DESCRIPTION, false, Eval_##NAME::eval, SetUniforms_##NAME::setUniforms, SHADER_SRC).release());		\
1254 		} while (deGetFalse())
1255 
1256 	UNIFORM_STRUCT_CASE(basic, "Basic struct usage",
1257 		LineStream()
1258 		<< "${HEADER}"
1259 		<< "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_one; };"
1260 		<< ""
1261 		<< "struct S {"
1262 		<< "	mediump float	a;"
1263 		<< "	mediump vec3	b;"
1264 		<< "	int				c;"
1265 		<< "};"
1266 		<< "layout (std140, set = 0, binding = 1) uniform buffer1 { S s; };"
1267 		<< ""
1268 		<< "void main (void)"
1269 		<< "{"
1270 		<< "	${DST} = vec4(s.a, s.b.x, s.b.y, s.c);"
1271 		<< "	${ASSIGN_POS}"
1272 		<< "}",
1273 		{
1274 			instance.useUniform(0u, UI_ONE);
1275 
1276 			struct S {
1277 				float			a;
1278 				float			_padding1[3];
1279 				tcu::Vec3		b;
1280 				int				c;
1281 			};
1282 
1283 			S s;
1284 			s.a = constCoords.x();
1285 			s.b = constCoords.swizzle(1, 2, 3);
1286 			s.c = 1;
1287 			instance.addUniform(1u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(S), &s);
1288 		},
1289 		{
1290 			c.color.xyz() = c.constCoords.swizzle(0, 1, 2);
1291 		});
1292 
1293 	UNIFORM_STRUCT_CASE(nested, "Nested struct",
1294 		LineStream()
1295 		<< "${HEADER}"
1296 		<< "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
1297 		<< "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
1298 		<< ""
1299 		<< "struct T {"
1300 		<< "	int				a;"
1301 		<< "	mediump vec2	b;"
1302 		<< "};"
1303 		<< "struct S {"
1304 		<< "	mediump float	a;"
1305 		<< "	T				b;"
1306 		<< "	int				c;"
1307 		<< "};"
1308 		<< "layout (std140, set = 0, binding = 2) uniform buffer2 { S s; };"
1309 		<< ""
1310 		<< "void main (void)"
1311 		<< "{"
1312 		<< "	${DST} = vec4(s.a, s.b.b, s.b.a + s.c);"
1313 		<< "	${ASSIGN_POS}"
1314 		<< "}",
1315 		{
1316 			instance.useUniform(0u, UI_ZERO);
1317 			instance.useUniform(1u, UI_ONE);
1318 
1319 			struct T {
1320 				int				a;
1321 				float			_padding1[1];
1322 				tcu::Vec2		b;
1323 			};
1324 
1325 			struct S {
1326 				float			a;
1327 				float			_padding1[3];
1328 				T				b;
1329 				int				c;
1330 				float			_padding2[3];
1331 			};
1332 
1333 			S s;
1334 			s.a = constCoords.x();
1335 			s.b.a = 0;
1336 			s.b.b = constCoords.swizzle(1, 2);
1337 			s.c = 1;
1338 			instance.addUniform(2u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,sizeof(S), &s);
1339 		},
1340 		{
1341 			c.color.xyz() = c.constCoords.swizzle(0, 1, 2);
1342 		});
1343 
1344 	UNIFORM_STRUCT_CASE(array_member, "Struct with array member",
1345 		LineStream()
1346 		<< "${HEADER}"
1347 		<< "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_one; };"
1348 		<< ""
1349 		<< "struct S {"
1350 		<< "	mediump float	a;"
1351 		<< "	mediump float	b[3];"
1352 		<< "	int				c;"
1353 		<< "};"
1354 		<< "layout (std140, set = 0, binding = 1) uniform buffer1 { S s; };"
1355 		<< ""
1356 		<< "void main (void)"
1357 		<< "{"
1358 		<< "	${DST} = vec4(s.a, s.b[0], s.b[1], s.c);"
1359 		<< "	${ASSIGN_POS}"
1360 		<< "}",
1361 		{
1362 			instance.useUniform(0u, UI_ONE);
1363 
1364 			struct paddedFloat {
1365 				float value;
1366 				float _padding[3];
1367 			};
1368 
1369 			struct S {
1370 				paddedFloat	a;
1371 				paddedFloat	b[3];
1372 				int			c;
1373 			};
1374 
1375 			S s;
1376 			s.a.value = constCoords.w();
1377 			s.b[0].value = constCoords.z();
1378 			s.b[1].value = constCoords.y();
1379 			s.b[2].value = constCoords.x();
1380 			s.c = 1;
1381 			instance.addUniform(1u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,sizeof(S), &s);
1382 		},
1383 		{
1384 			c.color.xyz() = c.constCoords.swizzle(3, 2, 1);
1385 		});
1386 
1387 	UNIFORM_STRUCT_CASE(array_member_dynamic_index, "Struct with array member, dynamic indexing",
1388 		LineStream()
1389 		<< "${HEADER}"
1390 		<< "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
1391 		<< "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
1392 		<< "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
1393 		<< ""
1394 		<< "struct S {"
1395 		<< "	mediump float	a;"
1396 		<< "	mediump float	b[3];"
1397 		<< "	int				c;"
1398 		<< "};"
1399 		<< "layout (std140, set = 0, binding = 3) uniform buffer3 { S s; };"
1400 		<< ""
1401 		<< "void main (void)"
1402 		<< "{"
1403 		<< "	${DST} = vec4(s.b[ui_one], s.b[ui_zero], s.b[ui_two], s.c);"
1404 		<< "	${ASSIGN_POS}"
1405 		<< "}",
1406 		{
1407 			instance.useUniform(0u, UI_ZERO);
1408 			instance.useUniform(1u, UI_ONE);
1409 			instance.useUniform(2u, UI_TWO);
1410 
1411 			struct paddedFloat {
1412 				float value;
1413 				float _padding[3];
1414 			};
1415 
1416 			struct S {
1417 				paddedFloat	a;
1418 				paddedFloat	b[3];
1419 				int			c;
1420 			};
1421 
1422 			S s;
1423 			s.a.value = constCoords.w();
1424 			s.b[0].value = constCoords.z();
1425 			s.b[1].value = constCoords.y();
1426 			s.b[2].value = constCoords.x();
1427 			s.c = 1;
1428 			instance.addUniform(3u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(S), &s);
1429 		},
1430 		{
1431 			c.color.xyz() = c.constCoords.swizzle(1, 2, 0);
1432 		});
1433 
1434 	UNIFORM_STRUCT_CASE(struct_array, "Struct array",
1435 		LineStream()
1436 		<< "${HEADER}"
1437 		<< "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
1438 		<< "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
1439 		<< "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
1440 		<< ""
1441 		<< "struct S {"
1442 		<< "	mediump float	a;"
1443 		<< "	mediump int		b;"
1444 		<< "};"
1445 		<< "layout (std140, set = 0, binding = 3) uniform buffer3 { S s[3]; };"
1446 		<< ""
1447 		<< "void main (void)"
1448 		<< "{"
1449 		<< "	${DST} = vec4(s[2].a, s[1].a, s[0].a, s[2].b - s[1].b + s[0].b);"
1450 		<< "	${ASSIGN_POS}"
1451 		<< "}",
1452 		{
1453 			instance.useUniform(0u, UI_ZERO);
1454 			instance.useUniform(1u, UI_ONE);
1455 			instance.useUniform(2u, UI_TWO);
1456 
1457 			struct S {
1458 				float	a;
1459 				int		b;
1460 				float	_padding1[2];
1461 			};
1462 
1463 			S s[3];
1464 			s[0].a = constCoords.x();
1465 			s[0].b = 0;
1466 			s[1].a = constCoords.y();
1467 			s[1].b = 1;
1468 			s[2].a = constCoords.z();
1469 			s[2].b = 2;
1470 			instance.addUniform(3u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3 * sizeof(S), s);
1471 		},
1472 		{
1473 			c.color.xyz() = c.constCoords.swizzle(2, 1, 0);
1474 		});
1475 
1476 	UNIFORM_STRUCT_CASE(struct_array_dynamic_index, "Struct array with dynamic indexing",
1477 		LineStream()
1478 		<< "${HEADER}"
1479 		<< "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
1480 		<< "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
1481 		<< "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
1482 		<< ""
1483 		<< "struct S {"
1484 		<< "	mediump float	a;"
1485 		<< "	mediump int		b;"
1486 		<< "};"
1487 		<< "layout (std140, set = 0, binding = 3) uniform buffer3 { S s[3]; };"
1488 		<< ""
1489 		<< "void main (void)"
1490 		<< "{"
1491 		<< "	${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);"
1492 		<< "	${ASSIGN_POS}"
1493 		<< "}",
1494 		{
1495 			instance.useUniform(0u, UI_ZERO);
1496 			instance.useUniform(1u, UI_ONE);
1497 			instance.useUniform(2u, UI_TWO);
1498 
1499 			struct S {
1500 				float	a;
1501 				int		b;
1502 				float	_padding1[2];
1503 			};
1504 
1505 			S s[3];
1506 			s[0].a = constCoords.x();
1507 			s[0].b = 0;
1508 			s[1].a = constCoords.y();
1509 			s[1].b = 1;
1510 			s[2].a = constCoords.z();
1511 			s[2].b = 2;
1512 			instance.addUniform(3u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3 * sizeof(S), s);
1513 		},
1514 		{
1515 			c.color.xyz() = c.constCoords.swizzle(2, 1, 0);
1516 		});
1517 
1518 	UNIFORM_STRUCT_CASE(nested_struct_array, "Nested struct array",
1519 		LineStream()
1520 		<< "${HEADER}"
1521 		<< "struct T {"
1522 		<< "	mediump float	a;"
1523 		<< "	mediump vec2	b[2];"
1524 		<< "};"
1525 		<< "struct S {"
1526 		<< "	mediump float	a;"
1527 		<< "	T				b[3];"
1528 		<< "	int				c;"
1529 		<< "};"
1530 		<< "layout (std140, set = 0, binding = 0) uniform buffer0 { S s[2]; };"
1531 		<< ""
1532 		<< "void main (void)"
1533 		<< "{"
1534 		<< "	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"
1535 		<< "	mediump float g = s[1].b[0].b[0].y * s[0].b[2].a * s[1].b[2].a; // x * 0.25 * 4"
1536 		<< "	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"
1537 		<< "	mediump float a = float(s[0].c) + s[1].b[2].a - s[1].b[1].a; // 0 + 4.0 - 3.0"
1538 		<< "	${DST} = vec4(r, g, b, a);"
1539 		<< "	${ASSIGN_POS}"
1540 		<< "}",
1541 		{
1542 
1543 			struct T {
1544 				float		a;
1545 				float		_padding1[3];
1546 				tcu::Vec4	b[2];
1547 			};
1548 
1549 			struct S {
1550 				float	a;
1551 				float	_padding1[3];
1552 				T		b[3];
1553 				int		c;
1554 				float	_padding2[3];
1555 			};
1556 
1557 			S s[2];
1558 			s[0].a = constCoords.x();
1559 			s[0].b[0].a = 0.5f;
1560 			s[0].b[0].b[0] = constCoords.swizzle(0,1,0,0);
1561 			s[0].b[0].b[1] = constCoords.swizzle(2,3,0,0);
1562 			s[0].b[1].a = 1.0f / 3.0f;
1563 			s[0].b[1].b[0] = constCoords.swizzle(2,3,0,0);
1564 			s[0].b[1].b[1] = constCoords.swizzle(0,1,0,0);
1565 			s[0].b[2].a = 1.0f / 4.0f;
1566 			s[0].b[2].b[0] = constCoords.swizzle(0,2,0,0);
1567 			s[0].b[2].b[1] = constCoords.swizzle(1,3,0,0);
1568 			s[0].c = 0;
1569 
1570 			s[1].a = constCoords.w();
1571 			s[1].b[0].a = 2.0f;
1572 			s[1].b[0].b[0] = constCoords.swizzle(0,0,0,0);
1573 			s[1].b[0].b[1] = constCoords.swizzle(1,1,0,0);
1574 			s[1].b[1].a = 3.0f;
1575 			s[1].b[1].b[0] = constCoords.swizzle(2,2,0,0);
1576 			s[1].b[1].b[1] = constCoords.swizzle(3,3,0,0);
1577 			s[1].b[2].a = 4.0f;
1578 			s[1].b[2].b[0] = constCoords.swizzle(1,0,0,0);
1579 			s[1].b[2].b[1] = constCoords.swizzle(3,2,0,0);
1580 			s[1].c = 1;
1581 
1582 			instance.addUniform(0u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2 * sizeof(S), s);
1583 		},
1584 		{
1585 			c.color.xyz() = c.constCoords.swizzle(2, 0, 3);
1586 		});
1587 
1588 	UNIFORM_STRUCT_CASE(nested_struct_array_dynamic_index, "Nested struct array with dynamic indexing",
1589 		LineStream()
1590 		<< "${HEADER}"
1591 		<< "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
1592 		<< "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
1593 		<< "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
1594 		<< ""
1595 		<< "struct T {"
1596 		<< "	mediump float	a;"
1597 		<< "	mediump vec2	b[2];"
1598 		<< "};"
1599 		<< "struct S {"
1600 		<< "	mediump float	a;"
1601 		<< "	T				b[3];"
1602 		<< "	int				c;"
1603 		<< "};"
1604 		<< "layout (set = 0, binding = 3) uniform buffer3 { S s[2]; };"
1605 		<< ""
1606 		<< "void main (void)"
1607 		<< "{"
1608 		<< "	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"
1609 		<< "	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"
1610 		<< "	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"
1611 		<< "	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"
1612 		<< "	${DST} = vec4(r, g, b, a);"
1613 		<< "	${ASSIGN_POS}"
1614 		<< "}",
1615 		{
1616 			struct T {
1617 				float		a;
1618 				float		_padding1[3];
1619 				tcu::Vec4	b[2];
1620 			};
1621 
1622 			struct S {
1623 				float	a;
1624 				float	_padding1[3];
1625 				T		b[3];
1626 				int		c;
1627 				float	_padding2[3];
1628 			};
1629 
1630 			S s[2];
1631 			s[0].a = constCoords.x();
1632 			s[0].b[0].a = 0.5f;
1633 			s[0].b[0].b[0] = constCoords.swizzle(0,1,0,0);
1634 			s[0].b[0].b[1] = constCoords.swizzle(2,3,0,0);
1635 			s[0].b[1].a = 1.0f / 3.0f;
1636 			s[0].b[1].b[0] = constCoords.swizzle(2,3,0,0);
1637 			s[0].b[1].b[1] = constCoords.swizzle(0,1,0,0);
1638 			s[0].b[2].a = 1.0f / 4.0f;
1639 			s[0].b[2].b[0] = constCoords.swizzle(0,2,0,0);
1640 			s[0].b[2].b[1] = constCoords.swizzle(1,3,0,0);
1641 			s[0].c = 0;
1642 
1643 			s[1].a = constCoords.w();
1644 			s[1].b[0].a = 2.0f;
1645 			s[1].b[0].b[0] = constCoords.swizzle(0,0,0,0);
1646 			s[1].b[0].b[1] = constCoords.swizzle(1,1,0,0);
1647 			s[1].b[1].a = 3.0f;
1648 			s[1].b[1].b[0] = constCoords.swizzle(2,2,0,0);
1649 			s[1].b[1].b[1] = constCoords.swizzle(3,3,0,0);
1650 			s[1].b[2].a = 4.0f;
1651 			s[1].b[2].b[0] = constCoords.swizzle(1,0,0,0);
1652 			s[1].b[2].b[1] = constCoords.swizzle(3,2,0,0);
1653 			s[1].c = 1;
1654 
1655 			instance.useUniform(0u, UI_ZERO);
1656 			instance.useUniform(1u, UI_ONE);
1657 			instance.useUniform(2u, UI_TWO);
1658 			instance.addUniform(3u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2 * sizeof(S), s);
1659 		},
1660 		{
1661 			c.color.xyz() = c.constCoords.swizzle(2, 0, 3);
1662 		});
1663 	UNIFORM_STRUCT_CASE(loop_struct_array, "Struct array usage in loop",
1664 		LineStream()
1665 		<< "${HEADER}"
1666 		<< "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
1667 		<< "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
1668 		<< "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
1669 		<< ""
1670 		<< "struct S {"
1671 		<< "	mediump float	a;"
1672 		<< "	mediump int		b;"
1673 		<< "};"
1674 		<< "layout (std140, set = 0, binding = 3) uniform buffer3 { S s[3]; };"
1675 		<< ""
1676 		<< "void main (void)"
1677 		<< "{"
1678 		<< "	mediump float rgb[3];"
1679 		<< "	int alpha = 0;"
1680 		<< "	for (int i = 0; i < 3; i++)"
1681 		<< "	{"
1682 		<< "		rgb[i] = s[2-i].a;"
1683 		<< "		alpha += s[i].b;"
1684 		<< "	}"
1685 		<< "	${DST} = vec4(rgb[0], rgb[1], rgb[2], alpha);"
1686 		<< "	${ASSIGN_POS}"
1687 		<< "}",
1688 		{
1689 			instance.useUniform(0u, UI_ZERO);
1690 			instance.useUniform(1u, UI_ONE);
1691 			instance.useUniform(2u, UI_TWO);
1692 
1693 			struct S {
1694 				float	a;
1695 				int		b;
1696 				float	_padding1[2];
1697 			};
1698 
1699 			S s[3];
1700 			s[0].a = constCoords.x();
1701 			s[0].b = 0;
1702 			s[1].a = constCoords.y();
1703 			s[1].b = -1;
1704 			s[2].a = constCoords.z();
1705 			s[2].b = 2;
1706 			instance.addUniform(3u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3u * sizeof(S), s);
1707 		},
1708 		{
1709 			c.color.xyz() = c.constCoords.swizzle(2, 1, 0);
1710 		});
1711 
1712 	UNIFORM_STRUCT_CASE(loop_nested_struct_array, "Nested struct array usage in loop",
1713 		LineStream()
1714 		<< "${HEADER}"
1715 		<< "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
1716 		<< "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
1717 		<< "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
1718 		<< "layout (std140, set = 0, binding = 3) uniform buffer3 { mediump float uf_two; };"
1719 		<< "layout (std140, set = 0, binding = 4) uniform buffer4 { mediump float uf_three; };"
1720 		<< "layout (std140, set = 0, binding = 5) uniform buffer5 { mediump float uf_four; };"
1721 		<< "layout (std140, set = 0, binding = 6) uniform buffer6 { mediump float uf_half; };"
1722 		<< "layout (std140, set = 0, binding = 7) uniform buffer7 { mediump float uf_third; };"
1723 		<< "layout (std140, set = 0, binding = 8) uniform buffer8 { mediump float uf_fourth; };"
1724 		<< "layout (std140, set = 0, binding = 9) uniform buffer9 { mediump float uf_sixth; };"
1725 		<< ""
1726 		<< "struct T {"
1727 		<< "	mediump float	a;"
1728 		<< "	mediump vec2	b[2];"
1729 		<< "};"
1730 		<< "struct S {"
1731 		<< "	mediump float	a;"
1732 		<< "	T				b[3];"
1733 		<< "	int				c;"
1734 		<< "};"
1735 		<< "layout (std140, set = 0, binding = 10) uniform buffer10 { S s[2]; };"
1736 		<< ""
1737 		<< "void main (void)"
1738 		<< "{"
1739 		<< "	mediump float r = 0.0; // (x*3 + y*3) / 6.0"
1740 		<< "	mediump float g = 0.0; // (y*3 + z*3) / 6.0"
1741 		<< "	mediump float b = 0.0; // (z*3 + w*3) / 6.0"
1742 		<< "	mediump float a = 1.0;"
1743 		<< "	for (int i = 0; i < 2; i++)"
1744 		<< "	{"
1745 		<< "		for (int j = 0; j < 3; j++)"
1746 		<< "		{"
1747 		<< "			r += s[0].b[j].b[i].y;"
1748 		<< "			g += s[i].b[j].b[0].x;"
1749 		<< "			b += s[i].b[j].b[1].x;"
1750 		<< "			a *= s[i].b[j].a;"
1751 		<< "		}"
1752 		<< "	}"
1753 		<< "	${DST} = vec4(r*uf_sixth, g*uf_sixth, b*uf_sixth, a);"
1754 		<< "	${ASSIGN_POS}"
1755 		<< "}",
1756 		{
1757 			instance.useUniform(0u, UI_ZERO);
1758 			instance.useUniform(1u, UI_ONE);
1759 			instance.useUniform(2u, UI_TWO);
1760 			instance.useUniform(3u, UF_TWO);
1761 			instance.useUniform(4u, UF_THREE);
1762 			instance.useUniform(5u, UF_FOUR);
1763 			instance.useUniform(6u, UF_HALF);
1764 			instance.useUniform(7u, UF_THIRD);
1765 			instance.useUniform(8u, UF_FOURTH);
1766 			instance.useUniform(9u, UF_SIXTH);
1767 
1768 			struct T {
1769 				float		a;
1770 				float		_padding1[3];
1771 				tcu::Vec4	b[2];
1772 			};
1773 
1774 			struct S {
1775 				float	a;
1776 				float	_padding1[3];
1777 				T		b[3];
1778 				int		c;
1779 				float	_padding2[3];
1780 			};
1781 
1782 			S s[2];
1783 			s[0].a = constCoords.x();
1784 			s[0].b[0].a = 0.5f;
1785 			s[0].b[0].b[0] = constCoords.swizzle(1,0,0,0);
1786 			s[0].b[0].b[1] = constCoords.swizzle(2,0,0,0);
1787 			s[0].b[1].a = 1.0f / 3.0f;
1788 			s[0].b[1].b[0] = constCoords.swizzle(1,1,0,0);
1789 			s[0].b[1].b[1] = constCoords.swizzle(3,1,0,0);
1790 			s[0].b[2].a = 1.0f / 4.0f;
1791 			s[0].b[2].b[0] = constCoords.swizzle(2,1,0,0);
1792 			s[0].b[2].b[1] = constCoords.swizzle(2,1,0,0);
1793 			s[0].c = 0;
1794 
1795 			s[1].a = constCoords.w();
1796 			s[1].b[0].a = 2.0f;
1797 			s[1].b[0].b[0] = constCoords.swizzle(2,0,0,0);
1798 			s[1].b[0].b[1] = constCoords.swizzle(2,1,0,0);
1799 			s[1].b[1].a = 3.0f;
1800 			s[1].b[1].b[0] = constCoords.swizzle(2,2,0,0);
1801 			s[1].b[1].b[1] = constCoords.swizzle(3,3,0,0);
1802 			s[1].b[2].a = 4.0f;
1803 			s[1].b[2].b[0] = constCoords.swizzle(1,0,0,0);
1804 			s[1].b[2].b[1] = constCoords.swizzle(3,2,0,0);
1805 			s[1].c = 1;
1806 
1807 			instance.addUniform(10u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2 * sizeof(S), s);
1808 
1809 		},
1810 		{
1811 			c.color.xyz() = (c.constCoords.swizzle(0, 1, 2) + c.constCoords.swizzle(1, 2, 3)) * 0.5f;
1812 		});
1813 
1814 	UNIFORM_STRUCT_CASE(dynamic_loop_struct_array, "Struct array usage in dynamic loop",
1815 		LineStream()
1816 		<< "${HEADER}"
1817 		<< "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
1818 		<< "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
1819 		<< "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
1820 		<< "layout (std140, set = 0, binding = 3) uniform buffer3 { int ui_three; };"
1821 		<< ""
1822 		<< "struct S {"
1823 		<< "	mediump float	a;"
1824 		<< "	mediump int		b;"
1825 		<< "};"
1826 		<< "layout (std140, set = 0, binding = 4) uniform buffer4 { S s[3]; };"
1827 		<< ""
1828 		<< "void main (void)"
1829 		<< "{"
1830 		<< "	mediump float rgb[3];"
1831 		<< "	int alpha = 0;"
1832 		<< "	for (int i = 0; i < ui_three; i++)"
1833 		<< "	{"
1834 		<< "		rgb[i] = s[2-i].a;"
1835 		<< "		alpha += s[i].b;"
1836 		<< "	}"
1837 		<< "	${DST} = vec4(rgb[0], rgb[1], rgb[2], alpha);"
1838 		<< "	${ASSIGN_POS}"
1839 		<< "}",
1840 		{
1841 			instance.useUniform(0u, UI_ZERO);
1842 			instance.useUniform(1u, UI_ONE);
1843 			instance.useUniform(2u, UI_TWO);
1844 			instance.useUniform(3u, UI_THREE);
1845 
1846 			struct S {
1847 				float	a;
1848 				int		b;
1849 				float	_padding1[2];
1850 			};
1851 
1852 			S s[3];
1853 			s[0].a = constCoords.x();
1854 			s[0].b = 0;
1855 			s[1].a = constCoords.y();
1856 			s[1].b = -1;
1857 			s[2].a = constCoords.z();
1858 			s[2].b = 2;
1859 			instance.addUniform(4u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3u * sizeof(S), s);
1860 
1861 		},
1862 		{
1863 			c.color.xyz() = c.constCoords.swizzle(2, 1, 0);
1864 		});
1865 
1866 	UNIFORM_STRUCT_CASE(dynamic_loop_nested_struct_array, "Nested struct array usage in dynamic loop",
1867 		LineStream()
1868 		<< "${HEADER}"
1869 		<< "layout (std140, set = 0, binding = 0) uniform buffer0 { int ui_zero; };"
1870 		<< "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_one; };"
1871 		<< "layout (std140, set = 0, binding = 2) uniform buffer2 { int ui_two; };"
1872 		<< "layout (std140, set = 0, binding = 3) uniform buffer3 { int ui_three; };"
1873 		<< "layout (std140, set = 0, binding = 4) uniform buffer4 { mediump float uf_two; };"
1874 		<< "layout (std140, set = 0, binding = 5) uniform buffer5 { mediump float uf_three; };"
1875 		<< "layout (std140, set = 0, binding = 6) uniform buffer6 { mediump float uf_four; };"
1876 		<< "layout (std140, set = 0, binding = 7) uniform buffer7 { mediump float uf_half; };"
1877 		<< "layout (std140, set = 0, binding = 8) uniform buffer8 { mediump float uf_third; };"
1878 		<< "layout (std140, set = 0, binding = 9) uniform buffer9 { mediump float uf_fourth; };"
1879 		<< "layout (std140, set = 0, binding = 10) uniform buffer10 { mediump float uf_sixth; };"
1880 		<< ""
1881 		<< "struct T {"
1882 		<< "	mediump float	a;"
1883 		<< "	mediump vec2	b[2];"
1884 		<< "};"
1885 		<< "struct S {"
1886 		<< "	mediump float	a;"
1887 		<< "	T				b[3];"
1888 		<< "	int				c;"
1889 		<< "};"
1890 		<< "layout (std140, set = 0, binding = 11) uniform buffer11 { S s[2]; };"
1891 		<< ""
1892 		<< "void main (void)"
1893 		<< "{"
1894 		<< "	mediump float r = 0.0; // (x*3 + y*3) / 6.0"
1895 		<< "	mediump float g = 0.0; // (y*3 + z*3) / 6.0"
1896 		<< "	mediump float b = 0.0; // (z*3 + w*3) / 6.0"
1897 		<< "	mediump float a = 1.0;"
1898 		<< "	for (int i = 0; i < ui_two; i++)"
1899 		<< "	{"
1900 		<< "		for (int j = 0; j < ui_three; j++)"
1901 		<< "		{"
1902 		<< "			r += s[0].b[j].b[i].y;"
1903 		<< "			g += s[i].b[j].b[0].x;"
1904 		<< "			b += s[i].b[j].b[1].x;"
1905 		<< "			a *= s[i].b[j].a;"
1906 		<< "		}"
1907 		<< "	}"
1908 		<< "	${DST} = vec4(r*uf_sixth, g*uf_sixth, b*uf_sixth, a);"
1909 		<< "	${ASSIGN_POS}"
1910 		<< "}",
1911 		{
1912 			instance.useUniform(0u, UI_ZERO);
1913 			instance.useUniform(1u, UI_ONE);
1914 			instance.useUniform(2u, UI_TWO);
1915 			instance.useUniform(3u, UI_THREE);
1916 			instance.useUniform(4u, UF_TWO);
1917 			instance.useUniform(5u, UF_THREE);
1918 			instance.useUniform(6u, UF_FOUR);
1919 			instance.useUniform(7u, UF_HALF);
1920 			instance.useUniform(8u, UF_THIRD);
1921 			instance.useUniform(9u, UF_FOURTH);
1922 			instance.useUniform(10u, UF_SIXTH);
1923 
1924 			struct T {
1925 				float		a;
1926 				float		_padding1[3];
1927 				tcu::Vec4	b[2];
1928 			};
1929 
1930 			struct S {
1931 				float	a;
1932 				float	_padding1[3];
1933 				T		b[3];
1934 				int		c;
1935 				float	_padding2[3];
1936 			};
1937 
1938 			S s[2];
1939 			s[0].a = constCoords.x();
1940 			s[0].b[0].a = 0.5f;
1941 			s[0].b[0].b[0] = constCoords.swizzle(1,0,0,0);
1942 			s[0].b[0].b[1] = constCoords.swizzle(2,0,0,0);
1943 			s[0].b[1].a = 1.0f / 3.0f;
1944 			s[0].b[1].b[0] = constCoords.swizzle(1,1,0,0);
1945 			s[0].b[1].b[1] = constCoords.swizzle(3,1,0,0);
1946 			s[0].b[2].a = 1.0f / 4.0f;
1947 			s[0].b[2].b[0] = constCoords.swizzle(2,1,0,0);
1948 			s[0].b[2].b[1] = constCoords.swizzle(2,1,0,0);
1949 			s[0].c = 0;
1950 
1951 			s[1].a = constCoords.w();
1952 			s[1].b[0].a = 2.0f;
1953 			s[1].b[0].b[0] = constCoords.swizzle(2,0,0,0);
1954 			s[1].b[0].b[1] = constCoords.swizzle(2,1,0,0);
1955 			s[1].b[1].a = 3.0f;
1956 			s[1].b[1].b[0] = constCoords.swizzle(2,2,0,0);
1957 			s[1].b[1].b[1] = constCoords.swizzle(3,3,0,0);
1958 			s[1].b[2].a = 4.0f;
1959 			s[1].b[2].b[0] = constCoords.swizzle(1,0,0,0);
1960 			s[1].b[2].b[1] = constCoords.swizzle(3,2,0,0);
1961 			s[1].c = 1;
1962 
1963 			instance.addUniform(11u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2 * sizeof(S), s);
1964 
1965 		},
1966 		{
1967 			c.color.xyz() = (c.constCoords.swizzle(0, 1, 2) + c.constCoords.swizzle(1, 2, 3)) * 0.5f;
1968 		});
1969 
1970 	UNIFORM_STRUCT_CASE(equal, "Struct equality",
1971 		LineStream()
1972 		<< "${HEADER}"
1973 		<< "layout (std140, set = 0, binding = 0) uniform buffer0 { mediump float uf_one; };"
1974 		<< "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_two; };"
1975 		<< ""
1976 		<< "struct S {"
1977 		<< "	mediump float	a;"
1978 		<< "	mediump vec3	b;"
1979 		<< "	int				c;"
1980 		<< "};"
1981 		<< "layout (std140, set = 0, binding = 2) uniform buffer2 { S a; };"
1982 		<< "layout (std140, set = 0, binding = 3) uniform buffer3 { S b; };"
1983 		<< "layout (std140, set = 0, binding = 4) uniform buffer4 { S c; };"
1984 		<< ""
1985 		<< "void main (void)"
1986 		<< "{"
1987 		<< "	S d = S(uf_one, vec3(0.0, floor(${COORDS}.y+1.0), 2.0), ui_two);"
1988 		<< "	${DST} = vec4(0.0, 0.0, 0.0, 1.0);"
1989 		<< "	if (a == b) ${DST}.x = 1.0;"
1990 		<< "	if (a == c) ${DST}.y = 1.0;"
1991 		<< "	if (a == d) ${DST}.z = 1.0;"
1992 		<< "	${ASSIGN_POS}"
1993 		<< "}",
1994 		{
1995 			DE_UNREF(constCoords);
1996 			instance.useUniform(0u, UF_ONE);
1997 			instance.useUniform(1u, UI_TWO);
1998 
1999 			struct S {
2000 				float			a;
2001 				float			_padding1[3];
2002 				tcu::Vec3		b;
2003 				int				c;
2004 			};
2005 
2006 			S sa;
2007 			sa.a = 1.0f;
2008 			sa.b = tcu::Vec3(0.0f, 1.0f, 2.0f);
2009 			sa.c = 2;
2010 			instance.addUniform(2u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(S), &sa);
2011 
2012 			S sb;
2013 			sb.a = 1.0f;
2014 			sb.b = tcu::Vec3(0.0f, 1.0f, 2.0f);
2015 			sb.c = 2;
2016 			instance.addUniform(3u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(S), &sb);
2017 
2018 			S sc;
2019 			sc.a = 1.0f;
2020 			sc.b = tcu::Vec3(0.0f, 1.1f, 2.0f);
2021 			sc.c = 2;
2022 			instance.addUniform(4u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(S), &sc);
2023 		},
2024 		{
2025 			c.color.xy() = tcu::Vec2(1.0f, 0.0f);
2026 			if (deFloatFloor(c.coords[1] + 1.0f) == deFloatFloor(1.1f))
2027 				c.color.z() = 1.0f;
2028 		});
2029 
2030 	UNIFORM_STRUCT_CASE(not_equal, "Struct equality",
2031 		LineStream()
2032 		<< "${HEADER}"
2033 		<< "layout (std140, set = 0, binding = 0) uniform buffer0 { mediump float uf_one; };"
2034 		<< "layout (std140, set = 0, binding = 1) uniform buffer1 { int ui_two; };"
2035 		<< ""
2036 		<< "struct S {"
2037 		<< "	mediump float	a;"
2038 		<< "	mediump vec3	b;"
2039 		<< "	int				c;"
2040 		<< "};"
2041 		<< "layout (std140, set = 0, binding = 2) uniform buffer2 { S a; };"
2042 		<< "layout (std140, set = 0, binding = 3) uniform buffer3 { S b; };"
2043 		<< "layout (std140, set = 0, binding = 4) uniform buffer4 { S c; };"
2044 		<< ""
2045 		<< "void main (void)"
2046 		<< "{"
2047 		<< "	S d = S(uf_one, vec3(0.0, floor(${COORDS}.y+1.0), 2.0), ui_two);"
2048 		<< "	${DST} = vec4(0.0, 0.0, 0.0, 1.0);"
2049 		<< "	if (a != b) ${DST}.x = 1.0;"
2050 		<< "	if (a != c) ${DST}.y = 1.0;"
2051 		<< "	if (a != d) ${DST}.z = 1.0;"
2052 		<< "	${ASSIGN_POS}"
2053 		<< "}",
2054 		{
2055 			DE_UNREF(constCoords);
2056 			instance.useUniform(0u, UF_ONE);
2057 			instance.useUniform(1u, UI_TWO);
2058 
2059 			struct S {
2060 				float			a;
2061 				float			_padding1[3];
2062 				tcu::Vec3		b;
2063 				int				c;
2064 			};
2065 
2066 			S sa;
2067 			sa.a = 1.0f;
2068 			sa.b = tcu::Vec3(0.0f, 1.0f, 2.0f);
2069 			sa.c = 2;
2070 			instance.addUniform(2u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(S), &sa);
2071 
2072 			S sb;
2073 			sb.a = 1.0f;
2074 			sb.b = tcu::Vec3(0.0f, 1.0f, 2.0f);
2075 			sb.c = 2;
2076 			instance.addUniform(3u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(S), &sb);
2077 
2078 			S sc;
2079 			sc.a = 1.0f;
2080 			sc.b = tcu::Vec3(0.0f, 1.1f, 2.0f);
2081 			sc.c = 2;
2082 			instance.addUniform(4u, vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, sizeof(S), &sc);
2083 		},
2084 		{
2085 			c.color.xy() = tcu::Vec2(0.0f, 1.0f);
2086 			if (deFloatFloor(c.coords[1] + 1.0f) != deFloatFloor(1.1f))
2087 				c.color.z() = 1.0f;
2088 		});
2089 }
2090 
2091 class ShaderStructTests : public tcu::TestCaseGroup
2092 {
2093 public:
2094 							ShaderStructTests		(tcu::TestContext& context);
2095 	virtual					~ShaderStructTests		(void);
2096 
2097 	virtual void			init					(void);
2098 
2099 private:
2100 							ShaderStructTests		(const ShaderStructTests&);		// not allowed!
2101 	ShaderStructTests&		operator=				(const ShaderStructTests&);		// not allowed!
2102 };
2103 
ShaderStructTests(tcu::TestContext & testCtx)2104 ShaderStructTests::ShaderStructTests (tcu::TestContext& testCtx)
2105 	: TestCaseGroup(testCtx, "struct", "Struct Tests")
2106 {
2107 }
2108 
~ShaderStructTests(void)2109 ShaderStructTests::~ShaderStructTests (void)
2110 {
2111 }
2112 
init(void)2113 void ShaderStructTests::init (void)
2114 {
2115 	addChild(new LocalStructTests(m_testCtx));
2116 	addChild(new UniformStructTests(m_testCtx));
2117 }
2118 
2119 } // anonymous
2120 
createStructTests(tcu::TestContext & testCtx)2121 tcu::TestCaseGroup* createStructTests (tcu::TestContext& testCtx)
2122 {
2123 	return new ShaderStructTests(testCtx);
2124 }
2125 
2126 } // sr
2127 } // vkt
2128