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