vktSpvAsmInstructionTests.cpp revision 9a7e44c293be9b55281335c1a6532af9088c0d6d
1/*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 Google Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and/or associated documentation files (the
9 * "Materials"), to deal in the Materials without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Materials, and to
12 * permit persons to whom the Materials are furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice(s) and this permission notice shall be
16 * included in all copies or substantial portions of the Materials.
17 *
18 * The Materials are Confidential Information as defined by the
19 * Khronos Membership Agreement until designated non-confidential by
20 * Khronos, at which point this condition clause shall be removed.
21 *
22 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
26 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
29 *
30 *//*!
31 * \file
32 * \brief SPIR-V Assembly Tests for Instructions (special opcode/operand)
33 *//*--------------------------------------------------------------------*/
34
35#include "vktSpvAsmInstructionTests.hpp"
36
37#include "tcuCommandLine.hpp"
38#include "tcuFormatUtil.hpp"
39#include "tcuRGBA.hpp"
40#include "tcuStringTemplate.hpp"
41#include "tcuTestLog.hpp"
42#include "tcuVectorUtil.hpp"
43
44#include "vkDefs.hpp"
45#include "vkDeviceUtil.hpp"
46#include "vkMemUtil.hpp"
47#include "vkPlatform.hpp"
48#include "vkPrograms.hpp"
49#include "vkQueryUtil.hpp"
50#include "vkRef.hpp"
51#include "vkRefUtil.hpp"
52#include "vkStrUtil.hpp"
53#include "vkTypeUtil.hpp"
54
55#include "deRandom.hpp"
56#include "deStringUtil.hpp"
57#include "deUniquePtr.hpp"
58#include "tcuStringTemplate.hpp"
59
60#include "vktSpvAsmComputeShaderCase.hpp"
61#include "vktSpvAsmComputeShaderTestUtil.hpp"
62#include "vktTestCaseUtil.hpp"
63
64#include <map>
65#include <string>
66#include <sstream>
67
68namespace vkt
69{
70namespace SpirVAssembly
71{
72
73namespace
74{
75
76using namespace vk;
77using std::map;
78using std::string;
79using std::vector;
80using tcu::IVec3;
81using tcu::IVec4;
82using tcu::RGBA;
83using tcu::TestLog;
84using tcu::TestStatus;
85using tcu::Vec4;
86using de::UniquePtr;
87using tcu::StringTemplate;
88
89typedef Unique<VkShaderModule>			ModuleHandleUp;
90typedef de::SharedPtr<ModuleHandleUp>	ModuleHandleSp;
91typedef Unique<VkShader>				VkShaderUp;
92typedef de::SharedPtr<VkShaderUp>		VkShaderSp;
93
94template<typename T>	T			randomScalar	(de::Random& rnd, T minValue, T maxValue);
95template<> inline		float		randomScalar	(de::Random& rnd, float minValue, float maxValue)		{ return rnd.getFloat(minValue, maxValue);	}
96template<> inline		deInt32		randomScalar	(de::Random& rnd, deInt32 minValue, deInt32 maxValue)	{ return rnd.getInt(minValue, maxValue);	}
97template<> inline		deUint32	randomScalar	(de::Random& rnd, deUint32 minValue, deUint32 maxValue)	{ return minValue + rnd.getUint32() % (maxValue - minValue + 1); }
98
99template<typename T>
100static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, int offset = 0)
101{
102	T* const typedPtr = (T*)dst;
103	for (int ndx = 0; ndx < numValues; ndx++)
104		typedPtr[offset + ndx] = randomScalar<T>(rnd, minValue, maxValue);
105}
106
107// \todo [2015-11-19 antiagainst] New rules for Vulkan pipeline interface requires that
108// all BuiltIn variables have to all be members in a block (struct with Block decoration).
109
110// Assembly code used for testing OpNop, OpConstant{Null|Composite}, Op[No]Line, OpSource[Continued], OpSourceExtension, OpUndef is based on GLSL source code:
111//
112// #version 430
113//
114// layout(std140, set = 0, binding = 0) readonly buffer Input {
115//   float elements[];
116// } input_data;
117// layout(std140, set = 0, binding = 1) writeonly buffer Output {
118//   float elements[];
119// } output_data;
120//
121// layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
122//
123// void main() {
124//   uint x = gl_GlobalInvocationID.x;
125//   output_data.elements[x] = -input_data.elements[x];
126// }
127
128static const char* const s_ShaderPreamble =
129		"OpCapability Shader\n"
130		"OpMemoryModel Logical GLSL450\n"
131		"OpEntryPoint GLCompute %main \"main\" %id\n"
132	"OpExecutionMode %main LocalSize 1 1 1\n";
133
134static const char* const s_CommonTypes =
135	"%bool      = OpTypeBool\n"
136	"%void      = OpTypeVoid\n"
137	"%voidf     = OpTypeFunction %void\n"
138	"%u32       = OpTypeInt 32 0\n"
139	"%i32       = OpTypeInt 32 1\n"
140	"%f32       = OpTypeFloat 32\n"
141	"%uvec3     = OpTypeVector %u32 3\n"
142	"%uvec3ptr  = OpTypePointer Input %uvec3\n"
143	"%f32ptr    = OpTypePointer Uniform %f32\n"
144	"%f32arr    = OpTypeRuntimeArray %f32\n";
145
146// Declares two uniform variables (indata, outdata) of type "struct { float[] }". Depends on type "f32arr" (for "float[]").
147static const char* const s_InputOutputBuffer =
148	"%inbuf     = OpTypeStruct %f32arr\n"
149	"%inbufptr  = OpTypePointer Uniform %inbuf\n"
150	"%indata    = OpVariable %inbufptr Uniform\n"
151	"%outbuf    = OpTypeStruct %f32arr\n"
152	"%outbufptr = OpTypePointer Uniform %outbuf\n"
153	"%outdata   = OpVariable %outbufptr Uniform\n";
154
155// Declares buffer type and layout for uniform variables indata and outdata. Both of them are SSBO bounded to descriptor set 0.
156// indata is at binding point 0, while outdata is at 1.
157static const char* const s_InputOutputBufferTraits =
158		"OpDecorate %inbuf BufferBlock\n"
159		"OpDecorate %indata DescriptorSet 0\n"
160		"OpDecorate %indata Binding 0\n"
161		"OpDecorate %outbuf BufferBlock\n"
162		"OpDecorate %outdata DescriptorSet 0\n"
163		"OpDecorate %outdata Binding 1\n"
164		"OpDecorate %f32arr ArrayStride 4\n"
165		"OpMemberDecorate %inbuf 0 Offset 0\n"
166	"OpMemberDecorate %outbuf 0 Offset 0\n";
167
168tcu::TestCaseGroup* createOpNopGroup (tcu::TestContext& testCtx)
169{
170	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opnop", "Test the OpNop instruction"));
171	ComputeShaderSpec				spec;
172	de::Random						rnd				(deStringHash(group->getName()));
173	const int						numElements		= 100;
174	vector<float>					positiveFloats	(numElements, 0);
175	vector<float>					negativeFloats	(numElements, 0);
176
177	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
178
179	for (size_t ndx = 0; ndx < numElements; ++ndx)
180		negativeFloats[ndx] = -positiveFloats[ndx];
181
182	spec.assembly =
183		"OpNop\n" // As the first instruction
184
185		+ string(s_ShaderPreamble) +
186
187		"OpNop\n" // After OpEntryPoint but before any type definitions
188
189		"OpSource GLSL 430\n"
190		"OpName %main           \"main\"\n"
191		"OpName %id             \"gl_GlobalInvocationID\"\n"
192
193		"OpDecorate %id BuiltIn GlobalInvocationId\n"
194
195		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
196
197		"OpNop\n" // In the middle of type definitions
198
199		+ string(s_InputOutputBuffer) +
200
201		"%id        = OpVariable %uvec3ptr Input\n"
202		"%zero      = OpConstant %i32 0\n"
203
204		"%main      = OpFunction %void None %voidf\n"
205		"%label     = OpLabel\n"
206		"%idval     = OpLoad %uvec3 %id\n"
207		"%x         = OpCompositeExtract %u32 %idval 0\n"
208
209		"             OpNop\n" // Inside a function body
210
211		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
212		"%inval     = OpLoad %f32 %inloc\n"
213		"%neg       = OpFNegate %f32 %inval\n"
214		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
215		"             OpStore %outloc %neg\n"
216		"             OpReturn\n"
217		"             OpFunctionEnd\n";
218	spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
219	spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
220	spec.numWorkGroups = IVec3(numElements, 1, 1);
221
222	group->addChild(new SpvAsmComputeShaderCase(testCtx, "all", "OpNop appearing at different places", spec));
223
224	return group.release();
225}
226
227tcu::TestCaseGroup* createOpLineGroup (tcu::TestContext& testCtx)
228{
229	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opline", "Test the OpLine instruction"));
230	ComputeShaderSpec				spec;
231	de::Random						rnd				(deStringHash(group->getName()));
232	const int						numElements		= 100;
233	vector<float>					positiveFloats	(numElements, 0);
234	vector<float>					negativeFloats	(numElements, 0);
235
236	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
237
238	for (size_t ndx = 0; ndx < numElements; ++ndx)
239		negativeFloats[ndx] = -positiveFloats[ndx];
240
241	spec.assembly =
242		string(s_ShaderPreamble) +
243
244		"%fname1 = OpString \"negateInputs.comp\"\n"
245		"%fname2 = OpString \"negateInputs\"\n"
246
247		"OpSource GLSL 430\n"
248		"OpName %main           \"main\"\n"
249		"OpName %id             \"gl_GlobalInvocationID\"\n"
250
251		"OpDecorate %id BuiltIn GlobalInvocationId\n"
252
253		+ string(s_InputOutputBufferTraits) +
254
255		"OpLine %fname1 0 0\n" // At the earliest possible position
256
257		+ string(s_CommonTypes) + string(s_InputOutputBuffer) +
258
259		"OpLine %fname1 0 1\n" // Multiple OpLines in sequence
260		"OpLine %fname2 1 0\n" // Different filenames
261		"OpLine %fname1 1000 100000\n"
262
263		"%id        = OpVariable %uvec3ptr Input\n"
264		"%zero      = OpConstant %i32 0\n"
265
266		"OpLine %fname1 1 1\n" // Before a function
267
268		"%main      = OpFunction %void None %voidf\n"
269		"%label     = OpLabel\n"
270
271		"OpLine %fname1 1 1\n" // In a function
272
273		"%idval     = OpLoad %uvec3 %id\n"
274		"%x         = OpCompositeExtract %u32 %idval 0\n"
275		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
276		"%inval     = OpLoad %f32 %inloc\n"
277		"%neg       = OpFNegate %f32 %inval\n"
278		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
279		"             OpStore %outloc %neg\n"
280		"             OpReturn\n"
281		"             OpFunctionEnd\n";
282	spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
283	spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
284	spec.numWorkGroups = IVec3(numElements, 1, 1);
285
286	group->addChild(new SpvAsmComputeShaderCase(testCtx, "all", "OpLine appearing at different places", spec));
287
288	return group.release();
289}
290
291tcu::TestCaseGroup* createOpNoLineGroup (tcu::TestContext& testCtx)
292{
293	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opnoline", "Test the OpNoLine instruction"));
294	ComputeShaderSpec				spec;
295	de::Random						rnd				(deStringHash(group->getName()));
296	const int						numElements		= 100;
297	vector<float>					positiveFloats	(numElements, 0);
298	vector<float>					negativeFloats	(numElements, 0);
299
300	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
301
302	for (size_t ndx = 0; ndx < numElements; ++ndx)
303		negativeFloats[ndx] = -positiveFloats[ndx];
304
305	spec.assembly =
306		string(s_ShaderPreamble) +
307
308		"%fname = OpString \"negateInputs.comp\"\n"
309
310		"OpSource GLSL 430\n"
311		"OpName %main           \"main\"\n"
312		"OpName %id             \"gl_GlobalInvocationID\"\n"
313
314		"OpDecorate %id BuiltIn GlobalInvocationId\n"
315
316		+ string(s_InputOutputBufferTraits) +
317
318		"OpNoLine\n" // At the earliest possible position, without preceding OpLine
319
320		+ string(s_CommonTypes) + string(s_InputOutputBuffer) +
321
322		"OpLine %fname 0 1\n"
323		"OpNoLine\n" // Immediately following a preceding OpLine
324
325		"OpLine %fname 1000 1\n"
326
327		"%id        = OpVariable %uvec3ptr Input\n"
328		"%zero      = OpConstant %i32 0\n"
329
330		"OpNoLine\n" // Contents after the previous OpLine
331
332		"%main      = OpFunction %void None %voidf\n"
333		"%label     = OpLabel\n"
334		"%idval     = OpLoad %uvec3 %id\n"
335		"%x         = OpCompositeExtract %u32 %idval 0\n"
336
337		"OpNoLine\n" // Multiple OpNoLine
338		"OpNoLine\n"
339		"OpNoLine\n"
340
341		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
342		"%inval     = OpLoad %f32 %inloc\n"
343		"%neg       = OpFNegate %f32 %inval\n"
344		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
345		"             OpStore %outloc %neg\n"
346		"             OpReturn\n"
347		"             OpFunctionEnd\n";
348	spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
349	spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
350	spec.numWorkGroups = IVec3(numElements, 1, 1);
351
352	group->addChild(new SpvAsmComputeShaderCase(testCtx, "all", "OpNoLine appearing at different places", spec));
353
354	return group.release();
355}
356
357// Assembly code used for testing OpUnreachable is based on GLSL source code:
358//
359// #version 430
360//
361// layout(std140, set = 0, binding = 0) readonly buffer Input {
362//   float elements[];
363// } input_data;
364// layout(std140, set = 0, binding = 1) writeonly buffer Output {
365//   float elements[];
366// } output_data;
367//
368// void not_called_func() {
369//   // place OpUnreachable here
370// }
371//
372// uint modulo4(uint val) {
373//   switch (val % uint(4)) {
374//     case 0:  return 3;
375//     case 1:  return 2;
376//     case 2:  return 1;
377//     case 3:  return 0;
378//     default: return 100; // place OpUnreachable here
379//   }
380// }
381//
382// uint const5() {
383//   return 5;
384//   // place OpUnreachable here
385// }
386//
387// void main() {
388//   uint x = gl_GlobalInvocationID.x;
389//   if (const5() > modulo4(1000)) {
390//     output_data.elements[x] = -input_data.elements[x];
391//   } else {
392//     // place OpUnreachable here
393//     output_data.elements[x] = input_data.elements[x];
394//   }
395// }
396
397tcu::TestCaseGroup* createOpUnreachableGroup (tcu::TestContext& testCtx)
398{
399	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opunreachable", "Test the OpUnreachable instruction"));
400	ComputeShaderSpec				spec;
401	de::Random						rnd				(deStringHash(group->getName()));
402	const int						numElements		= 100;
403	vector<float>					positiveFloats	(numElements, 0);
404	vector<float>					negativeFloats	(numElements, 0);
405
406	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
407
408	for (size_t ndx = 0; ndx < numElements; ++ndx)
409		negativeFloats[ndx] = -positiveFloats[ndx];
410
411	spec.assembly =
412		string(s_ShaderPreamble) +
413
414		"OpSource GLSL 430\n"
415		"OpName %func_main            \"main\"\n"
416		"OpName %func_not_called_func \"not_called_func(\"\n"
417		"OpName %func_modulo4         \"modulo4(u1;\"\n"
418		"OpName %func_const5          \"const5(\"\n"
419		"OpName %id                   \"gl_GlobalInvocationID\"\n"
420
421		"OpDecorate %id BuiltIn GlobalInvocationId\n"
422
423		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
424
425		"%u32ptr    = OpTypePointer Function %u32\n"
426		"%uintfuint = OpTypeFunction %u32 %u32ptr\n"
427		"%unitf     = OpTypeFunction %u32\n"
428
429		"%id        = OpVariable %uvec3ptr Input\n"
430		"%zero      = OpConstant %u32 0\n"
431		"%one       = OpConstant %u32 1\n"
432		"%two       = OpConstant %u32 2\n"
433		"%three     = OpConstant %u32 3\n"
434		"%four      = OpConstant %u32 4\n"
435		"%five      = OpConstant %u32 5\n"
436		"%hundred   = OpConstant %u32 100\n"
437		"%thousand  = OpConstant %u32 1000\n"
438
439		+ string(s_InputOutputBuffer) +
440
441		// Main()
442		"%func_main   = OpFunction %void None %voidf\n"
443		"%main_entry  = OpLabel\n"
444		"%idval       = OpLoad %uvec3 %id\n"
445		"%x           = OpCompositeExtract %u32 %idval 0\n"
446		"%inloc       = OpAccessChain %f32ptr %indata %zero %x\n"
447		"%inval       = OpLoad %f32 %inloc\n"
448		"%outloc      = OpAccessChain %f32ptr %outdata %zero %x\n"
449		"%ret_const5  = OpFunctionCall %u32 %func_const5\n"
450		"%ret_modulo4 = OpFunctionCall %u32 %func_modulo4 %thousand\n"
451		"%cmp_gt      = OpUGreaterThan %bool %ret_const5 %ret_modulo4\n"
452		"               OpSelectionMerge %if_end None\n"
453		"               OpBranchConditional %cmp_gt %if_true %if_false\n"
454		"%if_true     = OpLabel\n"
455		"%negate      = OpFNegate %f32 %inval\n"
456		"               OpStore %outloc %negate\n"
457		"               OpBranch %if_end\n"
458		"%if_false    = OpLabel\n"
459		"               OpUnreachable\n" // Unreachable else branch for if statement
460		"%if_end      = OpLabel\n"
461		"               OpReturn\n"
462		"               OpFunctionEnd\n"
463
464		// not_called_function()
465		"%func_not_called_func  = OpFunction %void None %voidf\n"
466		"%not_called_func_entry = OpLabel\n"
467		"                         OpUnreachable\n" // Unreachable entry block in not called static function
468		"                         OpFunctionEnd\n"
469
470		// modulo4()
471		"%func_modulo4  = OpFunction %u32 None %uintfuint\n"
472		"%valptr        = OpFunctionParameter %u32ptr\n"
473		"%modulo4_entry = OpLabel\n"
474		"%val           = OpLoad %u32 %valptr\n"
475		"%modulo        = OpUMod %u32 %val %four\n"
476		"                 OpSelectionMerge %switch_merge None\n"
477		"                 OpSwitch %modulo %default 0 %case0 1 %case1 2 %case2 3 %case3\n"
478		"%case0         = OpLabel\n"
479		"                 OpReturnValue %three\n"
480		"%case1         = OpLabel\n"
481		"                 OpReturnValue %two\n"
482		"%case2         = OpLabel\n"
483		"                 OpReturnValue %one\n"
484		"%case3         = OpLabel\n"
485		"                 OpReturnValue %zero\n"
486		"%default       = OpLabel\n"
487		"                 OpUnreachable\n" // Unreachable default case for switch statement
488		"%switch_merge  = OpLabel\n"
489		"                 OpUnreachable\n" // Unreachable merge block for switch statement
490		"                 OpFunctionEnd\n"
491
492		// const5()
493		"%func_const5  = OpFunction %u32 None %unitf\n"
494		"%const5_entry = OpLabel\n"
495		"                OpReturnValue %five\n"
496		"%unreachable  = OpLabel\n"
497		"                OpUnreachable\n" // Unreachable block in function
498		"                OpFunctionEnd\n";
499	spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
500	spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
501	spec.numWorkGroups = IVec3(numElements, 1, 1);
502
503	group->addChild(new SpvAsmComputeShaderCase(testCtx, "all", "OpUnreachable appearing at different places", spec));
504
505	return group.release();
506}
507
508// Assembly code used for testing decoration group is based on GLSL source code:
509//
510// #version 430
511//
512// layout(std140, set = 0, binding = 0) readonly buffer Input0 {
513//   float elements[];
514// } input_data0;
515// layout(std140, set = 0, binding = 1) readonly buffer Input1 {
516//   float elements[];
517// } input_data1;
518// layout(std140, set = 0, binding = 2) readonly buffer Input2 {
519//   float elements[];
520// } input_data2;
521// layout(std140, set = 0, binding = 3) readonly buffer Input3 {
522//   float elements[];
523// } input_data3;
524// layout(std140, set = 0, binding = 4) readonly buffer Input4 {
525//   float elements[];
526// } input_data4;
527// layout(std140, set = 0, binding = 5) writeonly buffer Output {
528//   float elements[];
529// } output_data;
530//
531// void main() {
532//   uint x = gl_GlobalInvocationID.x;
533//   output_data.elements[x] = input_data0.elements[x] + input_data1.elements[x] + input_data2.elements[x] + input_data3.elements[x] + input_data4.elements[x];
534// }
535tcu::TestCaseGroup* createDecorationGroupGroup (tcu::TestContext& testCtx)
536{
537	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "decoration_group", "Test the OpDecorationGroup & OpGroupDecorate instruction"));
538	ComputeShaderSpec				spec;
539	de::Random						rnd				(deStringHash(group->getName()));
540	const int						numElements		= 100;
541	vector<float>					inputFloats0	(numElements, 0);
542	vector<float>					inputFloats1	(numElements, 0);
543	vector<float>					inputFloats2	(numElements, 0);
544	vector<float>					inputFloats3	(numElements, 0);
545	vector<float>					inputFloats4	(numElements, 0);
546	vector<float>					outputFloats	(numElements, 0);
547
548	fillRandomScalars(rnd, -300.f, 300.f, &inputFloats0[0], numElements);
549	fillRandomScalars(rnd, -300.f, 300.f, &inputFloats1[0], numElements);
550	fillRandomScalars(rnd, -300.f, 300.f, &inputFloats2[0], numElements);
551	fillRandomScalars(rnd, -300.f, 300.f, &inputFloats3[0], numElements);
552	fillRandomScalars(rnd, -300.f, 300.f, &inputFloats4[0], numElements);
553
554	for (size_t ndx = 0; ndx < numElements; ++ndx)
555		outputFloats[ndx] = inputFloats0[ndx] + inputFloats1[ndx] + inputFloats2[ndx] + inputFloats3[ndx] + inputFloats4[ndx];
556
557	spec.assembly =
558		string(s_ShaderPreamble) +
559
560		"OpSource GLSL 430\n"
561		"OpName %main \"main\"\n"
562		"OpName %id \"gl_GlobalInvocationID\"\n"
563
564		// Not using group decoration on variable.
565		"OpDecorate %id BuiltIn GlobalInvocationId\n"
566		// Not using group decoration on type.
567		"OpDecorate %f32arr ArrayStride 4\n"
568
569		"OpDecorate %groups BufferBlock\n"
570		"OpDecorate %groupm Offset 0\n"
571		"%groups = OpDecorationGroup\n"
572		"%groupm = OpDecorationGroup\n"
573
574		// Group decoration on multiple structs.
575		"OpGroupDecorate %groups %outbuf %inbuf0 %inbuf1 %inbuf2 %inbuf3 %inbuf4\n"
576		// Group decoration on multiple struct members.
577		"OpGroupMemberDecorate %groupm %outbuf 0 %inbuf0 0 %inbuf1 0 %inbuf2 0 %inbuf3 0 %inbuf4 0\n"
578
579		"OpDecorate %group1 DescriptorSet 0\n"
580		"OpDecorate %group3 DescriptorSet 0\n"
581		"OpDecorate %group3 NonWritable\n"
582		"OpDecorate %group3 Restrict\n"
583		"%group0 = OpDecorationGroup\n"
584		"%group1 = OpDecorationGroup\n"
585		"%group3 = OpDecorationGroup\n"
586
587		// Applying the same decoration group multiple times.
588		"OpGroupDecorate %group1 %outdata\n"
589		"OpGroupDecorate %group1 %outdata\n"
590		"OpGroupDecorate %group1 %outdata\n"
591		"OpDecorate %outdata DescriptorSet 0\n"
592		"OpDecorate %outdata Binding 5\n"
593		// Applying decoration group containing nothing.
594		"OpGroupDecorate %group0 %indata0\n"
595		"OpDecorate %indata0 DescriptorSet 0\n"
596		"OpDecorate %indata0 Binding 0\n"
597		// Applying decoration group containing one decoration.
598		"OpGroupDecorate %group1 %indata1\n"
599		"OpDecorate %indata1 Binding 1\n"
600		// Applying decoration group containing multiple decorations.
601		"OpGroupDecorate %group3 %indata2 %indata3\n"
602		"OpDecorate %indata2 Binding 2\n"
603		"OpDecorate %indata3 Binding 3\n"
604		// Applying multiple decoration groups (with overlapping).
605		"OpGroupDecorate %group0 %indata4\n"
606		"OpGroupDecorate %group1 %indata4\n"
607		"OpGroupDecorate %group3 %indata4\n"
608		"OpDecorate %indata4 Binding 4\n"
609
610		+ string(s_CommonTypes) +
611
612		"%id   = OpVariable %uvec3ptr Input\n"
613		"%zero = OpConstant %i32 0\n"
614
615		"%outbuf    = OpTypeStruct %f32arr\n"
616		"%outbufptr = OpTypePointer Uniform %outbuf\n"
617		"%outdata   = OpVariable %outbufptr Uniform\n"
618		"%inbuf0    = OpTypeStruct %f32arr\n"
619		"%inbuf0ptr = OpTypePointer Uniform %inbuf0\n"
620		"%indata0   = OpVariable %inbuf0ptr Uniform\n"
621		"%inbuf1    = OpTypeStruct %f32arr\n"
622		"%inbuf1ptr = OpTypePointer Uniform %inbuf1\n"
623		"%indata1   = OpVariable %inbuf1ptr Uniform\n"
624		"%inbuf2    = OpTypeStruct %f32arr\n"
625		"%inbuf2ptr = OpTypePointer Uniform %inbuf2\n"
626		"%indata2   = OpVariable %inbuf2ptr Uniform\n"
627		"%inbuf3    = OpTypeStruct %f32arr\n"
628		"%inbuf3ptr = OpTypePointer Uniform %inbuf3\n"
629		"%indata3   = OpVariable %inbuf3ptr Uniform\n"
630		"%inbuf4    = OpTypeStruct %f32arr\n"
631		"%inbufptr  = OpTypePointer Uniform %inbuf4\n"
632		"%indata4   = OpVariable %inbufptr Uniform\n"
633
634		"%main   = OpFunction %void None %voidf\n"
635		"%label  = OpLabel\n"
636		"%idval  = OpLoad %uvec3 %id\n"
637		"%x      = OpCompositeExtract %u32 %idval 0\n"
638		"%inloc0 = OpAccessChain %f32ptr %indata0 %zero %x\n"
639		"%inloc1 = OpAccessChain %f32ptr %indata1 %zero %x\n"
640		"%inloc2 = OpAccessChain %f32ptr %indata2 %zero %x\n"
641		"%inloc3 = OpAccessChain %f32ptr %indata3 %zero %x\n"
642		"%inloc4 = OpAccessChain %f32ptr %indata4 %zero %x\n"
643		"%outloc = OpAccessChain %f32ptr %outdata %zero %x\n"
644		"%inval0 = OpLoad %f32 %inloc0\n"
645		"%inval1 = OpLoad %f32 %inloc1\n"
646		"%inval2 = OpLoad %f32 %inloc2\n"
647		"%inval3 = OpLoad %f32 %inloc3\n"
648		"%inval4 = OpLoad %f32 %inloc4\n"
649		"%add0   = OpFAdd %f32 %inval0 %inval1\n"
650		"%add1   = OpFAdd %f32 %add0 %inval2\n"
651		"%add2   = OpFAdd %f32 %add1 %inval3\n"
652		"%add    = OpFAdd %f32 %add2 %inval4\n"
653		"          OpStore %outloc %add\n"
654		"          OpReturn\n"
655		"          OpFunctionEnd\n";
656	spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats0)));
657	spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats1)));
658	spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats2)));
659	spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats3)));
660	spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats4)));
661	spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
662	spec.numWorkGroups = IVec3(numElements, 1, 1);
663
664	group->addChild(new SpvAsmComputeShaderCase(testCtx, "all", "decoration group cases", spec));
665
666	return group.release();
667}
668
669tcu::TestCaseGroup* createOpPhiGroup (tcu::TestContext& testCtx)
670{
671	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opphi", "Test the OpPhi instruction"));
672	ComputeShaderSpec				spec;
673	de::Random						rnd				(deStringHash(group->getName()));
674	const int						numElements		= 100;
675	vector<float>					inputFloats		(numElements, 0);
676	vector<float>					outputFloats	(numElements, 0);
677
678	fillRandomScalars(rnd, -300.f, 300.f, &inputFloats[0], numElements);
679
680	for (size_t ndx = 0; ndx < numElements; ++ndx)
681	{
682		switch (ndx % 3)
683		{
684			case 0:		outputFloats[ndx] = inputFloats[ndx] + 5.5f;	break;
685			case 1:		outputFloats[ndx] = inputFloats[ndx] + 20.5f;	break;
686			case 2:		outputFloats[ndx] = inputFloats[ndx] + 1.75f;	break;
687			default:	break;
688		}
689	}
690
691	spec.assembly =
692		string(s_ShaderPreamble) +
693
694		"OpSource GLSL 430\n"
695		"OpName %main \"main\"\n"
696		"OpName %id \"gl_GlobalInvocationID\"\n"
697
698		"OpDecorate %id BuiltIn GlobalInvocationId\n"
699
700		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
701
702		"%id = OpVariable %uvec3ptr Input\n"
703		"%zero       = OpConstant %i32 0\n"
704		"%three      = OpConstant %u32 3\n"
705		"%constf5p5  = OpConstant %f32 5.5\n"
706		"%constf20p5 = OpConstant %f32 20.5\n"
707		"%constf1p75 = OpConstant %f32 1.75\n"
708		"%constf8p5  = OpConstant %f32 8.5\n"
709		"%constf6p5  = OpConstant %f32 6.5\n"
710
711		"%main     = OpFunction %void None %voidf\n"
712		"%entry    = OpLabel\n"
713		"%idval    = OpLoad %uvec3 %id\n"
714		"%x        = OpCompositeExtract %u32 %idval 0\n"
715		"%selector = OpUMod %u32 %x %three\n"
716		"            OpSelectionMerge %default None\n"
717		"            OpSwitch %selector %default 0 %case0 1 %case1 2 %case2\n"
718
719		// Case 1 before OpPhi.
720		"%case1    = OpLabel\n"
721		"            OpBranch %phi\n"
722
723		"%default  = OpLabel\n"
724		"            OpUnreachable\n"
725
726		"%phi      = OpLabel\n"
727		"%operand  = OpPhi %f32 %constf1p75 %case2   %constf20p5 %case1   %constf5p5 %case0" // not in the order of blocks
728        "                       %constf8p5  %phi     %constf6p5  %default\n" // from the same block & from an unreachable block
729		"%inloc    = OpAccessChain %f32ptr %indata %zero %x\n"
730		"%inval    = OpLoad %f32 %inloc\n"
731		"%add      = OpFAdd %f32 %inval %operand\n"
732		"%outloc   = OpAccessChain %f32ptr %outdata %zero %x\n"
733		"            OpStore %outloc %add\n"
734		"            OpReturn\n"
735
736		// Case 0 after OpPhi.
737		"%case0    = OpLabel\n"
738		"            OpBranch %phi\n"
739
740
741		// Case 2 after OpPhi.
742		"%case2    = OpLabel\n"
743		"            OpBranch %phi\n"
744
745		"            OpFunctionEnd\n";
746	spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
747	spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
748	spec.numWorkGroups = IVec3(numElements, 1, 1);
749
750	group->addChild(new SpvAsmComputeShaderCase(testCtx, "all", "OpPhi corner cases", spec));
751
752	return group.release();
753}
754
755// Assembly code used for testing block order is based on GLSL source code:
756//
757// #version 430
758//
759// layout(std140, set = 0, binding = 0) readonly buffer Input {
760//   float elements[];
761// } input_data;
762// layout(std140, set = 0, binding = 1) writeonly buffer Output {
763//   float elements[];
764// } output_data;
765//
766// void main() {
767//   uint x = gl_GlobalInvocationID.x;
768//   output_data.elements[x] = input_data.elements[x];
769//   if (x > uint(50)) {
770//     switch (x % uint(3)) {
771//       case 0: output_data.elements[x] += 1.5f; break;
772//       case 1: output_data.elements[x] += 42.f; break;
773//       case 2: output_data.elements[x] -= 27.f; break;
774//       default: break;
775//     }
776//   } else {
777//     output_data.elements[x] = -input_data.elements[x];
778//   }
779// }
780tcu::TestCaseGroup* createBlockOrderGroup (tcu::TestContext& testCtx)
781{
782	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "block_order", "Test block orders"));
783	ComputeShaderSpec				spec;
784	de::Random						rnd				(deStringHash(group->getName()));
785	const int						numElements		= 100;
786	vector<float>					inputFloats		(numElements, 0);
787	vector<float>					outputFloats	(numElements, 0);
788
789	fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
790
791	for (size_t ndx = 0; ndx <= 50; ++ndx)
792		outputFloats[ndx] = -inputFloats[ndx];
793
794	for (size_t ndx = 51; ndx < numElements; ++ndx)
795	{
796		switch (ndx % 3)
797		{
798			case 0:		outputFloats[ndx] = inputFloats[ndx] + 1.5f; break;
799			case 1:		outputFloats[ndx] = inputFloats[ndx] + 42.f; break;
800			case 2:		outputFloats[ndx] = inputFloats[ndx] - 27.f; break;
801			default:	break;
802		}
803	}
804
805	spec.assembly =
806		string(s_ShaderPreamble) +
807
808		"OpSource GLSL 430\n"
809		"OpName %main \"main\"\n"
810		"OpName %id \"gl_GlobalInvocationID\"\n"
811
812		"OpDecorate %id BuiltIn GlobalInvocationId\n"
813
814		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
815
816		"%u32ptr       = OpTypePointer Function %u32\n"
817		"%u32ptr_input = OpTypePointer Input %u32\n"
818
819		+ string(s_InputOutputBuffer) +
820
821		"%id        = OpVariable %uvec3ptr Input\n"
822		"%zero      = OpConstant %i32 0\n"
823		"%const3    = OpConstant %u32 3\n"
824		"%const50   = OpConstant %u32 50\n"
825		"%constf1p5 = OpConstant %f32 1.5\n"
826		"%constf27  = OpConstant %f32 27.0\n"
827		"%constf42  = OpConstant %f32 42.0\n"
828
829		"%main = OpFunction %void None %voidf\n"
830
831		// entry block.
832		"%entry    = OpLabel\n"
833
834		// Create a temporary variable to hold the value of gl_GlobalInvocationID.x.
835		"%xvar     = OpVariable %u32ptr Function\n"
836		"%xptr     = OpAccessChain %u32ptr_input %id %zero\n"
837		"%x        = OpLoad %u32 %xptr\n"
838		"            OpStore %xvar %x\n"
839
840		"%cmp      = OpUGreaterThan %bool %x %const50\n"
841		"            OpSelectionMerge %if_merge None\n"
842		"            OpBranchConditional %cmp %if_true %if_false\n"
843
844		// Merge block for switch-statement: placed at the beginning.
845		"%switch_merge = OpLabel\n"
846		"                OpBranch %if_merge\n"
847
848		// Case 1 for switch-statement.
849		"%case1    = OpLabel\n"
850		"%x_1      = OpLoad %u32 %xvar\n"
851		"%inloc_1  = OpAccessChain %f32ptr %indata %zero %x_1\n"
852		"%inval_1  = OpLoad %f32 %inloc_1\n"
853		"%addf42   = OpFAdd %f32 %inval_1 %constf42\n"
854		"%outloc_1 = OpAccessChain %f32ptr %outdata %zero %x_1\n"
855		"            OpStore %outloc_1 %addf42\n"
856		"            OpBranch %switch_merge\n"
857
858		// False branch for if-statement: placed in the middle of switch cases and before true branch.
859		"%if_false = OpLabel\n"
860		"%x_f      = OpLoad %u32 %xvar\n"
861		"%inloc_f  = OpAccessChain %f32ptr %indata %zero %x_f\n"
862		"%inval_f  = OpLoad %f32 %inloc_f\n"
863		"%negate   = OpFNegate %f32 %inval_f\n"
864		"%outloc_f = OpAccessChain %f32ptr %outdata %zero %x_f\n"
865		"            OpStore %outloc_f %negate\n"
866		"            OpBranch %if_merge\n"
867
868		// Merge block for if-statement: placed in the middle of true and false branch.
869		"%if_merge = OpLabel\n"
870		"            OpReturn\n"
871
872		// True branch for if-statement: placed in the middle of swtich cases and after the false branch.
873		"%if_true  = OpLabel\n"
874		"%xval_t   = OpLoad %u32 %xvar\n"
875		"%mod      = OpUMod %u32 %xval_t %const3\n"
876		"            OpSelectionMerge %switch_merge None\n"
877		"            OpSwitch %mod %default 0 %case0 1 %case1 2 %case2\n"
878
879		// Case 2 for switch-statement.
880		"%case2    = OpLabel\n"
881		"%x_2      = OpLoad %u32 %xvar\n"
882		"%inloc_2  = OpAccessChain %f32ptr %indata %zero %x_2\n"
883		"%inval_2  = OpLoad %f32 %inloc_2\n"
884		"%subf27   = OpFSub %f32 %inval_2 %constf27\n"
885		"%outloc_2 = OpAccessChain %f32ptr %outdata %zero %x_2\n"
886		"            OpStore %outloc_2 %subf27\n"
887		"            OpBranch %switch_merge\n"
888
889		// Default case for switch-statement: placed in the middle of normal cases.
890		"%default = OpLabel\n"
891		"           OpBranch %switch_merge\n"
892
893		// Case 0 for switch-statement: out of order.
894		"%case0    = OpLabel\n"
895		"%x_0      = OpLoad %u32 %xvar\n"
896		"%inloc_0  = OpAccessChain %f32ptr %indata %zero %x_0\n"
897		"%inval_0  = OpLoad %f32 %inloc_0\n"
898		"%addf1p5  = OpFAdd %f32 %inval_0 %constf1p5\n"
899		"%outloc_0 = OpAccessChain %f32ptr %outdata %zero %x_0\n"
900		"            OpStore %outloc_0 %addf1p5\n"
901		"            OpBranch %switch_merge\n"
902
903		"            OpFunctionEnd\n";
904	spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
905	spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
906	spec.numWorkGroups = IVec3(numElements, 1, 1);
907
908	group->addChild(new SpvAsmComputeShaderCase(testCtx, "all", "various out-of-order blocks", spec));
909
910	return group.release();
911}
912
913struct CaseParameter
914{
915	const char*		name;
916	string			param;
917
918	CaseParameter	(const char* case_, const string& param_) : name(case_), param(param_) {}
919};
920
921tcu::TestCaseGroup* createOpSourceGroup (tcu::TestContext& testCtx)
922{
923	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opsource", "Tests the OpSource & OpSourceContinued instruction"));
924	vector<CaseParameter>			cases;
925	de::Random						rnd				(deStringHash(group->getName()));
926	const int						numElements		= 100;
927	vector<float>					positiveFloats	(numElements, 0);
928	vector<float>					negativeFloats	(numElements, 0);
929	const StringTemplate			shaderTemplate	(
930		"OpCapability Shader\n"
931		"OpMemoryModel Logical GLSL450\n"
932
933		"OpEntryPoint GLCompute %main \"main\" %id\n"
934		"OpExecutionMode %main LocalSize 1 1 1\n"
935
936		"${SOURCE}\n"
937
938		"OpName %main           \"main\"\n"
939		"OpName %id             \"gl_GlobalInvocationID\"\n"
940
941		"OpDecorate %id BuiltIn GlobalInvocationId\n"
942
943		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
944
945		"%id        = OpVariable %uvec3ptr Input\n"
946		"%zero      = OpConstant %i32 0\n"
947
948		"%main      = OpFunction %void None %voidf\n"
949		"%label     = OpLabel\n"
950		"%idval     = OpLoad %uvec3 %id\n"
951		"%x         = OpCompositeExtract %u32 %idval 0\n"
952		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
953		"%inval     = OpLoad %f32 %inloc\n"
954		"%neg       = OpFNegate %f32 %inval\n"
955		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
956		"             OpStore %outloc %neg\n"
957		"             OpReturn\n"
958		"             OpFunctionEnd\n");
959
960	cases.push_back(CaseParameter("unknown_source",							"OpSource Unknown 0"));
961	cases.push_back(CaseParameter("wrong_source",							"OpSource OpenCL 210"));
962	cases.push_back(CaseParameter("normal_filename",						"%fname = OpString \"filename\"\n"
963																			"OpSource GLSL 430 %fname"));
964	cases.push_back(CaseParameter("empty_filename",							"%fname = OpString \"\"\n"
965																			"OpSource GLSL 430 %fname"));
966	cases.push_back(CaseParameter("normal_source_code",						"%fname = OpString \"filename\"\n"
967																			"OpSource GLSL 430 %fname \"#version 430\nvoid main() {}\""));
968	cases.push_back(CaseParameter("empty_source_code",						"%fname = OpString \"filename\"\n"
969																			"OpSource GLSL 430 %fname \"\""));
970	cases.push_back(CaseParameter("long_source_code",						"%fname = OpString \"filename\"\n"
971																			"OpSource GLSL 430 %fname \"" + string(65530, 'x') + "\"")); // word count: 65535
972	cases.push_back(CaseParameter("utf8_source_code",						"%fname = OpString \"filename\"\n"
973																			"OpSource GLSL 430 %fname \"\xE2\x98\x82\xE2\x98\x85\"")); // umbrella & black star symbol
974	cases.push_back(CaseParameter("normal_sourcecontinued",					"%fname = OpString \"filename\"\n"
975																			"OpSource GLSL 430 %fname \"#version 430\nvo\"\n"
976																			"OpSourceContinued \"id main() {}\""));
977	cases.push_back(CaseParameter("empty_sourcecontinued",					"%fname = OpString \"filename\"\n"
978																			"OpSource GLSL 430 %fname \"#version 430\nvoid main() {}\"\n"
979																			"OpSourceContinued \"\""));
980	cases.push_back(CaseParameter("long_sourcecontinued",					"%fname = OpString \"filename\"\n"
981																			"OpSource GLSL 430 %fname \"#version 430\nvoid main() {}\"\n"
982																			"OpSourceContinued \"" + string(65533, 'x') + "\"")); // word count: 65535
983	cases.push_back(CaseParameter("utf8_sourcecontinued",					"%fname = OpString \"filename\"\n"
984																			"OpSource GLSL 430 %fname \"#version 430\nvoid main() {}\"\n"
985																			"OpSourceContinued \"\xE2\x98\x8E\xE2\x9A\x91\"")); // white telephone & black flag symbol
986	cases.push_back(CaseParameter("multi_sourcecontinued",					"%fname = OpString \"filename\"\n"
987																			"OpSource GLSL 430 %fname \"#version 430\n\"\n"
988																			"OpSourceContinued \"void\"\n"
989																			"OpSourceContinued \"main()\"\n"
990																			"OpSourceContinued \"{}\""));
991	cases.push_back(CaseParameter("empty_source_before_sourcecontinued",	"%fname = OpString \"filename\"\n"
992																			"OpSource GLSL 430 %fname \"\"\n"
993																			"OpSourceContinued \"#version 430\nvoid main() {}\""));
994
995	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
996
997	for (size_t ndx = 0; ndx < numElements; ++ndx)
998		negativeFloats[ndx] = -positiveFloats[ndx];
999
1000	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
1001	{
1002		map<string, string>		specializations;
1003		ComputeShaderSpec		spec;
1004
1005		specializations["SOURCE"] = cases[caseNdx].param;
1006		spec.assembly = shaderTemplate.specialize(specializations);
1007		spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
1008		spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
1009		spec.numWorkGroups = IVec3(numElements, 1, 1);
1010
1011		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
1012	}
1013
1014	return group.release();
1015}
1016
1017tcu::TestCaseGroup* createOpSourceExtensionGroup (tcu::TestContext& testCtx)
1018{
1019	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opsourceextension", "Tests the OpSource instruction"));
1020	vector<CaseParameter>			cases;
1021	de::Random						rnd				(deStringHash(group->getName()));
1022	const int						numElements		= 100;
1023	vector<float>					inputFloats		(numElements, 0);
1024	vector<float>					outputFloats	(numElements, 0);
1025	const StringTemplate			shaderTemplate	(
1026		string(s_ShaderPreamble) +
1027
1028		"OpSourceExtension \"${EXTENSION}\"\n"
1029
1030		"OpName %main           \"main\"\n"
1031		"OpName %id             \"gl_GlobalInvocationID\"\n"
1032
1033		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1034
1035		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
1036
1037		"%id        = OpVariable %uvec3ptr Input\n"
1038		"%zero      = OpConstant %i32 0\n"
1039
1040		"%main      = OpFunction %void None %voidf\n"
1041		"%label     = OpLabel\n"
1042		"%idval     = OpLoad %uvec3 %id\n"
1043		"%x         = OpCompositeExtract %u32 %idval 0\n"
1044		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
1045		"%inval     = OpLoad %f32 %inloc\n"
1046		"%neg       = OpFNegate %f32 %inval\n"
1047		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
1048		"             OpStore %outloc %neg\n"
1049		"             OpReturn\n"
1050		"             OpFunctionEnd\n");
1051
1052	cases.push_back(CaseParameter("empty_extension",	""));
1053	cases.push_back(CaseParameter("real_extension",		"GL_ARB_texture_rectangle"));
1054	cases.push_back(CaseParameter("fake_extension",		"GL_ARB_im_the_ultimate_extension"));
1055	cases.push_back(CaseParameter("utf8_extension",		"GL_ARB_\xE2\x98\x82\xE2\x98\x85"));
1056	cases.push_back(CaseParameter("long_extension",		string(65533, 'e'))); // word count: 65535
1057
1058	fillRandomScalars(rnd, -200.f, 200.f, &inputFloats[0], numElements);
1059
1060	for (size_t ndx = 0; ndx < numElements; ++ndx)
1061		outputFloats[ndx] = -inputFloats[ndx];
1062
1063	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
1064	{
1065		map<string, string>		specializations;
1066		ComputeShaderSpec		spec;
1067
1068		specializations["EXTENSION"] = cases[caseNdx].param;
1069		spec.assembly = shaderTemplate.specialize(specializations);
1070		spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
1071		spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
1072		spec.numWorkGroups = IVec3(numElements, 1, 1);
1073
1074		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
1075	}
1076
1077	return group.release();
1078}
1079
1080// Checks that a compute shader can generate a constant null value of various types, without exercising a computation on it.
1081tcu::TestCaseGroup* createOpConstantNullGroup (tcu::TestContext& testCtx)
1082{
1083	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opconstantnull", "Tests the OpConstantNull instruction"));
1084	vector<CaseParameter>			cases;
1085	de::Random						rnd				(deStringHash(group->getName()));
1086	const int						numElements		= 100;
1087	vector<float>					positiveFloats	(numElements, 0);
1088	vector<float>					negativeFloats	(numElements, 0);
1089	const StringTemplate			shaderTemplate	(
1090		string(s_ShaderPreamble) +
1091
1092		"OpSource GLSL 430\n"
1093		"OpName %main           \"main\"\n"
1094		"OpName %id             \"gl_GlobalInvocationID\"\n"
1095
1096		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1097
1098		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
1099
1100		"${TYPE}\n"
1101		"%null      = OpConstantNull %type\n"
1102
1103		"%id        = OpVariable %uvec3ptr Input\n"
1104		"%zero      = OpConstant %i32 0\n"
1105
1106		"%main      = OpFunction %void None %voidf\n"
1107		"%label     = OpLabel\n"
1108		"%idval     = OpLoad %uvec3 %id\n"
1109		"%x         = OpCompositeExtract %u32 %idval 0\n"
1110		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
1111		"%inval     = OpLoad %f32 %inloc\n"
1112		"%neg       = OpFNegate %f32 %inval\n"
1113		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
1114		"             OpStore %outloc %neg\n"
1115		"             OpReturn\n"
1116		"             OpFunctionEnd\n");
1117
1118	cases.push_back(CaseParameter("bool",			"%type = OpTypeBool"));
1119	cases.push_back(CaseParameter("sint32",			"%type = OpTypeInt 32 1"));
1120	cases.push_back(CaseParameter("uint32",			"%type = OpTypeInt 32 0"));
1121	cases.push_back(CaseParameter("float32",		"%type = OpTypeFloat 32"));
1122	cases.push_back(CaseParameter("vec4float32",	"%type = OpTypeVector %f32 4"));
1123	cases.push_back(CaseParameter("vec3bool",		"%type = OpTypeVector %bool 3"));
1124	cases.push_back(CaseParameter("vec2uint32",		"%type = OpTypeVector %u32 2"));
1125	cases.push_back(CaseParameter("matrix",			"%type = OpTypeMatrix %uvec3 3"));
1126	cases.push_back(CaseParameter("array",			"%100 = OpConstant %u32 100\n"
1127													"%type = OpTypeArray %i32 %100"));
1128	cases.push_back(CaseParameter("runtimearray",	"%type = OpTypeRuntimeArray %f32"));
1129	cases.push_back(CaseParameter("struct",			"%type = OpTypeStruct %f32 %i32 %u32"));
1130	cases.push_back(CaseParameter("pointer",		"%type = OpTypePointer Function %i32"));
1131
1132	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
1133
1134	for (size_t ndx = 0; ndx < numElements; ++ndx)
1135		negativeFloats[ndx] = -positiveFloats[ndx];
1136
1137	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
1138	{
1139		map<string, string>		specializations;
1140		ComputeShaderSpec		spec;
1141
1142		specializations["TYPE"] = cases[caseNdx].param;
1143		spec.assembly = shaderTemplate.specialize(specializations);
1144		spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
1145		spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
1146		spec.numWorkGroups = IVec3(numElements, 1, 1);
1147
1148		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
1149	}
1150
1151	return group.release();
1152}
1153
1154// Checks that a compute shader can generate a constant composite value of various types, without exercising a computation on it.
1155tcu::TestCaseGroup* createOpConstantCompositeGroup (tcu::TestContext& testCtx)
1156{
1157	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opconstantcomposite", "Tests the OpConstantComposite instruction"));
1158	vector<CaseParameter>			cases;
1159	de::Random						rnd				(deStringHash(group->getName()));
1160	const int						numElements		= 100;
1161	vector<float>					positiveFloats	(numElements, 0);
1162	vector<float>					negativeFloats	(numElements, 0);
1163	const StringTemplate			shaderTemplate	(
1164		string(s_ShaderPreamble) +
1165
1166		"OpSource GLSL 430\n"
1167		"OpName %main           \"main\"\n"
1168		"OpName %id             \"gl_GlobalInvocationID\"\n"
1169
1170		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1171
1172		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
1173
1174		"%id        = OpVariable %uvec3ptr Input\n"
1175		"%zero      = OpConstant %i32 0\n"
1176
1177		"${CONSTANT}\n"
1178
1179		"%main      = OpFunction %void None %voidf\n"
1180		"%label     = OpLabel\n"
1181		"%idval     = OpLoad %uvec3 %id\n"
1182		"%x         = OpCompositeExtract %u32 %idval 0\n"
1183		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
1184		"%inval     = OpLoad %f32 %inloc\n"
1185		"%neg       = OpFNegate %f32 %inval\n"
1186		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
1187		"             OpStore %outloc %neg\n"
1188		"             OpReturn\n"
1189		"             OpFunctionEnd\n");
1190
1191	cases.push_back(CaseParameter("vector",			"%five = OpConstant %u32 5\n"
1192													"%const = OpConstantComposite %uvec3 %five %zero %five"));
1193	cases.push_back(CaseParameter("matrix",			"%m3uvec3 = OpTypeMatrix %uvec3 3\n"
1194													"%ten = OpConstant %u32 10\n"
1195													"%vec = OpConstantComposite %uvec3 %ten %zero %ten\n"
1196													"%mat = OpConstantComposite %m3uvec3 %vec %vec %vec"));
1197	cases.push_back(CaseParameter("struct",			"%m2vec3 = OpTypeMatrix %uvec3 2\n"
1198													"%struct = OpTypeStruct %u32 %f32 %uvec3 %m2vec3\n"
1199													"%one = OpConstant %u32 1\n"
1200													"%point5 = OpConstant %f32 0.5\n"
1201													"%vec = OpConstantComposite %uvec3 %one %one %zero\n"
1202													"%mat = OpConstantComposite %m2vec3 %vec %vec\n"
1203													"%const = OpConstantComposite %one %point5 %vec %mat"));
1204	cases.push_back(CaseParameter("nested_struct",	"%st1 = OpTypeStruct %u32 %f32\n"
1205													"%st2 = OpTypeStruct %i32 %i32\n"
1206													"%struct = OpTypeStruct %st1 %st2\n"
1207													"%point5 = OpConstant %f32 0.5\n"
1208													"%one = OpConstant %u32 1\n"
1209													"%ten = OpConstant %i32 10\n"
1210													"%st1val = OpConstantComposite %one %point5\n"
1211													"%st2val = OpConstantComposite %ten %ten\n"
1212													"%const = OpConstantComposite %st1val %st2val"));
1213
1214	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
1215
1216	for (size_t ndx = 0; ndx < numElements; ++ndx)
1217		negativeFloats[ndx] = -positiveFloats[ndx];
1218
1219	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
1220	{
1221		map<string, string>		specializations;
1222		ComputeShaderSpec		spec;
1223
1224		specializations["CONSTANT"] = cases[caseNdx].param;
1225		spec.assembly = shaderTemplate.specialize(specializations);
1226		spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
1227		spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
1228		spec.numWorkGroups = IVec3(numElements, 1, 1);
1229
1230		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
1231	}
1232
1233	return group.release();
1234}
1235
1236// Checks that constant null/composite values can be used in computation.
1237tcu::TestCaseGroup* createOpConstantUsageGroup (tcu::TestContext& testCtx)
1238{
1239	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opconstantnullcomposite", "Spotcheck the OpConstantNull & OpConstantComposite instruction"));
1240	ComputeShaderSpec				spec;
1241	de::Random						rnd				(deStringHash(group->getName()));
1242	const int						numElements		= 100;
1243	vector<float>					positiveFloats	(numElements, 0);
1244	vector<float>					negativeFloats	(numElements, 0);
1245
1246	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
1247
1248	for (size_t ndx = 0; ndx < numElements; ++ndx)
1249		negativeFloats[ndx] = -positiveFloats[ndx];
1250
1251	spec.assembly =
1252		"OpCapability Shader\n"
1253		"%std450 = OpExtInstImport \"GLSL.std.450\"\n"
1254		"OpMemoryModel Logical GLSL450\n"
1255		"OpEntryPoint GLCompute %main \"main\" %id\n"
1256		"OpExecutionMode %main LocalSize 1 1 1\n"
1257
1258		"OpSource GLSL 430\n"
1259		"OpName %main           \"main\"\n"
1260		"OpName %id             \"gl_GlobalInvocationID\"\n"
1261
1262		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1263
1264		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
1265
1266		"%fvec3     = OpTypeVector %f32 3\n"
1267		"%fmat      = OpTypeMatrix %fvec3 3\n"
1268		"%ten       = OpConstant %u32 10\n"
1269		"%f32arr10  = OpTypeArray %f32 %ten\n"
1270		"%fst       = OpTypeStruct %f32 %f32\n"
1271
1272		+ string(s_InputOutputBuffer) +
1273
1274		"%id        = OpVariable %uvec3ptr Input\n"
1275		"%zero      = OpConstant %i32 0\n"
1276
1277		// Create a bunch of null values
1278		"%unull     = OpConstantNull %u32\n"
1279		"%fnull     = OpConstantNull %f32\n"
1280		"%vnull     = OpConstantNull %fvec3\n"
1281		"%mnull     = OpConstantNull %fmat\n"
1282		"%anull     = OpConstantNull %f32arr10\n"
1283		"%snull     = OpConstantComposite %fst %fnull %fnull\n"
1284
1285		"%main      = OpFunction %void None %voidf\n"
1286		"%label     = OpLabel\n"
1287		"%idval     = OpLoad %uvec3 %id\n"
1288		"%x         = OpCompositeExtract %u32 %idval 0\n"
1289		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
1290		"%inval     = OpLoad %f32 %inloc\n"
1291		"%neg       = OpFNegate %f32 %inval\n"
1292
1293		// Get the abs() of (a certain element of) those null values
1294		"%unull_cov = OpConvertUToF %f32 %unull\n"
1295		"%unull_abs = OpExtInst %f32 %std450 FAbs %unull_cov\n"
1296		"%fnull_abs = OpExtInst %f32 %std450 FAbs %fnull\n"
1297		"%vnull_0   = OpCompositeExtract %f32 %vnull 0\n"
1298		"%vnull_abs = OpExtInst %f32 %std450 FAbs %vnull_0\n"
1299		"%mnull_12  = OpCompositeExtract %f32 %mnull 1 2\n"
1300		"%mnull_abs = OpExtInst %f32 %std450 FAbs %mnull_12\n"
1301		"%anull_3   = OpCompositeExtract %f32 %anull 3\n"
1302		"%anull_abs = OpExtInst %f32 %std450 FAbs %anull_3\n"
1303		"%snull_1   = OpCompositeExtract %f32 %snull 1\n"
1304		"%snull_abs = OpExtInst %f32 %std450 FAbs %snull_1\n"
1305
1306		// Add them all
1307		"%add1      = OpFAdd %f32 %neg  %unull_abs\n"
1308		"%add2      = OpFAdd %f32 %add1 %fnull_abs\n"
1309		"%add3      = OpFAdd %f32 %add2 %vnull_abs\n"
1310		"%add4      = OpFAdd %f32 %add3 %mnull_abs\n"
1311		"%add5      = OpFAdd %f32 %add4 %anull_abs\n"
1312		"%final     = OpFAdd %f32 %add5 %snull_abs\n"
1313
1314		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
1315		"             OpStore %outloc %final\n" // write to output
1316		"             OpReturn\n"
1317		"             OpFunctionEnd\n";
1318	spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
1319	spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
1320	spec.numWorkGroups = IVec3(numElements, 1, 1);
1321
1322	group->addChild(new SpvAsmComputeShaderCase(testCtx, "spotcheck", "Check that values constructed via OpConstantNull & OpConstantComposite can be used", spec));
1323
1324	return group.release();
1325}
1326
1327// Assembly code used for testing loop control is based on GLSL source code:
1328// #version 430
1329//
1330// layout(std140, set = 0, binding = 0) readonly buffer Input {
1331//   float elements[];
1332// } input_data;
1333// layout(std140, set = 0, binding = 1) writeonly buffer Output {
1334//   float elements[];
1335// } output_data;
1336//
1337// void main() {
1338//   uint x = gl_GlobalInvocationID.x;
1339//   output_data.elements[x] = input_data.elements[x];
1340//   for (uint i = 0; i < 4; ++i)
1341//     output_data.elements[x] += 1.f;
1342// }
1343tcu::TestCaseGroup* createLoopControlGroup (tcu::TestContext& testCtx)
1344{
1345	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "loop_control", "Tests loop control cases"));
1346	vector<CaseParameter>			cases;
1347	de::Random						rnd				(deStringHash(group->getName()));
1348	const int						numElements		= 100;
1349	vector<float>					inputFloats		(numElements, 0);
1350	vector<float>					outputFloats	(numElements, 0);
1351	const StringTemplate			shaderTemplate	(
1352		string(s_ShaderPreamble) +
1353
1354		"OpSource GLSL 430\n"
1355		"OpName %main \"main\"\n"
1356		"OpName %id \"gl_GlobalInvocationID\"\n"
1357
1358		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1359
1360		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
1361
1362		"%u32ptr      = OpTypePointer Function %u32\n"
1363
1364		"%id          = OpVariable %uvec3ptr Input\n"
1365		"%zero        = OpConstant %i32 0\n"
1366		"%one         = OpConstant %i32 1\n"
1367		"%constf1     = OpConstant %f32 1.0\n"
1368		"%four        = OpConstant %u32 4\n"
1369
1370		"%main        = OpFunction %void None %voidf\n"
1371		"%entry       = OpLabel\n"
1372		"%i           = OpVariable %u32ptr Function\n"
1373		"               OpStore %i %zero\n"
1374
1375		"%idval       = OpLoad %uvec3 %id\n"
1376		"%x           = OpCompositeExtract %u32 %idval 0\n"
1377		"%inloc       = OpAccessChain %f32ptr %indata %zero %x\n"
1378		"%inval       = OpLoad %f32 %inloc\n"
1379		"%outloc      = OpAccessChain %f32ptr %outdata %zero %x\n"
1380		"               OpStore %outloc %inval\n"
1381		"               OpBranch %loop_entry\n"
1382
1383		"%loop_entry  = OpLabel\n"
1384		"%i_val       = OpLoad %u32 %i\n"
1385		"%cmp_lt      = OpULessThan %bool %i_val %four\n"
1386		"               OpLoopMerge %loop_merge %loop_entry ${CONTROL}\n"
1387		"               OpBranchConditional %cmp_lt %loop_body %loop_merge\n"
1388		"%loop_body   = OpLabel\n"
1389		"%outval      = OpLoad %f32 %outloc\n"
1390		"%addf1       = OpFAdd %f32 %outval %constf1\n"
1391		"               OpStore %outloc %addf1\n"
1392		"%new_i       = OpIAdd %u32 %i_val %one\n"
1393		"               OpStore %i %new_i\n"
1394		"               OpBranch %loop_entry\n"
1395		"%loop_merge  = OpLabel\n"
1396		"               OpReturn\n"
1397		"               OpFunctionEnd\n");
1398
1399	cases.push_back(CaseParameter("none",				"None"));
1400	cases.push_back(CaseParameter("unroll",				"Unroll"));
1401	cases.push_back(CaseParameter("dont_unroll",		"DontUnroll"));
1402	cases.push_back(CaseParameter("unroll_dont_unroll",	"Unroll|DontUnroll"));
1403
1404	fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
1405
1406	for (size_t ndx = 0; ndx < numElements; ++ndx)
1407		outputFloats[ndx] = inputFloats[ndx] + 4.f;
1408
1409	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
1410	{
1411		map<string, string>		specializations;
1412		ComputeShaderSpec		spec;
1413
1414		specializations["CONTROL"] = cases[caseNdx].param;
1415		spec.assembly = shaderTemplate.specialize(specializations);
1416		spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
1417		spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
1418		spec.numWorkGroups = IVec3(numElements, 1, 1);
1419
1420		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
1421	}
1422
1423	return group.release();
1424}
1425
1426// Assembly code used for testing selection control is based on GLSL source code:
1427// #version 430
1428//
1429// layout(std140, set = 0, binding = 0) readonly buffer Input {
1430//   float elements[];
1431// } input_data;
1432// layout(std140, set = 0, binding = 1) writeonly buffer Output {
1433//   float elements[];
1434// } output_data;
1435//
1436// void main() {
1437//   uint x = gl_GlobalInvocationID.x;
1438//   float val = input_data.elements[x];
1439//   if (val > 10.f)
1440//     output_data.elements[x] = val + 1.f;
1441//   else
1442//     output_data.elements[x] = val - 1.f;
1443// }
1444tcu::TestCaseGroup* createSelectionControlGroup (tcu::TestContext& testCtx)
1445{
1446	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "selection_control", "Tests selection control cases"));
1447	vector<CaseParameter>			cases;
1448	de::Random						rnd				(deStringHash(group->getName()));
1449	const int						numElements		= 100;
1450	vector<float>					inputFloats		(numElements, 0);
1451	vector<float>					outputFloats	(numElements, 0);
1452	const StringTemplate			shaderTemplate	(
1453		string(s_ShaderPreamble) +
1454
1455		"OpSource GLSL 430\n"
1456		"OpName %main \"main\"\n"
1457		"OpName %id \"gl_GlobalInvocationID\"\n"
1458
1459		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1460
1461		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
1462
1463		"%id       = OpVariable %uvec3ptr Input\n"
1464		"%zero     = OpConstant %i32 0\n"
1465		"%constf1  = OpConstant %f32 1.0\n"
1466		"%constf10 = OpConstant %f32 10.0\n"
1467
1468		"%main     = OpFunction %void None %voidf\n"
1469		"%entry    = OpLabel\n"
1470		"%idval    = OpLoad %uvec3 %id\n"
1471		"%x        = OpCompositeExtract %u32 %idval 0\n"
1472		"%inloc    = OpAccessChain %f32ptr %indata %zero %x\n"
1473		"%inval    = OpLoad %f32 %inloc\n"
1474		"%outloc   = OpAccessChain %f32ptr %outdata %zero %x\n"
1475		"%cmp_gt   = OpFOrdGreaterThan %bool %inval %constf10\n"
1476
1477		"            OpSelectionMerge %if_end ${CONTROL}\n"
1478		"            OpBranchConditional %cmp_gt %if_true %if_false\n"
1479		"%if_true  = OpLabel\n"
1480		"%addf1    = OpFAdd %f32 %inval %constf1\n"
1481		"            OpStore %outloc %addf1\n"
1482		"            OpBranch %if_end\n"
1483		"%if_false = OpLabel\n"
1484		"%subf1    = OpFSub %f32 %inval %constf1\n"
1485		"            OpStore %outloc %subf1\n"
1486		"            OpBranch %if_end\n"
1487		"%if_end   = OpLabel\n"
1488		"            OpReturn\n"
1489		"            OpFunctionEnd\n");
1490
1491	cases.push_back(CaseParameter("none",					"None"));
1492	cases.push_back(CaseParameter("flatten",				"Flatten"));
1493	cases.push_back(CaseParameter("dont_flatten",			"DontFlatten"));
1494	cases.push_back(CaseParameter("flatten_dont_flatten",	"DontFlatten|Flatten"));
1495
1496	fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
1497
1498	for (size_t ndx = 0; ndx < numElements; ++ndx)
1499		outputFloats[ndx] = inputFloats[ndx] + (inputFloats[ndx] > 10.f ? 1.f : -1.f);
1500
1501	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
1502	{
1503		map<string, string>		specializations;
1504		ComputeShaderSpec		spec;
1505
1506		specializations["CONTROL"] = cases[caseNdx].param;
1507		spec.assembly = shaderTemplate.specialize(specializations);
1508		spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
1509		spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
1510		spec.numWorkGroups = IVec3(numElements, 1, 1);
1511
1512		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
1513	}
1514
1515	return group.release();
1516}
1517
1518// Assembly code used for testing function control is based on GLSL source code:
1519//
1520// #version 430
1521//
1522// layout(std140, set = 0, binding = 0) readonly buffer Input {
1523//   float elements[];
1524// } input_data;
1525// layout(std140, set = 0, binding = 1) writeonly buffer Output {
1526//   float elements[];
1527// } output_data;
1528//
1529// float const10() { return 10.f; }
1530//
1531// void main() {
1532//   uint x = gl_GlobalInvocationID.x;
1533//   output_data.elements[x] = input_data.elements[x] + const10();
1534// }
1535tcu::TestCaseGroup* createFunctionControlGroup (tcu::TestContext& testCtx)
1536{
1537	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "function_control", "Tests function control cases"));
1538	vector<CaseParameter>			cases;
1539	de::Random						rnd				(deStringHash(group->getName()));
1540	const int						numElements		= 100;
1541	vector<float>					inputFloats		(numElements, 0);
1542	vector<float>					outputFloats	(numElements, 0);
1543	const StringTemplate			shaderTemplate	(
1544		string(s_ShaderPreamble) +
1545
1546		"OpSource GLSL 430\n"
1547		"OpName %main \"main\"\n"
1548		"OpName %func_const10 \"const10(\"\n"
1549		"OpName %id \"gl_GlobalInvocationID\"\n"
1550
1551		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1552
1553		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
1554
1555		"%f32f = OpTypeFunction %f32\n"
1556		"%id = OpVariable %uvec3ptr Input\n"
1557		"%zero = OpConstant %i32 0\n"
1558		"%constf10 = OpConstant %f32 10.0\n"
1559
1560		"%main         = OpFunction %void None %voidf\n"
1561		"%entry        = OpLabel\n"
1562		"%idval        = OpLoad %uvec3 %id\n"
1563		"%x            = OpCompositeExtract %u32 %idval 0\n"
1564		"%inloc        = OpAccessChain %f32ptr %indata %zero %x\n"
1565		"%inval        = OpLoad %f32 %inloc\n"
1566		"%ret_10       = OpFunctionCall %f32 %func_const10\n"
1567		"%fadd         = OpFAdd %f32 %inval %ret_10\n"
1568		"%outloc       = OpAccessChain %f32ptr %outdata %zero %x\n"
1569		"                OpStore %outloc %fadd\n"
1570		"                OpReturn\n"
1571		"                OpFunctionEnd\n"
1572
1573		"%func_const10 = OpFunction %f32 ${CONTROL} %f32f\n"
1574		"%label        = OpLabel\n"
1575		"                OpReturnValue %constf10\n"
1576		"                OpFunctionEnd\n");
1577
1578	cases.push_back(CaseParameter("none",						"None"));
1579	cases.push_back(CaseParameter("inline",						"Inline"));
1580	cases.push_back(CaseParameter("dont_inline",				"DontInline"));
1581	cases.push_back(CaseParameter("pure",						"Pure"));
1582	cases.push_back(CaseParameter("const",						"Const"));
1583	cases.push_back(CaseParameter("inline_pure",				"Inline|Pure"));
1584	cases.push_back(CaseParameter("const_dont_inline",			"Const|DontInline"));
1585	cases.push_back(CaseParameter("inline_dont_inline",			"Inline|DontInline"));
1586	cases.push_back(CaseParameter("pure_inline_dont_inline",	"Pure|Inline|DontInline"));
1587
1588	fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
1589
1590	for (size_t ndx = 0; ndx < numElements; ++ndx)
1591		outputFloats[ndx] = inputFloats[ndx] + 10.f;
1592
1593	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
1594	{
1595		map<string, string>		specializations;
1596		ComputeShaderSpec		spec;
1597
1598		specializations["CONTROL"] = cases[caseNdx].param;
1599		spec.assembly = shaderTemplate.specialize(specializations);
1600		spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
1601		spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
1602		spec.numWorkGroups = IVec3(numElements, 1, 1);
1603
1604		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
1605	}
1606
1607	return group.release();
1608}
1609
1610// Checks that we can get undefined values for various types, without exercising a computation with it.
1611tcu::TestCaseGroup* createOpUndefGroup (tcu::TestContext& testCtx)
1612{
1613	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opundef", "Tests the OpUndef instruction"));
1614	vector<CaseParameter>			cases;
1615	de::Random						rnd				(deStringHash(group->getName()));
1616	const int						numElements		= 100;
1617	vector<float>					positiveFloats	(numElements, 0);
1618	vector<float>					negativeFloats	(numElements, 0);
1619	const StringTemplate			shaderTemplate	(
1620		string(s_ShaderPreamble) +
1621
1622		"OpSource GLSL 430\n"
1623		"OpName %main           \"main\"\n"
1624		"OpName %id             \"gl_GlobalInvocationID\"\n"
1625
1626		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1627
1628		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
1629
1630		"${TYPE}\n"
1631
1632		"%id        = OpVariable %uvec3ptr Input\n"
1633		"%zero      = OpConstant %i32 0\n"
1634
1635		"%main      = OpFunction %void None %voidf\n"
1636		"%label     = OpLabel\n"
1637
1638		"%undef     = OpUndef %type\n"
1639
1640		"%idval     = OpLoad %uvec3 %id\n"
1641		"%x         = OpCompositeExtract %u32 %idval 0\n"
1642
1643		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
1644		"%inval     = OpLoad %f32 %inloc\n"
1645		"%neg       = OpFNegate %f32 %inval\n"
1646		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
1647		"             OpStore %outloc %neg\n"
1648		"             OpReturn\n"
1649		"             OpFunctionEnd\n");
1650
1651	cases.push_back(CaseParameter("bool",			"%type = OpTypeBool"));
1652	cases.push_back(CaseParameter("sint32",			"%type = OpTypeInt 32 1"));
1653	cases.push_back(CaseParameter("uint32",			"%type = OpTypeInt 32 0"));
1654	cases.push_back(CaseParameter("float32",		"%type = OpTypeFloat 32"));
1655	cases.push_back(CaseParameter("vec4float32",	"%type = OpTypeVector %f32 4"));
1656	cases.push_back(CaseParameter("vec2uint32",		"%type = OpTypeVector %u32 2"));
1657	cases.push_back(CaseParameter("matrix",			"%type = OpTypeMatrix %uvec3 3"));
1658	cases.push_back(CaseParameter("image",			"%type = OpTypeImage %f32 2D 0 0 0 0 Unknown"));
1659	cases.push_back(CaseParameter("sampler",		"%type = OpTypeSampler"));
1660	cases.push_back(CaseParameter("sampledimage",	"%img = OpTypeImage %f32 2D 0 0 0 0 Unknown\n"
1661													"%type = OpTypeSampledImage %img"));
1662	cases.push_back(CaseParameter("array",			"%100 = OpConstant %u32 100\n"
1663													"%type = OpTypeArray %i32 %100"));
1664	cases.push_back(CaseParameter("runtimearray",	"%type = OpTypeRuntimeArray %f32"));
1665	cases.push_back(CaseParameter("struct",			"%type = OpTypeStruct %f32 %i32 %u32"));
1666	cases.push_back(CaseParameter("pointer",		"%type = OpTypePointer Function %i32"));
1667	cases.push_back(CaseParameter("function",		"%type = OpTypeFunction %void %i32 %f32"));
1668
1669	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
1670
1671	for (size_t ndx = 0; ndx < numElements; ++ndx)
1672		negativeFloats[ndx] = -positiveFloats[ndx];
1673
1674	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
1675	{
1676		map<string, string>		specializations;
1677		ComputeShaderSpec		spec;
1678
1679		specializations["TYPE"] = cases[caseNdx].param;
1680		spec.assembly = shaderTemplate.specialize(specializations);
1681	spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
1682	spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
1683		spec.numWorkGroups = IVec3(numElements, 1, 1);
1684
1685		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
1686	}
1687
1688		return group.release();
1689}
1690
1691
1692typedef std::pair<std::string, VkShaderStage>	EntryToStage;
1693typedef map<string, vector<EntryToStage> >		ModuleMap;
1694
1695// Context for a specific test instantiation. For example, an instantiation
1696// may test colors yellow/magenta/cyan/mauve in a tesselation shader
1697// with an entry point named 'main_to_the_main'
1698struct InstanceContext
1699{
1700	// Map of modules to what entry_points we care to use from those modules.
1701	ModuleMap				moduleMap;
1702	RGBA					inputColors[4];
1703	RGBA					outputColors[4];
1704	// Concrete SPIR-V code to test via boilerplate specialization.
1705	map<string, string>		testCodeFragments;
1706
1707	InstanceContext (const RGBA (&inputs)[4], const RGBA (&outputs)[4], const map<string, string>& testCodeFragments_)
1708		: testCodeFragments		(testCodeFragments_)
1709	{
1710		inputColors[0]		= inputs[0];
1711		inputColors[1]		= inputs[1];
1712		inputColors[2]		= inputs[2];
1713		inputColors[3]		= inputs[3];
1714
1715		outputColors[0]		= outputs[0];
1716		outputColors[1]		= outputs[1];
1717		outputColors[2]		= outputs[2];
1718		outputColors[3]		= outputs[3];
1719	}
1720
1721	InstanceContext (const InstanceContext& other)
1722		: moduleMap			(other.moduleMap)
1723		, testCodeFragments	(other.testCodeFragments)
1724	{
1725		inputColors[0]		= other.inputColors[0];
1726		inputColors[1]		= other.inputColors[1];
1727		inputColors[2]		= other.inputColors[2];
1728		inputColors[3]		= other.inputColors[3];
1729
1730		outputColors[0]		= other.outputColors[0];
1731		outputColors[1]		= other.outputColors[1];
1732		outputColors[2]		= other.outputColors[2];
1733		outputColors[3]		= other.outputColors[3];
1734	}
1735};
1736
1737// A description of a shader to be used for a single stage of the graphics pipeline.
1738struct ShaderElement
1739{
1740	// The module that contains this shader entrypoint.
1741	const char*		moduleName;
1742
1743	// The name of the entrypoint.
1744	const char*		entryName;
1745
1746	// Which shader stage this entry point represents.
1747	VkShaderStage	stage;
1748
1749	ShaderElement (const char* moduleName_, const char* entryPoint_, VkShaderStage shaderStage_)
1750		: moduleName(moduleName_)
1751		, entryName(entryPoint_)
1752		, stage(shaderStage_)
1753	{
1754	}
1755};
1756
1757void getDefaultColors(RGBA (&colors)[4]) {
1758	colors[0] = RGBA::white();
1759	colors[1] = RGBA::red();
1760	colors[2] = RGBA::blue();
1761	colors[3] = RGBA::green();
1762}
1763
1764// Turns a statically sized array of ShaderElements into an instance-context
1765// by setting up the mapping of modules to their contained shaders and stages.
1766// The inputs and expected outputs are given by inputColors and outputColors
1767template<size_t N>
1768InstanceContext createInstanceContext (const ShaderElement (&elements)[N], const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map<string, string>& testCodeFragments)
1769{
1770	InstanceContext ctx (inputColors, outputColors, testCodeFragments);
1771	for (size_t i = 0; i < N; ++i)
1772	{
1773		ctx.moduleMap[elements[i].moduleName].push_back(std::make_pair(elements[i].entryName, elements[i].stage));
1774	}
1775	return ctx;
1776}
1777
1778// The same as createInstanceContext above, but with default colors.
1779template<size_t N>
1780InstanceContext createInstanceContext (const ShaderElement (&elements)[N], const map<string, string>& testCodeFragments)
1781{
1782	RGBA defaultColors[4];
1783	getDefaultColors(defaultColors);
1784	return createInstanceContext(elements, defaultColors, defaultColors, testCodeFragments);
1785}
1786
1787// For the current InstanceContext, constructs the required modules and shaders.
1788// Fills in the modules vector with all of the used modules, and stage_shaders with
1789// all stages and shaders that are to be used.
1790void createShaders (const DeviceInterface& vk, const VkDevice vkDevice, InstanceContext& instance, Context& context, vector<ModuleHandleSp>& modules, map<VkShaderStage, VkShaderSp>& stage_shaders)
1791{
1792	for (ModuleMap::const_iterator moduleNdx = instance.moduleMap.begin(); moduleNdx != instance.moduleMap.end(); ++moduleNdx)
1793	{
1794		const ModuleHandleSp mod(new Unique<VkShaderModule>(createShaderModule(vk, vkDevice, context.getBinaryCollection().get(moduleNdx->first), 0)));
1795		modules.push_back(ModuleHandleSp(mod));
1796		for (vector<EntryToStage>::const_iterator shaderNdx = moduleNdx->second.begin(); shaderNdx != moduleNdx->second.end(); ++shaderNdx)
1797		{
1798			const EntryToStage&			stage			= *shaderNdx;
1799			const VkShaderCreateInfo	shaderParam		=
1800			{
1801				VK_STRUCTURE_TYPE_SHADER_CREATE_INFO,			//	VkStructureType		sType;
1802				DE_NULL,										//	const void*			pNext;
1803				**modules.back(),								//	VkShaderModule		module;
1804				stage.first.c_str(),							//	const char*			pName;
1805				0u,												//	VkShaderCreateFlags	flags;
1806				stage.second,									//	VkShaderStage		stage;
1807			};
1808			stage_shaders[stage.second] = VkShaderSp(new Unique<VkShader>(createShader(vk, vkDevice, &shaderParam)));
1809		}
1810	}
1811}
1812
1813#define SPIRV_ASSEMBLY_TYPES												\
1814	"%void = OpTypeVoid\n"													\
1815	"%bool = OpTypeBool\n"													\
1816																			\
1817	"%i32 = OpTypeInt 32 1\n"												\
1818	"%u32 = OpTypeInt 32 0\n"												\
1819																			\
1820	"%f32 = OpTypeFloat 32\n"												\
1821	"%v3f32 = OpTypeVector %f32 3\n"										\
1822	"%v4f32 = OpTypeVector %f32 4\n"										\
1823																			\
1824	"%v4f32_function = OpTypeFunction %v4f32 %v4f32\n"						\
1825	"%fun = OpTypeFunction %void\n"											\
1826																			\
1827	"%ip_f32 = OpTypePointer Input %f32\n"									\
1828	"%ip_i32 = OpTypePointer Input %i32\n"									\
1829	"%ip_v3f32 = OpTypePointer Input %v3f32\n"								\
1830	"%ip_v4f32 = OpTypePointer Input %v4f32\n"								\
1831																			\
1832	"%op_f32 = OpTypePointer Output %f32\n"									\
1833	"%op_v4f32 = OpTypePointer Output %v4f32\n"
1834
1835#define SPIRV_ASSEMBLY_CONSTANTS											\
1836	"%c_f32_1 = OpConstant %f32 1\n"										\
1837	"%c_i32_0 = OpConstant %i32 0\n"										\
1838	"%c_i32_1 = OpConstant %i32 1\n"										\
1839	"%c_i32_2 = OpConstant %i32 2\n"										\
1840	"%c_u32_0 = OpConstant %u32 0\n"										\
1841	"%c_u32_1 = OpConstant %u32 1\n"										\
1842	"%c_u32_2 = OpConstant %u32 2\n"										\
1843	"%c_u32_3 = OpConstant %u32 3\n"										\
1844	"%c_u32_32 = OpConstant %u32 32\n"										\
1845	"%c_u32_4 = OpConstant %u32 4\n"
1846
1847#define SPIRV_ASSEMBLY_ARRAYS												\
1848	"%a1f32 = OpTypeArray %f32 %c_u32_1\n"									\
1849	"%a2f32 = OpTypeArray %f32 %c_u32_2\n"									\
1850	"%a3v4f32 = OpTypeArray %v4f32 %c_u32_3\n"								\
1851	"%a4f32 = OpTypeArray %f32 %c_u32_4\n"									\
1852	"%a32v4f32 = OpTypeArray %v4f32 %c_u32_32\n"							\
1853	"%ip_a3v4f32 = OpTypePointer Input %a3v4f32\n"							\
1854	"%ip_a32v4f32 = OpTypePointer Input %a32v4f32\n"						\
1855	"%op_a2f32 = OpTypePointer Output %a2f32\n"								\
1856	"%op_a3v4f32 = OpTypePointer Output %a3v4f32\n"							\
1857	"%op_a4f32 = OpTypePointer Output %a4f32\n"
1858
1859// Creates vertex-shader assembly by specializing a boilerplate StringTemplate
1860// on fragments, which must (at least) map "testfun" to an OpFunction definition
1861// for %test_code that takes and returns a %v4f32.  Boilerplate IDs are prefixed
1862// with "BP_" to avoid collisions with fragments.
1863//
1864// It corresponds roughly to this GLSL:
1865//;
1866// layout(location = 0) in vec4 position;
1867// layout(location = 1) in vec4 color;
1868// layout(location = 1) out highp vec4 vtxColor;
1869// void main (void) { gl_Position = position; vtxColor = test_func(color); }
1870string makeVertexShaderAssembly(const map<string, string>& fragments)
1871{
1872// \todo [2015-11-23 awoloszyn] Remove OpName once these have stabalized
1873// \todo [2015-11-23 awoloszyn] Remove Smooth decoration when we move to SPIR-V 1.0
1874	static const char vertexShaderBoilerplate[] =
1875		"OpCapability Shader\n"
1876		"OpMemoryModel Logical GLSL450\n"
1877		"OpEntryPoint Vertex %4 \"main\" %BP_Position %BP_vtxColor %BP_color "
1878		"%BP_vtxPosition %BP_vertex_id %BP_instance_id\n"
1879		"${debug:opt}\n"
1880		"OpName %main \"main\"\n"
1881		"OpName %BP_vtxPosition \"vtxPosition\"\n"
1882		"OpName %BP_Position \"position\"\n"
1883		"OpName %BP_vtxColor \"vtxColor\"\n"
1884		"OpName %BP_color \"color\"\n"
1885		"OpName %vertex_id \"gl_VertexID\"\n"
1886		"OpName %instance_id \"gl_InstanceID\"\n"
1887		"OpName %test_code \"testfun(vf4;\"\n"
1888		"OpDecorate %BP_vtxPosition Smooth\n"
1889		"OpDecorate %BP_vtxPosition Location 2\n"
1890		"OpDecorate %BP_Position Location 0\n"
1891		"OpDecorate %BP_vtxColor Smooth\n"
1892		"OpDecorate %BP_vtxColor Location 1\n"
1893		"OpDecorate %BP_color Location 1\n"
1894		"OpDecorate %BP_vertex_id BuiltIn VertexId\n"
1895		"OpDecorate %BP_instance_id BuiltIn InstanceId\n"
1896		SPIRV_ASSEMBLY_TYPES
1897		SPIRV_ASSEMBLY_CONSTANTS
1898		SPIRV_ASSEMBLY_ARRAYS
1899		"%BP_vtxPosition = OpVariable %op_v4f32 Output\n"
1900		"%BP_Position = OpVariable %ip_v4f32 Input\n"
1901		"%BP_vtxColor = OpVariable %op_v4f32 Output\n"
1902		"%BP_color = OpVariable %ip_v4f32 Input\n"
1903		"%BP_vertex_id = OpVariable %ip_i32 Input\n"
1904		"%BP_instance_id = OpVariable %ip_i32 Input\n"
1905		"%main = OpFunction %void None %fun\n"
1906		"%BP_label = OpLabel\n"
1907		"%BP_tmp_position = OpLoad %v4f32 %BP_Position\n"
1908		"OpStore %BP_vtxPosition %BP_tmp_position\n"
1909		"%BP_tmp_color = OpLoad %v4f32 %BP_color\n"
1910		"%BP_clr_transformed = OpFunctionCall %v4f32 %test_code %BP_tmp_color\n"
1911		"OpStore %BP_vtxColor %BP_clr_transformed\n"
1912		"OpReturn\n"
1913		"OpFunctionEnd\n"
1914		"${testfun}\n";
1915	return tcu::StringTemplate(vertexShaderBoilerplate).specialize(fragments);
1916}
1917
1918// Creates tess-control-shader assembly by specializing a boilerplate
1919// StringTemplate on fragments, which must (at least) map "testfun" to an
1920// OpFunction definition for %test_code that takes and returns a %v4f32.
1921// Boilerplate IDs are prefixed with "BP_" to avoid collisions with fragments.
1922//
1923// It roughly corresponds to the following GLSL.
1924//
1925// #version 450
1926// layout(vertices = 3) out;
1927// layout(location = 1) in vec4 in_color[];
1928// layout(location = 2) in vec4 in_position[];
1929// layout(location = 1) out vec4 out_color[];
1930// layout(location = 2) out vec4 out_position[];
1931//
1932// void main() {
1933//   out_color[gl_InvocationID] = testfun(in_color[gl_InvocationID]);
1934//   out_position[gl_InvocationID] = in_position[gl_InvocationID];
1935//   if (gl_InvocationID == 0) {
1936//     gl_TessLevelOuter[0] = 1.0;
1937//     gl_TessLevelOuter[1] = 1.0;
1938//     gl_TessLevelOuter[2] = 1.0;
1939//     gl_TessLevelInner[0] = 1.0;
1940//   }
1941// }
1942string makeTessControlShaderAssembly(const map<string, string>& fragments)
1943{
1944	static const char tessControlShaderBoilerplate[] =
1945		"OpCapability Tessellation\n"
1946		"OpMemoryModel Logical GLSL450\n"
1947		"OpEntryPoint TessellationControl %BP_main \"main\" %BP_out_color %BP_gl_InvocationID %BP_in_color %BP_out_position %BP_in_position %BP_gl_TessLevelOuter %BP_gl_TessLevelInner\n"
1948		"OpExecutionMode %BP_main OutputVertices 3\n"
1949		"${debug:opt}\n"
1950		"OpName %BP_main \"main\"\n"
1951		"OpName %BP_out_color \"out_color\"\n"
1952		"OpName %BP_gl_InvocationID \"gl_InvocationID\"\n"
1953		"OpName %BP_in_color \"in_color\"\n"
1954		"OpName %BP_out_position \"out_position\"\n"
1955		"OpName %BP_in_position \"in_position\"\n"
1956		"OpName %BP_gl_TessLevelOuter \"gl_TessLevelOuter\"\n"
1957		"OpName %BP_gl_TessLevelInner \"gl_TessLevelInner\"\n"
1958		"OpName %test_code \"testfun(vf4;\"\n"
1959		"OpDecorate %BP_out_color Location 1\n"
1960		"OpDecorate %BP_gl_InvocationID BuiltIn InvocationId\n"
1961		"OpDecorate %BP_in_color Location 1\n"
1962		"OpDecorate %BP_out_position Location 2\n"
1963		"OpDecorate %BP_in_position Location 2\n"
1964		"OpDecorate %BP_gl_TessLevelOuter Patch\n"
1965		"OpDecorate %BP_gl_TessLevelOuter BuiltIn TessLevelOuter\n"
1966		"OpDecorate %BP_gl_TessLevelInner Patch\n"
1967		"OpDecorate %BP_gl_TessLevelInner BuiltIn TessLevelInner\n"
1968		SPIRV_ASSEMBLY_TYPES
1969		SPIRV_ASSEMBLY_CONSTANTS
1970		SPIRV_ASSEMBLY_ARRAYS
1971		"%BP_out_color = OpVariable %op_a3v4f32 Output\n"
1972		"%BP_gl_InvocationID = OpVariable %ip_i32 Input\n"
1973		"%BP_in_color = OpVariable %ip_a32v4f32 Input\n"
1974		"%BP_out_position = OpVariable %op_a3v4f32 Output\n"
1975		"%BP_in_position = OpVariable %ip_a32v4f32 Input\n"
1976		"%BP_gl_TessLevelOuter = OpVariable %op_a4f32 Output\n"
1977		"%BP_gl_TessLevelInner = OpVariable %op_a2f32 Output\n"
1978
1979		"%BP_main = OpFunction %void None %fun\n"
1980		"%BP_label = OpLabel\n"
1981
1982		"%BP_invocation_id = OpLoad %i32 %BP_gl_InvocationID\n"
1983
1984		"%BP_in_color_ptr = OpAccessChain %ip_v4f32 %BP_in_color %BP_invocation_id\n"
1985		"%BP_in_position_ptr = OpAccessChain %ip_v4f32 %BP_in_position %BP_invocation_id\n"
1986
1987		"%BP_in_color_val = OpLoad %v4f32 %BP_in_color_ptr\n"
1988		"%BP_in_position_val = OpLoad %v4f32 %BP_in_position_ptr\n"
1989
1990		"%BP_clr_transformed = OpFunctionCall %v4f32 %test_code %BP_in_color_val\n"
1991
1992		"%BP_out_color_ptr = OpAccessChain %op_v4f32 %BP_out_color %BP_invocation_id\n"
1993		"%BP_out_position_ptr = OpAccessChain %op_v4f32 %BP_out_position %BP_invocation_id\n"
1994
1995		"OpStore %BP_out_color_ptr %BP_clr_transformed\n"
1996		"OpStore %BP_out_position_ptr %BP_in_position_val\n"
1997
1998		"%BP_is_first_invocation = OpIEqual %bool %BP_invocation_id %c_i32_0\n"
1999		"OpSelectionMerge %BP_merge_label None\n"
2000		"OpBranchConditional %BP_is_first_invocation %BP_first_invocation %BP_merge_label\n"
2001
2002		"%BP_first_invocation = OpLabel\n"
2003		"%BP_tess_outer_0 = OpAccessChain %op_f32 %BP_gl_TessLevelOuter %c_i32_0\n"
2004		"%BP_tess_outer_1 = OpAccessChain %op_f32 %BP_gl_TessLevelOuter %c_i32_1\n"
2005		"%BP_tess_outer_2 = OpAccessChain %op_f32 %BP_gl_TessLevelOuter %c_i32_2\n"
2006		"%BP_tess_inner = OpAccessChain %op_f32 %BP_gl_TessLevelInner %c_i32_0\n"
2007
2008		"OpStore %BP_tess_outer_0 %c_f32_1\n"
2009		"OpStore %BP_tess_outer_1 %c_f32_1\n"
2010		"OpStore %BP_tess_outer_2 %c_f32_1\n"
2011		"OpStore %BP_tess_inner %c_f32_1\n"
2012
2013		"OpBranch %BP_merge_label\n"
2014		"%BP_merge_label = OpLabel\n"
2015		"OpReturn\n"
2016		"OpFunctionEnd\n"
2017		"${testfun}\n";
2018	return tcu::StringTemplate(tessControlShaderBoilerplate).specialize(fragments);
2019}
2020
2021// Creates tess-evaluation-shader assembly by specializing a boilerplate
2022// StringTemplate on fragments, which must (at least) map "testfun" to an
2023// OpFunction definition for %test_code that takes and returns a %v4f32.
2024// Boilerplate IDs are prefixed with "BP_" to avoid collisions with fragments.
2025//
2026// It roughly corresponds to the following glsl.
2027//
2028// #version 450
2029//
2030// layout(triangles, equal_spacing, ccw) in;
2031// layout(location = 1) in vec4 in_color[];
2032// layout(location = 2) in vec4 in_position[];
2033// layout(location = 1) out vec4 out_color;
2034//
2035// #define interpolate(val)
2036//   vec4(gl_TessCoord.x) * val[0] + vec4(gl_TessCoord.y) * val[1] +
2037//          vec4(gl_TessCoord.z) * val[2]
2038//
2039// void main() {
2040//   gl_Position = vec4(gl_TessCoord.x) * in_position[0] +
2041//                  vec4(gl_TessCoord.y) * in_position[1] +
2042//                  vec4(gl_TessCoord.z) * in_position[2];
2043//   out_color = testfun(interpolate(in_color));
2044// }
2045string makeTessEvalShaderAssembly(const map<string, string>& fragments)
2046{
2047	static const char tessEvalBoilerplate[] =
2048		"OpCapability Tessellation\n"
2049		"OpMemoryModel Logical GLSL450\n"
2050		"OpEntryPoint TessellationEvaluation %BP_main \"main\" %BP_stream %BP_gl_tessCoord %BP_in_position %BP_out_color %BP_in_color \n"
2051		"OpExecutionMode %BP_main InputTriangles\n"
2052		"${debug:opt}\n"
2053		"OpName %BP_main \"main\"\n"
2054		"OpName %BP_per_vertex_out \"gl_PerVertex\"\n"
2055		"OpMemberName %BP_per_vertex_out 0 \"gl_Position\"\n"
2056		"OpMemberName %BP_per_vertex_out 1 \"gl_PointSize\"\n"
2057		"OpMemberName %BP_per_vertex_out 2 \"gl_ClipDistance\"\n"
2058		"OpMemberName %BP_per_vertex_out 3 \"gl_CullDistance\"\n"
2059		"OpName %BP_stream \"\"\n"
2060		"OpName %BP_gl_tessCoord \"gl_TessCoord\"\n"
2061		"OpName %BP_in_position \"in_position\"\n"
2062		"OpName %BP_out_color \"out_color\"\n"
2063		"OpName %BP_in_color \"in_color\"\n"
2064		"OpName %test_code \"testfun(vf4;\"\n"
2065		"OpMemberDecorate %BP_per_vertex_out 0 BuiltIn Position\n"
2066		"OpMemberDecorate %BP_per_vertex_out 1 BuiltIn PointSize\n"
2067		"OpMemberDecorate %BP_per_vertex_out 2 BuiltIn ClipDistance\n"
2068		"OpMemberDecorate %BP_per_vertex_out 3 BuiltIn CullDistance\n"
2069		"OpDecorate %BP_per_vertex_out Block\n"
2070		"OpDecorate %BP_gl_tessCoord BuiltIn TessCoord\n"
2071		"OpDecorate %BP_in_position Location 2\n"
2072		"OpDecorate %BP_out_color Location 1\n"
2073		"OpDecorate %BP_in_color Location 1\n"
2074		SPIRV_ASSEMBLY_TYPES
2075		SPIRV_ASSEMBLY_CONSTANTS
2076		SPIRV_ASSEMBLY_ARRAYS
2077		"%BP_per_vertex_out = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
2078		"%BP_op_per_vertex_out = OpTypePointer Output %BP_per_vertex_out\n"
2079		"%BP_stream = OpVariable %BP_op_per_vertex_out Output\n"
2080		"%BP_gl_tessCoord = OpVariable %ip_v3f32 Input\n"
2081		"%BP_in_position = OpVariable %ip_a32v4f32 Input\n"
2082		"%BP_out_color = OpVariable %op_v4f32 Output\n"
2083		"%BP_in_color = OpVariable %ip_a32v4f32 Input\n"
2084		"%BP_main = OpFunction %void None %fun\n"
2085		"%BP_label = OpLabel\n"
2086		"%BP_tc_0_ptr = OpAccessChain %ip_f32 %BP_gl_tessCoord %c_u32_0\n"
2087		"%BP_tc_1_ptr = OpAccessChain %ip_f32 %BP_gl_tessCoord %c_u32_1\n"
2088		"%BP_tc_2_ptr = OpAccessChain %ip_f32 %BP_gl_tessCoord %c_u32_2\n"
2089
2090		"%BP_tc_0 = OpLoad %f32 %BP_tc_0_ptr\n"
2091		"%BP_tc_1 = OpLoad %f32 %BP_tc_1_ptr\n"
2092		"%BP_tc_2 = OpLoad %f32 %BP_tc_2_ptr\n"
2093
2094		"%BP_in_pos_0_ptr = OpAccessChain %ip_v4f32 %BP_in_position %c_i32_0\n"
2095		"%BP_in_pos_1_ptr = OpAccessChain %ip_v4f32 %BP_in_position %c_i32_1\n"
2096		"%BP_in_pos_2_ptr = OpAccessChain %ip_v4f32 %BP_in_position %c_i32_2\n"
2097
2098		"%BP_in_pos_0 = OpLoad %v4f32 %BP_in_pos_0_ptr\n"
2099		"%BP_in_pos_1 = OpLoad %v4f32 %BP_in_pos_1_ptr\n"
2100		"%BP_in_pos_2 = OpLoad %v4f32 %BP_in_pos_2_ptr\n"
2101
2102		"%BP_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %BP_tc_0 %BP_in_pos_0\n"
2103		"%BP_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %BP_tc_1 %BP_in_pos_1\n"
2104		"%BP_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %BP_tc_2 %BP_in_pos_2\n"
2105
2106		"%BP_out_pos_ptr = OpAccessChain %op_v4f32 %BP_stream %c_i32_0\n"
2107
2108		"%BP_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %BP_in_pos_0_weighted %BP_in_pos_1_weighted\n"
2109		"%BP_computed_out = OpFAdd %v4f32 %BP_in_pos_0_plus_pos_1 %BP_in_pos_2_weighted\n"
2110		"OpStore %BP_out_pos_ptr %BP_computed_out\n"
2111
2112		"%BP_in_clr_0_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_0\n"
2113		"%BP_in_clr_1_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_1\n"
2114		"%BP_in_clr_2_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_2\n"
2115
2116		"%BP_in_clr_0 = OpLoad %v4f32 %BP_in_clr_0_ptr\n"
2117		"%BP_in_clr_1 = OpLoad %v4f32 %BP_in_clr_1_ptr\n"
2118		"%BP_in_clr_2 = OpLoad %v4f32 %BP_in_clr_2_ptr\n"
2119
2120		"%BP_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %BP_tc_0 %BP_in_clr_0\n"
2121		"%BP_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %BP_tc_1 %BP_in_clr_1\n"
2122		"%BP_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %BP_tc_2 %BP_in_clr_2\n"
2123
2124		"%BP_in_clr_0_plus_col_1 = OpFAdd %v4f32 %BP_in_clr_0_weighted %BP_in_clr_1_weighted\n"
2125		"%BP_computed_clr = OpFAdd %v4f32 %BP_in_clr_0_plus_col_1 %BP_in_clr_2_weighted\n"
2126		"%BP_clr_transformed = OpFunctionCall %v4f32 %test_code %BP_computed_clr\n"
2127
2128		"OpStore %BP_out_color %BP_clr_transformed\n"
2129		"OpReturn\n"
2130		"OpFunctionEnd\n"
2131		"${testfun}\n";
2132	return tcu::StringTemplate(tessEvalBoilerplate).specialize(fragments);
2133}
2134
2135// Creates geometry-shader assembly by specializing a boilerplate StringTemplate
2136// on fragments, which must (at least) map "testfun" to an OpFunction definition
2137// for %test_code that takes and returns a %v4f32.  Boilerplate IDs are prefixed
2138// with "BP_" to avoid collisions with fragments.
2139//
2140// Derived from this GLSL:
2141//
2142// #version 450
2143// layout(triangles) in;
2144// layout(triangle_strip, max_vertices = 3) out;
2145//
2146// layout(location = 1) in vec4 in_color[];
2147// layout(location = 1) out vec4 out_color;
2148//
2149// void main() {
2150// 	 gl_Position = gl_in[0].gl_Position;
2151// 	 out_color = test_fun(in_color[0]);
2152// 	 EmitVertex();
2153// 	 gl_Position = gl_in[1].gl_Position;
2154// 	 out_color = test_fun(in_color[1]);
2155// 	 EmitVertex();
2156// 	 gl_Position = gl_in[2].gl_Position;
2157// 	 out_color = test_fun(in_color[2]);
2158// 	 EmitVertex();
2159// 	 EndPrimitive();
2160// }
2161string makeGeometryShaderAssembly(const map<string, string>& fragments)
2162{
2163	static const char geometryShaderBoilerplate[] =
2164		"OpCapability Geometry\n"
2165		"OpMemoryModel Logical GLSL450\n"
2166		"OpEntryPoint Geometry %BP_main \"main\" %BP_out_gl_position %BP_gl_in %BP_out_color %BP_in_color\n"
2167		"OpExecutionMode %BP_main InputTriangles\n"
2168		"OpExecutionMode %BP_main Invocations 0\n"
2169		"OpExecutionMode %BP_main OutputTriangleStrip\n"
2170		"OpExecutionMode %BP_main OutputVertices 3\n"
2171		"${debug:opt}\n"
2172		"OpName %BP_main \"main\"\n"
2173		"OpName %BP_per_vertex_in \"gl_PerVertex\"\n"
2174		"OpMemberName %BP_per_vertex_in 0 \"gl_Position\"\n"
2175		"OpMemberName %BP_per_vertex_in 1 \"gl_PointSize\"\n"
2176		"OpMemberName %BP_per_vertex_in 2 \"gl_ClipDistance\"\n"
2177		"OpMemberName %BP_per_vertex_in 3 \"gl_CullDistance\"\n"
2178		"OpName %BP_gl_in \"gl_in\"\n"
2179		"OpName %BP_out_color \"out_color\"\n"
2180		"OpName %BP_in_color \"in_color\"\n"
2181		"OpName %test_code \"testfun(vf4;\"\n"
2182		"OpDecorate %BP_out_gl_position BuiltIn Position\n"
2183		"OpMemberDecorate %BP_per_vertex_in 0 BuiltIn Position\n"
2184		"OpMemberDecorate %BP_per_vertex_in 1 BuiltIn PointSize\n"
2185		"OpMemberDecorate %BP_per_vertex_in 2 BuiltIn ClipDistance\n"
2186		"OpMemberDecorate %BP_per_vertex_in 3 BuiltIn CullDistance\n"
2187		"OpDecorate %BP_per_vertex_in Block\n"
2188		"OpDecorate %BP_out_color Location 1\n"
2189		"OpDecorate %BP_out_color Stream 0\n"
2190		"OpDecorate %BP_in_color Location 1\n"
2191		SPIRV_ASSEMBLY_TYPES
2192		SPIRV_ASSEMBLY_CONSTANTS
2193		SPIRV_ASSEMBLY_ARRAYS
2194		"%BP_per_vertex_in = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
2195		"%BP_a3_per_vertex_in = OpTypeArray %BP_per_vertex_in %c_u32_3\n"
2196		"%BP_ip_a3_per_vertex_in = OpTypePointer Input %BP_a3_per_vertex_in\n"
2197
2198		"%BP_gl_in = OpVariable %BP_ip_a3_per_vertex_in Input\n"
2199		"%BP_out_color = OpVariable %op_v4f32 Output\n"
2200		"%BP_in_color = OpVariable %ip_a3v4f32 Input\n"
2201		"%BP_out_gl_position = OpVariable %op_v4f32 Output\n"
2202
2203		"%BP_main = OpFunction %void None %fun\n"
2204		"%BP_label = OpLabel\n"
2205		"%BP_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_0 %c_i32_0\n"
2206		"%BP_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_1 %c_i32_0\n"
2207		"%BP_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_2 %c_i32_0\n"
2208
2209		"%BP_in_position_0 = OpLoad %v4f32 %BP_gl_in_0_gl_position\n"
2210		"%BP_in_position_1 = OpLoad %v4f32 %BP_gl_in_1_gl_position\n"
2211		"%BP_in_position_2 = OpLoad %v4f32 %BP_gl_in_2_gl_position \n"
2212
2213		"%BP_in_color_0_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_0\n"
2214		"%BP_in_color_1_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_1\n"
2215		"%BP_in_color_2_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_2\n"
2216
2217		"%BP_in_color_0 = OpLoad %v4f32 %BP_in_color_0_ptr\n"
2218		"%BP_in_color_1 = OpLoad %v4f32 %BP_in_color_1_ptr\n"
2219		"%BP_in_color_2 = OpLoad %v4f32 %BP_in_color_2_ptr\n"
2220
2221		"%BP_transformed_in_color_0 = OpFunctionCall %v4f32 %test_code %BP_in_color_0\n"
2222		"%BP_transformed_in_color_1 = OpFunctionCall %v4f32 %test_code %BP_in_color_1\n"
2223		"%BP_transformed_in_color_2 = OpFunctionCall %v4f32 %test_code %BP_in_color_2\n"
2224		"OpStore %BP_out_gl_position %BP_in_position_0\n"
2225		"OpStore %BP_out_color %BP_transformed_in_color_0\n"
2226		"OpEmitVertex\n"
2227
2228		"OpStore %BP_out_gl_position %BP_in_position_1\n"
2229		"OpStore %BP_out_color %BP_transformed_in_color_1\n"
2230		"OpEmitVertex\n"
2231
2232		"OpStore %BP_out_gl_position %BP_in_position_2\n"
2233		"OpStore %BP_out_color %BP_transformed_in_color_2\n"
2234		"OpEmitVertex\n"
2235
2236		"OpEndPrimitive\n"
2237		"OpReturn\n"
2238		"OpFunctionEnd\n"
2239		"${testfun}\n";
2240	return tcu::StringTemplate(geometryShaderBoilerplate).specialize(fragments);
2241}
2242
2243// Creates fragment-shader assembly by specializing a boilerplate StringTemplate
2244// on fragments, which must (at least) map "testfun" to an OpFunction definition
2245// for %test_code that takes and returns a %v4f32.  Boilerplate IDs are prefixed
2246// with "BP_" to avoid collisions with fragments.
2247//
2248// Derived from this GLSL:
2249//
2250// layout(location = 0) in highp vec4 vtxColor;
2251// layout(location = 1) out highp vec4 fragColor;
2252// highp vec4 testfun(highp vec4 x) { return x; }
2253// void main(void) { fragColor = testfun(vtxColor); }
2254//
2255// with modifications including passing vtxColor by value and ripping out
2256// testfun() definition.
2257string makeFragmentShaderAssembly(const map<string, string>& fragments)
2258{
2259	static const char fragmentShaderBoilerplate[] =
2260		"OpCapability Shader\n"
2261		"OpMemoryModel Logical GLSL450\n"
2262		"OpEntryPoint Fragment %BP_main \"main\" %BP_vtxColor %BP_fragColor\n"
2263		"OpExecutionMode %BP_main OriginUpperLeft\n"
2264		"${debug:opt}\n"
2265		"OpName %BP_main \"main\"\n"
2266		"OpName %BP_fragColor \"fragColor\"\n"
2267		"OpName %BP_vtxColor \"vtxColor\"\n"
2268		"OpName %test_code \"testfun(vf4;\"\n"
2269		"OpDecorate %BP_fragColor Location 0\n"
2270		"OpDecorate %BP_vtxColor Smooth\n"
2271		"OpDecorate %BP_vtxColor Location 1\n"
2272		SPIRV_ASSEMBLY_TYPES
2273		SPIRV_ASSEMBLY_CONSTANTS
2274		SPIRV_ASSEMBLY_ARRAYS
2275		"%BP_fragColor = OpVariable %op_v4f32 Output\n"
2276		"%BP_vtxColor = OpVariable %ip_v4f32 Input\n"
2277		"%BP_main = OpFunction %void None %fun\n"
2278		"%BP_label_main = OpLabel\n"
2279		"%BP_tmp1 = OpLoad %v4f32 %BP_vtxColor\n"
2280		"%BP_tmp2 = OpFunctionCall %v4f32 %test_code %BP_tmp1\n"
2281		"OpStore %BP_fragColor %BP_tmp2\n"
2282		"OpReturn\n"
2283		"OpFunctionEnd\n"
2284		"${testfun}\n";
2285	return tcu::StringTemplate(fragmentShaderBoilerplate).specialize(fragments);
2286}
2287
2288// Creates fragments that specialize into a simple pass-through shader (of any kind).
2289map<string, string> passthruFragments(void)
2290{
2291	map<string, string> fragments;
2292	fragments["testfun"] =
2293		// A %test_code function that returns its argument unchanged.
2294		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
2295		"%param1 = OpFunctionParameter %v4f32\n"
2296		"%label_testfun = OpLabel\n"
2297		"OpReturnValue %param1\n"
2298		"OpFunctionEnd\n";
2299	return fragments;
2300}
2301
2302// Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
2303// Vertex shader gets custom code from context, the rest are pass-through.
2304void addShaderCodeCustomVertex(vk::SourceCollections& dst, InstanceContext context) {
2305	map<string, string> passthru = passthruFragments();
2306	dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(context.testCodeFragments);
2307	dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(passthru);
2308	dst.spirvAsmSources.add("tesse") << makeTessEvalShaderAssembly(passthru);
2309	dst.spirvAsmSources.add("geom") << makeGeometryShaderAssembly(passthru);
2310	dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(passthru);
2311}
2312
2313// Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
2314// Tessellation control shader gets custom code from context, the rest are
2315// pass-through.
2316void addShaderCodeCustomTessControl(vk::SourceCollections& dst, InstanceContext context) {
2317	map<string, string> passthru = passthruFragments();
2318	dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
2319	dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(context.testCodeFragments);
2320	dst.spirvAsmSources.add("tesse") << makeTessEvalShaderAssembly(passthru);
2321	dst.spirvAsmSources.add("geom") << makeGeometryShaderAssembly(passthru);
2322	dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(passthru);
2323}
2324
2325// Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
2326// Tessellation evaluation shader gets custom code from context, the rest are
2327// pass-through.
2328void addShaderCodeCustomTessEval(vk::SourceCollections& dst, InstanceContext context) {
2329	map<string, string> passthru = passthruFragments();
2330	dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
2331	dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(passthru);
2332	dst.spirvAsmSources.add("tesse") << makeTessEvalShaderAssembly(context.testCodeFragments);
2333	dst.spirvAsmSources.add("geom") << makeGeometryShaderAssembly(passthru);
2334	dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(passthru);
2335}
2336
2337// Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
2338// Geometry shader gets custom code from context, the rest are pass-through.
2339void addShaderCodeCustomGeometry(vk::SourceCollections& dst, InstanceContext context) {
2340	map<string, string> passthru = passthruFragments();
2341	dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
2342	dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(passthru);
2343	dst.spirvAsmSources.add("tesse") << makeTessEvalShaderAssembly(passthru);
2344	dst.spirvAsmSources.add("geom") << makeGeometryShaderAssembly(context.testCodeFragments);
2345	dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(passthru);
2346}
2347
2348// Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
2349// Fragment shader gets custom code from context, the rest are pass-through.
2350void addShaderCodeCustomFragment(vk::SourceCollections& dst, InstanceContext context) {
2351	map<string, string> passthru = passthruFragments();
2352	dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
2353	dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(passthru);
2354	dst.spirvAsmSources.add("tesse") << makeTessEvalShaderAssembly(passthru);
2355	dst.spirvAsmSources.add("geom") << makeGeometryShaderAssembly(passthru);
2356	dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(context.testCodeFragments);
2357}
2358
2359// Sets up and runs a Vulkan pipeline, then spot-checks the resulting image.
2360// Feeds the pipeline a set of colored triangles, which then must occur in the
2361// rendered image.  The surface is cleared before executing the pipeline, so
2362// whatever the shaders draw can be directly spot-checked.
2363TestStatus runAndVerifyDefaultPipeline (Context& context, InstanceContext instance)
2364{
2365	const VkDevice							vkDevice				= context.getDevice();
2366	const DeviceInterface&					vk						= context.getDeviceInterface();
2367	const VkQueue							queue					= context.getUniversalQueue();
2368	const deUint32							queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
2369	const tcu::IVec2						renderSize				(256, 256);
2370	vector<ModuleHandleSp>					modules;
2371	map<VkShaderStage, VkShaderSp>			shaders;
2372	const int								testSpecificSeed		= 31354125;
2373	const int								seed					= context.getTestContext().getCommandLine().getBaseSeed() ^ testSpecificSeed;
2374	de::Random(seed).shuffle(instance.inputColors, instance.inputColors+4);
2375	de::Random(seed).shuffle(instance.outputColors, instance.outputColors+4);
2376	const Vec4								vertexData[]			=
2377	{
2378		// Upper left corner:
2379		Vec4(-1.0f, -1.0f, 0.0f, 1.0f), instance.inputColors[0].toVec(),
2380		Vec4(-0.5f, -1.0f, 0.0f, 1.0f), instance.inputColors[0].toVec(),
2381		Vec4(-1.0f, -0.5f, 0.0f, 1.0f), instance.inputColors[0].toVec(),
2382
2383		// Upper right corner:
2384		Vec4(+0.5f, -1.0f, 0.0f, 1.0f), instance.inputColors[1].toVec(),
2385		Vec4(+1.0f, -1.0f, 0.0f, 1.0f), instance.inputColors[1].toVec(),
2386		Vec4(+1.0f, -0.5f, 0.0f, 1.0f), instance.inputColors[1].toVec(),
2387
2388		// Lower left corner:
2389		Vec4(-1.0f, +0.5f, 0.0f, 1.0f), instance.inputColors[2].toVec(),
2390		Vec4(-0.5f, +1.0f, 0.0f, 1.0f), instance.inputColors[2].toVec(),
2391		Vec4(-1.0f, +1.0f, 0.0f, 1.0f), instance.inputColors[2].toVec(),
2392
2393		// Lower right corner:
2394		Vec4(+1.0f, +0.5f, 0.0f, 1.0f), instance.inputColors[3].toVec(),
2395		Vec4(+1.0f, +1.0f, 0.0f, 1.0f), instance.inputColors[3].toVec(),
2396		Vec4(+0.5f, +1.0f, 0.0f, 1.0f), instance.inputColors[3].toVec()
2397	};
2398	const size_t							singleVertexDataSize	= 2 * sizeof(Vec4);
2399	const size_t							vertexCount				= sizeof(vertexData) / singleVertexDataSize;
2400
2401	const VkBufferCreateInfo				vertexBufferParams		=
2402	{
2403		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	//	VkStructureType		sType;
2404		DE_NULL,								//	const void*			pNext;
2405		(VkDeviceSize)sizeof(vertexData),		//	VkDeviceSize		size;
2406		VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,		//	VkBufferUsageFlags	usage;
2407		0u,										//	VkBufferCreateFlags	flags;
2408		VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode		sharingMode;
2409		1u,										//	deUint32			queueFamilyCount;
2410		&queueFamilyIndex,						//	const deUint32*		pQueueFamilyIndices;
2411	};
2412	const Unique<VkBuffer>					vertexBuffer			(createBuffer(vk, vkDevice, &vertexBufferParams));
2413	const UniquePtr<Allocation>				vertexBufferMemory		(context.getDefaultAllocator().allocate(getBufferMemoryRequirements(vk, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible));
2414
2415	VK_CHECK(vk.bindBufferMemory(vkDevice, *vertexBuffer, vertexBufferMemory->getMemory(), vertexBufferMemory->getOffset()));
2416
2417	const VkDeviceSize						imageSizeBytes			= (VkDeviceSize)(sizeof(deUint32)*renderSize.x()*renderSize.y());
2418	const VkBufferCreateInfo				readImageBufferParams	=
2419	{
2420		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		//	VkStructureType		sType;
2421		DE_NULL,									//	const void*			pNext;
2422		imageSizeBytes,								//	VkDeviceSize		size;
2423		VK_BUFFER_USAGE_TRANSFER_DESTINATION_BIT,	//	VkBufferUsageFlags	usage;
2424		0u,											//	VkBufferCreateFlags	flags;
2425		VK_SHARING_MODE_EXCLUSIVE,					//	VkSharingMode		sharingMode;
2426		1u,											//	deUint32			queueFamilyCount;
2427		&queueFamilyIndex,							//	const deUint32*		pQueueFamilyIndices;
2428	};
2429	const Unique<VkBuffer>					readImageBuffer			(createBuffer(vk, vkDevice, &readImageBufferParams));
2430	const UniquePtr<Allocation>				readImageBufferMemory	(context.getDefaultAllocator().allocate(getBufferMemoryRequirements(vk, vkDevice, *readImageBuffer), MemoryRequirement::HostVisible));
2431
2432	VK_CHECK(vk.bindBufferMemory(vkDevice, *readImageBuffer, readImageBufferMemory->getMemory(), readImageBufferMemory->getOffset()));
2433
2434	const VkImageCreateInfo					imageParams				=
2435	{
2436		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,									//	VkStructureType		sType;
2437		DE_NULL,																//	const void*			pNext;
2438		VK_IMAGE_TYPE_2D,														//	VkImageType			imageType;
2439		VK_FORMAT_R8G8B8A8_UNORM,												//	VkFormat			format;
2440		{ renderSize.x(), renderSize.y(), 1 },									//	VkExtent3D			extent;
2441		1u,																		//	deUint32			mipLevels;
2442		1u,																		//	deUint32			arraySize;
2443		1u,																		//	deUint32			samples;
2444		VK_IMAGE_TILING_OPTIMAL,												//	VkImageTiling		tiling;
2445		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT,	//	VkImageUsageFlags	usage;
2446		0u,																		//	VkImageCreateFlags	flags;
2447		VK_SHARING_MODE_EXCLUSIVE,												//	VkSharingMode		sharingMode;
2448		1u,																		//	deUint32			queueFamilyCount;
2449		&queueFamilyIndex,														//	const deUint32*		pQueueFamilyIndices;
2450		VK_IMAGE_LAYOUT_UNDEFINED,												//	VkImageLayout		initialLayout;
2451	};
2452
2453	const Unique<VkImage>					image					(createImage(vk, vkDevice, &imageParams));
2454	const UniquePtr<Allocation>				imageMemory				(context.getDefaultAllocator().allocate(getImageMemoryRequirements(vk, vkDevice, *image), MemoryRequirement::Any));
2455
2456	VK_CHECK(vk.bindImageMemory(vkDevice, *image, imageMemory->getMemory(), imageMemory->getOffset()));
2457
2458	const VkAttachmentDescription			colorAttDesc			=
2459	{
2460		VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION,		//	VkStructureType					sType;
2461		DE_NULL,										//	const void*						pNext;
2462		VK_FORMAT_R8G8B8A8_UNORM,						//	VkFormat						format;
2463		1u,												//	deUint32						samples;
2464		VK_ATTACHMENT_LOAD_OP_CLEAR,					//	VkAttachmentLoadOp				loadOp;
2465		VK_ATTACHMENT_STORE_OP_STORE,					//	VkAttachmentStoreOp				storeOp;
2466		VK_ATTACHMENT_LOAD_OP_DONT_CARE,				//	VkAttachmentLoadOp				stencilLoadOp;
2467		VK_ATTACHMENT_STORE_OP_DONT_CARE,				//	VkAttachmentStoreOp				stencilStoreOp;
2468		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,		//	VkImageLayout					initialLayout;
2469		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,		//	VkImageLayout					finalLayout;
2470		0u,												//	VkAttachmentDescriptionFlags	flags;
2471	};
2472	const VkAttachmentReference				colorAttRef				=
2473	{
2474		0u,												//	deUint32		attachment;
2475		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,		//	VkImageLayout	layout;
2476	};
2477	const VkSubpassDescription				subpassDesc				=
2478	{
2479		VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION,			//	VkStructureType					sType;
2480		DE_NULL,										//	const void*						pNext;
2481		VK_PIPELINE_BIND_POINT_GRAPHICS,				//	VkPipelineBindPoint				pipelineBindPoint;
2482		0u,												//	VkSubpassDescriptionFlags		flags;
2483		0u,												//	deUint32						inputCount;
2484		DE_NULL,										//	const VkAttachmentReference*	pInputAttachments;
2485		1u,												//	deUint32						colorCount;
2486		&colorAttRef,									//	const VkAttachmentReference*	pColorAttachments;
2487		DE_NULL,										//	const VkAttachmentReference*	pResolveAttachments;
2488		{ VK_NO_ATTACHMENT, VK_IMAGE_LAYOUT_GENERAL },	//	VkAttachmentReference			depthStencilAttachment;
2489		0u,												//	deUint32						preserveCount;
2490		DE_NULL,										//	const VkAttachmentReference*	pPreserveAttachments;
2491
2492	};
2493	const VkRenderPassCreateInfo			renderPassParams		=
2494	{
2495		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,		//	VkStructureType					sType;
2496		DE_NULL,										//	const void*						pNext;
2497		1u,												//	deUint32						attachmentCount;
2498		&colorAttDesc,									//	const VkAttachmentDescription*	pAttachments;
2499		1u,												//	deUint32						subpassCount;
2500		&subpassDesc,									//	const VkSubpassDescription*		pSubpasses;
2501		0u,												//	deUint32						dependencyCount;
2502		DE_NULL,										//	const VkSubpassDependency*		pDependencies;
2503	};
2504	const Unique<VkRenderPass>				renderPass				(createRenderPass(vk, vkDevice, &renderPassParams));
2505
2506	const VkImageViewCreateInfo				colorAttViewParams		=
2507	{
2508		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,		//	VkStructureType				sType;
2509		DE_NULL,										//	const void*					pNext;
2510		*image,											//	VkImage						image;
2511		VK_IMAGE_VIEW_TYPE_2D,							//	VkImageViewType				viewType;
2512		VK_FORMAT_R8G8B8A8_UNORM,						//	VkFormat					format;
2513		{
2514			VK_CHANNEL_SWIZZLE_R,
2515			VK_CHANNEL_SWIZZLE_G,
2516			VK_CHANNEL_SWIZZLE_B,
2517			VK_CHANNEL_SWIZZLE_A
2518		},												//	VkChannelMapping			channels;
2519		{
2520			VK_IMAGE_ASPECT_COLOR_BIT,						//	VkImageAspectFlags	aspectMask;
2521			0u,												//	deUint32			baseMipLevel;
2522			1u,												//	deUint32			mipLevels;
2523			0u,												//	deUint32			baseArrayLayer;
2524			1u,												//	deUint32			arraySize;
2525		},												//	VkImageSubresourceRange		subresourceRange;
2526		0u,												//	VkImageViewCreateFlags		flags;
2527	};
2528	const Unique<VkImageView>				colorAttView			(createImageView(vk, vkDevice, &colorAttViewParams));
2529
2530	createShaders(vk, vkDevice, instance, context, modules, shaders);
2531
2532	// Pipeline layout
2533	const VkPipelineLayoutCreateInfo		pipelineLayoutParams	=
2534	{
2535		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,			//	VkStructureType					sType;
2536		DE_NULL,												//	const void*						pNext;
2537		0u,														//	deUint32						descriptorSetCount;
2538		DE_NULL,												//	const VkDescriptorSetLayout*	pSetLayouts;
2539		0u,														//	deUint32						pushConstantRangeCount;
2540		DE_NULL,												//	const VkPushConstantRange*		pPushConstantRanges;
2541	};
2542	const Unique<VkPipelineLayout>			pipelineLayout			(createPipelineLayout(vk, vkDevice, &pipelineLayoutParams));
2543
2544	// Pipeline
2545	const VkSpecializationInfo				emptyShaderSpecParams	=
2546	{
2547		0u,														//	deUint32						mapEntryCount;
2548		DE_NULL,												//	const VkSpecializationMapEntry*	pMap;
2549		0,														//	const deUintptr					dataSize;
2550		DE_NULL,												//	const void*						pData;
2551	};
2552	vector<VkPipelineShaderStageCreateInfo> shaderStageParams;
2553	for(map<VkShaderStage, VkShaderSp>::const_iterator stage = shaders.begin(); stage != shaders.end(); ++stage) {
2554		VkPipelineShaderStageCreateInfo info = {
2555			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	//	VkStructureType				sType;
2556			DE_NULL,												//	const void*					pNext;
2557			stage->first,											//	VkShaderStage				stage;
2558			**stage->second,										//	VkShader					shader;
2559			&emptyShaderSpecParams,									//	const VkSpecializationInfo*	pSpecializationInfo;
2560		};
2561		shaderStageParams.push_back(info);
2562	}
2563	const VkPipelineDepthStencilStateCreateInfo	depthStencilParams		=
2564	{
2565		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	//	VkStructureType		sType;
2566		DE_NULL,													//	const void*			pNext;
2567		DE_FALSE,													//	deUint32			depthTestEnable;
2568		DE_FALSE,													//	deUint32			depthWriteEnable;
2569		VK_COMPARE_OP_ALWAYS,										//	VkCompareOp			depthCompareOp;
2570		DE_FALSE,													//	deUint32			depthBoundsTestEnable;
2571		DE_FALSE,													//	deUint32			stencilTestEnable;
2572		{
2573			VK_STENCIL_OP_KEEP,											//	VkStencilOp	stencilFailOp;
2574			VK_STENCIL_OP_KEEP,											//	VkStencilOp	stencilPassOp;
2575			VK_STENCIL_OP_KEEP,											//	VkStencilOp	stencilDepthFailOp;
2576			VK_COMPARE_OP_ALWAYS,										//	VkCompareOp	stencilCompareOp;
2577			0u,															//	deUint32	stencilCompareMask;
2578			0u,															//	deUint32	stencilWriteMask;
2579			0u,															//	deUint32	stencilReference;
2580		},															//	VkStencilOpState	front;
2581		{
2582			VK_STENCIL_OP_KEEP,											//	VkStencilOp	stencilFailOp;
2583			VK_STENCIL_OP_KEEP,											//	VkStencilOp	stencilPassOp;
2584			VK_STENCIL_OP_KEEP,											//	VkStencilOp	stencilDepthFailOp;
2585			VK_COMPARE_OP_ALWAYS,										//	VkCompareOp	stencilCompareOp;
2586			0u,															//	deUint32	stencilCompareMask;
2587			0u,															//	deUint32	stencilWriteMask;
2588			0u,															//	deUint32	stencilReference;
2589		},															//	VkStencilOpState	back;
2590		-1.0f,														//	float				minDepthBounds;
2591		+1.0f,														//	float				maxDepthBounds;
2592	};
2593	const VkViewport						viewport0				=
2594	{
2595		0.0f,														//	float	originX;
2596		0.0f,														//	float	originY;
2597		(float)renderSize.x(),										//	float	width;
2598		(float)renderSize.y(),										//	float	height;
2599		0.0f,														//	float	minDepth;
2600		1.0f,														//	float	maxDepth;
2601	};
2602	const VkRect2D							scissor0				=
2603	{
2604		{
2605			0u,															//	deInt32	x;
2606			0u,															//	deInt32	y;
2607		},															//	VkOffset2D	offset;
2608		{
2609			renderSize.x(),												//	deInt32	width;
2610			renderSize.y(),												//	deInt32	height;
2611		},															//	VkExtent2D	extent;
2612	};
2613	const VkPipelineViewportStateCreateInfo		viewportParams			=
2614	{
2615		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,		//	VkStructureType		sType;
2616		DE_NULL,													//	const void*			pNext;
2617		1u,															//	deUint32			viewportCount;
2618		&viewport0,
2619		1u,
2620		&scissor0
2621	};
2622	const VkSampleMask							sampleMask				= ~0u;
2623	const VkPipelineMultisampleStateCreateInfo	multisampleParams		=
2624	{
2625		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	//	VkStructureType	sType;
2626		DE_NULL,													//	const void*		pNext;
2627		1u,															//	deUint32		rasterSamples;
2628		DE_FALSE,													//	deUint32		sampleShadingEnable;
2629		0.0f,														//	float			minSampleShading;
2630		&sampleMask,												//	VkSampleMask	sampleMask;
2631	};
2632	const VkPipelineRasterStateCreateInfo		rasterParams			=
2633	{
2634		VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO,	//	VkStructureType	sType;
2635		DE_NULL,												//	const void*		pNext;
2636		DE_TRUE,												//	deUint32		depthClipEnable;
2637		DE_FALSE,												//	deUint32		rasterizerDiscardEnable;
2638		VK_FILL_MODE_SOLID,										//	VkFillMode		fillMode;
2639		VK_CULL_MODE_NONE,										//	VkCullMode		cullMode;
2640		VK_FRONT_FACE_CCW,										//	VkFrontFace		frontFace;
2641		VK_FALSE,												//	VkBool32		depthBiasEnable;
2642		0.0f,													//	float			depthBias;
2643		0.0f,													//	float			depthBiasClamp;
2644		0.0f,													//	float			slopeScaledDepthBias;
2645		1.0f,													//	float			lineWidth;
2646	};
2647	const VkPipelineInputAssemblyStateCreateInfo	inputAssemblyParams	=
2648	{
2649		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	//	VkStructureType		sType;
2650		DE_NULL,														//	const void*			pNext;
2651		VK_PRIMITIVE_TOPOLOGY_PATCH,									//	VkPrimitiveTopology	topology;
2652		DE_FALSE,														//	deUint32			primitiveRestartEnable;
2653	};
2654	const VkVertexInputBindingDescription		vertexBinding0 =
2655	{
2656		0u,									// deUint32					binding;
2657		deUint32(singleVertexDataSize),		// deUint32					strideInBytes;
2658		VK_VERTEX_INPUT_STEP_RATE_VERTEX	// VkVertexInputStepRate	stepRate;
2659	};
2660	const VkVertexInputAttributeDescription		vertexAttrib0[2] =
2661	{
2662		{
2663			0u,									// deUint32	location;
2664			0u,									// deUint32	binding;
2665			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat	format;
2666			0u									// deUint32	offsetInBytes;
2667		},
2668		{
2669			1u,									// deUint32	location;
2670			0u,									// deUint32	binding;
2671			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat	format;
2672			sizeof(Vec4),						// deUint32	offsetInBytes;
2673		}
2674	};
2675
2676	const VkPipelineVertexInputStateCreateInfo	vertexInputStateParams	=
2677	{
2678		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	VkStructureType								sType;
2679		DE_NULL,													//	const void*									pNext;
2680		1u,															//	deUint32									bindingCount;
2681		&vertexBinding0,											//	const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
2682		2u,															//	deUint32									attributeCount;
2683		vertexAttrib0,												//	const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
2684	};
2685	const VkPipelineColorBlendAttachmentState	attBlendParams			=
2686	{
2687		DE_FALSE,																//	deUint32		blendEnable;
2688		VK_BLEND_ONE,															//	VkBlend			srcBlendColor;
2689		VK_BLEND_ZERO,															//	VkBlend			destBlendColor;
2690		VK_BLEND_OP_ADD,														//	VkBlendOp		blendOpColor;
2691		VK_BLEND_ONE,															//	VkBlend			srcBlendAlpha;
2692		VK_BLEND_ZERO,															//	VkBlend			destBlendAlpha;
2693		VK_BLEND_OP_ADD,														//	VkBlendOp		blendOpAlpha;
2694		VK_CHANNEL_R_BIT|VK_CHANNEL_G_BIT|VK_CHANNEL_B_BIT|VK_CHANNEL_A_BIT,	//	VkChannelFlags	channelWriteMask;
2695	};
2696	const VkPipelineColorBlendStateCreateInfo	blendParams				=
2697	{
2698		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	//	VkStructureType								sType;
2699		DE_NULL,													//	const void*									pNext;
2700		DE_FALSE,													//	VkBool32									alphaToCoverageEnable;
2701		DE_FALSE,													//	VkBool32									alphaToOneEnable;
2702		DE_FALSE,													//	VkBool32									logicOpEnable;
2703		VK_LOGIC_OP_COPY,											//	VkLogicOp									logicOp;
2704		1u,															//	deUint32									attachmentCount;
2705		&attBlendParams,											//	const VkPipelineColorBlendAttachmentState*	pAttachments;
2706		{ 0.0f, 0.0f, 0.0f, 0.0f },									//	float										blendConst[4];
2707	};
2708	const VkPipelineDynamicStateCreateInfo	dynamicStateInfo		=
2709	{
2710		VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	//	VkStructureType			sType;
2711		DE_NULL,												//	const void*				pNext;
2712		0u,														//	deUint32				dynamicStateCount;
2713		DE_NULL													//	const VkDynamicState*	pDynamicStates;
2714	};
2715
2716	const VkPipelineTessellationStateCreateInfo	tessellationState	=
2717	{
2718		VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,
2719		DE_NULL,
2720		3u
2721	};
2722
2723	const VkGraphicsPipelineCreateInfo		pipelineParams			=
2724	{
2725		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,		//	VkStructureType									sType;
2726		DE_NULL,												//	const void*										pNext;
2727		(deUint32)shaderStageParams.size(),						//	deUint32										stageCount;
2728		&shaderStageParams[0],									//	const VkPipelineShaderStageCreateInfo*			pStages;
2729		&vertexInputStateParams,								//	const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
2730		&inputAssemblyParams,									//	const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
2731		&tessellationState,										//	const VkPipelineTessellationStateCreateInfo*	pTessellationState;
2732		&viewportParams,										//	const VkPipelineViewportStateCreateInfo*		pViewportState;
2733		&rasterParams,											//	const VkPipelineRasterStateCreateInfo*			pRasterState;
2734		&multisampleParams,										//	const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
2735		&depthStencilParams,									//	const VkPipelineDepthStencilStateCreateInfo*	pDepthStencilState;
2736		&blendParams,											//	const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
2737		&dynamicStateInfo,										//	const VkPipelineDynamicStateCreateInfo*			pDynamicState;
2738		0u,														//	VkPipelineCreateFlags							flags;
2739		*pipelineLayout,										//	VkPipelineLayout								layout;
2740		*renderPass,											//	VkRenderPass									renderPass;
2741		0u,														//	deUint32										subpass;
2742		DE_NULL,												//	VkPipeline										basePipelineHandle;
2743		0u,														//	deInt32											basePipelineIndex;
2744	};
2745
2746	const Unique<VkPipeline>				pipeline				(createGraphicsPipeline(vk, vkDevice, DE_NULL, &pipelineParams));
2747
2748	// Framebuffer
2749	const VkFramebufferCreateInfo			framebufferParams		=
2750	{
2751		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,				//	VkStructureType		sType;
2752		DE_NULL,												//	const void*			pNext;
2753		*renderPass,											//	VkRenderPass		renderPass;
2754		1u,														//	deUint32			attachmentCount;
2755		&*colorAttView,											//	const VkImageView*	pAttachments;
2756		(deUint32)renderSize.x(),								//	deUint32			width;
2757		(deUint32)renderSize.y(),								//	deUint32			height;
2758		1u,														//	deUint32			layers;
2759	};
2760	const Unique<VkFramebuffer>				framebuffer				(createFramebuffer(vk, vkDevice, &framebufferParams));
2761
2762	const VkCmdPoolCreateInfo				cmdPoolParams			=
2763	{
2764		VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO,						//	VkStructureType			sType;
2765		DE_NULL,													//	const void*				pNext;
2766		queueFamilyIndex,											//	deUint32				queueFamilyIndex;
2767		VK_CMD_POOL_CREATE_RESET_COMMAND_BUFFER_BIT					//	VkCmdPoolCreateFlags	flags;
2768	};
2769	const Unique<VkCmdPool>					cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
2770
2771	// Command buffer
2772	const VkCmdBufferCreateInfo				cmdBufParams			=
2773	{
2774		VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,				//	VkStructureType			sType;
2775		DE_NULL,												//	const void*				pNext;
2776		*cmdPool,												//	VkCmdPool				pool;
2777		VK_CMD_BUFFER_LEVEL_PRIMARY,							//	VkCmdBufferLevel		level;
2778		0u,														//	VkCmdBufferCreateFlags	flags;
2779	};
2780	const Unique<VkCmdBuffer>				cmdBuf					(createCommandBuffer(vk, vkDevice, &cmdBufParams));
2781
2782	const VkCmdBufferBeginInfo				cmdBufBeginParams		=
2783	{
2784		VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,				//	VkStructureType				sType;
2785		DE_NULL,												//	const void*					pNext;
2786		0u,														//	VkCmdBufferOptimizeFlags	flags;
2787		DE_NULL,												//	VkRenderPass				renderPass;
2788		0u,														//	deUint32					subpass;
2789		DE_NULL,												//	VkFramebuffer				framebuffer;
2790	};
2791
2792	// Record commands
2793	VK_CHECK(vk.beginCommandBuffer(*cmdBuf, &cmdBufBeginParams));
2794
2795	{
2796		const VkMemoryBarrier		vertFlushBarrier	=
2797		{
2798			VK_STRUCTURE_TYPE_MEMORY_BARRIER,			//	VkStructureType		sType;
2799			DE_NULL,									//	const void*			pNext;
2800			VK_MEMORY_OUTPUT_HOST_WRITE_BIT,			//	VkMemoryOutputFlags	outputMask;
2801			VK_MEMORY_INPUT_VERTEX_ATTRIBUTE_FETCH_BIT,	//	VkMemoryInputFlags	inputMask;
2802		};
2803		const VkImageMemoryBarrier	colorAttBarrier		=
2804		{
2805			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		//	VkStructureType			sType;
2806			DE_NULL,									//	const void*				pNext;
2807			0u,											//	VkMemoryOutputFlags		outputMask;
2808			VK_MEMORY_INPUT_COLOR_ATTACHMENT_BIT,		//	VkMemoryInputFlags		inputMask;
2809			VK_IMAGE_LAYOUT_UNDEFINED,					//	VkImageLayout			oldLayout;
2810			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout			newLayout;
2811			queueFamilyIndex,							//	deUint32				srcQueueFamilyIndex;
2812			queueFamilyIndex,							//	deUint32				destQueueFamilyIndex;
2813			*image,										//	VkImage					image;
2814			{
2815				VK_IMAGE_ASPECT_COLOR_BIT,					//	VkImageAspect	aspect;
2816				0u,											//	deUint32		baseMipLevel;
2817				1u,											//	deUint32		mipLevels;
2818				0u,											//	deUint32		baseArraySlice;
2819				1u,											//	deUint32		arraySize;
2820			}											//	VkImageSubresourceRange	subresourceRange;
2821		};
2822		const void*				barriers[]				= { &vertFlushBarrier, &colorAttBarrier };
2823		vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_ALL_GPU_COMMANDS, DE_FALSE, (deUint32)DE_LENGTH_OF_ARRAY(barriers), barriers);
2824	}
2825
2826	{
2827		const VkClearValue			clearValue		= makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f);
2828		const VkRenderPassBeginInfo	passBeginParams	=
2829		{
2830			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,			//	VkStructureType		sType;
2831			DE_NULL,											//	const void*			pNext;
2832			*renderPass,										//	VkRenderPass		renderPass;
2833			*framebuffer,										//	VkFramebuffer		framebuffer;
2834			{ { 0, 0 }, { renderSize.x(), renderSize.y() } },	//	VkRect2D			renderArea;
2835			1u,													//	deUint32			clearValueCount;
2836			&clearValue,										//	const VkClearValue*	pClearValues;
2837		};
2838		vk.cmdBeginRenderPass(*cmdBuf, &passBeginParams, VK_RENDER_PASS_CONTENTS_INLINE);
2839	}
2840
2841	vk.cmdBindPipeline(*cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
2842	{
2843		const VkDeviceSize bindingOffset = 0;
2844		vk.cmdBindVertexBuffers(*cmdBuf, 0u, 1u, &vertexBuffer.get(), &bindingOffset);
2845	}
2846	vk.cmdDraw(*cmdBuf, deUint32(vertexCount), 1u /*run pipeline once*/, 0u /*first vertex*/, 0u /*first instanceIndex*/);
2847	vk.cmdEndRenderPass(*cmdBuf);
2848
2849	{
2850		const VkImageMemoryBarrier	renderFinishBarrier	=
2851		{
2852			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		//	VkStructureType			sType;
2853			DE_NULL,									//	const void*				pNext;
2854			VK_MEMORY_OUTPUT_COLOR_ATTACHMENT_BIT,		//	VkMemoryOutputFlags		outputMask;
2855			VK_MEMORY_INPUT_TRANSFER_BIT,				//	VkMemoryInputFlags		inputMask;
2856			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout			oldLayout;
2857			VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL,	//	VkImageLayout			newLayout;
2858			queueFamilyIndex,							//	deUint32				srcQueueFamilyIndex;
2859			queueFamilyIndex,							//	deUint32				destQueueFamilyIndex;
2860			*image,										//	VkImage					image;
2861			{
2862				VK_IMAGE_ASPECT_COLOR_BIT,					//	VkImageAspectFlags	aspectMask;
2863				0u,											//	deUint32			baseMipLevel;
2864				1u,											//	deUint32			mipLevels;
2865				0u,											//	deUint32			baseArraySlice;
2866				1u,											//	deUint32			arraySize;
2867			}											//	VkImageSubresourceRange	subresourceRange;
2868		};
2869		const void*				barriers[]				= { &renderFinishBarrier };
2870		vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_ALL_GRAPHICS, VK_PIPELINE_STAGE_TRANSFER_BIT, DE_FALSE, (deUint32)DE_LENGTH_OF_ARRAY(barriers), barriers);
2871	}
2872
2873	{
2874		const VkBufferImageCopy	copyParams	=
2875		{
2876			(VkDeviceSize)0u,						//	VkDeviceSize			bufferOffset;
2877			(deUint32)renderSize.x(),				//	deUint32				bufferRowLength;
2878			(deUint32)renderSize.y(),				//	deUint32				bufferImageHeight;
2879			{
2880				VK_IMAGE_ASPECT_COLOR,					//	VkImageAspect		aspect;
2881				0u,										//	deUint32			mipLevel;
2882				0u,										//	deUint32			arrayLayer;
2883				1u,										//	deUint32			arraySize;
2884			},										//	VkImageSubresourceCopy	imageSubresource;
2885			{ 0u, 0u, 0u },							//	VkOffset3D				imageOffset;
2886			{ renderSize.x(), renderSize.y(), 1u }	//	VkExtent3D				imageExtent;
2887		};
2888		vk.cmdCopyImageToBuffer(*cmdBuf, *image, VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL, *readImageBuffer, 1u, &copyParams);
2889	}
2890
2891	{
2892		const VkBufferMemoryBarrier	copyFinishBarrier	=
2893		{
2894			VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	//	VkStructureType		sType;
2895			DE_NULL,									//	const void*			pNext;
2896			VK_MEMORY_OUTPUT_TRANSFER_BIT,				//	VkMemoryOutputFlags	outputMask;
2897			VK_MEMORY_INPUT_HOST_READ_BIT,				//	VkMemoryInputFlags	inputMask;
2898			queueFamilyIndex,							//	deUint32			srcQueueFamilyIndex;
2899			queueFamilyIndex,							//	deUint32			destQueueFamilyIndex;
2900			*readImageBuffer,							//	VkBuffer			buffer;
2901			0u,											//	VkDeviceSize		offset;
2902			imageSizeBytes								//	VkDeviceSize		size;
2903		};
2904		const void*				barriers[]				= { &copyFinishBarrier };
2905		vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, DE_FALSE, (deUint32)DE_LENGTH_OF_ARRAY(barriers), barriers);
2906	}
2907
2908	VK_CHECK(vk.endCommandBuffer(*cmdBuf));
2909
2910	// Upload vertex data
2911	{
2912		const VkMappedMemoryRange	range			=
2913		{
2914			VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,	//	VkStructureType	sType;
2915			DE_NULL,								//	const void*		pNext;
2916			vertexBufferMemory->getMemory(),		//	VkDeviceMemory	mem;
2917			0,										//	VkDeviceSize	offset;
2918			(VkDeviceSize)sizeof(vertexData),		//	VkDeviceSize	size;
2919		};
2920		void*						vertexBufPtr	= vertexBufferMemory->getHostPtr();
2921
2922		deMemcpy(vertexBufPtr, &vertexData[0], sizeof(vertexData));
2923		VK_CHECK(vk.flushMappedMemoryRanges(vkDevice, 1u, &range));
2924	}
2925
2926	// Submit & wait for completion
2927	{
2928		const VkFenceCreateInfo	fenceParams	=
2929		{
2930			VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,	//	VkStructureType		sType;
2931			DE_NULL,								//	const void*			pNext;
2932			0u,										//	VkFenceCreateFlags	flags;
2933		};
2934		const Unique<VkFence>	fence		(createFence(vk, vkDevice, &fenceParams));
2935
2936		VK_CHECK(vk.queueSubmit(queue, 1u, &cmdBuf.get(), *fence));
2937		VK_CHECK(vk.waitForFences(vkDevice, 1u, &fence.get(), DE_TRUE, ~0ull));
2938	}
2939
2940	const void* imagePtr	= readImageBufferMemory->getHostPtr();
2941	const tcu::ConstPixelBufferAccess pixelBuffer(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8),
2942												  renderSize.x(), renderSize.y(), 1, imagePtr);
2943	// Log image
2944	{
2945		const VkMappedMemoryRange	range		=
2946		{
2947			VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,	//	VkStructureType	sType;
2948			DE_NULL,								//	const void*		pNext;
2949			readImageBufferMemory->getMemory(),		//	VkDeviceMemory	mem;
2950			0,										//	VkDeviceSize	offset;
2951			imageSizeBytes,							//	VkDeviceSize	size;
2952		};
2953
2954		VK_CHECK(vk.invalidateMappedMemoryRanges(vkDevice, 1u, &range));
2955		context.getTestContext().getLog() << TestLog::Image("Result", "Result", pixelBuffer);
2956	}
2957
2958	const RGBA threshold(1, 1, 1, 1);
2959	const RGBA upperLeft(pixelBuffer.getPixel(1, 1));
2960	if (!tcu::compareThreshold(upperLeft, instance.outputColors[0], threshold))
2961		return TestStatus::fail("Upper left corner mismatch");
2962
2963	const RGBA upperRight(pixelBuffer.getPixel(pixelBuffer.getWidth() - 1, 1));
2964	if (!tcu::compareThreshold(upperRight, instance.outputColors[1], threshold))
2965		return TestStatus::fail("Upper right corner mismatch");
2966
2967	const RGBA lowerLeft(pixelBuffer.getPixel(1, pixelBuffer.getHeight() - 1));
2968	if (!tcu::compareThreshold(lowerLeft, instance.outputColors[2], threshold))
2969		return TestStatus::fail("Lower left corner mismatch");
2970
2971	const RGBA lowerRight(pixelBuffer.getPixel(pixelBuffer.getWidth() - 1, pixelBuffer.getHeight() - 1));
2972	if (!tcu::compareThreshold(lowerRight, instance.outputColors[3], threshold))
2973		return TestStatus::fail("Lower right corner mismatch");
2974
2975	return TestStatus::pass("Rendered output matches input");
2976}
2977
2978void createTestsForAllStages(const std::string& name,
2979							 const RGBA (&inputColors)[4],
2980							 const RGBA (&outputColors)[4],
2981							 const map<string, string>& testCodeFragments,
2982							 tcu::TestCaseGroup* tests)
2983{
2984	const ShaderElement		pipelineStages[]				=
2985	{
2986		ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX),
2987		ShaderElement("tessc", "main", VK_SHADER_STAGE_TESS_CONTROL),
2988		ShaderElement("tesse", "main", VK_SHADER_STAGE_TESS_EVALUATION),
2989		ShaderElement("geom", "main", VK_SHADER_STAGE_GEOMETRY),
2990		ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT),
2991	};
2992
2993	addFunctionCaseWithPrograms<InstanceContext>(tests, name + "-vert", "", addShaderCodeCustomVertex, runAndVerifyDefaultPipeline,
2994												 createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments));
2995
2996	addFunctionCaseWithPrograms<InstanceContext>(tests, name + "-tessc", "", addShaderCodeCustomTessControl, runAndVerifyDefaultPipeline,
2997												 createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments));
2998
2999	addFunctionCaseWithPrograms<InstanceContext>(tests, name + "-tesse", "", addShaderCodeCustomTessEval, runAndVerifyDefaultPipeline,
3000												 createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments));
3001
3002	addFunctionCaseWithPrograms<InstanceContext>(tests, name + "-geom", "", addShaderCodeCustomGeometry, runAndVerifyDefaultPipeline,
3003												 createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments));
3004
3005	addFunctionCaseWithPrograms<InstanceContext>(tests, name + "-frag", "", addShaderCodeCustomFragment, runAndVerifyDefaultPipeline,
3006												 createInstanceContext(pipelineStages, inputColors, outputColors, testCodeFragments));
3007}
3008} // anonymous
3009
3010tcu::TestCaseGroup* createInstructionTests (tcu::TestContext& testCtx)
3011{
3012	de::MovePtr<tcu::TestCaseGroup> instructionTests (new tcu::TestCaseGroup(testCtx, "instruction", "Instructions with special opcodes/operands"));
3013
3014	instructionTests->addChild(createOpNopGroup(testCtx));
3015	instructionTests->addChild(createOpLineGroup(testCtx));
3016	instructionTests->addChild(createOpNoLineGroup(testCtx));
3017	instructionTests->addChild(createOpConstantNullGroup(testCtx));
3018	instructionTests->addChild(createOpConstantCompositeGroup(testCtx));
3019	instructionTests->addChild(createOpConstantUsageGroup(testCtx));
3020	instructionTests->addChild(createOpSourceGroup(testCtx));
3021	instructionTests->addChild(createOpSourceExtensionGroup(testCtx));
3022	instructionTests->addChild(createDecorationGroupGroup(testCtx));
3023	instructionTests->addChild(createOpPhiGroup(testCtx));
3024	instructionTests->addChild(createLoopControlGroup(testCtx));
3025	instructionTests->addChild(createFunctionControlGroup(testCtx));
3026	instructionTests->addChild(createSelectionControlGroup(testCtx));
3027	instructionTests->addChild(createBlockOrderGroup(testCtx));
3028	instructionTests->addChild(createOpUndefGroup(testCtx));
3029	instructionTests->addChild(createOpUnreachableGroup(testCtx));
3030
3031    RGBA defaultColors[4];
3032	getDefaultColors(defaultColors);
3033	de::MovePtr<tcu::TestCaseGroup>	group	(new tcu::TestCaseGroup(testCtx, "graphics-assembly", "Test the graphics pipeline"));
3034	createTestsForAllStages("passthru", defaultColors, defaultColors, passthruFragments(), group.get());
3035	instructionTests->addChild(group.release());
3036	return instructionTests.release();
3037}
3038
3039} // SpirVAssembly
3040} // vkt
3041