1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 Google Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief SPIR-V Assembly Tests for Instructions (special opcode/operand)
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktSpvAsmInstructionTests.hpp"
25 
26 #include "tcuCommandLine.hpp"
27 #include "tcuFormatUtil.hpp"
28 #include "tcuFloat.hpp"
29 #include "tcuRGBA.hpp"
30 #include "tcuStringTemplate.hpp"
31 #include "tcuTestLog.hpp"
32 #include "tcuVectorUtil.hpp"
33 
34 #include "vkDefs.hpp"
35 #include "vkDeviceUtil.hpp"
36 #include "vkMemUtil.hpp"
37 #include "vkPlatform.hpp"
38 #include "vkPrograms.hpp"
39 #include "vkQueryUtil.hpp"
40 #include "vkRef.hpp"
41 #include "vkRefUtil.hpp"
42 #include "vkStrUtil.hpp"
43 #include "vkTypeUtil.hpp"
44 
45 #include "deRandom.hpp"
46 #include "deStringUtil.hpp"
47 #include "deUniquePtr.hpp"
48 #include "tcuStringTemplate.hpp"
49 
50 #include "vktSpvAsmComputeShaderCase.hpp"
51 #include "vktSpvAsmComputeShaderTestUtil.hpp"
52 #include "vktTestCaseUtil.hpp"
53 
54 #include <cmath>
55 #include <limits>
56 #include <map>
57 #include <string>
58 #include <sstream>
59 
60 namespace vkt
61 {
62 namespace SpirVAssembly
63 {
64 
65 namespace
66 {
67 
68 using namespace vk;
69 using std::map;
70 using std::string;
71 using std::vector;
72 using tcu::IVec3;
73 using tcu::IVec4;
74 using tcu::RGBA;
75 using tcu::TestLog;
76 using tcu::TestStatus;
77 using tcu::Vec4;
78 using de::UniquePtr;
79 using tcu::StringTemplate;
80 using tcu::Vec4;
81 
82 typedef Unique<VkShaderModule>			ModuleHandleUp;
83 typedef de::SharedPtr<ModuleHandleUp>	ModuleHandleSp;
84 
85 template<typename T>	T			randomScalar	(de::Random& rnd, T minValue, T maxValue);
randomScalar(de::Random & rnd,float minValue,float maxValue)86 template<> inline		float		randomScalar	(de::Random& rnd, float minValue, float maxValue)		{ return rnd.getFloat(minValue, maxValue);	}
randomScalar(de::Random & rnd,deInt32 minValue,deInt32 maxValue)87 template<> inline		deInt32		randomScalar	(de::Random& rnd, deInt32 minValue, deInt32 maxValue)	{ return rnd.getInt(minValue, maxValue);	}
88 
89 template<typename T>
fillRandomScalars(de::Random & rnd,T minValue,T maxValue,void * dst,int numValues,int offset=0)90 static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, int offset = 0)
91 {
92 	T* const typedPtr = (T*)dst;
93 	for (int ndx = 0; ndx < numValues; ndx++)
94 		typedPtr[offset + ndx] = randomScalar<T>(rnd, minValue, maxValue);
95 }
96 
floorAll(vector<float> & values)97 static void floorAll (vector<float>& values)
98 {
99 	for (size_t i = 0; i < values.size(); i++)
100 		values[i] = deFloatFloor(values[i]);
101 }
102 
floorAll(vector<Vec4> & values)103 static void floorAll (vector<Vec4>& values)
104 {
105 	for (size_t i = 0; i < values.size(); i++)
106 		values[i] = floor(values[i]);
107 }
108 
109 struct CaseParameter
110 {
111 	const char*		name;
112 	string			param;
113 
CaseParametervkt::SpirVAssembly::__anon889ef7250111::CaseParameter114 	CaseParameter	(const char* case_, const string& param_) : name(case_), param(param_) {}
115 };
116 
117 // Assembly code used for testing OpNop, OpConstant{Null|Composite}, Op[No]Line, OpSource[Continued], OpSourceExtension, OpUndef is based on GLSL source code:
118 //
119 // #version 430
120 //
121 // layout(std140, set = 0, binding = 0) readonly buffer Input {
122 //   float elements[];
123 // } input_data;
124 // layout(std140, set = 0, binding = 1) writeonly buffer Output {
125 //   float elements[];
126 // } output_data;
127 //
128 // layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
129 //
130 // void main() {
131 //   uint x = gl_GlobalInvocationID.x;
132 //   output_data.elements[x] = -input_data.elements[x];
133 // }
134 
135 static const char* const s_ShaderPreamble =
136 	"OpCapability Shader\n"
137 	"OpMemoryModel Logical GLSL450\n"
138 	"OpEntryPoint GLCompute %main \"main\" %id\n"
139 	"OpExecutionMode %main LocalSize 1 1 1\n";
140 
141 static const char* const s_CommonTypes =
142 	"%bool      = OpTypeBool\n"
143 	"%void      = OpTypeVoid\n"
144 	"%voidf     = OpTypeFunction %void\n"
145 	"%u32       = OpTypeInt 32 0\n"
146 	"%i32       = OpTypeInt 32 1\n"
147 	"%f32       = OpTypeFloat 32\n"
148 	"%uvec3     = OpTypeVector %u32 3\n"
149 	"%fvec3     = OpTypeVector %f32 3\n"
150 	"%uvec3ptr  = OpTypePointer Input %uvec3\n"
151 	"%i32ptr    = OpTypePointer Uniform %i32\n"
152 	"%f32ptr    = OpTypePointer Uniform %f32\n"
153 	"%i32arr    = OpTypeRuntimeArray %i32\n"
154 	"%f32arr    = OpTypeRuntimeArray %f32\n";
155 
156 // Declares two uniform variables (indata, outdata) of type "struct { float[] }". Depends on type "f32arr" (for "float[]").
157 static const char* const s_InputOutputBuffer =
158 	"%buf     = OpTypeStruct %f32arr\n"
159 	"%bufptr  = OpTypePointer Uniform %buf\n"
160 	"%indata    = OpVariable %bufptr Uniform\n"
161 	"%outdata   = OpVariable %bufptr Uniform\n";
162 
163 // Declares buffer type and layout for uniform variables indata and outdata. Both of them are SSBO bounded to descriptor set 0.
164 // indata is at binding point 0, while outdata is at 1.
165 static const char* const s_InputOutputBufferTraits =
166 	"OpDecorate %buf BufferBlock\n"
167 	"OpDecorate %indata DescriptorSet 0\n"
168 	"OpDecorate %indata Binding 0\n"
169 	"OpDecorate %outdata DescriptorSet 0\n"
170 	"OpDecorate %outdata Binding 1\n"
171 	"OpDecorate %f32arr ArrayStride 4\n"
172 	"OpMemberDecorate %buf 0 Offset 0\n";
173 
createOpNopGroup(tcu::TestContext & testCtx)174 tcu::TestCaseGroup* createOpNopGroup (tcu::TestContext& testCtx)
175 {
176 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opnop", "Test the OpNop instruction"));
177 	ComputeShaderSpec				spec;
178 	de::Random						rnd				(deStringHash(group->getName()));
179 	const int						numElements		= 100;
180 	vector<float>					positiveFloats	(numElements, 0);
181 	vector<float>					negativeFloats	(numElements, 0);
182 
183 	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
184 
185 	for (size_t ndx = 0; ndx < numElements; ++ndx)
186 		negativeFloats[ndx] = -positiveFloats[ndx];
187 
188 	spec.assembly =
189 		string(s_ShaderPreamble) +
190 
191 		"OpSource GLSL 430\n"
192 		"OpName %main           \"main\"\n"
193 		"OpName %id             \"gl_GlobalInvocationID\"\n"
194 
195 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
196 
197 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes)
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 
compareFUnord(const std::vector<BufferSp> & inputs,const vector<AllocationSp> & outputAllocs,const std::vector<BufferSp> & expectedOutputs,TestLog & log)227 bool compareFUnord (const std::vector<BufferSp>& inputs, const vector<AllocationSp>& outputAllocs, const std::vector<BufferSp>& expectedOutputs, TestLog& log)
228 {
229 	if (outputAllocs.size() != 1)
230 		return false;
231 
232 	const BufferSp&	expectedOutput			= expectedOutputs[0];
233 	const deInt32*	expectedOutputAsInt		= static_cast<const deInt32*>(expectedOutputs[0]->data());
234 	const deInt32*	outputAsInt				= static_cast<const deInt32*>(outputAllocs[0]->getHostPtr());
235 	const float*	input1AsFloat			= static_cast<const float*>(inputs[0]->data());
236 	const float*	input2AsFloat			= static_cast<const float*>(inputs[1]->data());
237 	bool returnValue						= true;
238 
239 	for (size_t idx = 0; idx < expectedOutput->getNumBytes() / sizeof(deInt32); ++idx)
240 	{
241 		if (outputAsInt[idx] != expectedOutputAsInt[idx])
242 		{
243 			log << TestLog::Message << "ERROR: Sub-case failed. inputs: " << input1AsFloat[idx] << "," << input2AsFloat[idx] << " output: " << outputAsInt[idx]<< " expected output: " << expectedOutputAsInt[idx] << TestLog::EndMessage;
244 			returnValue = false;
245 		}
246 	}
247 	return returnValue;
248 }
249 
250 typedef VkBool32 (*compareFuncType) (float, float);
251 
252 struct OpFUnordCase
253 {
254 	const char*		name;
255 	const char*		opCode;
256 	compareFuncType	compareFunc;
257 
OpFUnordCasevkt::SpirVAssembly::__anon889ef7250111::OpFUnordCase258 					OpFUnordCase			(const char* _name, const char* _opCode, compareFuncType _compareFunc)
259 						: name				(_name)
260 						, opCode			(_opCode)
261 						, compareFunc		(_compareFunc) {}
262 };
263 
264 #define ADD_OPFUNORD_CASE(NAME, OPCODE, OPERATOR) \
265 do { \
266     struct compare_##NAME { static VkBool32 compare(float x, float y) { return (x OPERATOR y) ? VK_TRUE : VK_FALSE; } }; \
267     cases.push_back(OpFUnordCase(#NAME, OPCODE, compare_##NAME::compare)); \
268 } while (deGetFalse())
269 
createOpFUnordGroup(tcu::TestContext & testCtx)270 tcu::TestCaseGroup* createOpFUnordGroup (tcu::TestContext& testCtx)
271 {
272 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opfunord", "Test the OpFUnord* opcodes"));
273 	de::Random						rnd				(deStringHash(group->getName()));
274 	const int						numElements		= 100;
275 	vector<OpFUnordCase>			cases;
276 
277 	const StringTemplate			shaderTemplate	(
278 
279 		string(s_ShaderPreamble) +
280 
281 		"OpSource GLSL 430\n"
282 		"OpName %main           \"main\"\n"
283 		"OpName %id             \"gl_GlobalInvocationID\"\n"
284 
285 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
286 
287 		"OpDecorate %buf BufferBlock\n"
288 		"OpDecorate %buf2 BufferBlock\n"
289 		"OpDecorate %indata1 DescriptorSet 0\n"
290 		"OpDecorate %indata1 Binding 0\n"
291 		"OpDecorate %indata2 DescriptorSet 0\n"
292 		"OpDecorate %indata2 Binding 1\n"
293 		"OpDecorate %outdata DescriptorSet 0\n"
294 		"OpDecorate %outdata Binding 2\n"
295 		"OpDecorate %f32arr ArrayStride 4\n"
296 		"OpDecorate %i32arr ArrayStride 4\n"
297 		"OpMemberDecorate %buf 0 Offset 0\n"
298 		"OpMemberDecorate %buf2 0 Offset 0\n"
299 
300 		+ string(s_CommonTypes) +
301 
302 		"%buf        = OpTypeStruct %f32arr\n"
303 		"%bufptr     = OpTypePointer Uniform %buf\n"
304 		"%indata1    = OpVariable %bufptr Uniform\n"
305 		"%indata2    = OpVariable %bufptr Uniform\n"
306 
307 		"%buf2       = OpTypeStruct %i32arr\n"
308 		"%buf2ptr    = OpTypePointer Uniform %buf2\n"
309 		"%outdata    = OpVariable %buf2ptr Uniform\n"
310 
311 		"%id        = OpVariable %uvec3ptr Input\n"
312 		"%zero      = OpConstant %i32 0\n"
313 		"%consti1   = OpConstant %i32 1\n"
314 		"%constf1   = OpConstant %f32 1.0\n"
315 
316 		"%main      = OpFunction %void None %voidf\n"
317 		"%label     = OpLabel\n"
318 		"%idval     = OpLoad %uvec3 %id\n"
319 		"%x         = OpCompositeExtract %u32 %idval 0\n"
320 
321 		"%inloc1    = OpAccessChain %f32ptr %indata1 %zero %x\n"
322 		"%inval1    = OpLoad %f32 %inloc1\n"
323 		"%inloc2    = OpAccessChain %f32ptr %indata2 %zero %x\n"
324 		"%inval2    = OpLoad %f32 %inloc2\n"
325 		"%outloc    = OpAccessChain %i32ptr %outdata %zero %x\n"
326 
327 		"%result    = ${OPCODE} %bool %inval1 %inval2\n"
328 		"%int_res   = OpSelect %i32 %result %consti1 %zero\n"
329 		"             OpStore %outloc %int_res\n"
330 
331 		"             OpReturn\n"
332 		"             OpFunctionEnd\n");
333 
334 	ADD_OPFUNORD_CASE(equal, "OpFUnordEqual", ==);
335 	ADD_OPFUNORD_CASE(less, "OpFUnordLessThan", <);
336 	ADD_OPFUNORD_CASE(lessequal, "OpFUnordLessThanEqual", <=);
337 	ADD_OPFUNORD_CASE(greater, "OpFUnordGreaterThan", >);
338 	ADD_OPFUNORD_CASE(greaterequal, "OpFUnordGreaterThanEqual", >=);
339 	ADD_OPFUNORD_CASE(notequal, "OpFUnordNotEqual", !=);
340 
341 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
342 	{
343 		map<string, string>			specializations;
344 		ComputeShaderSpec			spec;
345 		const float					NaN				= std::numeric_limits<float>::quiet_NaN();
346 		vector<float>				inputFloats1	(numElements, 0);
347 		vector<float>				inputFloats2	(numElements, 0);
348 		vector<deInt32>				expectedInts	(numElements, 0);
349 
350 		specializations["OPCODE"]	= cases[caseNdx].opCode;
351 		spec.assembly				= shaderTemplate.specialize(specializations);
352 
353 		fillRandomScalars(rnd, 1.f, 100.f, &inputFloats1[0], numElements);
354 		for (size_t ndx = 0; ndx < numElements; ++ndx)
355 		{
356 			switch (ndx % 6)
357 			{
358 				case 0:		inputFloats2[ndx] = inputFloats1[ndx] + 1.0f; break;
359 				case 1:		inputFloats2[ndx] = inputFloats1[ndx] - 1.0f; break;
360 				case 2:		inputFloats2[ndx] = inputFloats1[ndx]; break;
361 				case 3:		inputFloats2[ndx] = NaN; break;
362 				case 4:		inputFloats2[ndx] = inputFloats1[ndx];	inputFloats1[ndx] = NaN; break;
363 				case 5:		inputFloats2[ndx] = NaN;				inputFloats1[ndx] = NaN; break;
364 			}
365 			expectedInts[ndx] = tcu::Float32(inputFloats1[ndx]).isNaN() || tcu::Float32(inputFloats2[ndx]).isNaN() || cases[caseNdx].compareFunc(inputFloats1[ndx], inputFloats2[ndx]);
366 		}
367 
368 		spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats1)));
369 		spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats2)));
370 		spec.outputs.push_back(BufferSp(new Int32Buffer(expectedInts)));
371 		spec.numWorkGroups = IVec3(numElements, 1, 1);
372 		spec.verifyIO = &compareFUnord;
373 		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
374 	}
375 
376 	return group.release();
377 }
378 
379 struct OpAtomicCase
380 {
381 	const char*		name;
382 	const char*		assembly;
383 	void			(*calculateExpected)(deInt32&, deInt32);
384 	deInt32			numOutputElements;
385 
OpAtomicCasevkt::SpirVAssembly::__anon889ef7250111::OpAtomicCase386 					OpAtomicCase			(const char* _name, const char* _assembly, void (*_calculateExpected)(deInt32&, deInt32), deInt32 _numOutputElements)
387 						: name				(_name)
388 						, assembly			(_assembly)
389 						, calculateExpected	(_calculateExpected)
390 						, numOutputElements (_numOutputElements) {}
391 };
392 
createOpAtomicGroup(tcu::TestContext & testCtx)393 tcu::TestCaseGroup* createOpAtomicGroup (tcu::TestContext& testCtx)
394 {
395 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opatomic", "Test the OpAtomic* opcodes"));
396 	de::Random						rnd				(deStringHash(group->getName()));
397 	const int						numElements		= 1000000;
398 	vector<OpAtomicCase>			cases;
399 
400 	const StringTemplate			shaderTemplate	(
401 
402 		string(s_ShaderPreamble) +
403 
404 		"OpSource GLSL 430\n"
405 		"OpName %main           \"main\"\n"
406 		"OpName %id             \"gl_GlobalInvocationID\"\n"
407 
408 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
409 
410 		"OpDecorate %buf BufferBlock\n"
411 		"OpDecorate %indata DescriptorSet 0\n"
412 		"OpDecorate %indata Binding 0\n"
413 		"OpDecorate %i32arr ArrayStride 4\n"
414 		"OpMemberDecorate %buf 0 Offset 0\n"
415 
416 		"OpDecorate %sumbuf BufferBlock\n"
417 		"OpDecorate %sum DescriptorSet 0\n"
418 		"OpDecorate %sum Binding 1\n"
419 		"OpMemberDecorate %sumbuf 0 Coherent\n"
420 		"OpMemberDecorate %sumbuf 0 Offset 0\n"
421 
422 		+ string(s_CommonTypes) +
423 
424 		"%buf       = OpTypeStruct %i32arr\n"
425 		"%bufptr    = OpTypePointer Uniform %buf\n"
426 		"%indata    = OpVariable %bufptr Uniform\n"
427 
428 		"%sumbuf    = OpTypeStruct %i32arr\n"
429 		"%sumbufptr = OpTypePointer Uniform %sumbuf\n"
430 		"%sum       = OpVariable %sumbufptr Uniform\n"
431 
432 		"%id        = OpVariable %uvec3ptr Input\n"
433 		"%minusone  = OpConstant %i32 -1\n"
434 		"%zero      = OpConstant %i32 0\n"
435 		"%one       = OpConstant %u32 1\n"
436 		"%two       = OpConstant %i32 2\n"
437 
438 		"%main      = OpFunction %void None %voidf\n"
439 		"%label     = OpLabel\n"
440 		"%idval     = OpLoad %uvec3 %id\n"
441 		"%x         = OpCompositeExtract %u32 %idval 0\n"
442 
443 		"%inloc     = OpAccessChain %i32ptr %indata %zero %x\n"
444 		"%inval     = OpLoad %i32 %inloc\n"
445 
446 		"%outloc    = OpAccessChain %i32ptr %sum %zero ${INDEX}\n"
447 		"${INSTRUCTION}"
448 
449 		"             OpReturn\n"
450 		"             OpFunctionEnd\n");
451 
452 	#define ADD_OPATOMIC_CASE(NAME, ASSEMBLY, CALCULATE_EXPECTED, NUM_OUTPUT_ELEMENTS) \
453 	do { \
454 		DE_STATIC_ASSERT((NUM_OUTPUT_ELEMENTS) == 1 || (NUM_OUTPUT_ELEMENTS) == numElements); \
455 		struct calculateExpected_##NAME { static void calculateExpected(deInt32& expected, deInt32 input) CALCULATE_EXPECTED }; /* NOLINT(CALCULATE_EXPECTED) */ \
456 		cases.push_back(OpAtomicCase(#NAME, ASSEMBLY, calculateExpected_##NAME::calculateExpected, NUM_OUTPUT_ELEMENTS)); \
457 	} while (deGetFalse())
458 	#define ADD_OPATOMIC_CASE_1(NAME, ASSEMBLY, CALCULATE_EXPECTED) ADD_OPATOMIC_CASE(NAME, ASSEMBLY, CALCULATE_EXPECTED, 1)
459 	#define ADD_OPATOMIC_CASE_N(NAME, ASSEMBLY, CALCULATE_EXPECTED) ADD_OPATOMIC_CASE(NAME, ASSEMBLY, CALCULATE_EXPECTED, numElements)
460 
461 	ADD_OPATOMIC_CASE_1(iadd,	"%unused    = OpAtomicIAdd %i32 %outloc %one %zero %inval\n", { expected += input; } );
462 	ADD_OPATOMIC_CASE_1(isub,	"%unused    = OpAtomicISub %i32 %outloc %one %zero %inval\n", { expected -= input; } );
463 	ADD_OPATOMIC_CASE_1(iinc,	"%unused    = OpAtomicIIncrement %i32 %outloc %one %zero\n",  { ++expected; (void)input;} );
464 	ADD_OPATOMIC_CASE_1(idec,	"%unused    = OpAtomicIDecrement %i32 %outloc %one %zero\n",  { --expected; (void)input;} );
465 	ADD_OPATOMIC_CASE_N(load,	"%inval2    = OpAtomicLoad %i32 %inloc %zero %zero\n"
466 								"             OpStore %outloc %inval2\n",  { expected = input;} );
467 	ADD_OPATOMIC_CASE_N(store,	"             OpAtomicStore %outloc %zero %zero %inval\n",  { expected = input;} );
468 	ADD_OPATOMIC_CASE_N(compex, "%even      = OpSMod %i32 %inval %two\n"
469 								"             OpStore %outloc %even\n"
470 								"%unused    = OpAtomicCompareExchange %i32 %outloc %one %zero %zero %minusone %zero\n",  { expected = (input % 2) == 0 ? -1 : 1;} );
471 
472 	#undef ADD_OPATOMIC_CASE
473 	#undef ADD_OPATOMIC_CASE_1
474 	#undef ADD_OPATOMIC_CASE_N
475 
476 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
477 	{
478 		map<string, string>			specializations;
479 		ComputeShaderSpec			spec;
480 		vector<deInt32>				inputInts		(numElements, 0);
481 		vector<deInt32>				expected		(cases[caseNdx].numOutputElements, -1);
482 
483 		specializations["INDEX"]		= (cases[caseNdx].numOutputElements == 1) ? "%zero" : "%x";
484 		specializations["INSTRUCTION"]	= cases[caseNdx].assembly;
485 		spec.assembly					= shaderTemplate.specialize(specializations);
486 
487 		fillRandomScalars(rnd, 1, 100, &inputInts[0], numElements);
488 		for (size_t ndx = 0; ndx < numElements; ++ndx)
489 		{
490 			cases[caseNdx].calculateExpected((cases[caseNdx].numOutputElements == 1) ? expected[0] : expected[ndx], inputInts[ndx]);
491 		}
492 
493 		spec.inputs.push_back(BufferSp(new Int32Buffer(inputInts)));
494 		spec.outputs.push_back(BufferSp(new Int32Buffer(expected)));
495 		spec.numWorkGroups = IVec3(numElements, 1, 1);
496 		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
497 	}
498 
499 	return group.release();
500 }
501 
createOpLineGroup(tcu::TestContext & testCtx)502 tcu::TestCaseGroup* createOpLineGroup (tcu::TestContext& testCtx)
503 {
504 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opline", "Test the OpLine instruction"));
505 	ComputeShaderSpec				spec;
506 	de::Random						rnd				(deStringHash(group->getName()));
507 	const int						numElements		= 100;
508 	vector<float>					positiveFloats	(numElements, 0);
509 	vector<float>					negativeFloats	(numElements, 0);
510 
511 	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
512 
513 	for (size_t ndx = 0; ndx < numElements; ++ndx)
514 		negativeFloats[ndx] = -positiveFloats[ndx];
515 
516 	spec.assembly =
517 		string(s_ShaderPreamble) +
518 
519 		"%fname1 = OpString \"negateInputs.comp\"\n"
520 		"%fname2 = OpString \"negateInputs\"\n"
521 
522 		"OpSource GLSL 430\n"
523 		"OpName %main           \"main\"\n"
524 		"OpName %id             \"gl_GlobalInvocationID\"\n"
525 
526 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
527 
528 		+ string(s_InputOutputBufferTraits) +
529 
530 		"OpLine %fname1 0 0\n" // At the earliest possible position
531 
532 		+ string(s_CommonTypes) + string(s_InputOutputBuffer) +
533 
534 		"OpLine %fname1 0 1\n" // Multiple OpLines in sequence
535 		"OpLine %fname2 1 0\n" // Different filenames
536 		"OpLine %fname1 1000 100000\n"
537 
538 		"%id        = OpVariable %uvec3ptr Input\n"
539 		"%zero      = OpConstant %i32 0\n"
540 
541 		"OpLine %fname1 1 1\n" // Before a function
542 
543 		"%main      = OpFunction %void None %voidf\n"
544 		"%label     = OpLabel\n"
545 
546 		"OpLine %fname1 1 1\n" // In a function
547 
548 		"%idval     = OpLoad %uvec3 %id\n"
549 		"%x         = OpCompositeExtract %u32 %idval 0\n"
550 		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
551 		"%inval     = OpLoad %f32 %inloc\n"
552 		"%neg       = OpFNegate %f32 %inval\n"
553 		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
554 		"             OpStore %outloc %neg\n"
555 		"             OpReturn\n"
556 		"             OpFunctionEnd\n";
557 	spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
558 	spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
559 	spec.numWorkGroups = IVec3(numElements, 1, 1);
560 
561 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "all", "OpLine appearing at different places", spec));
562 
563 	return group.release();
564 }
565 
createOpNoLineGroup(tcu::TestContext & testCtx)566 tcu::TestCaseGroup* createOpNoLineGroup (tcu::TestContext& testCtx)
567 {
568 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opnoline", "Test the OpNoLine instruction"));
569 	ComputeShaderSpec				spec;
570 	de::Random						rnd				(deStringHash(group->getName()));
571 	const int						numElements		= 100;
572 	vector<float>					positiveFloats	(numElements, 0);
573 	vector<float>					negativeFloats	(numElements, 0);
574 
575 	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
576 
577 	for (size_t ndx = 0; ndx < numElements; ++ndx)
578 		negativeFloats[ndx] = -positiveFloats[ndx];
579 
580 	spec.assembly =
581 		string(s_ShaderPreamble) +
582 
583 		"%fname = OpString \"negateInputs.comp\"\n"
584 
585 		"OpSource GLSL 430\n"
586 		"OpName %main           \"main\"\n"
587 		"OpName %id             \"gl_GlobalInvocationID\"\n"
588 
589 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
590 
591 		+ string(s_InputOutputBufferTraits) +
592 
593 		"OpNoLine\n" // At the earliest possible position, without preceding OpLine
594 
595 		+ string(s_CommonTypes) + string(s_InputOutputBuffer) +
596 
597 		"OpLine %fname 0 1\n"
598 		"OpNoLine\n" // Immediately following a preceding OpLine
599 
600 		"OpLine %fname 1000 1\n"
601 
602 		"%id        = OpVariable %uvec3ptr Input\n"
603 		"%zero      = OpConstant %i32 0\n"
604 
605 		"OpNoLine\n" // Contents after the previous OpLine
606 
607 		"%main      = OpFunction %void None %voidf\n"
608 		"%label     = OpLabel\n"
609 		"%idval     = OpLoad %uvec3 %id\n"
610 		"%x         = OpCompositeExtract %u32 %idval 0\n"
611 
612 		"OpNoLine\n" // Multiple OpNoLine
613 		"OpNoLine\n"
614 		"OpNoLine\n"
615 
616 		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
617 		"%inval     = OpLoad %f32 %inloc\n"
618 		"%neg       = OpFNegate %f32 %inval\n"
619 		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
620 		"             OpStore %outloc %neg\n"
621 		"             OpReturn\n"
622 		"             OpFunctionEnd\n";
623 	spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
624 	spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
625 	spec.numWorkGroups = IVec3(numElements, 1, 1);
626 
627 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "all", "OpNoLine appearing at different places", spec));
628 
629 	return group.release();
630 }
631 
632 // Compare instruction for the contraction compute case.
633 // Returns true if the output is what is expected from the test case.
compareNoContractCase(const std::vector<BufferSp> &,const vector<AllocationSp> & outputAllocs,const std::vector<BufferSp> & expectedOutputs,TestLog &)634 bool compareNoContractCase(const std::vector<BufferSp>&, const vector<AllocationSp>& outputAllocs, const std::vector<BufferSp>& expectedOutputs, TestLog&)
635 {
636 	if (outputAllocs.size() != 1)
637 		return false;
638 
639 	// We really just need this for size because we are not comparing the exact values.
640 	const BufferSp&	expectedOutput	= expectedOutputs[0];
641 	const float*	outputAsFloat	= static_cast<const float*>(outputAllocs[0]->getHostPtr());;
642 
643 	for(size_t i = 0; i < expectedOutput->getNumBytes() / sizeof(float); ++i) {
644 		if (outputAsFloat[i] != 0.f &&
645 			outputAsFloat[i] != -ldexp(1, -24)) {
646 			return false;
647 		}
648 	}
649 
650 	return true;
651 }
652 
createNoContractionGroup(tcu::TestContext & testCtx)653 tcu::TestCaseGroup* createNoContractionGroup (tcu::TestContext& testCtx)
654 {
655 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "nocontraction", "Test the NoContraction decoration"));
656 	vector<CaseParameter>			cases;
657 	const int						numElements		= 100;
658 	vector<float>					inputFloats1	(numElements, 0);
659 	vector<float>					inputFloats2	(numElements, 0);
660 	vector<float>					outputFloats	(numElements, 0);
661 	const StringTemplate			shaderTemplate	(
662 		string(s_ShaderPreamble) +
663 
664 		"OpName %main           \"main\"\n"
665 		"OpName %id             \"gl_GlobalInvocationID\"\n"
666 
667 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
668 
669 		"${DECORATION}\n"
670 
671 		"OpDecorate %buf BufferBlock\n"
672 		"OpDecorate %indata1 DescriptorSet 0\n"
673 		"OpDecorate %indata1 Binding 0\n"
674 		"OpDecorate %indata2 DescriptorSet 0\n"
675 		"OpDecorate %indata2 Binding 1\n"
676 		"OpDecorate %outdata DescriptorSet 0\n"
677 		"OpDecorate %outdata Binding 2\n"
678 		"OpDecorate %f32arr ArrayStride 4\n"
679 		"OpMemberDecorate %buf 0 Offset 0\n"
680 
681 		+ string(s_CommonTypes) +
682 
683 		"%buf        = OpTypeStruct %f32arr\n"
684 		"%bufptr     = OpTypePointer Uniform %buf\n"
685 		"%indata1    = OpVariable %bufptr Uniform\n"
686 		"%indata2    = OpVariable %bufptr Uniform\n"
687 		"%outdata    = OpVariable %bufptr Uniform\n"
688 
689 		"%id         = OpVariable %uvec3ptr Input\n"
690 		"%zero       = OpConstant %i32 0\n"
691 		"%c_f_m1     = OpConstant %f32 -1.\n"
692 
693 		"%main       = OpFunction %void None %voidf\n"
694 		"%label      = OpLabel\n"
695 		"%idval      = OpLoad %uvec3 %id\n"
696 		"%x          = OpCompositeExtract %u32 %idval 0\n"
697 		"%inloc1     = OpAccessChain %f32ptr %indata1 %zero %x\n"
698 		"%inval1     = OpLoad %f32 %inloc1\n"
699 		"%inloc2     = OpAccessChain %f32ptr %indata2 %zero %x\n"
700 		"%inval2     = OpLoad %f32 %inloc2\n"
701 		"%mul        = OpFMul %f32 %inval1 %inval2\n"
702 		"%add        = OpFAdd %f32 %mul %c_f_m1\n"
703 		"%outloc     = OpAccessChain %f32ptr %outdata %zero %x\n"
704 		"              OpStore %outloc %add\n"
705 		"              OpReturn\n"
706 		"              OpFunctionEnd\n");
707 
708 	cases.push_back(CaseParameter("multiplication",	"OpDecorate %mul NoContraction"));
709 	cases.push_back(CaseParameter("addition",		"OpDecorate %add NoContraction"));
710 	cases.push_back(CaseParameter("both",			"OpDecorate %mul NoContraction\nOpDecorate %add NoContraction"));
711 
712 	for (size_t ndx = 0; ndx < numElements; ++ndx)
713 	{
714 		inputFloats1[ndx]	= 1.f + std::ldexp(1.f, -23); // 1 + 2^-23.
715 		inputFloats2[ndx]	= 1.f - std::ldexp(1.f, -23); // 1 - 2^-23.
716 		// Result for (1 + 2^-23) * (1 - 2^-23) - 1. With NoContraction, the multiplication will be
717 		// conducted separately and the result is rounded to 1, or 0x1.fffffcp-1
718 		// So the final result will be 0.f or 0x1p-24.
719 		// If the operation is combined into a precise fused multiply-add, then the result would be
720 		// 2^-46 (0xa8800000).
721 		outputFloats[ndx]	= 0.f;
722 	}
723 
724 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
725 	{
726 		map<string, string>		specializations;
727 		ComputeShaderSpec		spec;
728 
729 		specializations["DECORATION"] = cases[caseNdx].param;
730 		spec.assembly = shaderTemplate.specialize(specializations);
731 		spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats1)));
732 		spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats2)));
733 		spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
734 		spec.numWorkGroups = IVec3(numElements, 1, 1);
735 		// Check against the two possible answers based on rounding mode.
736 		spec.verifyIO = &compareNoContractCase;
737 
738 		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
739 	}
740 	return group.release();
741 }
742 
compareFRem(const std::vector<BufferSp> &,const vector<AllocationSp> & outputAllocs,const std::vector<BufferSp> & expectedOutputs,TestLog &)743 bool compareFRem(const std::vector<BufferSp>&, const vector<AllocationSp>& outputAllocs, const std::vector<BufferSp>& expectedOutputs, TestLog&)
744 {
745 	if (outputAllocs.size() != 1)
746 		return false;
747 
748 	const BufferSp& expectedOutput = expectedOutputs[0];
749 	const float *expectedOutputAsFloat = static_cast<const float*>(expectedOutput->data());
750 	const float* outputAsFloat = static_cast<const float*>(outputAllocs[0]->getHostPtr());;
751 
752 	for (size_t idx = 0; idx < expectedOutput->getNumBytes() / sizeof(float); ++idx)
753 	{
754 		const float f0 = expectedOutputAsFloat[idx];
755 		const float f1 = outputAsFloat[idx];
756 		// \todo relative error needs to be fairly high because FRem may be implemented as
757 		// (roughly) frac(a/b)*b, so LSB errors can be magnified. But this should be fine for now.
758 		if (deFloatAbs((f1 - f0) / f0) > 0.02)
759 			return false;
760 	}
761 
762 	return true;
763 }
764 
createOpFRemGroup(tcu::TestContext & testCtx)765 tcu::TestCaseGroup* createOpFRemGroup (tcu::TestContext& testCtx)
766 {
767 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opfrem", "Test the OpFRem instruction"));
768 	ComputeShaderSpec				spec;
769 	de::Random						rnd				(deStringHash(group->getName()));
770 	const int						numElements		= 200;
771 	vector<float>					inputFloats1	(numElements, 0);
772 	vector<float>					inputFloats2	(numElements, 0);
773 	vector<float>					outputFloats	(numElements, 0);
774 
775 	fillRandomScalars(rnd, -10000.f, 10000.f, &inputFloats1[0], numElements);
776 	fillRandomScalars(rnd, -100.f, 100.f, &inputFloats2[0], numElements);
777 
778 	for (size_t ndx = 0; ndx < numElements; ++ndx)
779 	{
780 		// Guard against divisors near zero.
781 		if (std::fabs(inputFloats2[ndx]) < 1e-3)
782 			inputFloats2[ndx] = 8.f;
783 
784 		// The return value of std::fmod() has the same sign as its first operand, which is how OpFRem spec'd.
785 		outputFloats[ndx] = std::fmod(inputFloats1[ndx], inputFloats2[ndx]);
786 	}
787 
788 	spec.assembly =
789 		string(s_ShaderPreamble) +
790 
791 		"OpName %main           \"main\"\n"
792 		"OpName %id             \"gl_GlobalInvocationID\"\n"
793 
794 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
795 
796 		"OpDecorate %buf BufferBlock\n"
797 		"OpDecorate %indata1 DescriptorSet 0\n"
798 		"OpDecorate %indata1 Binding 0\n"
799 		"OpDecorate %indata2 DescriptorSet 0\n"
800 		"OpDecorate %indata2 Binding 1\n"
801 		"OpDecorate %outdata DescriptorSet 0\n"
802 		"OpDecorate %outdata Binding 2\n"
803 		"OpDecorate %f32arr ArrayStride 4\n"
804 		"OpMemberDecorate %buf 0 Offset 0\n"
805 
806 		+ string(s_CommonTypes) +
807 
808 		"%buf        = OpTypeStruct %f32arr\n"
809 		"%bufptr     = OpTypePointer Uniform %buf\n"
810 		"%indata1    = OpVariable %bufptr Uniform\n"
811 		"%indata2    = OpVariable %bufptr Uniform\n"
812 		"%outdata    = OpVariable %bufptr Uniform\n"
813 
814 		"%id        = OpVariable %uvec3ptr Input\n"
815 		"%zero      = OpConstant %i32 0\n"
816 
817 		"%main      = OpFunction %void None %voidf\n"
818 		"%label     = OpLabel\n"
819 		"%idval     = OpLoad %uvec3 %id\n"
820 		"%x         = OpCompositeExtract %u32 %idval 0\n"
821 		"%inloc1    = OpAccessChain %f32ptr %indata1 %zero %x\n"
822 		"%inval1    = OpLoad %f32 %inloc1\n"
823 		"%inloc2    = OpAccessChain %f32ptr %indata2 %zero %x\n"
824 		"%inval2    = OpLoad %f32 %inloc2\n"
825 		"%rem       = OpFRem %f32 %inval1 %inval2\n"
826 		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
827 		"             OpStore %outloc %rem\n"
828 		"             OpReturn\n"
829 		"             OpFunctionEnd\n";
830 
831 	spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats1)));
832 	spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats2)));
833 	spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
834 	spec.numWorkGroups = IVec3(numElements, 1, 1);
835 	spec.verifyIO = &compareFRem;
836 
837 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "all", "", spec));
838 
839 	return group.release();
840 }
841 
842 // Copy contents in the input buffer to the output buffer.
createOpCopyMemoryGroup(tcu::TestContext & testCtx)843 tcu::TestCaseGroup* createOpCopyMemoryGroup (tcu::TestContext& testCtx)
844 {
845 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opcopymemory", "Test the OpCopyMemory instruction"));
846 	de::Random						rnd				(deStringHash(group->getName()));
847 	const int						numElements		= 100;
848 
849 	// The following case adds vec4(0., 0.5, 1.5, 2.5) to each of the elements in the input buffer and writes output to the output buffer.
850 	ComputeShaderSpec				spec1;
851 	vector<Vec4>					inputFloats1	(numElements);
852 	vector<Vec4>					outputFloats1	(numElements);
853 
854 	fillRandomScalars(rnd, -200.f, 200.f, &inputFloats1[0], numElements * 4);
855 
856 	// CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
857 	floorAll(inputFloats1);
858 
859 	for (size_t ndx = 0; ndx < numElements; ++ndx)
860 		outputFloats1[ndx] = inputFloats1[ndx] + Vec4(0.f, 0.5f, 1.5f, 2.5f);
861 
862 	spec1.assembly =
863 		string(s_ShaderPreamble) +
864 
865 		"OpName %main           \"main\"\n"
866 		"OpName %id             \"gl_GlobalInvocationID\"\n"
867 
868 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
869 		"OpDecorate %vec4arr ArrayStride 16\n"
870 
871 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
872 
873 		"%vec4       = OpTypeVector %f32 4\n"
874 		"%vec4ptr_u  = OpTypePointer Uniform %vec4\n"
875 		"%vec4ptr_f  = OpTypePointer Function %vec4\n"
876 		"%vec4arr    = OpTypeRuntimeArray %vec4\n"
877 		"%buf        = OpTypeStruct %vec4arr\n"
878 		"%bufptr     = OpTypePointer Uniform %buf\n"
879 		"%indata     = OpVariable %bufptr Uniform\n"
880 		"%outdata    = OpVariable %bufptr Uniform\n"
881 
882 		"%id         = OpVariable %uvec3ptr Input\n"
883 		"%zero       = OpConstant %i32 0\n"
884 		"%c_f_0      = OpConstant %f32 0.\n"
885 		"%c_f_0_5    = OpConstant %f32 0.5\n"
886 		"%c_f_1_5    = OpConstant %f32 1.5\n"
887 		"%c_f_2_5    = OpConstant %f32 2.5\n"
888 		"%c_vec4     = OpConstantComposite %vec4 %c_f_0 %c_f_0_5 %c_f_1_5 %c_f_2_5\n"
889 
890 		"%main       = OpFunction %void None %voidf\n"
891 		"%label      = OpLabel\n"
892 		"%v_vec4     = OpVariable %vec4ptr_f Function\n"
893 		"%idval      = OpLoad %uvec3 %id\n"
894 		"%x          = OpCompositeExtract %u32 %idval 0\n"
895 		"%inloc      = OpAccessChain %vec4ptr_u %indata %zero %x\n"
896 		"%outloc     = OpAccessChain %vec4ptr_u %outdata %zero %x\n"
897 		"              OpCopyMemory %v_vec4 %inloc\n"
898 		"%v_vec4_val = OpLoad %vec4 %v_vec4\n"
899 		"%add        = OpFAdd %vec4 %v_vec4_val %c_vec4\n"
900 		"              OpStore %outloc %add\n"
901 		"              OpReturn\n"
902 		"              OpFunctionEnd\n";
903 
904 	spec1.inputs.push_back(BufferSp(new Vec4Buffer(inputFloats1)));
905 	spec1.outputs.push_back(BufferSp(new Vec4Buffer(outputFloats1)));
906 	spec1.numWorkGroups = IVec3(numElements, 1, 1);
907 
908 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "vector", "OpCopyMemory elements of vector type", spec1));
909 
910 	// The following case copies a float[100] variable from the input buffer to the output buffer.
911 	ComputeShaderSpec				spec2;
912 	vector<float>					inputFloats2	(numElements);
913 	vector<float>					outputFloats2	(numElements);
914 
915 	fillRandomScalars(rnd, -200.f, 200.f, &inputFloats2[0], numElements);
916 
917 	for (size_t ndx = 0; ndx < numElements; ++ndx)
918 		outputFloats2[ndx] = inputFloats2[ndx];
919 
920 	spec2.assembly =
921 		string(s_ShaderPreamble) +
922 
923 		"OpName %main           \"main\"\n"
924 		"OpName %id             \"gl_GlobalInvocationID\"\n"
925 
926 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
927 		"OpDecorate %f32arr100 ArrayStride 4\n"
928 
929 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
930 
931 		"%hundred        = OpConstant %u32 100\n"
932 		"%f32arr100      = OpTypeArray %f32 %hundred\n"
933 		"%f32arr100ptr_f = OpTypePointer Function %f32arr100\n"
934 		"%f32arr100ptr_u = OpTypePointer Uniform %f32arr100\n"
935 		"%buf            = OpTypeStruct %f32arr100\n"
936 		"%bufptr         = OpTypePointer Uniform %buf\n"
937 		"%indata         = OpVariable %bufptr Uniform\n"
938 		"%outdata        = OpVariable %bufptr Uniform\n"
939 
940 		"%id             = OpVariable %uvec3ptr Input\n"
941 		"%zero           = OpConstant %i32 0\n"
942 
943 		"%main           = OpFunction %void None %voidf\n"
944 		"%label          = OpLabel\n"
945 		"%var            = OpVariable %f32arr100ptr_f Function\n"
946 		"%inarr          = OpAccessChain %f32arr100ptr_u %indata %zero\n"
947 		"%outarr         = OpAccessChain %f32arr100ptr_u %outdata %zero\n"
948 		"                  OpCopyMemory %var %inarr\n"
949 		"                  OpCopyMemory %outarr %var\n"
950 		"                  OpReturn\n"
951 		"                  OpFunctionEnd\n";
952 
953 	spec2.inputs.push_back(BufferSp(new Float32Buffer(inputFloats2)));
954 	spec2.outputs.push_back(BufferSp(new Float32Buffer(outputFloats2)));
955 	spec2.numWorkGroups = IVec3(1, 1, 1);
956 
957 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "array", "OpCopyMemory elements of array type", spec2));
958 
959 	// The following case copies a struct{vec4, vec4, vec4, vec4} variable from the input buffer to the output buffer.
960 	ComputeShaderSpec				spec3;
961 	vector<float>					inputFloats3	(16);
962 	vector<float>					outputFloats3	(16);
963 
964 	fillRandomScalars(rnd, -200.f, 200.f, &inputFloats3[0], 16);
965 
966 	for (size_t ndx = 0; ndx < 16; ++ndx)
967 		outputFloats3[ndx] = inputFloats3[ndx];
968 
969 	spec3.assembly =
970 		string(s_ShaderPreamble) +
971 
972 		"OpName %main           \"main\"\n"
973 		"OpName %id             \"gl_GlobalInvocationID\"\n"
974 
975 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
976 		"OpMemberDecorate %buf 0 Offset 0\n"
977 		"OpMemberDecorate %buf 1 Offset 16\n"
978 		"OpMemberDecorate %buf 2 Offset 32\n"
979 		"OpMemberDecorate %buf 3 Offset 48\n"
980 
981 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
982 
983 		"%vec4      = OpTypeVector %f32 4\n"
984 		"%buf       = OpTypeStruct %vec4 %vec4 %vec4 %vec4\n"
985 		"%bufptr    = OpTypePointer Uniform %buf\n"
986 		"%indata    = OpVariable %bufptr Uniform\n"
987 		"%outdata   = OpVariable %bufptr Uniform\n"
988 		"%vec4stptr = OpTypePointer Function %buf\n"
989 
990 		"%id        = OpVariable %uvec3ptr Input\n"
991 		"%zero      = OpConstant %i32 0\n"
992 
993 		"%main      = OpFunction %void None %voidf\n"
994 		"%label     = OpLabel\n"
995 		"%var       = OpVariable %vec4stptr Function\n"
996 		"             OpCopyMemory %var %indata\n"
997 		"             OpCopyMemory %outdata %var\n"
998 		"             OpReturn\n"
999 		"             OpFunctionEnd\n";
1000 
1001 	spec3.inputs.push_back(BufferSp(new Float32Buffer(inputFloats3)));
1002 	spec3.outputs.push_back(BufferSp(new Float32Buffer(outputFloats3)));
1003 	spec3.numWorkGroups = IVec3(1, 1, 1);
1004 
1005 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "struct", "OpCopyMemory elements of struct type", spec3));
1006 
1007 	// The following case negates multiple float variables from the input buffer and stores the results to the output buffer.
1008 	ComputeShaderSpec				spec4;
1009 	vector<float>					inputFloats4	(numElements);
1010 	vector<float>					outputFloats4	(numElements);
1011 
1012 	fillRandomScalars(rnd, -200.f, 200.f, &inputFloats4[0], numElements);
1013 
1014 	for (size_t ndx = 0; ndx < numElements; ++ndx)
1015 		outputFloats4[ndx] = -inputFloats4[ndx];
1016 
1017 	spec4.assembly =
1018 		string(s_ShaderPreamble) +
1019 
1020 		"OpName %main           \"main\"\n"
1021 		"OpName %id             \"gl_GlobalInvocationID\"\n"
1022 
1023 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1024 
1025 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
1026 
1027 		"%f32ptr_f  = OpTypePointer Function %f32\n"
1028 		"%id        = OpVariable %uvec3ptr Input\n"
1029 		"%zero      = OpConstant %i32 0\n"
1030 
1031 		"%main      = OpFunction %void None %voidf\n"
1032 		"%label     = OpLabel\n"
1033 		"%var       = OpVariable %f32ptr_f Function\n"
1034 		"%idval     = OpLoad %uvec3 %id\n"
1035 		"%x         = OpCompositeExtract %u32 %idval 0\n"
1036 		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
1037 		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
1038 		"             OpCopyMemory %var %inloc\n"
1039 		"%val       = OpLoad %f32 %var\n"
1040 		"%neg       = OpFNegate %f32 %val\n"
1041 		"             OpStore %outloc %neg\n"
1042 		"             OpReturn\n"
1043 		"             OpFunctionEnd\n";
1044 
1045 	spec4.inputs.push_back(BufferSp(new Float32Buffer(inputFloats4)));
1046 	spec4.outputs.push_back(BufferSp(new Float32Buffer(outputFloats4)));
1047 	spec4.numWorkGroups = IVec3(numElements, 1, 1);
1048 
1049 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "float", "OpCopyMemory elements of float type", spec4));
1050 
1051 	return group.release();
1052 }
1053 
createOpCopyObjectGroup(tcu::TestContext & testCtx)1054 tcu::TestCaseGroup* createOpCopyObjectGroup (tcu::TestContext& testCtx)
1055 {
1056 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opcopyobject", "Test the OpCopyObject instruction"));
1057 	ComputeShaderSpec				spec;
1058 	de::Random						rnd				(deStringHash(group->getName()));
1059 	const int						numElements		= 100;
1060 	vector<float>					inputFloats		(numElements, 0);
1061 	vector<float>					outputFloats	(numElements, 0);
1062 
1063 	fillRandomScalars(rnd, -200.f, 200.f, &inputFloats[0], numElements);
1064 
1065 	// CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
1066 	floorAll(inputFloats);
1067 
1068 	for (size_t ndx = 0; ndx < numElements; ++ndx)
1069 		outputFloats[ndx] = inputFloats[ndx] + 7.5f;
1070 
1071 	spec.assembly =
1072 		string(s_ShaderPreamble) +
1073 
1074 		"OpName %main           \"main\"\n"
1075 		"OpName %id             \"gl_GlobalInvocationID\"\n"
1076 
1077 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1078 
1079 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
1080 
1081 		"%fmat     = OpTypeMatrix %fvec3 3\n"
1082 		"%three    = OpConstant %u32 3\n"
1083 		"%farr     = OpTypeArray %f32 %three\n"
1084 		"%fst      = OpTypeStruct %f32 %f32\n"
1085 
1086 		+ string(s_InputOutputBuffer) +
1087 
1088 		"%id            = OpVariable %uvec3ptr Input\n"
1089 		"%zero          = OpConstant %i32 0\n"
1090 		"%c_f           = OpConstant %f32 1.5\n"
1091 		"%c_fvec3       = OpConstantComposite %fvec3 %c_f %c_f %c_f\n"
1092 		"%c_fmat        = OpConstantComposite %fmat %c_fvec3 %c_fvec3 %c_fvec3\n"
1093 		"%c_farr        = OpConstantComposite %farr %c_f %c_f %c_f\n"
1094 		"%c_fst         = OpConstantComposite %fst %c_f %c_f\n"
1095 
1096 		"%main          = OpFunction %void None %voidf\n"
1097 		"%label         = OpLabel\n"
1098 		"%c_f_copy      = OpCopyObject %f32   %c_f\n"
1099 		"%c_fvec3_copy  = OpCopyObject %fvec3 %c_fvec3\n"
1100 		"%c_fmat_copy   = OpCopyObject %fmat  %c_fmat\n"
1101 		"%c_farr_copy   = OpCopyObject %farr  %c_farr\n"
1102 		"%c_fst_copy    = OpCopyObject %fst   %c_fst\n"
1103 		"%fvec3_elem    = OpCompositeExtract %f32 %c_fvec3_copy 0\n"
1104 		"%fmat_elem     = OpCompositeExtract %f32 %c_fmat_copy 1 2\n"
1105 		"%farr_elem     = OpCompositeExtract %f32 %c_farr_copy 2\n"
1106 		"%fst_elem      = OpCompositeExtract %f32 %c_fst_copy 1\n"
1107 		// Add up. 1.5 * 5 = 7.5.
1108 		"%add1          = OpFAdd %f32 %c_f_copy %fvec3_elem\n"
1109 		"%add2          = OpFAdd %f32 %add1     %fmat_elem\n"
1110 		"%add3          = OpFAdd %f32 %add2     %farr_elem\n"
1111 		"%add4          = OpFAdd %f32 %add3     %fst_elem\n"
1112 
1113 		"%idval         = OpLoad %uvec3 %id\n"
1114 		"%x             = OpCompositeExtract %u32 %idval 0\n"
1115 		"%inloc         = OpAccessChain %f32ptr %indata %zero %x\n"
1116 		"%outloc        = OpAccessChain %f32ptr %outdata %zero %x\n"
1117 		"%inval         = OpLoad %f32 %inloc\n"
1118 		"%add           = OpFAdd %f32 %add4 %inval\n"
1119 		"                 OpStore %outloc %add\n"
1120 		"                 OpReturn\n"
1121 		"                 OpFunctionEnd\n";
1122 	spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
1123 	spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
1124 	spec.numWorkGroups = IVec3(numElements, 1, 1);
1125 
1126 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "spotcheck", "OpCopyObject on different types", spec));
1127 
1128 	return group.release();
1129 }
1130 // Assembly code used for testing OpUnreachable is based on GLSL source code:
1131 //
1132 // #version 430
1133 //
1134 // layout(std140, set = 0, binding = 0) readonly buffer Input {
1135 //   float elements[];
1136 // } input_data;
1137 // layout(std140, set = 0, binding = 1) writeonly buffer Output {
1138 //   float elements[];
1139 // } output_data;
1140 //
1141 // void not_called_func() {
1142 //   // place OpUnreachable here
1143 // }
1144 //
1145 // uint modulo4(uint val) {
1146 //   switch (val % uint(4)) {
1147 //     case 0:  return 3;
1148 //     case 1:  return 2;
1149 //     case 2:  return 1;
1150 //     case 3:  return 0;
1151 //     default: return 100; // place OpUnreachable here
1152 //   }
1153 // }
1154 //
1155 // uint const5() {
1156 //   return 5;
1157 //   // place OpUnreachable here
1158 // }
1159 //
1160 // void main() {
1161 //   uint x = gl_GlobalInvocationID.x;
1162 //   if (const5() > modulo4(1000)) {
1163 //     output_data.elements[x] = -input_data.elements[x];
1164 //   } else {
1165 //     // place OpUnreachable here
1166 //     output_data.elements[x] = input_data.elements[x];
1167 //   }
1168 // }
1169 
createOpUnreachableGroup(tcu::TestContext & testCtx)1170 tcu::TestCaseGroup* createOpUnreachableGroup (tcu::TestContext& testCtx)
1171 {
1172 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opunreachable", "Test the OpUnreachable instruction"));
1173 	ComputeShaderSpec				spec;
1174 	de::Random						rnd				(deStringHash(group->getName()));
1175 	const int						numElements		= 100;
1176 	vector<float>					positiveFloats	(numElements, 0);
1177 	vector<float>					negativeFloats	(numElements, 0);
1178 
1179 	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
1180 
1181 	for (size_t ndx = 0; ndx < numElements; ++ndx)
1182 		negativeFloats[ndx] = -positiveFloats[ndx];
1183 
1184 	spec.assembly =
1185 		string(s_ShaderPreamble) +
1186 
1187 		"OpSource GLSL 430\n"
1188 		"OpName %main            \"main\"\n"
1189 		"OpName %func_not_called_func \"not_called_func(\"\n"
1190 		"OpName %func_modulo4         \"modulo4(u1;\"\n"
1191 		"OpName %func_const5          \"const5(\"\n"
1192 		"OpName %id                   \"gl_GlobalInvocationID\"\n"
1193 
1194 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1195 
1196 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
1197 
1198 		"%u32ptr    = OpTypePointer Function %u32\n"
1199 		"%uintfuint = OpTypeFunction %u32 %u32ptr\n"
1200 		"%unitf     = OpTypeFunction %u32\n"
1201 
1202 		"%id        = OpVariable %uvec3ptr Input\n"
1203 		"%zero      = OpConstant %u32 0\n"
1204 		"%one       = OpConstant %u32 1\n"
1205 		"%two       = OpConstant %u32 2\n"
1206 		"%three     = OpConstant %u32 3\n"
1207 		"%four      = OpConstant %u32 4\n"
1208 		"%five      = OpConstant %u32 5\n"
1209 		"%hundred   = OpConstant %u32 100\n"
1210 		"%thousand  = OpConstant %u32 1000\n"
1211 
1212 		+ string(s_InputOutputBuffer) +
1213 
1214 		// Main()
1215 		"%main   = OpFunction %void None %voidf\n"
1216 		"%main_entry  = OpLabel\n"
1217 		"%v_thousand  = OpVariable %u32ptr Function %thousand\n"
1218 		"%idval       = OpLoad %uvec3 %id\n"
1219 		"%x           = OpCompositeExtract %u32 %idval 0\n"
1220 		"%inloc       = OpAccessChain %f32ptr %indata %zero %x\n"
1221 		"%inval       = OpLoad %f32 %inloc\n"
1222 		"%outloc      = OpAccessChain %f32ptr %outdata %zero %x\n"
1223 		"%ret_const5  = OpFunctionCall %u32 %func_const5\n"
1224 		"%ret_modulo4 = OpFunctionCall %u32 %func_modulo4 %v_thousand\n"
1225 		"%cmp_gt      = OpUGreaterThan %bool %ret_const5 %ret_modulo4\n"
1226 		"               OpSelectionMerge %if_end None\n"
1227 		"               OpBranchConditional %cmp_gt %if_true %if_false\n"
1228 		"%if_true     = OpLabel\n"
1229 		"%negate      = OpFNegate %f32 %inval\n"
1230 		"               OpStore %outloc %negate\n"
1231 		"               OpBranch %if_end\n"
1232 		"%if_false    = OpLabel\n"
1233 		"               OpUnreachable\n" // Unreachable else branch for if statement
1234 		"%if_end      = OpLabel\n"
1235 		"               OpReturn\n"
1236 		"               OpFunctionEnd\n"
1237 
1238 		// not_called_function()
1239 		"%func_not_called_func  = OpFunction %void None %voidf\n"
1240 		"%not_called_func_entry = OpLabel\n"
1241 		"                         OpUnreachable\n" // Unreachable entry block in not called static function
1242 		"                         OpFunctionEnd\n"
1243 
1244 		// modulo4()
1245 		"%func_modulo4  = OpFunction %u32 None %uintfuint\n"
1246 		"%valptr        = OpFunctionParameter %u32ptr\n"
1247 		"%modulo4_entry = OpLabel\n"
1248 		"%val           = OpLoad %u32 %valptr\n"
1249 		"%modulo        = OpUMod %u32 %val %four\n"
1250 		"                 OpSelectionMerge %switch_merge None\n"
1251 		"                 OpSwitch %modulo %default 0 %case0 1 %case1 2 %case2 3 %case3\n"
1252 		"%case0         = OpLabel\n"
1253 		"                 OpReturnValue %three\n"
1254 		"%case1         = OpLabel\n"
1255 		"                 OpReturnValue %two\n"
1256 		"%case2         = OpLabel\n"
1257 		"                 OpReturnValue %one\n"
1258 		"%case3         = OpLabel\n"
1259 		"                 OpReturnValue %zero\n"
1260 		"%default       = OpLabel\n"
1261 		"                 OpUnreachable\n" // Unreachable default case for switch statement
1262 		"%switch_merge  = OpLabel\n"
1263 		"                 OpUnreachable\n" // Unreachable merge block for switch statement
1264 		"                 OpFunctionEnd\n"
1265 
1266 		// const5()
1267 		"%func_const5  = OpFunction %u32 None %unitf\n"
1268 		"%const5_entry = OpLabel\n"
1269 		"                OpReturnValue %five\n"
1270 		"%unreachable  = OpLabel\n"
1271 		"                OpUnreachable\n" // Unreachable block in function
1272 		"                OpFunctionEnd\n";
1273 	spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
1274 	spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
1275 	spec.numWorkGroups = IVec3(numElements, 1, 1);
1276 
1277 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "all", "OpUnreachable appearing at different places", spec));
1278 
1279 	return group.release();
1280 }
1281 
1282 // Assembly code used for testing decoration group is based on GLSL source code:
1283 //
1284 // #version 430
1285 //
1286 // layout(std140, set = 0, binding = 0) readonly buffer Input0 {
1287 //   float elements[];
1288 // } input_data0;
1289 // layout(std140, set = 0, binding = 1) readonly buffer Input1 {
1290 //   float elements[];
1291 // } input_data1;
1292 // layout(std140, set = 0, binding = 2) readonly buffer Input2 {
1293 //   float elements[];
1294 // } input_data2;
1295 // layout(std140, set = 0, binding = 3) readonly buffer Input3 {
1296 //   float elements[];
1297 // } input_data3;
1298 // layout(std140, set = 0, binding = 4) readonly buffer Input4 {
1299 //   float elements[];
1300 // } input_data4;
1301 // layout(std140, set = 0, binding = 5) writeonly buffer Output {
1302 //   float elements[];
1303 // } output_data;
1304 //
1305 // void main() {
1306 //   uint x = gl_GlobalInvocationID.x;
1307 //   output_data.elements[x] = input_data0.elements[x] + input_data1.elements[x] + input_data2.elements[x] + input_data3.elements[x] + input_data4.elements[x];
1308 // }
createDecorationGroupGroup(tcu::TestContext & testCtx)1309 tcu::TestCaseGroup* createDecorationGroupGroup (tcu::TestContext& testCtx)
1310 {
1311 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "decoration_group", "Test the OpDecorationGroup & OpGroupDecorate instruction"));
1312 	ComputeShaderSpec				spec;
1313 	de::Random						rnd				(deStringHash(group->getName()));
1314 	const int						numElements		= 100;
1315 	vector<float>					inputFloats0	(numElements, 0);
1316 	vector<float>					inputFloats1	(numElements, 0);
1317 	vector<float>					inputFloats2	(numElements, 0);
1318 	vector<float>					inputFloats3	(numElements, 0);
1319 	vector<float>					inputFloats4	(numElements, 0);
1320 	vector<float>					outputFloats	(numElements, 0);
1321 
1322 	fillRandomScalars(rnd, -300.f, 300.f, &inputFloats0[0], numElements);
1323 	fillRandomScalars(rnd, -300.f, 300.f, &inputFloats1[0], numElements);
1324 	fillRandomScalars(rnd, -300.f, 300.f, &inputFloats2[0], numElements);
1325 	fillRandomScalars(rnd, -300.f, 300.f, &inputFloats3[0], numElements);
1326 	fillRandomScalars(rnd, -300.f, 300.f, &inputFloats4[0], numElements);
1327 
1328 	// CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
1329 	floorAll(inputFloats0);
1330 	floorAll(inputFloats1);
1331 	floorAll(inputFloats2);
1332 	floorAll(inputFloats3);
1333 	floorAll(inputFloats4);
1334 
1335 	for (size_t ndx = 0; ndx < numElements; ++ndx)
1336 		outputFloats[ndx] = inputFloats0[ndx] + inputFloats1[ndx] + inputFloats2[ndx] + inputFloats3[ndx] + inputFloats4[ndx];
1337 
1338 	spec.assembly =
1339 		string(s_ShaderPreamble) +
1340 
1341 		"OpSource GLSL 430\n"
1342 		"OpName %main \"main\"\n"
1343 		"OpName %id \"gl_GlobalInvocationID\"\n"
1344 
1345 		// Not using group decoration on variable.
1346 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1347 		// Not using group decoration on type.
1348 		"OpDecorate %f32arr ArrayStride 4\n"
1349 
1350 		"OpDecorate %groups BufferBlock\n"
1351 		"OpDecorate %groupm Offset 0\n"
1352 		"%groups = OpDecorationGroup\n"
1353 		"%groupm = OpDecorationGroup\n"
1354 
1355 		// Group decoration on multiple structs.
1356 		"OpGroupDecorate %groups %outbuf %inbuf0 %inbuf1 %inbuf2 %inbuf3 %inbuf4\n"
1357 		// Group decoration on multiple struct members.
1358 		"OpGroupMemberDecorate %groupm %outbuf 0 %inbuf0 0 %inbuf1 0 %inbuf2 0 %inbuf3 0 %inbuf4 0\n"
1359 
1360 		"OpDecorate %group1 DescriptorSet 0\n"
1361 		"OpDecorate %group3 DescriptorSet 0\n"
1362 		"OpDecorate %group3 NonWritable\n"
1363 		"OpDecorate %group3 Restrict\n"
1364 		"%group0 = OpDecorationGroup\n"
1365 		"%group1 = OpDecorationGroup\n"
1366 		"%group3 = OpDecorationGroup\n"
1367 
1368 		// Applying the same decoration group multiple times.
1369 		"OpGroupDecorate %group1 %outdata\n"
1370 		"OpGroupDecorate %group1 %outdata\n"
1371 		"OpGroupDecorate %group1 %outdata\n"
1372 		"OpDecorate %outdata DescriptorSet 0\n"
1373 		"OpDecorate %outdata Binding 5\n"
1374 		// Applying decoration group containing nothing.
1375 		"OpGroupDecorate %group0 %indata0\n"
1376 		"OpDecorate %indata0 DescriptorSet 0\n"
1377 		"OpDecorate %indata0 Binding 0\n"
1378 		// Applying decoration group containing one decoration.
1379 		"OpGroupDecorate %group1 %indata1\n"
1380 		"OpDecorate %indata1 Binding 1\n"
1381 		// Applying decoration group containing multiple decorations.
1382 		"OpGroupDecorate %group3 %indata2 %indata3\n"
1383 		"OpDecorate %indata2 Binding 2\n"
1384 		"OpDecorate %indata3 Binding 3\n"
1385 		// Applying multiple decoration groups (with overlapping).
1386 		"OpGroupDecorate %group0 %indata4\n"
1387 		"OpGroupDecorate %group1 %indata4\n"
1388 		"OpGroupDecorate %group3 %indata4\n"
1389 		"OpDecorate %indata4 Binding 4\n"
1390 
1391 		+ string(s_CommonTypes) +
1392 
1393 		"%id   = OpVariable %uvec3ptr Input\n"
1394 		"%zero = OpConstant %i32 0\n"
1395 
1396 		"%outbuf    = OpTypeStruct %f32arr\n"
1397 		"%outbufptr = OpTypePointer Uniform %outbuf\n"
1398 		"%outdata   = OpVariable %outbufptr Uniform\n"
1399 		"%inbuf0    = OpTypeStruct %f32arr\n"
1400 		"%inbuf0ptr = OpTypePointer Uniform %inbuf0\n"
1401 		"%indata0   = OpVariable %inbuf0ptr Uniform\n"
1402 		"%inbuf1    = OpTypeStruct %f32arr\n"
1403 		"%inbuf1ptr = OpTypePointer Uniform %inbuf1\n"
1404 		"%indata1   = OpVariable %inbuf1ptr Uniform\n"
1405 		"%inbuf2    = OpTypeStruct %f32arr\n"
1406 		"%inbuf2ptr = OpTypePointer Uniform %inbuf2\n"
1407 		"%indata2   = OpVariable %inbuf2ptr Uniform\n"
1408 		"%inbuf3    = OpTypeStruct %f32arr\n"
1409 		"%inbuf3ptr = OpTypePointer Uniform %inbuf3\n"
1410 		"%indata3   = OpVariable %inbuf3ptr Uniform\n"
1411 		"%inbuf4    = OpTypeStruct %f32arr\n"
1412 		"%inbufptr  = OpTypePointer Uniform %inbuf4\n"
1413 		"%indata4   = OpVariable %inbufptr Uniform\n"
1414 
1415 		"%main   = OpFunction %void None %voidf\n"
1416 		"%label  = OpLabel\n"
1417 		"%idval  = OpLoad %uvec3 %id\n"
1418 		"%x      = OpCompositeExtract %u32 %idval 0\n"
1419 		"%inloc0 = OpAccessChain %f32ptr %indata0 %zero %x\n"
1420 		"%inloc1 = OpAccessChain %f32ptr %indata1 %zero %x\n"
1421 		"%inloc2 = OpAccessChain %f32ptr %indata2 %zero %x\n"
1422 		"%inloc3 = OpAccessChain %f32ptr %indata3 %zero %x\n"
1423 		"%inloc4 = OpAccessChain %f32ptr %indata4 %zero %x\n"
1424 		"%outloc = OpAccessChain %f32ptr %outdata %zero %x\n"
1425 		"%inval0 = OpLoad %f32 %inloc0\n"
1426 		"%inval1 = OpLoad %f32 %inloc1\n"
1427 		"%inval2 = OpLoad %f32 %inloc2\n"
1428 		"%inval3 = OpLoad %f32 %inloc3\n"
1429 		"%inval4 = OpLoad %f32 %inloc4\n"
1430 		"%add0   = OpFAdd %f32 %inval0 %inval1\n"
1431 		"%add1   = OpFAdd %f32 %add0 %inval2\n"
1432 		"%add2   = OpFAdd %f32 %add1 %inval3\n"
1433 		"%add    = OpFAdd %f32 %add2 %inval4\n"
1434 		"          OpStore %outloc %add\n"
1435 		"          OpReturn\n"
1436 		"          OpFunctionEnd\n";
1437 	spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats0)));
1438 	spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats1)));
1439 	spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats2)));
1440 	spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats3)));
1441 	spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats4)));
1442 	spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
1443 	spec.numWorkGroups = IVec3(numElements, 1, 1);
1444 
1445 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "all", "decoration group cases", spec));
1446 
1447 	return group.release();
1448 }
1449 
1450 struct SpecConstantTwoIntCase
1451 {
1452 	const char*		caseName;
1453 	const char*		scDefinition0;
1454 	const char*		scDefinition1;
1455 	const char*		scResultType;
1456 	const char*		scOperation;
1457 	deInt32			scActualValue0;
1458 	deInt32			scActualValue1;
1459 	const char*		resultOperation;
1460 	vector<deInt32>	expectedOutput;
1461 
SpecConstantTwoIntCasevkt::SpirVAssembly::__anon889ef7250111::SpecConstantTwoIntCase1462 					SpecConstantTwoIntCase (const char* name,
1463 											const char* definition0,
1464 											const char* definition1,
1465 											const char* resultType,
1466 											const char* operation,
1467 											deInt32 value0,
1468 											deInt32 value1,
1469 											const char* resultOp,
1470 											const vector<deInt32>& output)
1471 						: caseName			(name)
1472 						, scDefinition0		(definition0)
1473 						, scDefinition1		(definition1)
1474 						, scResultType		(resultType)
1475 						, scOperation		(operation)
1476 						, scActualValue0	(value0)
1477 						, scActualValue1	(value1)
1478 						, resultOperation	(resultOp)
1479 						, expectedOutput	(output) {}
1480 };
1481 
createSpecConstantGroup(tcu::TestContext & testCtx)1482 tcu::TestCaseGroup* createSpecConstantGroup (tcu::TestContext& testCtx)
1483 {
1484 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opspecconstantop", "Test the OpSpecConstantOp instruction"));
1485 	vector<SpecConstantTwoIntCase>	cases;
1486 	de::Random						rnd				(deStringHash(group->getName()));
1487 	const int						numElements		= 100;
1488 	vector<deInt32>					inputInts		(numElements, 0);
1489 	vector<deInt32>					outputInts1		(numElements, 0);
1490 	vector<deInt32>					outputInts2		(numElements, 0);
1491 	vector<deInt32>					outputInts3		(numElements, 0);
1492 	vector<deInt32>					outputInts4		(numElements, 0);
1493 	const StringTemplate			shaderTemplate	(
1494 		string(s_ShaderPreamble) +
1495 
1496 		"OpName %main           \"main\"\n"
1497 		"OpName %id             \"gl_GlobalInvocationID\"\n"
1498 
1499 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1500 		"OpDecorate %sc_0  SpecId 0\n"
1501 		"OpDecorate %sc_1  SpecId 1\n"
1502 		"OpDecorate %i32arr ArrayStride 4\n"
1503 
1504 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
1505 
1506 		"%buf     = OpTypeStruct %i32arr\n"
1507 		"%bufptr  = OpTypePointer Uniform %buf\n"
1508 		"%indata    = OpVariable %bufptr Uniform\n"
1509 		"%outdata   = OpVariable %bufptr Uniform\n"
1510 
1511 		"%id        = OpVariable %uvec3ptr Input\n"
1512 		"%zero      = OpConstant %i32 0\n"
1513 
1514 		"%sc_0      = OpSpecConstant${SC_DEF0}\n"
1515 		"%sc_1      = OpSpecConstant${SC_DEF1}\n"
1516 		"%sc_final  = OpSpecConstantOp ${SC_RESULT_TYPE} ${SC_OP}\n"
1517 
1518 		"%main      = OpFunction %void None %voidf\n"
1519 		"%label     = OpLabel\n"
1520 		"%idval     = OpLoad %uvec3 %id\n"
1521 		"%x         = OpCompositeExtract %u32 %idval 0\n"
1522 		"%inloc     = OpAccessChain %i32ptr %indata %zero %x\n"
1523 		"%inval     = OpLoad %i32 %inloc\n"
1524 		"%final     = ${GEN_RESULT}\n"
1525 		"%outloc    = OpAccessChain %i32ptr %outdata %zero %x\n"
1526 		"             OpStore %outloc %final\n"
1527 		"             OpReturn\n"
1528 		"             OpFunctionEnd\n");
1529 
1530 	fillRandomScalars(rnd, -65536, 65536, &inputInts[0], numElements);
1531 
1532 	for (size_t ndx = 0; ndx < numElements; ++ndx)
1533 	{
1534 		outputInts1[ndx] = inputInts[ndx] + 42;
1535 		outputInts2[ndx] = inputInts[ndx];
1536 		outputInts3[ndx] = inputInts[ndx] - 11200;
1537 		outputInts4[ndx] = inputInts[ndx] + 1;
1538 	}
1539 
1540 	const char addScToInput[]		= "OpIAdd %i32 %inval %sc_final";
1541 	const char selectTrueUsingSc[]	= "OpSelect %i32 %sc_final %inval %zero";
1542 	const char selectFalseUsingSc[]	= "OpSelect %i32 %sc_final %zero %inval";
1543 
1544 	cases.push_back(SpecConstantTwoIntCase("iadd",					" %i32 0",		" %i32 0",		"%i32",		"IAdd                 %sc_0 %sc_1",			62,		-20,	addScToInput,		outputInts1));
1545 	cases.push_back(SpecConstantTwoIntCase("isub",					" %i32 0",		" %i32 0",		"%i32",		"ISub                 %sc_0 %sc_1",			100,	58,		addScToInput,		outputInts1));
1546 	cases.push_back(SpecConstantTwoIntCase("imul",					" %i32 0",		" %i32 0",		"%i32",		"IMul                 %sc_0 %sc_1",			-2,		-21,	addScToInput,		outputInts1));
1547 	cases.push_back(SpecConstantTwoIntCase("sdiv",					" %i32 0",		" %i32 0",		"%i32",		"SDiv                 %sc_0 %sc_1",			-126,	-3,		addScToInput,		outputInts1));
1548 	cases.push_back(SpecConstantTwoIntCase("udiv",					" %i32 0",		" %i32 0",		"%i32",		"UDiv                 %sc_0 %sc_1",			126,	3,		addScToInput,		outputInts1));
1549 	cases.push_back(SpecConstantTwoIntCase("srem",					" %i32 0",		" %i32 0",		"%i32",		"SRem                 %sc_0 %sc_1",			7,		3,		addScToInput,		outputInts4));
1550 	cases.push_back(SpecConstantTwoIntCase("smod",					" %i32 0",		" %i32 0",		"%i32",		"SMod                 %sc_0 %sc_1",			7,		3,		addScToInput,		outputInts4));
1551 	cases.push_back(SpecConstantTwoIntCase("umod",					" %i32 0",		" %i32 0",		"%i32",		"UMod                 %sc_0 %sc_1",			342,	50,		addScToInput,		outputInts1));
1552 	cases.push_back(SpecConstantTwoIntCase("bitwiseand",			" %i32 0",		" %i32 0",		"%i32",		"BitwiseAnd           %sc_0 %sc_1",			42,		63,		addScToInput,		outputInts1));
1553 	cases.push_back(SpecConstantTwoIntCase("bitwiseor",				" %i32 0",		" %i32 0",		"%i32",		"BitwiseOr            %sc_0 %sc_1",			34,		8,		addScToInput,		outputInts1));
1554 	cases.push_back(SpecConstantTwoIntCase("bitwisexor",			" %i32 0",		" %i32 0",		"%i32",		"BitwiseXor           %sc_0 %sc_1",			18,		56,		addScToInput,		outputInts1));
1555 	cases.push_back(SpecConstantTwoIntCase("shiftrightlogical",		" %i32 0",		" %i32 0",		"%i32",		"ShiftRightLogical    %sc_0 %sc_1",			168,	2,		addScToInput,		outputInts1));
1556 	cases.push_back(SpecConstantTwoIntCase("shiftrightarithmetic",	" %i32 0",		" %i32 0",		"%i32",		"ShiftRightArithmetic %sc_0 %sc_1",			168,	2,		addScToInput,		outputInts1));
1557 	cases.push_back(SpecConstantTwoIntCase("shiftleftlogical",		" %i32 0",		" %i32 0",		"%i32",		"ShiftLeftLogical     %sc_0 %sc_1",			21,		1,		addScToInput,		outputInts1));
1558 	cases.push_back(SpecConstantTwoIntCase("slessthan",				" %i32 0",		" %i32 0",		"%bool",	"SLessThan            %sc_0 %sc_1",			-20,	-10,	selectTrueUsingSc,	outputInts2));
1559 	cases.push_back(SpecConstantTwoIntCase("ulessthan",				" %i32 0",		" %i32 0",		"%bool",	"ULessThan            %sc_0 %sc_1",			10,		20,		selectTrueUsingSc,	outputInts2));
1560 	cases.push_back(SpecConstantTwoIntCase("sgreaterthan",			" %i32 0",		" %i32 0",		"%bool",	"SGreaterThan         %sc_0 %sc_1",			-1000,	50,		selectFalseUsingSc,	outputInts2));
1561 	cases.push_back(SpecConstantTwoIntCase("ugreaterthan",			" %i32 0",		" %i32 0",		"%bool",	"UGreaterThan         %sc_0 %sc_1",			10,		5,		selectTrueUsingSc,	outputInts2));
1562 	cases.push_back(SpecConstantTwoIntCase("slessthanequal",		" %i32 0",		" %i32 0",		"%bool",	"SLessThanEqual       %sc_0 %sc_1",			-10,	-10,	selectTrueUsingSc,	outputInts2));
1563 	cases.push_back(SpecConstantTwoIntCase("ulessthanequal",		" %i32 0",		" %i32 0",		"%bool",	"ULessThanEqual       %sc_0 %sc_1",			50,		100,	selectTrueUsingSc,	outputInts2));
1564 	cases.push_back(SpecConstantTwoIntCase("sgreaterthanequal",		" %i32 0",		" %i32 0",		"%bool",	"SGreaterThanEqual    %sc_0 %sc_1",			-1000,	50,		selectFalseUsingSc,	outputInts2));
1565 	cases.push_back(SpecConstantTwoIntCase("ugreaterthanequal",		" %i32 0",		" %i32 0",		"%bool",	"UGreaterThanEqual    %sc_0 %sc_1",			10,		10,		selectTrueUsingSc,	outputInts2));
1566 	cases.push_back(SpecConstantTwoIntCase("iequal",				" %i32 0",		" %i32 0",		"%bool",	"IEqual               %sc_0 %sc_1",			42,		24,		selectFalseUsingSc,	outputInts2));
1567 	cases.push_back(SpecConstantTwoIntCase("logicaland",			"True %bool",	"True %bool",	"%bool",	"LogicalAnd           %sc_0 %sc_1",			0,		1,		selectFalseUsingSc,	outputInts2));
1568 	cases.push_back(SpecConstantTwoIntCase("logicalor",				"False %bool",	"False %bool",	"%bool",	"LogicalOr            %sc_0 %sc_1",			1,		0,		selectTrueUsingSc,	outputInts2));
1569 	cases.push_back(SpecConstantTwoIntCase("logicalequal",			"True %bool",	"True %bool",	"%bool",	"LogicalEqual         %sc_0 %sc_1",			0,		1,		selectFalseUsingSc,	outputInts2));
1570 	cases.push_back(SpecConstantTwoIntCase("logicalnotequal",		"False %bool",	"False %bool",	"%bool",	"LogicalNotEqual      %sc_0 %sc_1",			1,		0,		selectTrueUsingSc,	outputInts2));
1571 	cases.push_back(SpecConstantTwoIntCase("snegate",				" %i32 0",		" %i32 0",		"%i32",		"SNegate              %sc_0",				-42,	0,		addScToInput,		outputInts1));
1572 	cases.push_back(SpecConstantTwoIntCase("not",					" %i32 0",		" %i32 0",		"%i32",		"Not                  %sc_0",				-43,	0,		addScToInput,		outputInts1));
1573 	cases.push_back(SpecConstantTwoIntCase("logicalnot",			"False %bool",	"False %bool",	"%bool",	"LogicalNot           %sc_0",				1,		0,		selectFalseUsingSc,	outputInts2));
1574 	cases.push_back(SpecConstantTwoIntCase("select",				"False %bool",	" %i32 0",		"%i32",		"Select               %sc_0 %sc_1 %zero",	1,		42,		addScToInput,		outputInts1));
1575 	// OpSConvert, OpFConvert: these two instructions involve ints/floats of different bitwidths.
1576 
1577 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
1578 	{
1579 		map<string, string>		specializations;
1580 		ComputeShaderSpec		spec;
1581 
1582 		specializations["SC_DEF0"]			= cases[caseNdx].scDefinition0;
1583 		specializations["SC_DEF1"]			= cases[caseNdx].scDefinition1;
1584 		specializations["SC_RESULT_TYPE"]	= cases[caseNdx].scResultType;
1585 		specializations["SC_OP"]			= cases[caseNdx].scOperation;
1586 		specializations["GEN_RESULT"]		= cases[caseNdx].resultOperation;
1587 
1588 		spec.assembly = shaderTemplate.specialize(specializations);
1589 		spec.inputs.push_back(BufferSp(new Int32Buffer(inputInts)));
1590 		spec.outputs.push_back(BufferSp(new Int32Buffer(cases[caseNdx].expectedOutput)));
1591 		spec.numWorkGroups = IVec3(numElements, 1, 1);
1592 		spec.specConstants.push_back(cases[caseNdx].scActualValue0);
1593 		spec.specConstants.push_back(cases[caseNdx].scActualValue1);
1594 
1595 		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].caseName, cases[caseNdx].caseName, spec));
1596 	}
1597 
1598 	ComputeShaderSpec				spec;
1599 
1600 	spec.assembly =
1601 		string(s_ShaderPreamble) +
1602 
1603 		"OpName %main           \"main\"\n"
1604 		"OpName %id             \"gl_GlobalInvocationID\"\n"
1605 
1606 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1607 		"OpDecorate %sc_0  SpecId 0\n"
1608 		"OpDecorate %sc_1  SpecId 1\n"
1609 		"OpDecorate %sc_2  SpecId 2\n"
1610 		"OpDecorate %i32arr ArrayStride 4\n"
1611 
1612 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
1613 
1614 		"%ivec3     = OpTypeVector %i32 3\n"
1615 		"%buf     = OpTypeStruct %i32arr\n"
1616 		"%bufptr  = OpTypePointer Uniform %buf\n"
1617 		"%indata    = OpVariable %bufptr Uniform\n"
1618 		"%outdata   = OpVariable %bufptr Uniform\n"
1619 
1620 		"%id        = OpVariable %uvec3ptr Input\n"
1621 		"%zero      = OpConstant %i32 0\n"
1622 		"%ivec3_0   = OpConstantComposite %ivec3 %zero %zero %zero\n"
1623 
1624 		"%sc_0        = OpSpecConstant %i32 0\n"
1625 		"%sc_1        = OpSpecConstant %i32 0\n"
1626 		"%sc_2        = OpSpecConstant %i32 0\n"
1627 		"%sc_vec3_0   = OpSpecConstantOp %ivec3 CompositeInsert  %sc_0        %ivec3_0   0\n"     // (sc_0, 0, 0)
1628 		"%sc_vec3_1   = OpSpecConstantOp %ivec3 CompositeInsert  %sc_1        %ivec3_0   1\n"     // (0, sc_1, 0)
1629 		"%sc_vec3_2   = OpSpecConstantOp %ivec3 CompositeInsert  %sc_2        %ivec3_0   2\n"     // (0, 0, sc_2)
1630 		"%sc_vec3_01  = OpSpecConstantOp %ivec3 VectorShuffle    %sc_vec3_0   %sc_vec3_1 1 0 4\n" // (0,    sc_0, sc_1)
1631 		"%sc_vec3_012 = OpSpecConstantOp %ivec3 VectorShuffle    %sc_vec3_01  %sc_vec3_2 5 1 2\n" // (sc_2, sc_0, sc_1)
1632 		"%sc_ext_0    = OpSpecConstantOp %i32   CompositeExtract %sc_vec3_012            0\n"     // sc_2
1633 		"%sc_ext_1    = OpSpecConstantOp %i32   CompositeExtract %sc_vec3_012            1\n"     // sc_0
1634 		"%sc_ext_2    = OpSpecConstantOp %i32   CompositeExtract %sc_vec3_012            2\n"     // sc_1
1635 		"%sc_sub      = OpSpecConstantOp %i32   ISub             %sc_ext_0    %sc_ext_1\n"        // (sc_2 - sc_0)
1636 		"%sc_final    = OpSpecConstantOp %i32   IMul             %sc_sub      %sc_ext_2\n"        // (sc_2 - sc_0) * sc_1
1637 
1638 		"%main      = OpFunction %void None %voidf\n"
1639 		"%label     = OpLabel\n"
1640 		"%idval     = OpLoad %uvec3 %id\n"
1641 		"%x         = OpCompositeExtract %u32 %idval 0\n"
1642 		"%inloc     = OpAccessChain %i32ptr %indata %zero %x\n"
1643 		"%inval     = OpLoad %i32 %inloc\n"
1644 		"%final     = OpIAdd %i32 %inval %sc_final\n"
1645 		"%outloc    = OpAccessChain %i32ptr %outdata %zero %x\n"
1646 		"             OpStore %outloc %final\n"
1647 		"             OpReturn\n"
1648 		"             OpFunctionEnd\n";
1649 	spec.inputs.push_back(BufferSp(new Int32Buffer(inputInts)));
1650 	spec.outputs.push_back(BufferSp(new Int32Buffer(outputInts3)));
1651 	spec.numWorkGroups = IVec3(numElements, 1, 1);
1652 	spec.specConstants.push_back(123);
1653 	spec.specConstants.push_back(56);
1654 	spec.specConstants.push_back(-77);
1655 
1656 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "vector_related", "VectorShuffle, CompositeExtract, & CompositeInsert", spec));
1657 
1658 	return group.release();
1659 }
1660 
createOpPhiGroup(tcu::TestContext & testCtx)1661 tcu::TestCaseGroup* createOpPhiGroup (tcu::TestContext& testCtx)
1662 {
1663 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opphi", "Test the OpPhi instruction"));
1664 	ComputeShaderSpec				spec1;
1665 	ComputeShaderSpec				spec2;
1666 	ComputeShaderSpec				spec3;
1667 	de::Random						rnd				(deStringHash(group->getName()));
1668 	const int						numElements		= 100;
1669 	vector<float>					inputFloats		(numElements, 0);
1670 	vector<float>					outputFloats1	(numElements, 0);
1671 	vector<float>					outputFloats2	(numElements, 0);
1672 	vector<float>					outputFloats3	(numElements, 0);
1673 
1674 	fillRandomScalars(rnd, -300.f, 300.f, &inputFloats[0], numElements);
1675 
1676 	// CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
1677 	floorAll(inputFloats);
1678 
1679 	for (size_t ndx = 0; ndx < numElements; ++ndx)
1680 	{
1681 		switch (ndx % 3)
1682 		{
1683 			case 0:		outputFloats1[ndx] = inputFloats[ndx] + 5.5f;	break;
1684 			case 1:		outputFloats1[ndx] = inputFloats[ndx] + 20.5f;	break;
1685 			case 2:		outputFloats1[ndx] = inputFloats[ndx] + 1.75f;	break;
1686 			default:	break;
1687 		}
1688 		outputFloats2[ndx] = inputFloats[ndx] + 6.5f * 3;
1689 		outputFloats3[ndx] = 8.5f - inputFloats[ndx];
1690 	}
1691 
1692 	spec1.assembly =
1693 		string(s_ShaderPreamble) +
1694 
1695 		"OpSource GLSL 430\n"
1696 		"OpName %main \"main\"\n"
1697 		"OpName %id \"gl_GlobalInvocationID\"\n"
1698 
1699 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1700 
1701 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
1702 
1703 		"%id = OpVariable %uvec3ptr Input\n"
1704 		"%zero       = OpConstant %i32 0\n"
1705 		"%three      = OpConstant %u32 3\n"
1706 		"%constf5p5  = OpConstant %f32 5.5\n"
1707 		"%constf20p5 = OpConstant %f32 20.5\n"
1708 		"%constf1p75 = OpConstant %f32 1.75\n"
1709 		"%constf8p5  = OpConstant %f32 8.5\n"
1710 		"%constf6p5  = OpConstant %f32 6.5\n"
1711 
1712 		"%main     = OpFunction %void None %voidf\n"
1713 		"%entry    = OpLabel\n"
1714 		"%idval    = OpLoad %uvec3 %id\n"
1715 		"%x        = OpCompositeExtract %u32 %idval 0\n"
1716 		"%selector = OpUMod %u32 %x %three\n"
1717 		"            OpSelectionMerge %phi None\n"
1718 		"            OpSwitch %selector %default 0 %case0 1 %case1 2 %case2\n"
1719 
1720 		// Case 1 before OpPhi.
1721 		"%case1    = OpLabel\n"
1722 		"            OpBranch %phi\n"
1723 
1724 		"%default  = OpLabel\n"
1725 		"            OpUnreachable\n"
1726 
1727 		"%phi      = OpLabel\n"
1728 		"%operand  = OpPhi %f32   %constf1p75 %case2   %constf20p5 %case1   %constf5p5 %case0\n" // not in the order of blocks
1729 		"%inloc    = OpAccessChain %f32ptr %indata %zero %x\n"
1730 		"%inval    = OpLoad %f32 %inloc\n"
1731 		"%add      = OpFAdd %f32 %inval %operand\n"
1732 		"%outloc   = OpAccessChain %f32ptr %outdata %zero %x\n"
1733 		"            OpStore %outloc %add\n"
1734 		"            OpReturn\n"
1735 
1736 		// Case 0 after OpPhi.
1737 		"%case0    = OpLabel\n"
1738 		"            OpBranch %phi\n"
1739 
1740 
1741 		// Case 2 after OpPhi.
1742 		"%case2    = OpLabel\n"
1743 		"            OpBranch %phi\n"
1744 
1745 		"            OpFunctionEnd\n";
1746 	spec1.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
1747 	spec1.outputs.push_back(BufferSp(new Float32Buffer(outputFloats1)));
1748 	spec1.numWorkGroups = IVec3(numElements, 1, 1);
1749 
1750 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "block", "out-of-order and unreachable blocks for OpPhi", spec1));
1751 
1752 	spec2.assembly =
1753 		string(s_ShaderPreamble) +
1754 
1755 		"OpName %main \"main\"\n"
1756 		"OpName %id \"gl_GlobalInvocationID\"\n"
1757 
1758 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1759 
1760 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
1761 
1762 		"%id         = OpVariable %uvec3ptr Input\n"
1763 		"%zero       = OpConstant %i32 0\n"
1764 		"%one        = OpConstant %i32 1\n"
1765 		"%three      = OpConstant %i32 3\n"
1766 		"%constf6p5  = OpConstant %f32 6.5\n"
1767 
1768 		"%main       = OpFunction %void None %voidf\n"
1769 		"%entry      = OpLabel\n"
1770 		"%idval      = OpLoad %uvec3 %id\n"
1771 		"%x          = OpCompositeExtract %u32 %idval 0\n"
1772 		"%inloc      = OpAccessChain %f32ptr %indata %zero %x\n"
1773 		"%outloc     = OpAccessChain %f32ptr %outdata %zero %x\n"
1774 		"%inval      = OpLoad %f32 %inloc\n"
1775 		"              OpBranch %phi\n"
1776 
1777 		"%phi        = OpLabel\n"
1778 		"%step       = OpPhi %i32 %zero  %entry %step_next  %phi\n"
1779 		"%accum      = OpPhi %f32 %inval %entry %accum_next %phi\n"
1780 		"%step_next  = OpIAdd %i32 %step %one\n"
1781 		"%accum_next = OpFAdd %f32 %accum %constf6p5\n"
1782 		"%still_loop = OpSLessThan %bool %step %three\n"
1783 		"              OpLoopMerge %exit %phi None\n"
1784 		"              OpBranchConditional %still_loop %phi %exit\n"
1785 
1786 		"%exit       = OpLabel\n"
1787 		"              OpStore %outloc %accum\n"
1788 		"              OpReturn\n"
1789 		"              OpFunctionEnd\n";
1790 	spec2.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
1791 	spec2.outputs.push_back(BufferSp(new Float32Buffer(outputFloats2)));
1792 	spec2.numWorkGroups = IVec3(numElements, 1, 1);
1793 
1794 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "induction", "The usual way induction variables are handled in LLVM IR", spec2));
1795 
1796 	spec3.assembly =
1797 		string(s_ShaderPreamble) +
1798 
1799 		"OpName %main \"main\"\n"
1800 		"OpName %id \"gl_GlobalInvocationID\"\n"
1801 
1802 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1803 
1804 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
1805 
1806 		"%f32ptr_f   = OpTypePointer Function %f32\n"
1807 		"%id         = OpVariable %uvec3ptr Input\n"
1808 		"%true       = OpConstantTrue %bool\n"
1809 		"%false      = OpConstantFalse %bool\n"
1810 		"%zero       = OpConstant %i32 0\n"
1811 		"%constf8p5  = OpConstant %f32 8.5\n"
1812 
1813 		"%main       = OpFunction %void None %voidf\n"
1814 		"%entry      = OpLabel\n"
1815 		"%b          = OpVariable %f32ptr_f Function %constf8p5\n"
1816 		"%idval      = OpLoad %uvec3 %id\n"
1817 		"%x          = OpCompositeExtract %u32 %idval 0\n"
1818 		"%inloc      = OpAccessChain %f32ptr %indata %zero %x\n"
1819 		"%outloc     = OpAccessChain %f32ptr %outdata %zero %x\n"
1820 		"%a_init     = OpLoad %f32 %inloc\n"
1821 		"%b_init     = OpLoad %f32 %b\n"
1822 		"              OpBranch %phi\n"
1823 
1824 		"%phi        = OpLabel\n"
1825 		"%still_loop = OpPhi %bool %true   %entry %false  %phi\n"
1826 		"%a_next     = OpPhi %f32  %a_init %entry %b_next %phi\n"
1827 		"%b_next     = OpPhi %f32  %b_init %entry %a_next %phi\n"
1828 		"              OpLoopMerge %exit %phi None\n"
1829 		"              OpBranchConditional %still_loop %phi %exit\n"
1830 
1831 		"%exit       = OpLabel\n"
1832 		"%sub        = OpFSub %f32 %a_next %b_next\n"
1833 		"              OpStore %outloc %sub\n"
1834 		"              OpReturn\n"
1835 		"              OpFunctionEnd\n";
1836 	spec3.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
1837 	spec3.outputs.push_back(BufferSp(new Float32Buffer(outputFloats3)));
1838 	spec3.numWorkGroups = IVec3(numElements, 1, 1);
1839 
1840 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "swap", "Swap the values of two variables using OpPhi", spec3));
1841 
1842 	return group.release();
1843 }
1844 
1845 // Assembly code used for testing block order is based on GLSL source code:
1846 //
1847 // #version 430
1848 //
1849 // layout(std140, set = 0, binding = 0) readonly buffer Input {
1850 //   float elements[];
1851 // } input_data;
1852 // layout(std140, set = 0, binding = 1) writeonly buffer Output {
1853 //   float elements[];
1854 // } output_data;
1855 //
1856 // void main() {
1857 //   uint x = gl_GlobalInvocationID.x;
1858 //   output_data.elements[x] = input_data.elements[x];
1859 //   if (x > uint(50)) {
1860 //     switch (x % uint(3)) {
1861 //       case 0: output_data.elements[x] += 1.5f; break;
1862 //       case 1: output_data.elements[x] += 42.f; break;
1863 //       case 2: output_data.elements[x] -= 27.f; break;
1864 //       default: break;
1865 //     }
1866 //   } else {
1867 //     output_data.elements[x] = -input_data.elements[x];
1868 //   }
1869 // }
createBlockOrderGroup(tcu::TestContext & testCtx)1870 tcu::TestCaseGroup* createBlockOrderGroup (tcu::TestContext& testCtx)
1871 {
1872 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "block_order", "Test block orders"));
1873 	ComputeShaderSpec				spec;
1874 	de::Random						rnd				(deStringHash(group->getName()));
1875 	const int						numElements		= 100;
1876 	vector<float>					inputFloats		(numElements, 0);
1877 	vector<float>					outputFloats	(numElements, 0);
1878 
1879 	fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
1880 
1881 	// CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
1882 	floorAll(inputFloats);
1883 
1884 	for (size_t ndx = 0; ndx <= 50; ++ndx)
1885 		outputFloats[ndx] = -inputFloats[ndx];
1886 
1887 	for (size_t ndx = 51; ndx < numElements; ++ndx)
1888 	{
1889 		switch (ndx % 3)
1890 		{
1891 			case 0:		outputFloats[ndx] = inputFloats[ndx] + 1.5f; break;
1892 			case 1:		outputFloats[ndx] = inputFloats[ndx] + 42.f; break;
1893 			case 2:		outputFloats[ndx] = inputFloats[ndx] - 27.f; break;
1894 			default:	break;
1895 		}
1896 	}
1897 
1898 	spec.assembly =
1899 		string(s_ShaderPreamble) +
1900 
1901 		"OpSource GLSL 430\n"
1902 		"OpName %main \"main\"\n"
1903 		"OpName %id \"gl_GlobalInvocationID\"\n"
1904 
1905 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
1906 
1907 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
1908 
1909 		"%u32ptr       = OpTypePointer Function %u32\n"
1910 		"%u32ptr_input = OpTypePointer Input %u32\n"
1911 
1912 		+ string(s_InputOutputBuffer) +
1913 
1914 		"%id        = OpVariable %uvec3ptr Input\n"
1915 		"%zero      = OpConstant %i32 0\n"
1916 		"%const3    = OpConstant %u32 3\n"
1917 		"%const50   = OpConstant %u32 50\n"
1918 		"%constf1p5 = OpConstant %f32 1.5\n"
1919 		"%constf27  = OpConstant %f32 27.0\n"
1920 		"%constf42  = OpConstant %f32 42.0\n"
1921 
1922 		"%main = OpFunction %void None %voidf\n"
1923 
1924 		// entry block.
1925 		"%entry    = OpLabel\n"
1926 
1927 		// Create a temporary variable to hold the value of gl_GlobalInvocationID.x.
1928 		"%xvar     = OpVariable %u32ptr Function\n"
1929 		"%xptr     = OpAccessChain %u32ptr_input %id %zero\n"
1930 		"%x        = OpLoad %u32 %xptr\n"
1931 		"            OpStore %xvar %x\n"
1932 
1933 		"%cmp      = OpUGreaterThan %bool %x %const50\n"
1934 		"            OpSelectionMerge %if_merge None\n"
1935 		"            OpBranchConditional %cmp %if_true %if_false\n"
1936 
1937 		// False branch for if-statement: placed in the middle of switch cases and before true branch.
1938 		"%if_false = OpLabel\n"
1939 		"%x_f      = OpLoad %u32 %xvar\n"
1940 		"%inloc_f  = OpAccessChain %f32ptr %indata %zero %x_f\n"
1941 		"%inval_f  = OpLoad %f32 %inloc_f\n"
1942 		"%negate   = OpFNegate %f32 %inval_f\n"
1943 		"%outloc_f = OpAccessChain %f32ptr %outdata %zero %x_f\n"
1944 		"            OpStore %outloc_f %negate\n"
1945 		"            OpBranch %if_merge\n"
1946 
1947 		// Merge block for if-statement: placed in the middle of true and false branch.
1948 		"%if_merge = OpLabel\n"
1949 		"            OpReturn\n"
1950 
1951 		// True branch for if-statement: placed in the middle of swtich cases and after the false branch.
1952 		"%if_true  = OpLabel\n"
1953 		"%xval_t   = OpLoad %u32 %xvar\n"
1954 		"%mod      = OpUMod %u32 %xval_t %const3\n"
1955 		"            OpSelectionMerge %switch_merge None\n"
1956 		"            OpSwitch %mod %default 0 %case0 1 %case1 2 %case2\n"
1957 
1958 		// Merge block for switch-statement: placed before the case
1959                 // bodies.  But it must follow OpSwitch which dominates it.
1960 		"%switch_merge = OpLabel\n"
1961 		"                OpBranch %if_merge\n"
1962 
1963 		// Case 1 for switch-statement: placed before case 0.
1964                 // It must follow the OpSwitch that dominates it.
1965 		"%case1    = OpLabel\n"
1966 		"%x_1      = OpLoad %u32 %xvar\n"
1967 		"%inloc_1  = OpAccessChain %f32ptr %indata %zero %x_1\n"
1968 		"%inval_1  = OpLoad %f32 %inloc_1\n"
1969 		"%addf42   = OpFAdd %f32 %inval_1 %constf42\n"
1970 		"%outloc_1 = OpAccessChain %f32ptr %outdata %zero %x_1\n"
1971 		"            OpStore %outloc_1 %addf42\n"
1972 		"            OpBranch %switch_merge\n"
1973 
1974 		// Case 2 for switch-statement.
1975 		"%case2    = OpLabel\n"
1976 		"%x_2      = OpLoad %u32 %xvar\n"
1977 		"%inloc_2  = OpAccessChain %f32ptr %indata %zero %x_2\n"
1978 		"%inval_2  = OpLoad %f32 %inloc_2\n"
1979 		"%subf27   = OpFSub %f32 %inval_2 %constf27\n"
1980 		"%outloc_2 = OpAccessChain %f32ptr %outdata %zero %x_2\n"
1981 		"            OpStore %outloc_2 %subf27\n"
1982 		"            OpBranch %switch_merge\n"
1983 
1984 		// Default case for switch-statement: placed in the middle of normal cases.
1985 		"%default = OpLabel\n"
1986 		"           OpBranch %switch_merge\n"
1987 
1988 		// Case 0 for switch-statement: out of order.
1989 		"%case0    = OpLabel\n"
1990 		"%x_0      = OpLoad %u32 %xvar\n"
1991 		"%inloc_0  = OpAccessChain %f32ptr %indata %zero %x_0\n"
1992 		"%inval_0  = OpLoad %f32 %inloc_0\n"
1993 		"%addf1p5  = OpFAdd %f32 %inval_0 %constf1p5\n"
1994 		"%outloc_0 = OpAccessChain %f32ptr %outdata %zero %x_0\n"
1995 		"            OpStore %outloc_0 %addf1p5\n"
1996 		"            OpBranch %switch_merge\n"
1997 
1998 		"            OpFunctionEnd\n";
1999 	spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
2000 	spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
2001 	spec.numWorkGroups = IVec3(numElements, 1, 1);
2002 
2003 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "all", "various out-of-order blocks", spec));
2004 
2005 	return group.release();
2006 }
2007 
createMultipleShaderGroup(tcu::TestContext & testCtx)2008 tcu::TestCaseGroup* createMultipleShaderGroup (tcu::TestContext& testCtx)
2009 {
2010 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "multiple_shaders", "Test multiple shaders in the same module"));
2011 	ComputeShaderSpec				spec1;
2012 	ComputeShaderSpec				spec2;
2013 	de::Random						rnd				(deStringHash(group->getName()));
2014 	const int						numElements		= 100;
2015 	vector<float>					inputFloats		(numElements, 0);
2016 	vector<float>					outputFloats1	(numElements, 0);
2017 	vector<float>					outputFloats2	(numElements, 0);
2018 	fillRandomScalars(rnd, -500.f, 500.f, &inputFloats[0], numElements);
2019 
2020 	for (size_t ndx = 0; ndx < numElements; ++ndx)
2021 	{
2022 		outputFloats1[ndx] = inputFloats[ndx] + inputFloats[ndx];
2023 		outputFloats2[ndx] = -inputFloats[ndx];
2024 	}
2025 
2026 	const string assembly(
2027 		"OpCapability Shader\n"
2028 		"OpCapability ClipDistance\n"
2029 		"OpMemoryModel Logical GLSL450\n"
2030 		"OpEntryPoint GLCompute %comp_main1 \"entrypoint1\" %id\n"
2031 		"OpEntryPoint GLCompute %comp_main2 \"entrypoint2\" %id\n"
2032 		// A module cannot have two OpEntryPoint instructions with the same Execution Model and the same Name string.
2033 		"OpEntryPoint Vertex    %vert_main  \"entrypoint2\" %vert_builtins %vertexIndex %instanceIndex\n"
2034 		"OpExecutionMode %comp_main1 LocalSize 1 1 1\n"
2035 		"OpExecutionMode %comp_main2 LocalSize 1 1 1\n"
2036 
2037 		"OpName %comp_main1              \"entrypoint1\"\n"
2038 		"OpName %comp_main2              \"entrypoint2\"\n"
2039 		"OpName %vert_main               \"entrypoint2\"\n"
2040 		"OpName %id                      \"gl_GlobalInvocationID\"\n"
2041 		"OpName %vert_builtin_st         \"gl_PerVertex\"\n"
2042 		"OpName %vertexIndex             \"gl_VertexIndex\"\n"
2043 		"OpName %instanceIndex           \"gl_InstanceIndex\"\n"
2044 		"OpMemberName %vert_builtin_st 0 \"gl_Position\"\n"
2045 		"OpMemberName %vert_builtin_st 1 \"gl_PointSize\"\n"
2046 		"OpMemberName %vert_builtin_st 2 \"gl_ClipDistance\"\n"
2047 
2048 		"OpDecorate %id                      BuiltIn GlobalInvocationId\n"
2049 		"OpDecorate %vertexIndex             BuiltIn VertexIndex\n"
2050 		"OpDecorate %instanceIndex           BuiltIn InstanceIndex\n"
2051 		"OpDecorate %vert_builtin_st         Block\n"
2052 		"OpMemberDecorate %vert_builtin_st 0 BuiltIn Position\n"
2053 		"OpMemberDecorate %vert_builtin_st 1 BuiltIn PointSize\n"
2054 		"OpMemberDecorate %vert_builtin_st 2 BuiltIn ClipDistance\n"
2055 
2056 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
2057 
2058 		"%zero       = OpConstant %i32 0\n"
2059 		"%one        = OpConstant %u32 1\n"
2060 		"%c_f32_1    = OpConstant %f32 1\n"
2061 
2062 		"%i32inputptr         = OpTypePointer Input %i32\n"
2063 		"%vec4                = OpTypeVector %f32 4\n"
2064 		"%vec4ptr             = OpTypePointer Output %vec4\n"
2065 		"%f32arr1             = OpTypeArray %f32 %one\n"
2066 		"%vert_builtin_st     = OpTypeStruct %vec4 %f32 %f32arr1\n"
2067 		"%vert_builtin_st_ptr = OpTypePointer Output %vert_builtin_st\n"
2068 		"%vert_builtins       = OpVariable %vert_builtin_st_ptr Output\n"
2069 
2070 		"%id         = OpVariable %uvec3ptr Input\n"
2071 		"%vertexIndex = OpVariable %i32inputptr Input\n"
2072 		"%instanceIndex = OpVariable %i32inputptr Input\n"
2073 		"%c_vec4_1   = OpConstantComposite %vec4 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_1\n"
2074 
2075 		// gl_Position = vec4(1.);
2076 		"%vert_main  = OpFunction %void None %voidf\n"
2077 		"%vert_entry = OpLabel\n"
2078 		"%position   = OpAccessChain %vec4ptr %vert_builtins %zero\n"
2079 		"              OpStore %position %c_vec4_1\n"
2080 		"              OpReturn\n"
2081 		"              OpFunctionEnd\n"
2082 
2083 		// Double inputs.
2084 		"%comp_main1  = OpFunction %void None %voidf\n"
2085 		"%comp1_entry = OpLabel\n"
2086 		"%idval1      = OpLoad %uvec3 %id\n"
2087 		"%x1          = OpCompositeExtract %u32 %idval1 0\n"
2088 		"%inloc1      = OpAccessChain %f32ptr %indata %zero %x1\n"
2089 		"%inval1      = OpLoad %f32 %inloc1\n"
2090 		"%add         = OpFAdd %f32 %inval1 %inval1\n"
2091 		"%outloc1     = OpAccessChain %f32ptr %outdata %zero %x1\n"
2092 		"               OpStore %outloc1 %add\n"
2093 		"               OpReturn\n"
2094 		"               OpFunctionEnd\n"
2095 
2096 		// Negate inputs.
2097 		"%comp_main2  = OpFunction %void None %voidf\n"
2098 		"%comp2_entry = OpLabel\n"
2099 		"%idval2      = OpLoad %uvec3 %id\n"
2100 		"%x2          = OpCompositeExtract %u32 %idval2 0\n"
2101 		"%inloc2      = OpAccessChain %f32ptr %indata %zero %x2\n"
2102 		"%inval2      = OpLoad %f32 %inloc2\n"
2103 		"%neg         = OpFNegate %f32 %inval2\n"
2104 		"%outloc2     = OpAccessChain %f32ptr %outdata %zero %x2\n"
2105 		"               OpStore %outloc2 %neg\n"
2106 		"               OpReturn\n"
2107 		"               OpFunctionEnd\n");
2108 
2109 	spec1.assembly = assembly;
2110 	spec1.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
2111 	spec1.outputs.push_back(BufferSp(new Float32Buffer(outputFloats1)));
2112 	spec1.numWorkGroups = IVec3(numElements, 1, 1);
2113 	spec1.entryPoint = "entrypoint1";
2114 
2115 	spec2.assembly = assembly;
2116 	spec2.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
2117 	spec2.outputs.push_back(BufferSp(new Float32Buffer(outputFloats2)));
2118 	spec2.numWorkGroups = IVec3(numElements, 1, 1);
2119 	spec2.entryPoint = "entrypoint2";
2120 
2121 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "shader1", "multiple shaders in the same module", spec1));
2122 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "shader2", "multiple shaders in the same module", spec2));
2123 
2124 	return group.release();
2125 }
2126 
makeLongUTF8String(size_t num4ByteChars)2127 inline std::string makeLongUTF8String (size_t num4ByteChars)
2128 {
2129 	// An example of a longest valid UTF-8 character.  Be explicit about the
2130 	// character type because Microsoft compilers can otherwise interpret the
2131 	// character string as being over wide (16-bit) characters. Ideally, we
2132 	// would just use a C++11 UTF-8 string literal, but we want to support older
2133 	// Microsoft compilers.
2134 	const std::basic_string<char> earthAfrica("\xF0\x9F\x8C\x8D");
2135 	std::string longString;
2136 	longString.reserve(num4ByteChars * 4);
2137 	for (size_t count = 0; count < num4ByteChars; count++)
2138 	{
2139 		longString += earthAfrica;
2140 	}
2141 	return longString;
2142 }
2143 
createOpSourceGroup(tcu::TestContext & testCtx)2144 tcu::TestCaseGroup* createOpSourceGroup (tcu::TestContext& testCtx)
2145 {
2146 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opsource", "Tests the OpSource & OpSourceContinued instruction"));
2147 	vector<CaseParameter>			cases;
2148 	de::Random						rnd				(deStringHash(group->getName()));
2149 	const int						numElements		= 100;
2150 	vector<float>					positiveFloats	(numElements, 0);
2151 	vector<float>					negativeFloats	(numElements, 0);
2152 	const StringTemplate			shaderTemplate	(
2153 		"OpCapability Shader\n"
2154 		"OpMemoryModel Logical GLSL450\n"
2155 
2156 		"OpEntryPoint GLCompute %main \"main\" %id\n"
2157 		"OpExecutionMode %main LocalSize 1 1 1\n"
2158 
2159 		"${SOURCE}\n"
2160 
2161 		"OpName %main           \"main\"\n"
2162 		"OpName %id             \"gl_GlobalInvocationID\"\n"
2163 
2164 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
2165 
2166 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
2167 
2168 		"%id        = OpVariable %uvec3ptr Input\n"
2169 		"%zero      = OpConstant %i32 0\n"
2170 
2171 		"%main      = OpFunction %void None %voidf\n"
2172 		"%label     = OpLabel\n"
2173 		"%idval     = OpLoad %uvec3 %id\n"
2174 		"%x         = OpCompositeExtract %u32 %idval 0\n"
2175 		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
2176 		"%inval     = OpLoad %f32 %inloc\n"
2177 		"%neg       = OpFNegate %f32 %inval\n"
2178 		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
2179 		"             OpStore %outloc %neg\n"
2180 		"             OpReturn\n"
2181 		"             OpFunctionEnd\n");
2182 
2183 	cases.push_back(CaseParameter("unknown_source",							"OpSource Unknown 0"));
2184 	cases.push_back(CaseParameter("wrong_source",							"OpSource OpenCL_C 210"));
2185 	cases.push_back(CaseParameter("normal_filename",						"%fname = OpString \"filename\"\n"
2186 																			"OpSource GLSL 430 %fname"));
2187 	cases.push_back(CaseParameter("empty_filename",							"%fname = OpString \"\"\n"
2188 																			"OpSource GLSL 430 %fname"));
2189 	cases.push_back(CaseParameter("normal_source_code",						"%fname = OpString \"filename\"\n"
2190 																			"OpSource GLSL 430 %fname \"#version 430\nvoid main() {}\""));
2191 	cases.push_back(CaseParameter("empty_source_code",						"%fname = OpString \"filename\"\n"
2192 																			"OpSource GLSL 430 %fname \"\""));
2193 	cases.push_back(CaseParameter("long_source_code",						"%fname = OpString \"filename\"\n"
2194 																			"OpSource GLSL 430 %fname \"" + makeLongUTF8String(65530) + "ccc\"")); // word count: 65535
2195 	cases.push_back(CaseParameter("utf8_source_code",						"%fname = OpString \"filename\"\n"
2196 																			"OpSource GLSL 430 %fname \"\xE2\x98\x82\xE2\x98\x85\"")); // umbrella & black star symbol
2197 	cases.push_back(CaseParameter("normal_sourcecontinued",					"%fname = OpString \"filename\"\n"
2198 																			"OpSource GLSL 430 %fname \"#version 430\nvo\"\n"
2199 																			"OpSourceContinued \"id main() {}\""));
2200 	cases.push_back(CaseParameter("empty_sourcecontinued",					"%fname = OpString \"filename\"\n"
2201 																			"OpSource GLSL 430 %fname \"#version 430\nvoid main() {}\"\n"
2202 																			"OpSourceContinued \"\""));
2203 	cases.push_back(CaseParameter("long_sourcecontinued",					"%fname = OpString \"filename\"\n"
2204 																			"OpSource GLSL 430 %fname \"#version 430\nvoid main() {}\"\n"
2205 																			"OpSourceContinued \"" + makeLongUTF8String(65533) + "ccc\"")); // word count: 65535
2206 	cases.push_back(CaseParameter("utf8_sourcecontinued",					"%fname = OpString \"filename\"\n"
2207 																			"OpSource GLSL 430 %fname \"#version 430\nvoid main() {}\"\n"
2208 																			"OpSourceContinued \"\xE2\x98\x8E\xE2\x9A\x91\"")); // white telephone & black flag symbol
2209 	cases.push_back(CaseParameter("multi_sourcecontinued",					"%fname = OpString \"filename\"\n"
2210 																			"OpSource GLSL 430 %fname \"#version 430\n\"\n"
2211 																			"OpSourceContinued \"void\"\n"
2212 																			"OpSourceContinued \"main()\"\n"
2213 																			"OpSourceContinued \"{}\""));
2214 	cases.push_back(CaseParameter("empty_source_before_sourcecontinued",	"%fname = OpString \"filename\"\n"
2215 																			"OpSource GLSL 430 %fname \"\"\n"
2216 																			"OpSourceContinued \"#version 430\nvoid main() {}\""));
2217 
2218 	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
2219 
2220 	for (size_t ndx = 0; ndx < numElements; ++ndx)
2221 		negativeFloats[ndx] = -positiveFloats[ndx];
2222 
2223 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
2224 	{
2225 		map<string, string>		specializations;
2226 		ComputeShaderSpec		spec;
2227 
2228 		specializations["SOURCE"] = cases[caseNdx].param;
2229 		spec.assembly = shaderTemplate.specialize(specializations);
2230 		spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
2231 		spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
2232 		spec.numWorkGroups = IVec3(numElements, 1, 1);
2233 
2234 		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
2235 	}
2236 
2237 	return group.release();
2238 }
2239 
createOpSourceExtensionGroup(tcu::TestContext & testCtx)2240 tcu::TestCaseGroup* createOpSourceExtensionGroup (tcu::TestContext& testCtx)
2241 {
2242 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opsourceextension", "Tests the OpSource instruction"));
2243 	vector<CaseParameter>			cases;
2244 	de::Random						rnd				(deStringHash(group->getName()));
2245 	const int						numElements		= 100;
2246 	vector<float>					inputFloats		(numElements, 0);
2247 	vector<float>					outputFloats	(numElements, 0);
2248 	const StringTemplate			shaderTemplate	(
2249 		string(s_ShaderPreamble) +
2250 
2251 		"OpSourceExtension \"${EXTENSION}\"\n"
2252 
2253 		"OpName %main           \"main\"\n"
2254 		"OpName %id             \"gl_GlobalInvocationID\"\n"
2255 
2256 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
2257 
2258 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
2259 
2260 		"%id        = OpVariable %uvec3ptr Input\n"
2261 		"%zero      = OpConstant %i32 0\n"
2262 
2263 		"%main      = OpFunction %void None %voidf\n"
2264 		"%label     = OpLabel\n"
2265 		"%idval     = OpLoad %uvec3 %id\n"
2266 		"%x         = OpCompositeExtract %u32 %idval 0\n"
2267 		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
2268 		"%inval     = OpLoad %f32 %inloc\n"
2269 		"%neg       = OpFNegate %f32 %inval\n"
2270 		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
2271 		"             OpStore %outloc %neg\n"
2272 		"             OpReturn\n"
2273 		"             OpFunctionEnd\n");
2274 
2275 	cases.push_back(CaseParameter("empty_extension",	""));
2276 	cases.push_back(CaseParameter("real_extension",		"GL_ARB_texture_rectangle"));
2277 	cases.push_back(CaseParameter("fake_extension",		"GL_ARB_im_the_ultimate_extension"));
2278 	cases.push_back(CaseParameter("utf8_extension",		"GL_ARB_\xE2\x98\x82\xE2\x98\x85"));
2279 	cases.push_back(CaseParameter("long_extension",		makeLongUTF8String(65533) + "ccc")); // word count: 65535
2280 
2281 	fillRandomScalars(rnd, -200.f, 200.f, &inputFloats[0], numElements);
2282 
2283 	for (size_t ndx = 0; ndx < numElements; ++ndx)
2284 		outputFloats[ndx] = -inputFloats[ndx];
2285 
2286 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
2287 	{
2288 		map<string, string>		specializations;
2289 		ComputeShaderSpec		spec;
2290 
2291 		specializations["EXTENSION"] = cases[caseNdx].param;
2292 		spec.assembly = shaderTemplate.specialize(specializations);
2293 		spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
2294 		spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
2295 		spec.numWorkGroups = IVec3(numElements, 1, 1);
2296 
2297 		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
2298 	}
2299 
2300 	return group.release();
2301 }
2302 
2303 // Checks that a compute shader can generate a constant null value of various types, without exercising a computation on it.
createOpConstantNullGroup(tcu::TestContext & testCtx)2304 tcu::TestCaseGroup* createOpConstantNullGroup (tcu::TestContext& testCtx)
2305 {
2306 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opconstantnull", "Tests the OpConstantNull instruction"));
2307 	vector<CaseParameter>			cases;
2308 	de::Random						rnd				(deStringHash(group->getName()));
2309 	const int						numElements		= 100;
2310 	vector<float>					positiveFloats	(numElements, 0);
2311 	vector<float>					negativeFloats	(numElements, 0);
2312 	const StringTemplate			shaderTemplate	(
2313 		string(s_ShaderPreamble) +
2314 
2315 		"OpSource GLSL 430\n"
2316 		"OpName %main           \"main\"\n"
2317 		"OpName %id             \"gl_GlobalInvocationID\"\n"
2318 
2319 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
2320 
2321 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
2322 		"%uvec2     = OpTypeVector %u32 2\n"
2323 		"%bvec3     = OpTypeVector %bool 3\n"
2324 		"%fvec4     = OpTypeVector %f32 4\n"
2325 		"%fmat33    = OpTypeMatrix %fvec3 3\n"
2326 		"%const100  = OpConstant %u32 100\n"
2327 		"%uarr100   = OpTypeArray %i32 %const100\n"
2328 		"%struct    = OpTypeStruct %f32 %i32 %u32\n"
2329 		"%pointer   = OpTypePointer Function %i32\n"
2330 		+ string(s_InputOutputBuffer) +
2331 
2332 		"%null      = OpConstantNull ${TYPE}\n"
2333 
2334 		"%id        = OpVariable %uvec3ptr Input\n"
2335 		"%zero      = OpConstant %i32 0\n"
2336 
2337 		"%main      = OpFunction %void None %voidf\n"
2338 		"%label     = OpLabel\n"
2339 		"%idval     = OpLoad %uvec3 %id\n"
2340 		"%x         = OpCompositeExtract %u32 %idval 0\n"
2341 		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
2342 		"%inval     = OpLoad %f32 %inloc\n"
2343 		"%neg       = OpFNegate %f32 %inval\n"
2344 		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
2345 		"             OpStore %outloc %neg\n"
2346 		"             OpReturn\n"
2347 		"             OpFunctionEnd\n");
2348 
2349 	cases.push_back(CaseParameter("bool",			"%bool"));
2350 	cases.push_back(CaseParameter("sint32",			"%i32"));
2351 	cases.push_back(CaseParameter("uint32",			"%u32"));
2352 	cases.push_back(CaseParameter("float32",		"%f32"));
2353 	cases.push_back(CaseParameter("vec4float32",	"%fvec4"));
2354 	cases.push_back(CaseParameter("vec3bool",		"%bvec3"));
2355 	cases.push_back(CaseParameter("vec2uint32",		"%uvec2"));
2356 	cases.push_back(CaseParameter("matrix",			"%fmat33"));
2357 	cases.push_back(CaseParameter("array",			"%uarr100"));
2358 	cases.push_back(CaseParameter("struct",			"%struct"));
2359 	cases.push_back(CaseParameter("pointer",		"%pointer"));
2360 
2361 	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
2362 
2363 	for (size_t ndx = 0; ndx < numElements; ++ndx)
2364 		negativeFloats[ndx] = -positiveFloats[ndx];
2365 
2366 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
2367 	{
2368 		map<string, string>		specializations;
2369 		ComputeShaderSpec		spec;
2370 
2371 		specializations["TYPE"] = cases[caseNdx].param;
2372 		spec.assembly = shaderTemplate.specialize(specializations);
2373 		spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
2374 		spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
2375 		spec.numWorkGroups = IVec3(numElements, 1, 1);
2376 
2377 		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
2378 	}
2379 
2380 	return group.release();
2381 }
2382 
2383 // Checks that a compute shader can generate a constant composite value of various types, without exercising a computation on it.
createOpConstantCompositeGroup(tcu::TestContext & testCtx)2384 tcu::TestCaseGroup* createOpConstantCompositeGroup (tcu::TestContext& testCtx)
2385 {
2386 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opconstantcomposite", "Tests the OpConstantComposite instruction"));
2387 	vector<CaseParameter>			cases;
2388 	de::Random						rnd				(deStringHash(group->getName()));
2389 	const int						numElements		= 100;
2390 	vector<float>					positiveFloats	(numElements, 0);
2391 	vector<float>					negativeFloats	(numElements, 0);
2392 	const StringTemplate			shaderTemplate	(
2393 		string(s_ShaderPreamble) +
2394 
2395 		"OpSource GLSL 430\n"
2396 		"OpName %main           \"main\"\n"
2397 		"OpName %id             \"gl_GlobalInvocationID\"\n"
2398 
2399 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
2400 
2401 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
2402 
2403 		"%id        = OpVariable %uvec3ptr Input\n"
2404 		"%zero      = OpConstant %i32 0\n"
2405 
2406 		"${CONSTANT}\n"
2407 
2408 		"%main      = OpFunction %void None %voidf\n"
2409 		"%label     = OpLabel\n"
2410 		"%idval     = OpLoad %uvec3 %id\n"
2411 		"%x         = OpCompositeExtract %u32 %idval 0\n"
2412 		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
2413 		"%inval     = OpLoad %f32 %inloc\n"
2414 		"%neg       = OpFNegate %f32 %inval\n"
2415 		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
2416 		"             OpStore %outloc %neg\n"
2417 		"             OpReturn\n"
2418 		"             OpFunctionEnd\n");
2419 
2420 	cases.push_back(CaseParameter("vector",			"%five = OpConstant %u32 5\n"
2421 													"%const = OpConstantComposite %uvec3 %five %zero %five"));
2422 	cases.push_back(CaseParameter("matrix",			"%m3fvec3 = OpTypeMatrix %fvec3 3\n"
2423 													"%ten = OpConstant %f32 10.\n"
2424 													"%fzero = OpConstant %f32 0.\n"
2425 													"%vec = OpConstantComposite %fvec3 %ten %fzero %ten\n"
2426 													"%mat = OpConstantComposite %m3fvec3 %vec %vec %vec"));
2427 	cases.push_back(CaseParameter("struct",			"%m2vec3 = OpTypeMatrix %fvec3 2\n"
2428 													"%struct = OpTypeStruct %i32 %f32 %fvec3 %m2vec3\n"
2429 													"%fzero = OpConstant %f32 0.\n"
2430 													"%one = OpConstant %f32 1.\n"
2431 													"%point5 = OpConstant %f32 0.5\n"
2432 													"%vec = OpConstantComposite %fvec3 %one %one %fzero\n"
2433 													"%mat = OpConstantComposite %m2vec3 %vec %vec\n"
2434 													"%const = OpConstantComposite %struct %zero %point5 %vec %mat"));
2435 	cases.push_back(CaseParameter("nested_struct",	"%st1 = OpTypeStruct %u32 %f32\n"
2436 													"%st2 = OpTypeStruct %i32 %i32\n"
2437 													"%struct = OpTypeStruct %st1 %st2\n"
2438 													"%point5 = OpConstant %f32 0.5\n"
2439 													"%one = OpConstant %u32 1\n"
2440 													"%ten = OpConstant %i32 10\n"
2441 													"%st1val = OpConstantComposite %st1 %one %point5\n"
2442 													"%st2val = OpConstantComposite %st2 %ten %ten\n"
2443 													"%const = OpConstantComposite %struct %st1val %st2val"));
2444 
2445 	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
2446 
2447 	for (size_t ndx = 0; ndx < numElements; ++ndx)
2448 		negativeFloats[ndx] = -positiveFloats[ndx];
2449 
2450 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
2451 	{
2452 		map<string, string>		specializations;
2453 		ComputeShaderSpec		spec;
2454 
2455 		specializations["CONSTANT"] = cases[caseNdx].param;
2456 		spec.assembly = shaderTemplate.specialize(specializations);
2457 		spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
2458 		spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
2459 		spec.numWorkGroups = IVec3(numElements, 1, 1);
2460 
2461 		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
2462 	}
2463 
2464 	return group.release();
2465 }
2466 
2467 // Creates a floating point number with the given exponent, and significand
2468 // bits set. It can only create normalized numbers. Only the least significant
2469 // 24 bits of the significand will be examined. The final bit of the
2470 // significand will also be ignored. This allows alignment to be written
2471 // similarly to C99 hex-floats.
2472 // For example if you wanted to write 0x1.7f34p-12 you would call
2473 // constructNormalizedFloat(-12, 0x7f3400)
constructNormalizedFloat(deInt32 exponent,deUint32 significand)2474 float constructNormalizedFloat (deInt32 exponent, deUint32 significand)
2475 {
2476 	float f = 1.0f;
2477 
2478 	for (deInt32 idx = 0; idx < 23; ++idx)
2479 	{
2480 		f += ((significand & 0x800000) == 0) ? 0.f : std::ldexp(1.0f, -(idx + 1));
2481 		significand <<= 1;
2482 	}
2483 
2484 	return std::ldexp(f, exponent);
2485 }
2486 
2487 // Compare instruction for the OpQuantizeF16 compute exact case.
2488 // Returns true if the output is what is expected from the test case.
compareOpQuantizeF16ComputeExactCase(const std::vector<BufferSp> &,const vector<AllocationSp> & outputAllocs,const std::vector<BufferSp> & expectedOutputs,TestLog &)2489 bool compareOpQuantizeF16ComputeExactCase (const std::vector<BufferSp>&, const vector<AllocationSp>& outputAllocs, const std::vector<BufferSp>& expectedOutputs, TestLog&)
2490 {
2491 	if (outputAllocs.size() != 1)
2492 		return false;
2493 
2494 	// We really just need this for size because we cannot compare Nans.
2495 	const BufferSp&	expectedOutput	= expectedOutputs[0];
2496 	const float*	outputAsFloat	= static_cast<const float*>(outputAllocs[0]->getHostPtr());;
2497 
2498 	if (expectedOutput->getNumBytes() != 4*sizeof(float)) {
2499 		return false;
2500 	}
2501 
2502 	if (*outputAsFloat != constructNormalizedFloat(8, 0x304000) &&
2503 		*outputAsFloat != constructNormalizedFloat(8, 0x300000)) {
2504 		return false;
2505 	}
2506 	outputAsFloat++;
2507 
2508 	if (*outputAsFloat != -constructNormalizedFloat(-7, 0x600000) &&
2509 		*outputAsFloat != -constructNormalizedFloat(-7, 0x604000)) {
2510 		return false;
2511 	}
2512 	outputAsFloat++;
2513 
2514 	if (*outputAsFloat != constructNormalizedFloat(2, 0x01C000) &&
2515 		*outputAsFloat != constructNormalizedFloat(2, 0x020000)) {
2516 		return false;
2517 	}
2518 	outputAsFloat++;
2519 
2520 	if (*outputAsFloat != constructNormalizedFloat(1, 0xFFC000) &&
2521 		*outputAsFloat != constructNormalizedFloat(2, 0x000000)) {
2522 		return false;
2523 	}
2524 
2525 	return true;
2526 }
2527 
2528 // Checks that every output from a test-case is a float NaN.
compareNan(const std::vector<BufferSp> &,const vector<AllocationSp> & outputAllocs,const std::vector<BufferSp> & expectedOutputs,TestLog &)2529 bool compareNan (const std::vector<BufferSp>&, const vector<AllocationSp>& outputAllocs, const std::vector<BufferSp>& expectedOutputs, TestLog&)
2530 {
2531 	if (outputAllocs.size() != 1)
2532 		return false;
2533 
2534 	// We really just need this for size because we cannot compare Nans.
2535 	const BufferSp& expectedOutput		= expectedOutputs[0];
2536 	const float* output_as_float		= static_cast<const float*>(outputAllocs[0]->getHostPtr());;
2537 
2538 	for (size_t idx = 0; idx < expectedOutput->getNumBytes() / sizeof(float); ++idx)
2539 	{
2540 		if (!deFloatIsNaN(output_as_float[idx]))
2541 		{
2542 			return false;
2543 		}
2544 	}
2545 
2546 	return true;
2547 }
2548 
2549 // Checks that a compute shader can generate a constant composite value of various types, without exercising a computation on it.
createOpQuantizeToF16Group(tcu::TestContext & testCtx)2550 tcu::TestCaseGroup* createOpQuantizeToF16Group (tcu::TestContext& testCtx)
2551 {
2552 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opquantize", "Tests the OpQuantizeToF16 instruction"));
2553 
2554 	const std::string shader (
2555 		string(s_ShaderPreamble) +
2556 
2557 		"OpSource GLSL 430\n"
2558 		"OpName %main           \"main\"\n"
2559 		"OpName %id             \"gl_GlobalInvocationID\"\n"
2560 
2561 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
2562 
2563 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
2564 
2565 		"%id        = OpVariable %uvec3ptr Input\n"
2566 		"%zero      = OpConstant %i32 0\n"
2567 
2568 		"%main      = OpFunction %void None %voidf\n"
2569 		"%label     = OpLabel\n"
2570 		"%idval     = OpLoad %uvec3 %id\n"
2571 		"%x         = OpCompositeExtract %u32 %idval 0\n"
2572 		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
2573 		"%inval     = OpLoad %f32 %inloc\n"
2574 		"%quant     = OpQuantizeToF16 %f32 %inval\n"
2575 		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
2576 		"             OpStore %outloc %quant\n"
2577 		"             OpReturn\n"
2578 		"             OpFunctionEnd\n");
2579 
2580 	{
2581 		ComputeShaderSpec	spec;
2582 		const deUint32		numElements		= 100;
2583 		vector<float>		infinities;
2584 		vector<float>		results;
2585 
2586 		infinities.reserve(numElements);
2587 		results.reserve(numElements);
2588 
2589 		for (size_t idx = 0; idx < numElements; ++idx)
2590 		{
2591 			switch(idx % 4)
2592 			{
2593 				case 0:
2594 					infinities.push_back(std::numeric_limits<float>::infinity());
2595 					results.push_back(std::numeric_limits<float>::infinity());
2596 					break;
2597 				case 1:
2598 					infinities.push_back(-std::numeric_limits<float>::infinity());
2599 					results.push_back(-std::numeric_limits<float>::infinity());
2600 					break;
2601 				case 2:
2602 					infinities.push_back(std::ldexp(1.0f, 16));
2603 					results.push_back(std::numeric_limits<float>::infinity());
2604 					break;
2605 				case 3:
2606 					infinities.push_back(std::ldexp(-1.0f, 32));
2607 					results.push_back(-std::numeric_limits<float>::infinity());
2608 					break;
2609 			}
2610 		}
2611 
2612 		spec.assembly = shader;
2613 		spec.inputs.push_back(BufferSp(new Float32Buffer(infinities)));
2614 		spec.outputs.push_back(BufferSp(new Float32Buffer(results)));
2615 		spec.numWorkGroups = IVec3(numElements, 1, 1);
2616 
2617 		group->addChild(new SpvAsmComputeShaderCase(
2618 			testCtx, "infinities", "Check that infinities propagated and created", spec));
2619 	}
2620 
2621 	{
2622 		ComputeShaderSpec	spec;
2623 		vector<float>		nans;
2624 		const deUint32		numElements		= 100;
2625 
2626 		nans.reserve(numElements);
2627 
2628 		for (size_t idx = 0; idx < numElements; ++idx)
2629 		{
2630 			if (idx % 2 == 0)
2631 			{
2632 				nans.push_back(std::numeric_limits<float>::quiet_NaN());
2633 			}
2634 			else
2635 			{
2636 				nans.push_back(-std::numeric_limits<float>::quiet_NaN());
2637 			}
2638 		}
2639 
2640 		spec.assembly = shader;
2641 		spec.inputs.push_back(BufferSp(new Float32Buffer(nans)));
2642 		spec.outputs.push_back(BufferSp(new Float32Buffer(nans)));
2643 		spec.numWorkGroups = IVec3(numElements, 1, 1);
2644 		spec.verifyIO = &compareNan;
2645 
2646 		group->addChild(new SpvAsmComputeShaderCase(
2647 			testCtx, "propagated_nans", "Check that nans are propagated", spec));
2648 	}
2649 
2650 	{
2651 		ComputeShaderSpec	spec;
2652 		vector<float>		small;
2653 		vector<float>		zeros;
2654 		const deUint32		numElements		= 100;
2655 
2656 		small.reserve(numElements);
2657 		zeros.reserve(numElements);
2658 
2659 		for (size_t idx = 0; idx < numElements; ++idx)
2660 		{
2661 			switch(idx % 6)
2662 			{
2663 				case 0:
2664 					small.push_back(0.f);
2665 					zeros.push_back(0.f);
2666 					break;
2667 				case 1:
2668 					small.push_back(-0.f);
2669 					zeros.push_back(-0.f);
2670 					break;
2671 				case 2:
2672 					small.push_back(std::ldexp(1.0f, -16));
2673 					zeros.push_back(0.f);
2674 					break;
2675 				case 3:
2676 					small.push_back(std::ldexp(-1.0f, -32));
2677 					zeros.push_back(-0.f);
2678 					break;
2679 				case 4:
2680 					small.push_back(std::ldexp(1.0f, -127));
2681 					zeros.push_back(0.f);
2682 					break;
2683 				case 5:
2684 					small.push_back(-std::ldexp(1.0f, -128));
2685 					zeros.push_back(-0.f);
2686 					break;
2687 			}
2688 		}
2689 
2690 		spec.assembly = shader;
2691 		spec.inputs.push_back(BufferSp(new Float32Buffer(small)));
2692 		spec.outputs.push_back(BufferSp(new Float32Buffer(zeros)));
2693 		spec.numWorkGroups = IVec3(numElements, 1, 1);
2694 
2695 		group->addChild(new SpvAsmComputeShaderCase(
2696 			testCtx, "flush_to_zero", "Check that values are zeroed correctly", spec));
2697 	}
2698 
2699 	{
2700 		ComputeShaderSpec	spec;
2701 		vector<float>		exact;
2702 		const deUint32		numElements		= 200;
2703 
2704 		exact.reserve(numElements);
2705 
2706 		for (size_t idx = 0; idx < numElements; ++idx)
2707 			exact.push_back(static_cast<float>(static_cast<int>(idx) - 100));
2708 
2709 		spec.assembly = shader;
2710 		spec.inputs.push_back(BufferSp(new Float32Buffer(exact)));
2711 		spec.outputs.push_back(BufferSp(new Float32Buffer(exact)));
2712 		spec.numWorkGroups = IVec3(numElements, 1, 1);
2713 
2714 		group->addChild(new SpvAsmComputeShaderCase(
2715 			testCtx, "exact", "Check that values exactly preserved where appropriate", spec));
2716 	}
2717 
2718 	{
2719 		ComputeShaderSpec	spec;
2720 		vector<float>		inputs;
2721 		const deUint32		numElements		= 4;
2722 
2723 		inputs.push_back(constructNormalizedFloat(8,	0x300300));
2724 		inputs.push_back(-constructNormalizedFloat(-7,	0x600800));
2725 		inputs.push_back(constructNormalizedFloat(2,	0x01E000));
2726 		inputs.push_back(constructNormalizedFloat(1,	0xFFE000));
2727 
2728 		spec.assembly = shader;
2729 		spec.verifyIO = &compareOpQuantizeF16ComputeExactCase;
2730 		spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
2731 		spec.outputs.push_back(BufferSp(new Float32Buffer(inputs)));
2732 		spec.numWorkGroups = IVec3(numElements, 1, 1);
2733 
2734 		group->addChild(new SpvAsmComputeShaderCase(
2735 			testCtx, "rounded", "Check that are rounded when needed", spec));
2736 	}
2737 
2738 	return group.release();
2739 }
2740 
2741 // Performs a bitwise copy of source to the destination type Dest.
2742 template <typename Dest, typename Src>
bitwiseCast(Src source)2743 Dest bitwiseCast(Src source)
2744 {
2745   Dest dest;
2746   DE_STATIC_ASSERT(sizeof(source) == sizeof(dest));
2747   deMemcpy(&dest, &source, sizeof(dest));
2748   return dest;
2749 }
2750 
createSpecConstantOpQuantizeToF16Group(tcu::TestContext & testCtx)2751 tcu::TestCaseGroup* createSpecConstantOpQuantizeToF16Group (tcu::TestContext& testCtx)
2752 {
2753 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opspecconstantop_opquantize", "Tests the OpQuantizeToF16 opcode for the OpSpecConstantOp instruction"));
2754 
2755 	const std::string shader (
2756 		string(s_ShaderPreamble) +
2757 
2758 		"OpName %main           \"main\"\n"
2759 		"OpName %id             \"gl_GlobalInvocationID\"\n"
2760 
2761 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
2762 
2763 		"OpDecorate %sc_0  SpecId 0\n"
2764 		"OpDecorate %sc_1  SpecId 1\n"
2765 		"OpDecorate %sc_2  SpecId 2\n"
2766 		"OpDecorate %sc_3  SpecId 3\n"
2767 		"OpDecorate %sc_4  SpecId 4\n"
2768 		"OpDecorate %sc_5  SpecId 5\n"
2769 
2770 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
2771 
2772 		"%id        = OpVariable %uvec3ptr Input\n"
2773 		"%zero      = OpConstant %i32 0\n"
2774 		"%c_u32_6   = OpConstant %u32 6\n"
2775 
2776 		"%sc_0      = OpSpecConstant %f32 0.\n"
2777 		"%sc_1      = OpSpecConstant %f32 0.\n"
2778 		"%sc_2      = OpSpecConstant %f32 0.\n"
2779 		"%sc_3      = OpSpecConstant %f32 0.\n"
2780 		"%sc_4      = OpSpecConstant %f32 0.\n"
2781 		"%sc_5      = OpSpecConstant %f32 0.\n"
2782 
2783 		"%sc_0_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_0\n"
2784 		"%sc_1_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_1\n"
2785 		"%sc_2_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_2\n"
2786 		"%sc_3_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_3\n"
2787 		"%sc_4_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_4\n"
2788 		"%sc_5_quant = OpSpecConstantOp %f32 QuantizeToF16 %sc_5\n"
2789 
2790 		"%main      = OpFunction %void None %voidf\n"
2791 		"%label     = OpLabel\n"
2792 		"%idval     = OpLoad %uvec3 %id\n"
2793 		"%x         = OpCompositeExtract %u32 %idval 0\n"
2794 		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
2795 		"%selector  = OpUMod %u32 %x %c_u32_6\n"
2796 		"            OpSelectionMerge %exit None\n"
2797 		"            OpSwitch %selector %exit 0 %case0 1 %case1 2 %case2 3 %case3 4 %case4 5 %case5\n"
2798 
2799 		"%case0     = OpLabel\n"
2800 		"             OpStore %outloc %sc_0_quant\n"
2801 		"             OpBranch %exit\n"
2802 
2803 		"%case1     = OpLabel\n"
2804 		"             OpStore %outloc %sc_1_quant\n"
2805 		"             OpBranch %exit\n"
2806 
2807 		"%case2     = OpLabel\n"
2808 		"             OpStore %outloc %sc_2_quant\n"
2809 		"             OpBranch %exit\n"
2810 
2811 		"%case3     = OpLabel\n"
2812 		"             OpStore %outloc %sc_3_quant\n"
2813 		"             OpBranch %exit\n"
2814 
2815 		"%case4     = OpLabel\n"
2816 		"             OpStore %outloc %sc_4_quant\n"
2817 		"             OpBranch %exit\n"
2818 
2819 		"%case5     = OpLabel\n"
2820 		"             OpStore %outloc %sc_5_quant\n"
2821 		"             OpBranch %exit\n"
2822 
2823 		"%exit      = OpLabel\n"
2824 		"             OpReturn\n"
2825 
2826 		"             OpFunctionEnd\n");
2827 
2828 	{
2829 		ComputeShaderSpec	spec;
2830 		const deUint8		numCases	= 4;
2831 		vector<float>		inputs		(numCases, 0.f);
2832 		vector<float>		outputs;
2833 
2834 		spec.assembly		= shader;
2835 		spec.numWorkGroups	= IVec3(numCases, 1, 1);
2836 
2837 		spec.specConstants.push_back(bitwiseCast<deUint32>(std::numeric_limits<float>::infinity()));
2838 		spec.specConstants.push_back(bitwiseCast<deUint32>(-std::numeric_limits<float>::infinity()));
2839 		spec.specConstants.push_back(bitwiseCast<deUint32>(std::ldexp(1.0f, 16)));
2840 		spec.specConstants.push_back(bitwiseCast<deUint32>(std::ldexp(-1.0f, 32)));
2841 
2842 		outputs.push_back(std::numeric_limits<float>::infinity());
2843 		outputs.push_back(-std::numeric_limits<float>::infinity());
2844 		outputs.push_back(std::numeric_limits<float>::infinity());
2845 		outputs.push_back(-std::numeric_limits<float>::infinity());
2846 
2847 		spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
2848 		spec.outputs.push_back(BufferSp(new Float32Buffer(outputs)));
2849 
2850 		group->addChild(new SpvAsmComputeShaderCase(
2851 			testCtx, "infinities", "Check that infinities propagated and created", spec));
2852 	}
2853 
2854 	{
2855 		ComputeShaderSpec	spec;
2856 		const deUint8		numCases	= 2;
2857 		vector<float>		inputs		(numCases, 0.f);
2858 		vector<float>		outputs;
2859 
2860 		spec.assembly		= shader;
2861 		spec.numWorkGroups	= IVec3(numCases, 1, 1);
2862 		spec.verifyIO		= &compareNan;
2863 
2864 		outputs.push_back(std::numeric_limits<float>::quiet_NaN());
2865 		outputs.push_back(-std::numeric_limits<float>::quiet_NaN());
2866 
2867 		for (deUint8 idx = 0; idx < numCases; ++idx)
2868 			spec.specConstants.push_back(bitwiseCast<deUint32>(outputs[idx]));
2869 
2870 		spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
2871 		spec.outputs.push_back(BufferSp(new Float32Buffer(outputs)));
2872 
2873 		group->addChild(new SpvAsmComputeShaderCase(
2874 			testCtx, "propagated_nans", "Check that nans are propagated", spec));
2875 	}
2876 
2877 	{
2878 		ComputeShaderSpec	spec;
2879 		const deUint8		numCases	= 6;
2880 		vector<float>		inputs		(numCases, 0.f);
2881 		vector<float>		outputs;
2882 
2883 		spec.assembly		= shader;
2884 		spec.numWorkGroups	= IVec3(numCases, 1, 1);
2885 
2886 		spec.specConstants.push_back(bitwiseCast<deUint32>(0.f));
2887 		spec.specConstants.push_back(bitwiseCast<deUint32>(-0.f));
2888 		spec.specConstants.push_back(bitwiseCast<deUint32>(std::ldexp(1.0f, -16)));
2889 		spec.specConstants.push_back(bitwiseCast<deUint32>(std::ldexp(-1.0f, -32)));
2890 		spec.specConstants.push_back(bitwiseCast<deUint32>(std::ldexp(1.0f, -127)));
2891 		spec.specConstants.push_back(bitwiseCast<deUint32>(-std::ldexp(1.0f, -128)));
2892 
2893 		outputs.push_back(0.f);
2894 		outputs.push_back(-0.f);
2895 		outputs.push_back(0.f);
2896 		outputs.push_back(-0.f);
2897 		outputs.push_back(0.f);
2898 		outputs.push_back(-0.f);
2899 
2900 		spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
2901 		spec.outputs.push_back(BufferSp(new Float32Buffer(outputs)));
2902 
2903 		group->addChild(new SpvAsmComputeShaderCase(
2904 			testCtx, "flush_to_zero", "Check that values are zeroed correctly", spec));
2905 	}
2906 
2907 	{
2908 		ComputeShaderSpec	spec;
2909 		const deUint8		numCases	= 6;
2910 		vector<float>		inputs		(numCases, 0.f);
2911 		vector<float>		outputs;
2912 
2913 		spec.assembly		= shader;
2914 		spec.numWorkGroups	= IVec3(numCases, 1, 1);
2915 
2916 		for (deUint8 idx = 0; idx < 6; ++idx)
2917 		{
2918 			const float f = static_cast<float>(idx * 10 - 30) / 4.f;
2919 			spec.specConstants.push_back(bitwiseCast<deUint32>(f));
2920 			outputs.push_back(f);
2921 		}
2922 
2923 		spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
2924 		spec.outputs.push_back(BufferSp(new Float32Buffer(outputs)));
2925 
2926 		group->addChild(new SpvAsmComputeShaderCase(
2927 			testCtx, "exact", "Check that values exactly preserved where appropriate", spec));
2928 	}
2929 
2930 	{
2931 		ComputeShaderSpec	spec;
2932 		const deUint8		numCases	= 4;
2933 		vector<float>		inputs		(numCases, 0.f);
2934 		vector<float>		outputs;
2935 
2936 		spec.assembly		= shader;
2937 		spec.numWorkGroups	= IVec3(numCases, 1, 1);
2938 		spec.verifyIO		= &compareOpQuantizeF16ComputeExactCase;
2939 
2940 		outputs.push_back(constructNormalizedFloat(8, 0x300300));
2941 		outputs.push_back(-constructNormalizedFloat(-7, 0x600800));
2942 		outputs.push_back(constructNormalizedFloat(2, 0x01E000));
2943 		outputs.push_back(constructNormalizedFloat(1, 0xFFE000));
2944 
2945 		for (deUint8 idx = 0; idx < numCases; ++idx)
2946 			spec.specConstants.push_back(bitwiseCast<deUint32>(outputs[idx]));
2947 
2948 		spec.inputs.push_back(BufferSp(new Float32Buffer(inputs)));
2949 		spec.outputs.push_back(BufferSp(new Float32Buffer(outputs)));
2950 
2951 		group->addChild(new SpvAsmComputeShaderCase(
2952 			testCtx, "rounded", "Check that are rounded when needed", spec));
2953 	}
2954 
2955 	return group.release();
2956 }
2957 
2958 // Checks that constant null/composite values can be used in computation.
createOpConstantUsageGroup(tcu::TestContext & testCtx)2959 tcu::TestCaseGroup* createOpConstantUsageGroup (tcu::TestContext& testCtx)
2960 {
2961 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opconstantnullcomposite", "Spotcheck the OpConstantNull & OpConstantComposite instruction"));
2962 	ComputeShaderSpec				spec;
2963 	de::Random						rnd				(deStringHash(group->getName()));
2964 	const int						numElements		= 100;
2965 	vector<float>					positiveFloats	(numElements, 0);
2966 	vector<float>					negativeFloats	(numElements, 0);
2967 
2968 	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
2969 
2970 	for (size_t ndx = 0; ndx < numElements; ++ndx)
2971 		negativeFloats[ndx] = -positiveFloats[ndx];
2972 
2973 	spec.assembly =
2974 		"OpCapability Shader\n"
2975 		"%std450 = OpExtInstImport \"GLSL.std.450\"\n"
2976 		"OpMemoryModel Logical GLSL450\n"
2977 		"OpEntryPoint GLCompute %main \"main\" %id\n"
2978 		"OpExecutionMode %main LocalSize 1 1 1\n"
2979 
2980 		"OpSource GLSL 430\n"
2981 		"OpName %main           \"main\"\n"
2982 		"OpName %id             \"gl_GlobalInvocationID\"\n"
2983 
2984 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
2985 
2986 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
2987 
2988 		"%fmat      = OpTypeMatrix %fvec3 3\n"
2989 		"%ten       = OpConstant %u32 10\n"
2990 		"%f32arr10  = OpTypeArray %f32 %ten\n"
2991 		"%fst       = OpTypeStruct %f32 %f32\n"
2992 
2993 		+ string(s_InputOutputBuffer) +
2994 
2995 		"%id        = OpVariable %uvec3ptr Input\n"
2996 		"%zero      = OpConstant %i32 0\n"
2997 
2998 		// Create a bunch of null values
2999 		"%unull     = OpConstantNull %u32\n"
3000 		"%fnull     = OpConstantNull %f32\n"
3001 		"%vnull     = OpConstantNull %fvec3\n"
3002 		"%mnull     = OpConstantNull %fmat\n"
3003 		"%anull     = OpConstantNull %f32arr10\n"
3004 		"%snull     = OpConstantComposite %fst %fnull %fnull\n"
3005 
3006 		"%main      = OpFunction %void None %voidf\n"
3007 		"%label     = OpLabel\n"
3008 		"%idval     = OpLoad %uvec3 %id\n"
3009 		"%x         = OpCompositeExtract %u32 %idval 0\n"
3010 		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
3011 		"%inval     = OpLoad %f32 %inloc\n"
3012 		"%neg       = OpFNegate %f32 %inval\n"
3013 
3014 		// Get the abs() of (a certain element of) those null values
3015 		"%unull_cov = OpConvertUToF %f32 %unull\n"
3016 		"%unull_abs = OpExtInst %f32 %std450 FAbs %unull_cov\n"
3017 		"%fnull_abs = OpExtInst %f32 %std450 FAbs %fnull\n"
3018 		"%vnull_0   = OpCompositeExtract %f32 %vnull 0\n"
3019 		"%vnull_abs = OpExtInst %f32 %std450 FAbs %vnull_0\n"
3020 		"%mnull_12  = OpCompositeExtract %f32 %mnull 1 2\n"
3021 		"%mnull_abs = OpExtInst %f32 %std450 FAbs %mnull_12\n"
3022 		"%anull_3   = OpCompositeExtract %f32 %anull 3\n"
3023 		"%anull_abs = OpExtInst %f32 %std450 FAbs %anull_3\n"
3024 		"%snull_1   = OpCompositeExtract %f32 %snull 1\n"
3025 		"%snull_abs = OpExtInst %f32 %std450 FAbs %snull_1\n"
3026 
3027 		// Add them all
3028 		"%add1      = OpFAdd %f32 %neg  %unull_abs\n"
3029 		"%add2      = OpFAdd %f32 %add1 %fnull_abs\n"
3030 		"%add3      = OpFAdd %f32 %add2 %vnull_abs\n"
3031 		"%add4      = OpFAdd %f32 %add3 %mnull_abs\n"
3032 		"%add5      = OpFAdd %f32 %add4 %anull_abs\n"
3033 		"%final     = OpFAdd %f32 %add5 %snull_abs\n"
3034 
3035 		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
3036 		"             OpStore %outloc %final\n" // write to output
3037 		"             OpReturn\n"
3038 		"             OpFunctionEnd\n";
3039 	spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
3040 	spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
3041 	spec.numWorkGroups = IVec3(numElements, 1, 1);
3042 
3043 	group->addChild(new SpvAsmComputeShaderCase(testCtx, "spotcheck", "Check that values constructed via OpConstantNull & OpConstantComposite can be used", spec));
3044 
3045 	return group.release();
3046 }
3047 
3048 // Assembly code used for testing loop control is based on GLSL source code:
3049 // #version 430
3050 //
3051 // layout(std140, set = 0, binding = 0) readonly buffer Input {
3052 //   float elements[];
3053 // } input_data;
3054 // layout(std140, set = 0, binding = 1) writeonly buffer Output {
3055 //   float elements[];
3056 // } output_data;
3057 //
3058 // void main() {
3059 //   uint x = gl_GlobalInvocationID.x;
3060 //   output_data.elements[x] = input_data.elements[x];
3061 //   for (uint i = 0; i < 4; ++i)
3062 //     output_data.elements[x] += 1.f;
3063 // }
createLoopControlGroup(tcu::TestContext & testCtx)3064 tcu::TestCaseGroup* createLoopControlGroup (tcu::TestContext& testCtx)
3065 {
3066 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "loop_control", "Tests loop control cases"));
3067 	vector<CaseParameter>			cases;
3068 	de::Random						rnd				(deStringHash(group->getName()));
3069 	const int						numElements		= 100;
3070 	vector<float>					inputFloats		(numElements, 0);
3071 	vector<float>					outputFloats	(numElements, 0);
3072 	const StringTemplate			shaderTemplate	(
3073 		string(s_ShaderPreamble) +
3074 
3075 		"OpSource GLSL 430\n"
3076 		"OpName %main \"main\"\n"
3077 		"OpName %id \"gl_GlobalInvocationID\"\n"
3078 
3079 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
3080 
3081 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
3082 
3083 		"%u32ptr      = OpTypePointer Function %u32\n"
3084 
3085 		"%id          = OpVariable %uvec3ptr Input\n"
3086 		"%zero        = OpConstant %i32 0\n"
3087 		"%uzero       = OpConstant %u32 0\n"
3088 		"%one         = OpConstant %i32 1\n"
3089 		"%constf1     = OpConstant %f32 1.0\n"
3090 		"%four        = OpConstant %u32 4\n"
3091 
3092 		"%main        = OpFunction %void None %voidf\n"
3093 		"%entry       = OpLabel\n"
3094 		"%i           = OpVariable %u32ptr Function\n"
3095 		"               OpStore %i %uzero\n"
3096 
3097 		"%idval       = OpLoad %uvec3 %id\n"
3098 		"%x           = OpCompositeExtract %u32 %idval 0\n"
3099 		"%inloc       = OpAccessChain %f32ptr %indata %zero %x\n"
3100 		"%inval       = OpLoad %f32 %inloc\n"
3101 		"%outloc      = OpAccessChain %f32ptr %outdata %zero %x\n"
3102 		"               OpStore %outloc %inval\n"
3103 		"               OpBranch %loop_entry\n"
3104 
3105 		"%loop_entry  = OpLabel\n"
3106 		"%i_val       = OpLoad %u32 %i\n"
3107 		"%cmp_lt      = OpULessThan %bool %i_val %four\n"
3108 		"               OpLoopMerge %loop_merge %loop_body ${CONTROL}\n"
3109 		"               OpBranchConditional %cmp_lt %loop_body %loop_merge\n"
3110 		"%loop_body   = OpLabel\n"
3111 		"%outval      = OpLoad %f32 %outloc\n"
3112 		"%addf1       = OpFAdd %f32 %outval %constf1\n"
3113 		"               OpStore %outloc %addf1\n"
3114 		"%new_i       = OpIAdd %u32 %i_val %one\n"
3115 		"               OpStore %i %new_i\n"
3116 		"               OpBranch %loop_entry\n"
3117 		"%loop_merge  = OpLabel\n"
3118 		"               OpReturn\n"
3119 		"               OpFunctionEnd\n");
3120 
3121 	cases.push_back(CaseParameter("none",				"None"));
3122 	cases.push_back(CaseParameter("unroll",				"Unroll"));
3123 	cases.push_back(CaseParameter("dont_unroll",		"DontUnroll"));
3124 	cases.push_back(CaseParameter("unroll_dont_unroll",	"Unroll|DontUnroll"));
3125 
3126 	fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
3127 
3128 	for (size_t ndx = 0; ndx < numElements; ++ndx)
3129 		outputFloats[ndx] = inputFloats[ndx] + 4.f;
3130 
3131 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
3132 	{
3133 		map<string, string>		specializations;
3134 		ComputeShaderSpec		spec;
3135 
3136 		specializations["CONTROL"] = cases[caseNdx].param;
3137 		spec.assembly = shaderTemplate.specialize(specializations);
3138 		spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
3139 		spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
3140 		spec.numWorkGroups = IVec3(numElements, 1, 1);
3141 
3142 		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
3143 	}
3144 
3145 	return group.release();
3146 }
3147 
3148 // Assembly code used for testing selection control is based on GLSL source code:
3149 // #version 430
3150 //
3151 // layout(std140, set = 0, binding = 0) readonly buffer Input {
3152 //   float elements[];
3153 // } input_data;
3154 // layout(std140, set = 0, binding = 1) writeonly buffer Output {
3155 //   float elements[];
3156 // } output_data;
3157 //
3158 // void main() {
3159 //   uint x = gl_GlobalInvocationID.x;
3160 //   float val = input_data.elements[x];
3161 //   if (val > 10.f)
3162 //     output_data.elements[x] = val + 1.f;
3163 //   else
3164 //     output_data.elements[x] = val - 1.f;
3165 // }
createSelectionControlGroup(tcu::TestContext & testCtx)3166 tcu::TestCaseGroup* createSelectionControlGroup (tcu::TestContext& testCtx)
3167 {
3168 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "selection_control", "Tests selection control cases"));
3169 	vector<CaseParameter>			cases;
3170 	de::Random						rnd				(deStringHash(group->getName()));
3171 	const int						numElements		= 100;
3172 	vector<float>					inputFloats		(numElements, 0);
3173 	vector<float>					outputFloats	(numElements, 0);
3174 	const StringTemplate			shaderTemplate	(
3175 		string(s_ShaderPreamble) +
3176 
3177 		"OpSource GLSL 430\n"
3178 		"OpName %main \"main\"\n"
3179 		"OpName %id \"gl_GlobalInvocationID\"\n"
3180 
3181 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
3182 
3183 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
3184 
3185 		"%id       = OpVariable %uvec3ptr Input\n"
3186 		"%zero     = OpConstant %i32 0\n"
3187 		"%constf1  = OpConstant %f32 1.0\n"
3188 		"%constf10 = OpConstant %f32 10.0\n"
3189 
3190 		"%main     = OpFunction %void None %voidf\n"
3191 		"%entry    = OpLabel\n"
3192 		"%idval    = OpLoad %uvec3 %id\n"
3193 		"%x        = OpCompositeExtract %u32 %idval 0\n"
3194 		"%inloc    = OpAccessChain %f32ptr %indata %zero %x\n"
3195 		"%inval    = OpLoad %f32 %inloc\n"
3196 		"%outloc   = OpAccessChain %f32ptr %outdata %zero %x\n"
3197 		"%cmp_gt   = OpFOrdGreaterThan %bool %inval %constf10\n"
3198 
3199 		"            OpSelectionMerge %if_end ${CONTROL}\n"
3200 		"            OpBranchConditional %cmp_gt %if_true %if_false\n"
3201 		"%if_true  = OpLabel\n"
3202 		"%addf1    = OpFAdd %f32 %inval %constf1\n"
3203 		"            OpStore %outloc %addf1\n"
3204 		"            OpBranch %if_end\n"
3205 		"%if_false = OpLabel\n"
3206 		"%subf1    = OpFSub %f32 %inval %constf1\n"
3207 		"            OpStore %outloc %subf1\n"
3208 		"            OpBranch %if_end\n"
3209 		"%if_end   = OpLabel\n"
3210 		"            OpReturn\n"
3211 		"            OpFunctionEnd\n");
3212 
3213 	cases.push_back(CaseParameter("none",					"None"));
3214 	cases.push_back(CaseParameter("flatten",				"Flatten"));
3215 	cases.push_back(CaseParameter("dont_flatten",			"DontFlatten"));
3216 	cases.push_back(CaseParameter("flatten_dont_flatten",	"DontFlatten|Flatten"));
3217 
3218 	fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
3219 
3220 	// CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
3221 	floorAll(inputFloats);
3222 
3223 	for (size_t ndx = 0; ndx < numElements; ++ndx)
3224 		outputFloats[ndx] = inputFloats[ndx] + (inputFloats[ndx] > 10.f ? 1.f : -1.f);
3225 
3226 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
3227 	{
3228 		map<string, string>		specializations;
3229 		ComputeShaderSpec		spec;
3230 
3231 		specializations["CONTROL"] = cases[caseNdx].param;
3232 		spec.assembly = shaderTemplate.specialize(specializations);
3233 		spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
3234 		spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
3235 		spec.numWorkGroups = IVec3(numElements, 1, 1);
3236 
3237 		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
3238 	}
3239 
3240 	return group.release();
3241 }
3242 
3243 // Assembly code used for testing function control is based on GLSL source code:
3244 //
3245 // #version 430
3246 //
3247 // layout(std140, set = 0, binding = 0) readonly buffer Input {
3248 //   float elements[];
3249 // } input_data;
3250 // layout(std140, set = 0, binding = 1) writeonly buffer Output {
3251 //   float elements[];
3252 // } output_data;
3253 //
3254 // float const10() { return 10.f; }
3255 //
3256 // void main() {
3257 //   uint x = gl_GlobalInvocationID.x;
3258 //   output_data.elements[x] = input_data.elements[x] + const10();
3259 // }
createFunctionControlGroup(tcu::TestContext & testCtx)3260 tcu::TestCaseGroup* createFunctionControlGroup (tcu::TestContext& testCtx)
3261 {
3262 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "function_control", "Tests function control cases"));
3263 	vector<CaseParameter>			cases;
3264 	de::Random						rnd				(deStringHash(group->getName()));
3265 	const int						numElements		= 100;
3266 	vector<float>					inputFloats		(numElements, 0);
3267 	vector<float>					outputFloats	(numElements, 0);
3268 	const StringTemplate			shaderTemplate	(
3269 		string(s_ShaderPreamble) +
3270 
3271 		"OpSource GLSL 430\n"
3272 		"OpName %main \"main\"\n"
3273 		"OpName %func_const10 \"const10(\"\n"
3274 		"OpName %id \"gl_GlobalInvocationID\"\n"
3275 
3276 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
3277 
3278 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
3279 
3280 		"%f32f = OpTypeFunction %f32\n"
3281 		"%id = OpVariable %uvec3ptr Input\n"
3282 		"%zero = OpConstant %i32 0\n"
3283 		"%constf10 = OpConstant %f32 10.0\n"
3284 
3285 		"%main         = OpFunction %void None %voidf\n"
3286 		"%entry        = OpLabel\n"
3287 		"%idval        = OpLoad %uvec3 %id\n"
3288 		"%x            = OpCompositeExtract %u32 %idval 0\n"
3289 		"%inloc        = OpAccessChain %f32ptr %indata %zero %x\n"
3290 		"%inval        = OpLoad %f32 %inloc\n"
3291 		"%ret_10       = OpFunctionCall %f32 %func_const10\n"
3292 		"%fadd         = OpFAdd %f32 %inval %ret_10\n"
3293 		"%outloc       = OpAccessChain %f32ptr %outdata %zero %x\n"
3294 		"                OpStore %outloc %fadd\n"
3295 		"                OpReturn\n"
3296 		"                OpFunctionEnd\n"
3297 
3298 		"%func_const10 = OpFunction %f32 ${CONTROL} %f32f\n"
3299 		"%label        = OpLabel\n"
3300 		"                OpReturnValue %constf10\n"
3301 		"                OpFunctionEnd\n");
3302 
3303 	cases.push_back(CaseParameter("none",						"None"));
3304 	cases.push_back(CaseParameter("inline",						"Inline"));
3305 	cases.push_back(CaseParameter("dont_inline",				"DontInline"));
3306 	cases.push_back(CaseParameter("pure",						"Pure"));
3307 	cases.push_back(CaseParameter("const",						"Const"));
3308 	cases.push_back(CaseParameter("inline_pure",				"Inline|Pure"));
3309 	cases.push_back(CaseParameter("const_dont_inline",			"Const|DontInline"));
3310 	cases.push_back(CaseParameter("inline_dont_inline",			"Inline|DontInline"));
3311 	cases.push_back(CaseParameter("pure_inline_dont_inline",	"Pure|Inline|DontInline"));
3312 
3313 	fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
3314 
3315 	// CPU might not use the same rounding mode as the GPU. Use whole numbers to avoid rounding differences.
3316 	floorAll(inputFloats);
3317 
3318 	for (size_t ndx = 0; ndx < numElements; ++ndx)
3319 		outputFloats[ndx] = inputFloats[ndx] + 10.f;
3320 
3321 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
3322 	{
3323 		map<string, string>		specializations;
3324 		ComputeShaderSpec		spec;
3325 
3326 		specializations["CONTROL"] = cases[caseNdx].param;
3327 		spec.assembly = shaderTemplate.specialize(specializations);
3328 		spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
3329 		spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
3330 		spec.numWorkGroups = IVec3(numElements, 1, 1);
3331 
3332 		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
3333 	}
3334 
3335 	return group.release();
3336 }
3337 
createMemoryAccessGroup(tcu::TestContext & testCtx)3338 tcu::TestCaseGroup* createMemoryAccessGroup (tcu::TestContext& testCtx)
3339 {
3340 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "memory_access", "Tests memory access cases"));
3341 	vector<CaseParameter>			cases;
3342 	de::Random						rnd				(deStringHash(group->getName()));
3343 	const int						numElements		= 100;
3344 	vector<float>					inputFloats		(numElements, 0);
3345 	vector<float>					outputFloats	(numElements, 0);
3346 	const StringTemplate			shaderTemplate	(
3347 		string(s_ShaderPreamble) +
3348 
3349 		"OpSource GLSL 430\n"
3350 		"OpName %main           \"main\"\n"
3351 		"OpName %id             \"gl_GlobalInvocationID\"\n"
3352 
3353 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
3354 
3355 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) + string(s_InputOutputBuffer) +
3356 
3357 		"%f32ptr_f  = OpTypePointer Function %f32\n"
3358 
3359 		"%id        = OpVariable %uvec3ptr Input\n"
3360 		"%zero      = OpConstant %i32 0\n"
3361 		"%four      = OpConstant %i32 4\n"
3362 
3363 		"%main      = OpFunction %void None %voidf\n"
3364 		"%label     = OpLabel\n"
3365 		"%copy      = OpVariable %f32ptr_f Function\n"
3366 		"%idval     = OpLoad %uvec3 %id ${ACCESS}\n"
3367 		"%x         = OpCompositeExtract %u32 %idval 0\n"
3368 		"%inloc     = OpAccessChain %f32ptr %indata  %zero %x\n"
3369 		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
3370 		"             OpCopyMemory %copy %inloc ${ACCESS}\n"
3371 		"%val1      = OpLoad %f32 %copy\n"
3372 		"%val2      = OpLoad %f32 %inloc\n"
3373 		"%add       = OpFAdd %f32 %val1 %val2\n"
3374 		"             OpStore %outloc %add ${ACCESS}\n"
3375 		"             OpReturn\n"
3376 		"             OpFunctionEnd\n");
3377 
3378 	cases.push_back(CaseParameter("null",					""));
3379 	cases.push_back(CaseParameter("none",					"None"));
3380 	cases.push_back(CaseParameter("volatile",				"Volatile"));
3381 	cases.push_back(CaseParameter("aligned",				"Aligned 4"));
3382 	cases.push_back(CaseParameter("nontemporal",			"Nontemporal"));
3383 	cases.push_back(CaseParameter("aligned_nontemporal",	"Aligned|Nontemporal 4"));
3384 	cases.push_back(CaseParameter("aligned_volatile",		"Volatile|Aligned 4"));
3385 
3386 	fillRandomScalars(rnd, -100.f, 100.f, &inputFloats[0], numElements);
3387 
3388 	for (size_t ndx = 0; ndx < numElements; ++ndx)
3389 		outputFloats[ndx] = inputFloats[ndx] + inputFloats[ndx];
3390 
3391 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
3392 	{
3393 		map<string, string>		specializations;
3394 		ComputeShaderSpec		spec;
3395 
3396 		specializations["ACCESS"] = cases[caseNdx].param;
3397 		spec.assembly = shaderTemplate.specialize(specializations);
3398 		spec.inputs.push_back(BufferSp(new Float32Buffer(inputFloats)));
3399 		spec.outputs.push_back(BufferSp(new Float32Buffer(outputFloats)));
3400 		spec.numWorkGroups = IVec3(numElements, 1, 1);
3401 
3402 		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
3403 	}
3404 
3405 	return group.release();
3406 }
3407 
3408 // Checks that we can get undefined values for various types, without exercising a computation with it.
createOpUndefGroup(tcu::TestContext & testCtx)3409 tcu::TestCaseGroup* createOpUndefGroup (tcu::TestContext& testCtx)
3410 {
3411 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opundef", "Tests the OpUndef instruction"));
3412 	vector<CaseParameter>			cases;
3413 	de::Random						rnd				(deStringHash(group->getName()));
3414 	const int						numElements		= 100;
3415 	vector<float>					positiveFloats	(numElements, 0);
3416 	vector<float>					negativeFloats	(numElements, 0);
3417 	const StringTemplate			shaderTemplate	(
3418 		string(s_ShaderPreamble) +
3419 
3420 		"OpSource GLSL 430\n"
3421 		"OpName %main           \"main\"\n"
3422 		"OpName %id             \"gl_GlobalInvocationID\"\n"
3423 
3424 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
3425 
3426 		+ string(s_InputOutputBufferTraits) + string(s_CommonTypes) +
3427 		"%uvec2     = OpTypeVector %u32 2\n"
3428 		"%fvec4     = OpTypeVector %f32 4\n"
3429 		"%fmat33    = OpTypeMatrix %fvec3 3\n"
3430 		"%image     = OpTypeImage %f32 2D 0 0 0 1 Unknown\n"
3431 		"%sampler   = OpTypeSampler\n"
3432 		"%simage    = OpTypeSampledImage %image\n"
3433 		"%const100  = OpConstant %u32 100\n"
3434 		"%uarr100   = OpTypeArray %i32 %const100\n"
3435 		"%struct    = OpTypeStruct %f32 %i32 %u32\n"
3436 		"%pointer   = OpTypePointer Function %i32\n"
3437 		+ string(s_InputOutputBuffer) +
3438 		"%id        = OpVariable %uvec3ptr Input\n"
3439 		"%zero      = OpConstant %i32 0\n"
3440 
3441 		"%main      = OpFunction %void None %voidf\n"
3442 		"%label     = OpLabel\n"
3443 
3444 		"%undef     = OpUndef ${TYPE}\n"
3445 
3446 		"%idval     = OpLoad %uvec3 %id\n"
3447 		"%x         = OpCompositeExtract %u32 %idval 0\n"
3448 
3449 		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
3450 		"%inval     = OpLoad %f32 %inloc\n"
3451 		"%neg       = OpFNegate %f32 %inval\n"
3452 		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
3453 		"             OpStore %outloc %neg\n"
3454 		"             OpReturn\n"
3455 		"             OpFunctionEnd\n");
3456 
3457 	cases.push_back(CaseParameter("bool",			"%bool"));
3458 	cases.push_back(CaseParameter("sint32",			"%i32"));
3459 	cases.push_back(CaseParameter("uint32",			"%u32"));
3460 	cases.push_back(CaseParameter("float32",		"%f32"));
3461 	cases.push_back(CaseParameter("vec4float32",	"%fvec4"));
3462 	cases.push_back(CaseParameter("vec2uint32",		"%uvec2"));
3463 	cases.push_back(CaseParameter("matrix",			"%fmat33"));
3464 	cases.push_back(CaseParameter("image",			"%image"));
3465 	cases.push_back(CaseParameter("sampler",		"%sampler"));
3466 	cases.push_back(CaseParameter("sampledimage",	"%simage"));
3467 	cases.push_back(CaseParameter("array",			"%uarr100"));
3468 	cases.push_back(CaseParameter("runtimearray",	"%f32arr"));
3469 	cases.push_back(CaseParameter("struct",			"%struct"));
3470 	cases.push_back(CaseParameter("pointer",		"%pointer"));
3471 
3472 	fillRandomScalars(rnd, 1.f, 100.f, &positiveFloats[0], numElements);
3473 
3474 	for (size_t ndx = 0; ndx < numElements; ++ndx)
3475 		negativeFloats[ndx] = -positiveFloats[ndx];
3476 
3477 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
3478 	{
3479 		map<string, string>		specializations;
3480 		ComputeShaderSpec		spec;
3481 
3482 		specializations["TYPE"] = cases[caseNdx].param;
3483 		spec.assembly = shaderTemplate.specialize(specializations);
3484 		spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
3485 		spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
3486 		spec.numWorkGroups = IVec3(numElements, 1, 1);
3487 
3488 		group->addChild(new SpvAsmComputeShaderCase(testCtx, cases[caseNdx].name, cases[caseNdx].name, spec));
3489 	}
3490 
3491 		return group.release();
3492 }
3493 typedef std::pair<std::string, VkShaderStageFlagBits>	EntryToStage;
3494 typedef map<string, vector<EntryToStage> >				ModuleMap;
3495 typedef map<VkShaderStageFlagBits, vector<deInt32> >	StageToSpecConstantMap;
3496 
3497 // Context for a specific test instantiation. For example, an instantiation
3498 // may test colors yellow/magenta/cyan/mauve in a tesselation shader
3499 // with an entry point named 'main_to_the_main'
3500 struct InstanceContext
3501 {
3502 	// Map of modules to what entry_points we care to use from those modules.
3503 	ModuleMap				moduleMap;
3504 	RGBA					inputColors[4];
3505 	RGBA					outputColors[4];
3506 	// Concrete SPIR-V code to test via boilerplate specialization.
3507 	map<string, string>		testCodeFragments;
3508 	StageToSpecConstantMap	specConstants;
3509 	bool					hasTessellation;
3510 	VkShaderStageFlagBits	requiredStages;
3511 
InstanceContextvkt::SpirVAssembly::__anon889ef7250111::InstanceContext3512 	InstanceContext (const RGBA (&inputs)[4], const RGBA (&outputs)[4], const map<string, string>& testCodeFragments_, const StageToSpecConstantMap& specConstants_)
3513 		: testCodeFragments		(testCodeFragments_)
3514 		, specConstants			(specConstants_)
3515 		, hasTessellation		(false)
3516 		, requiredStages		(static_cast<VkShaderStageFlagBits>(0))
3517 	{
3518 		inputColors[0]		= inputs[0];
3519 		inputColors[1]		= inputs[1];
3520 		inputColors[2]		= inputs[2];
3521 		inputColors[3]		= inputs[3];
3522 
3523 		outputColors[0]		= outputs[0];
3524 		outputColors[1]		= outputs[1];
3525 		outputColors[2]		= outputs[2];
3526 		outputColors[3]		= outputs[3];
3527 	}
3528 
InstanceContextvkt::SpirVAssembly::__anon889ef7250111::InstanceContext3529 	InstanceContext (const InstanceContext& other)
3530 		: moduleMap			(other.moduleMap)
3531 		, testCodeFragments	(other.testCodeFragments)
3532 		, specConstants		(other.specConstants)
3533 		, hasTessellation	(other.hasTessellation)
3534 		, requiredStages    (other.requiredStages)
3535 	{
3536 		inputColors[0]		= other.inputColors[0];
3537 		inputColors[1]		= other.inputColors[1];
3538 		inputColors[2]		= other.inputColors[2];
3539 		inputColors[3]		= other.inputColors[3];
3540 
3541 		outputColors[0]		= other.outputColors[0];
3542 		outputColors[1]		= other.outputColors[1];
3543 		outputColors[2]		= other.outputColors[2];
3544 		outputColors[3]		= other.outputColors[3];
3545 	}
3546 };
3547 
3548 // A description of a shader to be used for a single stage of the graphics pipeline.
3549 struct ShaderElement
3550 {
3551 	// The module that contains this shader entrypoint.
3552 	string					moduleName;
3553 
3554 	// The name of the entrypoint.
3555 	string					entryName;
3556 
3557 	// Which shader stage this entry point represents.
3558 	VkShaderStageFlagBits	stage;
3559 
ShaderElementvkt::SpirVAssembly::__anon889ef7250111::ShaderElement3560 	ShaderElement (const string& moduleName_, const string& entryPoint_, VkShaderStageFlagBits shaderStage_)
3561 		: moduleName(moduleName_)
3562 		, entryName(entryPoint_)
3563 		, stage(shaderStage_)
3564 	{
3565 	}
3566 };
3567 
getDefaultColors(RGBA (& colors)[4])3568 void getDefaultColors (RGBA (&colors)[4])
3569 {
3570 	colors[0] = RGBA::white();
3571 	colors[1] = RGBA::red();
3572 	colors[2] = RGBA::green();
3573 	colors[3] = RGBA::blue();
3574 }
3575 
getHalfColorsFullAlpha(RGBA (& colors)[4])3576 void getHalfColorsFullAlpha (RGBA (&colors)[4])
3577 {
3578 	colors[0] = RGBA(127, 127, 127, 255);
3579 	colors[1] = RGBA(127, 0,   0,	255);
3580 	colors[2] = RGBA(0,	  127, 0,	255);
3581 	colors[3] = RGBA(0,	  0,   127, 255);
3582 }
3583 
getInvertedDefaultColors(RGBA (& colors)[4])3584 void getInvertedDefaultColors (RGBA (&colors)[4])
3585 {
3586 	colors[0] = RGBA(0,		0,		0,		255);
3587 	colors[1] = RGBA(0,		255,	255,	255);
3588 	colors[2] = RGBA(255,	0,		255,	255);
3589 	colors[3] = RGBA(255,	255,	0,		255);
3590 }
3591 
3592 // Turns a statically sized array of ShaderElements into an instance-context
3593 // by setting up the mapping of modules to their contained shaders and stages.
3594 // The inputs and expected outputs are given by inputColors and outputColors
3595 template<size_t N>
createInstanceContext(const ShaderElement (& elements)[N],const RGBA (& inputColors)[4],const RGBA (& outputColors)[4],const map<string,string> & testCodeFragments,const StageToSpecConstantMap & specConstants)3596 InstanceContext createInstanceContext (const ShaderElement (&elements)[N], const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map<string, string>& testCodeFragments, const StageToSpecConstantMap& specConstants)
3597 {
3598 	InstanceContext ctx (inputColors, outputColors, testCodeFragments, specConstants);
3599 	for (size_t i = 0; i < N; ++i)
3600 	{
3601 		ctx.moduleMap[elements[i].moduleName].push_back(std::make_pair(elements[i].entryName, elements[i].stage));
3602 		ctx.requiredStages = static_cast<VkShaderStageFlagBits>(ctx.requiredStages | elements[i].stage);
3603 	}
3604 	return ctx;
3605 }
3606 
3607 template<size_t N>
createInstanceContext(const ShaderElement (& elements)[N],RGBA (& inputColors)[4],const RGBA (& outputColors)[4],const map<string,string> & testCodeFragments)3608 inline InstanceContext createInstanceContext (const ShaderElement (&elements)[N], RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map<string, string>& testCodeFragments)
3609 {
3610 	return createInstanceContext(elements, inputColors, outputColors, testCodeFragments, StageToSpecConstantMap());
3611 }
3612 
3613 // The same as createInstanceContext above, but with default colors.
3614 template<size_t N>
createInstanceContext(const ShaderElement (& elements)[N],const map<string,string> & testCodeFragments)3615 InstanceContext createInstanceContext (const ShaderElement (&elements)[N], const map<string, string>& testCodeFragments)
3616 {
3617 	RGBA defaultColors[4];
3618 	getDefaultColors(defaultColors);
3619 	return createInstanceContext(elements, defaultColors, defaultColors, testCodeFragments);
3620 }
3621 
3622 // For the current InstanceContext, constructs the required modules and shader stage create infos.
createPipelineShaderStages(const DeviceInterface & vk,const VkDevice vkDevice,InstanceContext & instance,Context & context,vector<ModuleHandleSp> & modules,vector<VkPipelineShaderStageCreateInfo> & createInfos)3623 void createPipelineShaderStages (const DeviceInterface& vk, const VkDevice vkDevice, InstanceContext& instance, Context& context, vector<ModuleHandleSp>& modules, vector<VkPipelineShaderStageCreateInfo>& createInfos)
3624 {
3625 	for (ModuleMap::const_iterator moduleNdx = instance.moduleMap.begin(); moduleNdx != instance.moduleMap.end(); ++moduleNdx)
3626 	{
3627 		const ModuleHandleSp mod(new Unique<VkShaderModule>(createShaderModule(vk, vkDevice, context.getBinaryCollection().get(moduleNdx->first), 0)));
3628 		modules.push_back(ModuleHandleSp(mod));
3629 		for (vector<EntryToStage>::const_iterator shaderNdx = moduleNdx->second.begin(); shaderNdx != moduleNdx->second.end(); ++shaderNdx)
3630 		{
3631 			const EntryToStage&						stage			= *shaderNdx;
3632 			const VkPipelineShaderStageCreateInfo	shaderParam		=
3633 			{
3634 				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	//	VkStructureType			sType;
3635 				DE_NULL,												//	const void*				pNext;
3636 				(VkPipelineShaderStageCreateFlags)0,
3637 				stage.second,											//	VkShaderStageFlagBits	stage;
3638 				**modules.back(),										//	VkShaderModule			module;
3639 				stage.first.c_str(),									//	const char*				pName;
3640 				(const VkSpecializationInfo*)DE_NULL,
3641 			};
3642 			createInfos.push_back(shaderParam);
3643 		}
3644 	}
3645 }
3646 
3647 #define SPIRV_ASSEMBLY_TYPES																	\
3648 	"%void = OpTypeVoid\n"																		\
3649 	"%bool = OpTypeBool\n"																		\
3650 																								\
3651 	"%i32 = OpTypeInt 32 1\n"																	\
3652 	"%u32 = OpTypeInt 32 0\n"																	\
3653 																								\
3654 	"%f32 = OpTypeFloat 32\n"																	\
3655 	"%v3f32 = OpTypeVector %f32 3\n"															\
3656 	"%v4f32 = OpTypeVector %f32 4\n"															\
3657 	"%v4bool = OpTypeVector %bool 4\n"															\
3658 																								\
3659 	"%v4f32_function = OpTypeFunction %v4f32 %v4f32\n"											\
3660 	"%fun = OpTypeFunction %void\n"																\
3661 																								\
3662 	"%ip_f32 = OpTypePointer Input %f32\n"														\
3663 	"%ip_i32 = OpTypePointer Input %i32\n"														\
3664 	"%ip_v3f32 = OpTypePointer Input %v3f32\n"													\
3665 	"%ip_v4f32 = OpTypePointer Input %v4f32\n"													\
3666 																								\
3667 	"%op_f32 = OpTypePointer Output %f32\n"														\
3668 	"%op_v4f32 = OpTypePointer Output %v4f32\n"													\
3669 																								\
3670 	"%fp_f32   = OpTypePointer Function %f32\n"													\
3671 	"%fp_i32   = OpTypePointer Function %i32\n"													\
3672 	"%fp_v4f32 = OpTypePointer Function %v4f32\n"
3673 
3674 #define SPIRV_ASSEMBLY_CONSTANTS																\
3675 	"%c_f32_1 = OpConstant %f32 1.0\n"															\
3676 	"%c_f32_0 = OpConstant %f32 0.0\n"															\
3677 	"%c_f32_0_5 = OpConstant %f32 0.5\n"														\
3678 	"%c_f32_n1  = OpConstant %f32 -1.\n"														\
3679 	"%c_f32_7 = OpConstant %f32 7.0\n"															\
3680 	"%c_f32_8 = OpConstant %f32 8.0\n"															\
3681 	"%c_i32_0 = OpConstant %i32 0\n"															\
3682 	"%c_i32_1 = OpConstant %i32 1\n"															\
3683 	"%c_i32_2 = OpConstant %i32 2\n"															\
3684 	"%c_i32_3 = OpConstant %i32 3\n"															\
3685 	"%c_i32_4 = OpConstant %i32 4\n"															\
3686 	"%c_u32_0 = OpConstant %u32 0\n"															\
3687 	"%c_u32_1 = OpConstant %u32 1\n"															\
3688 	"%c_u32_2 = OpConstant %u32 2\n"															\
3689 	"%c_u32_3 = OpConstant %u32 3\n"															\
3690 	"%c_u32_32 = OpConstant %u32 32\n"															\
3691 	"%c_u32_4 = OpConstant %u32 4\n"															\
3692 	"%c_u32_31_bits = OpConstant %u32 0x7FFFFFFF\n"												\
3693 	"%c_v4f32_1_1_1_1 = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_1\n"		\
3694 	"%c_v4f32_1_0_0_1 = OpConstantComposite %v4f32 %c_f32_1 %c_f32_0 %c_f32_0 %c_f32_1\n"		\
3695 	"%c_v4f32_0_5_0_5_0_5_0_5 = OpConstantComposite %v4f32 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5\n"
3696 
3697 #define SPIRV_ASSEMBLY_ARRAYS																	\
3698 	"%a1f32 = OpTypeArray %f32 %c_u32_1\n"														\
3699 	"%a2f32 = OpTypeArray %f32 %c_u32_2\n"														\
3700 	"%a3v4f32 = OpTypeArray %v4f32 %c_u32_3\n"													\
3701 	"%a4f32 = OpTypeArray %f32 %c_u32_4\n"														\
3702 	"%a32v4f32 = OpTypeArray %v4f32 %c_u32_32\n"												\
3703 	"%ip_a3v4f32 = OpTypePointer Input %a3v4f32\n"												\
3704 	"%ip_a32v4f32 = OpTypePointer Input %a32v4f32\n"											\
3705 	"%op_a2f32 = OpTypePointer Output %a2f32\n"													\
3706 	"%op_a3v4f32 = OpTypePointer Output %a3v4f32\n"												\
3707 	"%op_a4f32 = OpTypePointer Output %a4f32\n"
3708 
3709 // Creates vertex-shader assembly by specializing a boilerplate StringTemplate
3710 // on fragments, which must (at least) map "testfun" to an OpFunction definition
3711 // for %test_code that takes and returns a %v4f32.  Boilerplate IDs are prefixed
3712 // with "BP_" to avoid collisions with fragments.
3713 //
3714 // It corresponds roughly to this GLSL:
3715 //;
3716 // layout(location = 0) in vec4 position;
3717 // layout(location = 1) in vec4 color;
3718 // layout(location = 1) out highp vec4 vtxColor;
3719 // void main (void) { gl_Position = position; vtxColor = test_func(color); }
makeVertexShaderAssembly(const map<string,string> & fragments)3720 string makeVertexShaderAssembly(const map<string, string>& fragments)
3721 {
3722 // \todo [2015-11-23 awoloszyn] Remove OpName once these have stabalized
3723 	static const char vertexShaderBoilerplate[] =
3724 		"OpCapability Shader\n"
3725 		"OpCapability ClipDistance\n"
3726 		"OpCapability CullDistance\n"
3727 		"OpMemoryModel Logical GLSL450\n"
3728 		"OpEntryPoint Vertex %main \"main\" %BP_stream %BP_position %BP_vtx_color %BP_color %BP_gl_VertexIndex %BP_gl_InstanceIndex\n"
3729 		"${debug:opt}\n"
3730 		"OpName %main \"main\"\n"
3731 		"OpName %BP_gl_PerVertex \"gl_PerVertex\"\n"
3732 		"OpMemberName %BP_gl_PerVertex 0 \"gl_Position\"\n"
3733 		"OpMemberName %BP_gl_PerVertex 1 \"gl_PointSize\"\n"
3734 		"OpMemberName %BP_gl_PerVertex 2 \"gl_ClipDistance\"\n"
3735 		"OpMemberName %BP_gl_PerVertex 3 \"gl_CullDistance\"\n"
3736 		"OpName %test_code \"testfun(vf4;\"\n"
3737 		"OpName %BP_stream \"\"\n"
3738 		"OpName %BP_position \"position\"\n"
3739 		"OpName %BP_vtx_color \"vtxColor\"\n"
3740 		"OpName %BP_color \"color\"\n"
3741 		"OpName %BP_gl_VertexIndex \"gl_VertexIndex\"\n"
3742 		"OpName %BP_gl_InstanceIndex \"gl_InstanceIndex\"\n"
3743 		"OpMemberDecorate %BP_gl_PerVertex 0 BuiltIn Position\n"
3744 		"OpMemberDecorate %BP_gl_PerVertex 1 BuiltIn PointSize\n"
3745 		"OpMemberDecorate %BP_gl_PerVertex 2 BuiltIn ClipDistance\n"
3746 		"OpMemberDecorate %BP_gl_PerVertex 3 BuiltIn CullDistance\n"
3747 		"OpDecorate %BP_gl_PerVertex Block\n"
3748 		"OpDecorate %BP_position Location 0\n"
3749 		"OpDecorate %BP_vtx_color Location 1\n"
3750 		"OpDecorate %BP_color Location 1\n"
3751 		"OpDecorate %BP_gl_VertexIndex BuiltIn VertexIndex\n"
3752 		"OpDecorate %BP_gl_InstanceIndex BuiltIn InstanceIndex\n"
3753 		"${decoration:opt}\n"
3754 		SPIRV_ASSEMBLY_TYPES
3755 		SPIRV_ASSEMBLY_CONSTANTS
3756 		SPIRV_ASSEMBLY_ARRAYS
3757 		"%BP_gl_PerVertex = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
3758 		"%BP_op_gl_PerVertex = OpTypePointer Output %BP_gl_PerVertex\n"
3759 		"%BP_stream = OpVariable %BP_op_gl_PerVertex Output\n"
3760 		"%BP_position = OpVariable %ip_v4f32 Input\n"
3761 		"%BP_vtx_color = OpVariable %op_v4f32 Output\n"
3762 		"%BP_color = OpVariable %ip_v4f32 Input\n"
3763 		"%BP_gl_VertexIndex = OpVariable %ip_i32 Input\n"
3764 		"%BP_gl_InstanceIndex = OpVariable %ip_i32 Input\n"
3765 		"${pre_main:opt}\n"
3766 		"%main = OpFunction %void None %fun\n"
3767 		"%BP_label = OpLabel\n"
3768 		"%BP_pos = OpLoad %v4f32 %BP_position\n"
3769 		"%BP_gl_pos = OpAccessChain %op_v4f32 %BP_stream %c_i32_0\n"
3770 		"OpStore %BP_gl_pos %BP_pos\n"
3771 		"%BP_col = OpLoad %v4f32 %BP_color\n"
3772 		"%BP_col_transformed = OpFunctionCall %v4f32 %test_code %BP_col\n"
3773 		"OpStore %BP_vtx_color %BP_col_transformed\n"
3774 		"OpReturn\n"
3775 		"OpFunctionEnd\n"
3776 		"${testfun}\n";
3777 	return tcu::StringTemplate(vertexShaderBoilerplate).specialize(fragments);
3778 }
3779 
3780 // Creates tess-control-shader assembly by specializing a boilerplate
3781 // StringTemplate on fragments, which must (at least) map "testfun" to an
3782 // OpFunction definition for %test_code that takes and returns a %v4f32.
3783 // Boilerplate IDs are prefixed with "BP_" to avoid collisions with fragments.
3784 //
3785 // It roughly corresponds to the following GLSL.
3786 //
3787 // #version 450
3788 // layout(vertices = 3) out;
3789 // layout(location = 1) in vec4 in_color[];
3790 // layout(location = 1) out vec4 out_color[];
3791 //
3792 // void main() {
3793 //   out_color[gl_InvocationID] = testfun(in_color[gl_InvocationID]);
3794 //   gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
3795 //   if (gl_InvocationID == 0) {
3796 //     gl_TessLevelOuter[0] = 1.0;
3797 //     gl_TessLevelOuter[1] = 1.0;
3798 //     gl_TessLevelOuter[2] = 1.0;
3799 //     gl_TessLevelInner[0] = 1.0;
3800 //   }
3801 // }
makeTessControlShaderAssembly(const map<string,string> & fragments)3802 string makeTessControlShaderAssembly (const map<string, string>& fragments)
3803 {
3804 	static const char tessControlShaderBoilerplate[] =
3805 		"OpCapability Tessellation\n"
3806 		"OpCapability ClipDistance\n"
3807 		"OpCapability CullDistance\n"
3808 		"OpMemoryModel Logical GLSL450\n"
3809 		"OpEntryPoint TessellationControl %BP_main \"main\" %BP_out_color %BP_gl_InvocationID %BP_in_color %BP_gl_out %BP_gl_in %BP_gl_TessLevelOuter %BP_gl_TessLevelInner\n"
3810 		"OpExecutionMode %BP_main OutputVertices 3\n"
3811 		"${debug:opt}\n"
3812 		"OpName %BP_main \"main\"\n"
3813 		"OpName %test_code \"testfun(vf4;\"\n"
3814 		"OpName %BP_out_color \"out_color\"\n"
3815 		"OpName %BP_gl_InvocationID \"gl_InvocationID\"\n"
3816 		"OpName %BP_in_color \"in_color\"\n"
3817 		"OpName %BP_gl_PerVertex \"gl_PerVertex\"\n"
3818 		"OpMemberName %BP_gl_PerVertex 0 \"gl_Position\"\n"
3819 		"OpMemberName %BP_gl_PerVertex 1 \"gl_PointSize\"\n"
3820 		"OpMemberName %BP_gl_PerVertex 2 \"gl_ClipDistance\"\n"
3821 		"OpMemberName %BP_gl_PerVertex 3 \"gl_CullDistance\"\n"
3822 		"OpName %BP_gl_out \"gl_out\"\n"
3823 		"OpName %BP_gl_PVOut \"gl_PerVertex\"\n"
3824 		"OpMemberName %BP_gl_PVOut 0 \"gl_Position\"\n"
3825 		"OpMemberName %BP_gl_PVOut 1 \"gl_PointSize\"\n"
3826 		"OpMemberName %BP_gl_PVOut 2 \"gl_ClipDistance\"\n"
3827 		"OpMemberName %BP_gl_PVOut 3 \"gl_CullDistance\"\n"
3828 		"OpName %BP_gl_in \"gl_in\"\n"
3829 		"OpName %BP_gl_TessLevelOuter \"gl_TessLevelOuter\"\n"
3830 		"OpName %BP_gl_TessLevelInner \"gl_TessLevelInner\"\n"
3831 		"OpDecorate %BP_out_color Location 1\n"
3832 		"OpDecorate %BP_gl_InvocationID BuiltIn InvocationId\n"
3833 		"OpDecorate %BP_in_color Location 1\n"
3834 		"OpMemberDecorate %BP_gl_PerVertex 0 BuiltIn Position\n"
3835 		"OpMemberDecorate %BP_gl_PerVertex 1 BuiltIn PointSize\n"
3836 		"OpMemberDecorate %BP_gl_PerVertex 2 BuiltIn ClipDistance\n"
3837 		"OpMemberDecorate %BP_gl_PerVertex 3 BuiltIn CullDistance\n"
3838 		"OpDecorate %BP_gl_PerVertex Block\n"
3839 		"OpMemberDecorate %BP_gl_PVOut 0 BuiltIn Position\n"
3840 		"OpMemberDecorate %BP_gl_PVOut 1 BuiltIn PointSize\n"
3841 		"OpMemberDecorate %BP_gl_PVOut 2 BuiltIn ClipDistance\n"
3842 		"OpMemberDecorate %BP_gl_PVOut 3 BuiltIn CullDistance\n"
3843 		"OpDecorate %BP_gl_PVOut Block\n"
3844 		"OpDecorate %BP_gl_TessLevelOuter Patch\n"
3845 		"OpDecorate %BP_gl_TessLevelOuter BuiltIn TessLevelOuter\n"
3846 		"OpDecorate %BP_gl_TessLevelInner Patch\n"
3847 		"OpDecorate %BP_gl_TessLevelInner BuiltIn TessLevelInner\n"
3848 		"${decoration:opt}\n"
3849 		SPIRV_ASSEMBLY_TYPES
3850 		SPIRV_ASSEMBLY_CONSTANTS
3851 		SPIRV_ASSEMBLY_ARRAYS
3852 		"%BP_out_color = OpVariable %op_a3v4f32 Output\n"
3853 		"%BP_gl_InvocationID = OpVariable %ip_i32 Input\n"
3854 		"%BP_in_color = OpVariable %ip_a32v4f32 Input\n"
3855 		"%BP_gl_PerVertex = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
3856 		"%BP_a3_gl_PerVertex = OpTypeArray %BP_gl_PerVertex %c_u32_3\n"
3857 		"%BP_op_a3_gl_PerVertex = OpTypePointer Output %BP_a3_gl_PerVertex\n"
3858 		"%BP_gl_out = OpVariable %BP_op_a3_gl_PerVertex Output\n"
3859 		"%BP_gl_PVOut = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
3860 		"%BP_a32_gl_PVOut = OpTypeArray %BP_gl_PVOut %c_u32_32\n"
3861 		"%BP_ip_a32_gl_PVOut = OpTypePointer Input %BP_a32_gl_PVOut\n"
3862 		"%BP_gl_in = OpVariable %BP_ip_a32_gl_PVOut Input\n"
3863 		"%BP_gl_TessLevelOuter = OpVariable %op_a4f32 Output\n"
3864 		"%BP_gl_TessLevelInner = OpVariable %op_a2f32 Output\n"
3865 		"${pre_main:opt}\n"
3866 
3867 		"%BP_main = OpFunction %void None %fun\n"
3868 		"%BP_label = OpLabel\n"
3869 
3870 		"%BP_gl_Invoc = OpLoad %i32 %BP_gl_InvocationID\n"
3871 
3872 		"%BP_in_col_loc = OpAccessChain %ip_v4f32 %BP_in_color %BP_gl_Invoc\n"
3873 		"%BP_out_col_loc = OpAccessChain %op_v4f32 %BP_out_color %BP_gl_Invoc\n"
3874 		"%BP_in_col_val = OpLoad %v4f32 %BP_in_col_loc\n"
3875 		"%BP_clr_transformed = OpFunctionCall %v4f32 %test_code %BP_in_col_val\n"
3876 		"OpStore %BP_out_col_loc %BP_clr_transformed\n"
3877 
3878 		"%BP_in_pos_loc = OpAccessChain %ip_v4f32 %BP_gl_in %BP_gl_Invoc %c_i32_0\n"
3879 		"%BP_out_pos_loc = OpAccessChain %op_v4f32 %BP_gl_out %BP_gl_Invoc %c_i32_0\n"
3880 		"%BP_in_pos_val = OpLoad %v4f32 %BP_in_pos_loc\n"
3881 		"OpStore %BP_out_pos_loc %BP_in_pos_val\n"
3882 
3883 		"%BP_cmp = OpIEqual %bool %BP_gl_Invoc %c_i32_0\n"
3884 		"OpSelectionMerge %BP_merge_label None\n"
3885 		"OpBranchConditional %BP_cmp %BP_if_label %BP_merge_label\n"
3886 		"%BP_if_label = OpLabel\n"
3887 		"%BP_gl_TessLevelOuterPos_0 = OpAccessChain %op_f32 %BP_gl_TessLevelOuter %c_i32_0\n"
3888 		"%BP_gl_TessLevelOuterPos_1 = OpAccessChain %op_f32 %BP_gl_TessLevelOuter %c_i32_1\n"
3889 		"%BP_gl_TessLevelOuterPos_2 = OpAccessChain %op_f32 %BP_gl_TessLevelOuter %c_i32_2\n"
3890 		"%BP_gl_TessLevelInnerPos_0 = OpAccessChain %op_f32 %BP_gl_TessLevelInner %c_i32_0\n"
3891 		"OpStore %BP_gl_TessLevelOuterPos_0 %c_f32_1\n"
3892 		"OpStore %BP_gl_TessLevelOuterPos_1 %c_f32_1\n"
3893 		"OpStore %BP_gl_TessLevelOuterPos_2 %c_f32_1\n"
3894 		"OpStore %BP_gl_TessLevelInnerPos_0 %c_f32_1\n"
3895 		"OpBranch %BP_merge_label\n"
3896 		"%BP_merge_label = OpLabel\n"
3897 		"OpReturn\n"
3898 		"OpFunctionEnd\n"
3899 		"${testfun}\n";
3900 	return tcu::StringTemplate(tessControlShaderBoilerplate).specialize(fragments);
3901 }
3902 
3903 // Creates tess-evaluation-shader assembly by specializing a boilerplate
3904 // StringTemplate on fragments, which must (at least) map "testfun" to an
3905 // OpFunction definition for %test_code that takes and returns a %v4f32.
3906 // Boilerplate IDs are prefixed with "BP_" to avoid collisions with fragments.
3907 //
3908 // It roughly corresponds to the following glsl.
3909 //
3910 // #version 450
3911 //
3912 // layout(triangles, equal_spacing, ccw) in;
3913 // layout(location = 1) in vec4 in_color[];
3914 // layout(location = 1) out vec4 out_color;
3915 //
3916 // #define interpolate(val)
3917 //   vec4(gl_TessCoord.x) * val[0] + vec4(gl_TessCoord.y) * val[1] +
3918 //          vec4(gl_TessCoord.z) * val[2]
3919 //
3920 // void main() {
3921 //   gl_Position = vec4(gl_TessCoord.x) * gl_in[0].gl_Position +
3922 //                  vec4(gl_TessCoord.y) * gl_in[1].gl_Position +
3923 //                  vec4(gl_TessCoord.z) * gl_in[2].gl_Position;
3924 //   out_color = testfun(interpolate(in_color));
3925 // }
makeTessEvalShaderAssembly(const map<string,string> & fragments)3926 string makeTessEvalShaderAssembly(const map<string, string>& fragments)
3927 {
3928 	static const char tessEvalBoilerplate[] =
3929 		"OpCapability Tessellation\n"
3930 		"OpCapability ClipDistance\n"
3931 		"OpCapability CullDistance\n"
3932 		"OpMemoryModel Logical GLSL450\n"
3933 		"OpEntryPoint TessellationEvaluation %BP_main \"main\" %BP_stream %BP_gl_TessCoord %BP_gl_in %BP_out_color %BP_in_color\n"
3934 		"OpExecutionMode %BP_main Triangles\n"
3935 		"OpExecutionMode %BP_main SpacingEqual\n"
3936 		"OpExecutionMode %BP_main VertexOrderCcw\n"
3937 		"${debug:opt}\n"
3938 		"OpName %BP_main \"main\"\n"
3939 		"OpName %test_code \"testfun(vf4;\"\n"
3940 		"OpName %BP_gl_PerVertexOut \"gl_PerVertex\"\n"
3941 		"OpMemberName %BP_gl_PerVertexOut 0 \"gl_Position\"\n"
3942 		"OpMemberName %BP_gl_PerVertexOut 1 \"gl_PointSize\"\n"
3943 		"OpMemberName %BP_gl_PerVertexOut 2 \"gl_ClipDistance\"\n"
3944 		"OpMemberName %BP_gl_PerVertexOut 3 \"gl_CullDistance\"\n"
3945 		"OpName %BP_stream \"\"\n"
3946 		"OpName %BP_gl_TessCoord \"gl_TessCoord\"\n"
3947 		"OpName %BP_gl_PerVertexIn \"gl_PerVertex\"\n"
3948 		"OpMemberName %BP_gl_PerVertexIn 0 \"gl_Position\"\n"
3949 		"OpMemberName %BP_gl_PerVertexIn 1 \"gl_PointSize\"\n"
3950 		"OpMemberName %BP_gl_PerVertexIn 2 \"gl_ClipDistance\"\n"
3951 		"OpMemberName %BP_gl_PerVertexIn 3 \"gl_CullDistance\"\n"
3952 		"OpName %BP_gl_in \"gl_in\"\n"
3953 		"OpName %BP_out_color \"out_color\"\n"
3954 		"OpName %BP_in_color \"in_color\"\n"
3955 		"OpMemberDecorate %BP_gl_PerVertexOut 0 BuiltIn Position\n"
3956 		"OpMemberDecorate %BP_gl_PerVertexOut 1 BuiltIn PointSize\n"
3957 		"OpMemberDecorate %BP_gl_PerVertexOut 2 BuiltIn ClipDistance\n"
3958 		"OpMemberDecorate %BP_gl_PerVertexOut 3 BuiltIn CullDistance\n"
3959 		"OpDecorate %BP_gl_PerVertexOut Block\n"
3960 		"OpDecorate %BP_gl_TessCoord BuiltIn TessCoord\n"
3961 		"OpMemberDecorate %BP_gl_PerVertexIn 0 BuiltIn Position\n"
3962 		"OpMemberDecorate %BP_gl_PerVertexIn 1 BuiltIn PointSize\n"
3963 		"OpMemberDecorate %BP_gl_PerVertexIn 2 BuiltIn ClipDistance\n"
3964 		"OpMemberDecorate %BP_gl_PerVertexIn 3 BuiltIn CullDistance\n"
3965 		"OpDecorate %BP_gl_PerVertexIn Block\n"
3966 		"OpDecorate %BP_out_color Location 1\n"
3967 		"OpDecorate %BP_in_color Location 1\n"
3968 		"${decoration:opt}\n"
3969 		SPIRV_ASSEMBLY_TYPES
3970 		SPIRV_ASSEMBLY_CONSTANTS
3971 		SPIRV_ASSEMBLY_ARRAYS
3972 		"%BP_gl_PerVertexOut = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
3973 		"%BP_op_gl_PerVertexOut = OpTypePointer Output %BP_gl_PerVertexOut\n"
3974 		"%BP_stream = OpVariable %BP_op_gl_PerVertexOut Output\n"
3975 		"%BP_gl_TessCoord = OpVariable %ip_v3f32 Input\n"
3976 		"%BP_gl_PerVertexIn = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
3977 		"%BP_a32_gl_PerVertexIn = OpTypeArray %BP_gl_PerVertexIn %c_u32_32\n"
3978 		"%BP_ip_a32_gl_PerVertexIn = OpTypePointer Input %BP_a32_gl_PerVertexIn\n"
3979 		"%BP_gl_in = OpVariable %BP_ip_a32_gl_PerVertexIn Input\n"
3980 		"%BP_out_color = OpVariable %op_v4f32 Output\n"
3981 		"%BP_in_color = OpVariable %ip_a32v4f32 Input\n"
3982 		"${pre_main:opt}\n"
3983 		"%BP_main = OpFunction %void None %fun\n"
3984 		"%BP_label = OpLabel\n"
3985 		"%BP_gl_TC_0 = OpAccessChain %ip_f32 %BP_gl_TessCoord %c_u32_0\n"
3986 		"%BP_gl_TC_1 = OpAccessChain %ip_f32 %BP_gl_TessCoord %c_u32_1\n"
3987 		"%BP_gl_TC_2 = OpAccessChain %ip_f32 %BP_gl_TessCoord %c_u32_2\n"
3988 		"%BP_gl_in_gl_Pos_0 = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_0 %c_i32_0\n"
3989 		"%BP_gl_in_gl_Pos_1 = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_1 %c_i32_0\n"
3990 		"%BP_gl_in_gl_Pos_2 = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_2 %c_i32_0\n"
3991 
3992 		"%BP_gl_OPos = OpAccessChain %op_v4f32 %BP_stream %c_i32_0\n"
3993 		"%BP_in_color_0 = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_0\n"
3994 		"%BP_in_color_1 = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_1\n"
3995 		"%BP_in_color_2 = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_2\n"
3996 
3997 		"%BP_TC_W_0 = OpLoad %f32 %BP_gl_TC_0\n"
3998 		"%BP_TC_W_1 = OpLoad %f32 %BP_gl_TC_1\n"
3999 		"%BP_TC_W_2 = OpLoad %f32 %BP_gl_TC_2\n"
4000 		"%BP_v4f32_TC_0 = OpCompositeConstruct %v4f32 %BP_TC_W_0 %BP_TC_W_0 %BP_TC_W_0 %BP_TC_W_0\n"
4001 		"%BP_v4f32_TC_1 = OpCompositeConstruct %v4f32 %BP_TC_W_1 %BP_TC_W_1 %BP_TC_W_1 %BP_TC_W_1\n"
4002 		"%BP_v4f32_TC_2 = OpCompositeConstruct %v4f32 %BP_TC_W_2 %BP_TC_W_2 %BP_TC_W_2 %BP_TC_W_2\n"
4003 
4004 		"%BP_gl_IP_0 = OpLoad %v4f32 %BP_gl_in_gl_Pos_0\n"
4005 		"%BP_gl_IP_1 = OpLoad %v4f32 %BP_gl_in_gl_Pos_1\n"
4006 		"%BP_gl_IP_2 = OpLoad %v4f32 %BP_gl_in_gl_Pos_2\n"
4007 
4008 		"%BP_IP_W_0 = OpFMul %v4f32 %BP_v4f32_TC_0 %BP_gl_IP_0\n"
4009 		"%BP_IP_W_1 = OpFMul %v4f32 %BP_v4f32_TC_1 %BP_gl_IP_1\n"
4010 		"%BP_IP_W_2 = OpFMul %v4f32 %BP_v4f32_TC_2 %BP_gl_IP_2\n"
4011 
4012 		"%BP_pos_sum_0 = OpFAdd %v4f32 %BP_IP_W_0 %BP_IP_W_1\n"
4013 		"%BP_pos_sum_1 = OpFAdd %v4f32 %BP_pos_sum_0 %BP_IP_W_2\n"
4014 
4015 		"OpStore %BP_gl_OPos %BP_pos_sum_1\n"
4016 
4017 		"%BP_IC_0 = OpLoad %v4f32 %BP_in_color_0\n"
4018 		"%BP_IC_1 = OpLoad %v4f32 %BP_in_color_1\n"
4019 		"%BP_IC_2 = OpLoad %v4f32 %BP_in_color_2\n"
4020 
4021 		"%BP_IC_W_0 = OpFMul %v4f32 %BP_v4f32_TC_0 %BP_IC_0\n"
4022 		"%BP_IC_W_1 = OpFMul %v4f32 %BP_v4f32_TC_1 %BP_IC_1\n"
4023 		"%BP_IC_W_2 = OpFMul %v4f32 %BP_v4f32_TC_2 %BP_IC_2\n"
4024 
4025 		"%BP_col_sum_0 = OpFAdd %v4f32 %BP_IC_W_0 %BP_IC_W_1\n"
4026 		"%BP_col_sum_1 = OpFAdd %v4f32 %BP_col_sum_0 %BP_IC_W_2\n"
4027 
4028 		"%BP_clr_transformed = OpFunctionCall %v4f32 %test_code %BP_col_sum_1\n"
4029 
4030 		"OpStore %BP_out_color %BP_clr_transformed\n"
4031 		"OpReturn\n"
4032 		"OpFunctionEnd\n"
4033 		"${testfun}\n";
4034 	return tcu::StringTemplate(tessEvalBoilerplate).specialize(fragments);
4035 }
4036 
4037 // Creates geometry-shader assembly by specializing a boilerplate StringTemplate
4038 // on fragments, which must (at least) map "testfun" to an OpFunction definition
4039 // for %test_code that takes and returns a %v4f32.  Boilerplate IDs are prefixed
4040 // with "BP_" to avoid collisions with fragments.
4041 //
4042 // Derived from this GLSL:
4043 //
4044 // #version 450
4045 // layout(triangles) in;
4046 // layout(triangle_strip, max_vertices = 3) out;
4047 //
4048 // layout(location = 1) in vec4 in_color[];
4049 // layout(location = 1) out vec4 out_color;
4050 //
4051 // void main() {
4052 //   gl_Position = gl_in[0].gl_Position;
4053 //   out_color = test_fun(in_color[0]);
4054 //   EmitVertex();
4055 //   gl_Position = gl_in[1].gl_Position;
4056 //   out_color = test_fun(in_color[1]);
4057 //   EmitVertex();
4058 //   gl_Position = gl_in[2].gl_Position;
4059 //   out_color = test_fun(in_color[2]);
4060 //   EmitVertex();
4061 //   EndPrimitive();
4062 // }
makeGeometryShaderAssembly(const map<string,string> & fragments)4063 string makeGeometryShaderAssembly(const map<string, string>& fragments)
4064 {
4065 	static const char geometryShaderBoilerplate[] =
4066 		"OpCapability Geometry\n"
4067 		"OpCapability ClipDistance\n"
4068 		"OpCapability CullDistance\n"
4069 		"OpMemoryModel Logical GLSL450\n"
4070 		"OpEntryPoint Geometry %BP_main \"main\" %BP_out_gl_position %BP_gl_in %BP_out_color %BP_in_color\n"
4071 		"OpExecutionMode %BP_main Triangles\n"
4072 		"OpExecutionMode %BP_main OutputTriangleStrip\n"
4073 		"OpExecutionMode %BP_main OutputVertices 3\n"
4074 		"${debug:opt}\n"
4075 		"OpName %BP_main \"main\"\n"
4076 		"OpName %BP_per_vertex_in \"gl_PerVertex\"\n"
4077 		"OpMemberName %BP_per_vertex_in 0 \"gl_Position\"\n"
4078 		"OpMemberName %BP_per_vertex_in 1 \"gl_PointSize\"\n"
4079 		"OpMemberName %BP_per_vertex_in 2 \"gl_ClipDistance\"\n"
4080 		"OpMemberName %BP_per_vertex_in 3 \"gl_CullDistance\"\n"
4081 		"OpName %BP_gl_in \"gl_in\"\n"
4082 		"OpName %BP_out_color \"out_color\"\n"
4083 		"OpName %BP_in_color \"in_color\"\n"
4084 		"OpName %test_code \"testfun(vf4;\"\n"
4085 		"OpDecorate %BP_out_gl_position BuiltIn Position\n"
4086 		"OpMemberDecorate %BP_per_vertex_in 0 BuiltIn Position\n"
4087 		"OpMemberDecorate %BP_per_vertex_in 1 BuiltIn PointSize\n"
4088 		"OpMemberDecorate %BP_per_vertex_in 2 BuiltIn ClipDistance\n"
4089 		"OpMemberDecorate %BP_per_vertex_in 3 BuiltIn CullDistance\n"
4090 		"OpDecorate %BP_per_vertex_in Block\n"
4091 		"OpDecorate %BP_out_color Location 1\n"
4092 		"OpDecorate %BP_in_color Location 1\n"
4093 		"${decoration:opt}\n"
4094 		SPIRV_ASSEMBLY_TYPES
4095 		SPIRV_ASSEMBLY_CONSTANTS
4096 		SPIRV_ASSEMBLY_ARRAYS
4097 		"%BP_per_vertex_in = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
4098 		"%BP_a3_per_vertex_in = OpTypeArray %BP_per_vertex_in %c_u32_3\n"
4099 		"%BP_ip_a3_per_vertex_in = OpTypePointer Input %BP_a3_per_vertex_in\n"
4100 
4101 		"%BP_gl_in = OpVariable %BP_ip_a3_per_vertex_in Input\n"
4102 		"%BP_out_color = OpVariable %op_v4f32 Output\n"
4103 		"%BP_in_color = OpVariable %ip_a3v4f32 Input\n"
4104 		"%BP_out_gl_position = OpVariable %op_v4f32 Output\n"
4105 		"${pre_main:opt}\n"
4106 
4107 		"%BP_main = OpFunction %void None %fun\n"
4108 		"%BP_label = OpLabel\n"
4109 		"%BP_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_0 %c_i32_0\n"
4110 		"%BP_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_1 %c_i32_0\n"
4111 		"%BP_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_2 %c_i32_0\n"
4112 
4113 		"%BP_in_position_0 = OpLoad %v4f32 %BP_gl_in_0_gl_position\n"
4114 		"%BP_in_position_1 = OpLoad %v4f32 %BP_gl_in_1_gl_position\n"
4115 		"%BP_in_position_2 = OpLoad %v4f32 %BP_gl_in_2_gl_position \n"
4116 
4117 		"%BP_in_color_0_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_0\n"
4118 		"%BP_in_color_1_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_1\n"
4119 		"%BP_in_color_2_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_2\n"
4120 
4121 		"%BP_in_color_0 = OpLoad %v4f32 %BP_in_color_0_ptr\n"
4122 		"%BP_in_color_1 = OpLoad %v4f32 %BP_in_color_1_ptr\n"
4123 		"%BP_in_color_2 = OpLoad %v4f32 %BP_in_color_2_ptr\n"
4124 
4125 		"%BP_transformed_in_color_0 = OpFunctionCall %v4f32 %test_code %BP_in_color_0\n"
4126 		"%BP_transformed_in_color_1 = OpFunctionCall %v4f32 %test_code %BP_in_color_1\n"
4127 		"%BP_transformed_in_color_2 = OpFunctionCall %v4f32 %test_code %BP_in_color_2\n"
4128 
4129 
4130 		"OpStore %BP_out_gl_position %BP_in_position_0\n"
4131 		"OpStore %BP_out_color %BP_transformed_in_color_0\n"
4132 		"OpEmitVertex\n"
4133 
4134 		"OpStore %BP_out_gl_position %BP_in_position_1\n"
4135 		"OpStore %BP_out_color %BP_transformed_in_color_1\n"
4136 		"OpEmitVertex\n"
4137 
4138 		"OpStore %BP_out_gl_position %BP_in_position_2\n"
4139 		"OpStore %BP_out_color %BP_transformed_in_color_2\n"
4140 		"OpEmitVertex\n"
4141 
4142 		"OpEndPrimitive\n"
4143 		"OpReturn\n"
4144 		"OpFunctionEnd\n"
4145 		"${testfun}\n";
4146 	return tcu::StringTemplate(geometryShaderBoilerplate).specialize(fragments);
4147 }
4148 
4149 // Creates fragment-shader assembly by specializing a boilerplate StringTemplate
4150 // on fragments, which must (at least) map "testfun" to an OpFunction definition
4151 // for %test_code that takes and returns a %v4f32.  Boilerplate IDs are prefixed
4152 // with "BP_" to avoid collisions with fragments.
4153 //
4154 // Derived from this GLSL:
4155 //
4156 // layout(location = 1) in highp vec4 vtxColor;
4157 // layout(location = 0) out highp vec4 fragColor;
4158 // highp vec4 testfun(highp vec4 x) { return x; }
4159 // void main(void) { fragColor = testfun(vtxColor); }
4160 //
4161 // with modifications including passing vtxColor by value and ripping out
4162 // testfun() definition.
makeFragmentShaderAssembly(const map<string,string> & fragments)4163 string makeFragmentShaderAssembly(const map<string, string>& fragments)
4164 {
4165 	static const char fragmentShaderBoilerplate[] =
4166 		"OpCapability Shader\n"
4167 		"OpMemoryModel Logical GLSL450\n"
4168 		"OpEntryPoint Fragment %BP_main \"main\" %BP_vtxColor %BP_fragColor\n"
4169 		"OpExecutionMode %BP_main OriginUpperLeft\n"
4170 		"${debug:opt}\n"
4171 		"OpName %BP_main \"main\"\n"
4172 		"OpName %BP_fragColor \"fragColor\"\n"
4173 		"OpName %BP_vtxColor \"vtxColor\"\n"
4174 		"OpName %test_code \"testfun(vf4;\"\n"
4175 		"OpDecorate %BP_fragColor Location 0\n"
4176 		"OpDecorate %BP_vtxColor Location 1\n"
4177 		"${decoration:opt}\n"
4178 		SPIRV_ASSEMBLY_TYPES
4179 		SPIRV_ASSEMBLY_CONSTANTS
4180 		SPIRV_ASSEMBLY_ARRAYS
4181 		"%BP_fragColor = OpVariable %op_v4f32 Output\n"
4182 		"%BP_vtxColor = OpVariable %ip_v4f32 Input\n"
4183 		"${pre_main:opt}\n"
4184 		"%BP_main = OpFunction %void None %fun\n"
4185 		"%BP_label_main = OpLabel\n"
4186 		"%BP_tmp1 = OpLoad %v4f32 %BP_vtxColor\n"
4187 		"%BP_tmp2 = OpFunctionCall %v4f32 %test_code %BP_tmp1\n"
4188 		"OpStore %BP_fragColor %BP_tmp2\n"
4189 		"OpReturn\n"
4190 		"OpFunctionEnd\n"
4191 		"${testfun}\n";
4192 	return tcu::StringTemplate(fragmentShaderBoilerplate).specialize(fragments);
4193 }
4194 
4195 // Creates fragments that specialize into a simple pass-through shader (of any kind).
passthruFragments(void)4196 map<string, string> passthruFragments(void)
4197 {
4198 	map<string, string> fragments;
4199 	fragments["testfun"] =
4200 		// A %test_code function that returns its argument unchanged.
4201 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
4202 		"%param1 = OpFunctionParameter %v4f32\n"
4203 		"%label_testfun = OpLabel\n"
4204 		"OpReturnValue %param1\n"
4205 		"OpFunctionEnd\n";
4206 	return fragments;
4207 }
4208 
4209 // Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
4210 // Vertex shader gets custom code from context, the rest are pass-through.
addShaderCodeCustomVertex(vk::SourceCollections & dst,InstanceContext context)4211 void addShaderCodeCustomVertex(vk::SourceCollections& dst, InstanceContext context)
4212 {
4213 	map<string, string> passthru = passthruFragments();
4214 	dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(context.testCodeFragments);
4215 	dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(passthru);
4216 }
4217 
4218 // Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
4219 // Tessellation control shader gets custom code from context, the rest are
4220 // pass-through.
addShaderCodeCustomTessControl(vk::SourceCollections & dst,InstanceContext context)4221 void addShaderCodeCustomTessControl(vk::SourceCollections& dst, InstanceContext context)
4222 {
4223 	map<string, string> passthru = passthruFragments();
4224 	dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
4225 	dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(context.testCodeFragments);
4226 	dst.spirvAsmSources.add("tesse") << makeTessEvalShaderAssembly(passthru);
4227 	dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(passthru);
4228 }
4229 
4230 // Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
4231 // Tessellation evaluation shader gets custom code from context, the rest are
4232 // pass-through.
addShaderCodeCustomTessEval(vk::SourceCollections & dst,InstanceContext context)4233 void addShaderCodeCustomTessEval(vk::SourceCollections& dst, InstanceContext context)
4234 {
4235 	map<string, string> passthru = passthruFragments();
4236 	dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
4237 	dst.spirvAsmSources.add("tessc") << makeTessControlShaderAssembly(passthru);
4238 	dst.spirvAsmSources.add("tesse") << makeTessEvalShaderAssembly(context.testCodeFragments);
4239 	dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(passthru);
4240 }
4241 
4242 // Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
4243 // Geometry shader gets custom code from context, the rest are pass-through.
addShaderCodeCustomGeometry(vk::SourceCollections & dst,InstanceContext context)4244 void addShaderCodeCustomGeometry(vk::SourceCollections& dst, InstanceContext context)
4245 {
4246 	map<string, string> passthru = passthruFragments();
4247 	dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
4248 	dst.spirvAsmSources.add("geom") << makeGeometryShaderAssembly(context.testCodeFragments);
4249 	dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(passthru);
4250 }
4251 
4252 // Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
4253 // Fragment shader gets custom code from context, the rest are pass-through.
addShaderCodeCustomFragment(vk::SourceCollections & dst,InstanceContext context)4254 void addShaderCodeCustomFragment(vk::SourceCollections& dst, InstanceContext context)
4255 {
4256 	map<string, string> passthru = passthruFragments();
4257 	dst.spirvAsmSources.add("vert") << makeVertexShaderAssembly(passthru);
4258 	dst.spirvAsmSources.add("frag") << makeFragmentShaderAssembly(context.testCodeFragments);
4259 }
4260 
createCombinedModule(vk::SourceCollections & dst,InstanceContext)4261 void createCombinedModule(vk::SourceCollections& dst, InstanceContext)
4262 {
4263 	// \todo [2015-12-07 awoloszyn] Make tessellation / geometry conditional
4264 	// \todo [2015-12-07 awoloszyn] Remove OpName and OpMemberName at some point
4265 	dst.spirvAsmSources.add("module") <<
4266 		"OpCapability Shader\n"
4267 		"OpCapability ClipDistance\n"
4268 		"OpCapability CullDistance\n"
4269 		"OpCapability Geometry\n"
4270 		"OpCapability Tessellation\n"
4271 		"OpMemoryModel Logical GLSL450\n"
4272 
4273 		"OpEntryPoint Vertex %vert_main \"main\" %vert_Position %vert_vtxColor %vert_color %vert_vtxPosition %vert_vertex_id %vert_instance_id\n"
4274 		"OpEntryPoint Geometry %geom_main \"main\" %geom_out_gl_position %geom_gl_in %geom_out_color %geom_in_color\n"
4275 		"OpEntryPoint TessellationControl %tessc_main \"main\" %tessc_out_color %tessc_gl_InvocationID %tessc_in_color %tessc_out_position %tessc_in_position %tessc_gl_TessLevelOuter %tessc_gl_TessLevelInner\n"
4276 		"OpEntryPoint TessellationEvaluation %tesse_main \"main\" %tesse_stream %tesse_gl_tessCoord %tesse_in_position %tesse_out_color %tesse_in_color \n"
4277 		"OpEntryPoint Fragment %frag_main \"main\" %frag_vtxColor %frag_fragColor\n"
4278 
4279 		"OpExecutionMode %geom_main Triangles\n"
4280 		"OpExecutionMode %geom_main OutputTriangleStrip\n"
4281 		"OpExecutionMode %geom_main OutputVertices 3\n"
4282 
4283 		"OpExecutionMode %tessc_main OutputVertices 3\n"
4284 
4285 		"OpExecutionMode %tesse_main Triangles\n"
4286 		"OpExecutionMode %tesse_main SpacingEqual\n"
4287 		"OpExecutionMode %tesse_main VertexOrderCcw\n"
4288 
4289 		"OpExecutionMode %frag_main OriginUpperLeft\n"
4290 
4291 		"OpName %vert_main \"main\"\n"
4292 		"OpName %vert_vtxPosition \"vtxPosition\"\n"
4293 		"OpName %vert_Position \"position\"\n"
4294 		"OpName %vert_vtxColor \"vtxColor\"\n"
4295 		"OpName %vert_color \"color\"\n"
4296 		"OpName %vert_vertex_id \"gl_VertexIndex\"\n"
4297 		"OpName %vert_instance_id \"gl_InstanceIndex\"\n"
4298 		"OpName %geom_main \"main\"\n"
4299 		"OpName %geom_per_vertex_in \"gl_PerVertex\"\n"
4300 		"OpMemberName %geom_per_vertex_in 0 \"gl_Position\"\n"
4301 		"OpMemberName %geom_per_vertex_in 1 \"gl_PointSize\"\n"
4302 		"OpMemberName %geom_per_vertex_in 2 \"gl_ClipDistance\"\n"
4303 		"OpMemberName %geom_per_vertex_in 3 \"gl_CullDistance\"\n"
4304 		"OpName %geom_gl_in \"gl_in\"\n"
4305 		"OpName %geom_out_color \"out_color\"\n"
4306 		"OpName %geom_in_color \"in_color\"\n"
4307 		"OpName %tessc_main \"main\"\n"
4308 		"OpName %tessc_out_color \"out_color\"\n"
4309 		"OpName %tessc_gl_InvocationID \"gl_InvocationID\"\n"
4310 		"OpName %tessc_in_color \"in_color\"\n"
4311 		"OpName %tessc_out_position \"out_position\"\n"
4312 		"OpName %tessc_in_position \"in_position\"\n"
4313 		"OpName %tessc_gl_TessLevelOuter \"gl_TessLevelOuter\"\n"
4314 		"OpName %tessc_gl_TessLevelInner \"gl_TessLevelInner\"\n"
4315 		"OpName %tesse_main \"main\"\n"
4316 		"OpName %tesse_per_vertex_out \"gl_PerVertex\"\n"
4317 		"OpMemberName %tesse_per_vertex_out 0 \"gl_Position\"\n"
4318 		"OpMemberName %tesse_per_vertex_out 1 \"gl_PointSize\"\n"
4319 		"OpMemberName %tesse_per_vertex_out 2 \"gl_ClipDistance\"\n"
4320 		"OpMemberName %tesse_per_vertex_out 3 \"gl_CullDistance\"\n"
4321 		"OpName %tesse_stream \"\"\n"
4322 		"OpName %tesse_gl_tessCoord \"gl_TessCoord\"\n"
4323 		"OpName %tesse_in_position \"in_position\"\n"
4324 		"OpName %tesse_out_color \"out_color\"\n"
4325 		"OpName %tesse_in_color \"in_color\"\n"
4326 		"OpName %frag_main \"main\"\n"
4327 		"OpName %frag_fragColor \"fragColor\"\n"
4328 		"OpName %frag_vtxColor \"vtxColor\"\n"
4329 
4330 		"; Vertex decorations\n"
4331 		"OpDecorate %vert_vtxPosition Location 2\n"
4332 		"OpDecorate %vert_Position Location 0\n"
4333 		"OpDecorate %vert_vtxColor Location 1\n"
4334 		"OpDecorate %vert_color Location 1\n"
4335 		"OpDecorate %vert_vertex_id BuiltIn VertexIndex\n"
4336 		"OpDecorate %vert_instance_id BuiltIn InstanceIndex\n"
4337 
4338 		"; Geometry decorations\n"
4339 		"OpDecorate %geom_out_gl_position BuiltIn Position\n"
4340 		"OpMemberDecorate %geom_per_vertex_in 0 BuiltIn Position\n"
4341 		"OpMemberDecorate %geom_per_vertex_in 1 BuiltIn PointSize\n"
4342 		"OpMemberDecorate %geom_per_vertex_in 2 BuiltIn ClipDistance\n"
4343 		"OpMemberDecorate %geom_per_vertex_in 3 BuiltIn CullDistance\n"
4344 		"OpDecorate %geom_per_vertex_in Block\n"
4345 		"OpDecorate %geom_out_color Location 1\n"
4346 		"OpDecorate %geom_in_color Location 1\n"
4347 
4348 		"; Tessellation Control decorations\n"
4349 		"OpDecorate %tessc_out_color Location 1\n"
4350 		"OpDecorate %tessc_gl_InvocationID BuiltIn InvocationId\n"
4351 		"OpDecorate %tessc_in_color Location 1\n"
4352 		"OpDecorate %tessc_out_position Location 2\n"
4353 		"OpDecorate %tessc_in_position Location 2\n"
4354 		"OpDecorate %tessc_gl_TessLevelOuter Patch\n"
4355 		"OpDecorate %tessc_gl_TessLevelOuter BuiltIn TessLevelOuter\n"
4356 		"OpDecorate %tessc_gl_TessLevelInner Patch\n"
4357 		"OpDecorate %tessc_gl_TessLevelInner BuiltIn TessLevelInner\n"
4358 
4359 		"; Tessellation Evaluation decorations\n"
4360 		"OpMemberDecorate %tesse_per_vertex_out 0 BuiltIn Position\n"
4361 		"OpMemberDecorate %tesse_per_vertex_out 1 BuiltIn PointSize\n"
4362 		"OpMemberDecorate %tesse_per_vertex_out 2 BuiltIn ClipDistance\n"
4363 		"OpMemberDecorate %tesse_per_vertex_out 3 BuiltIn CullDistance\n"
4364 		"OpDecorate %tesse_per_vertex_out Block\n"
4365 		"OpDecorate %tesse_gl_tessCoord BuiltIn TessCoord\n"
4366 		"OpDecorate %tesse_in_position Location 2\n"
4367 		"OpDecorate %tesse_out_color Location 1\n"
4368 		"OpDecorate %tesse_in_color Location 1\n"
4369 
4370 		"; Fragment decorations\n"
4371 		"OpDecorate %frag_fragColor Location 0\n"
4372 		"OpDecorate %frag_vtxColor Location 1\n"
4373 
4374 		SPIRV_ASSEMBLY_TYPES
4375 		SPIRV_ASSEMBLY_CONSTANTS
4376 		SPIRV_ASSEMBLY_ARRAYS
4377 
4378 		"; Vertex Variables\n"
4379 		"%vert_vtxPosition = OpVariable %op_v4f32 Output\n"
4380 		"%vert_Position = OpVariable %ip_v4f32 Input\n"
4381 		"%vert_vtxColor = OpVariable %op_v4f32 Output\n"
4382 		"%vert_color = OpVariable %ip_v4f32 Input\n"
4383 		"%vert_vertex_id = OpVariable %ip_i32 Input\n"
4384 		"%vert_instance_id = OpVariable %ip_i32 Input\n"
4385 
4386 		"; Geometry Variables\n"
4387 		"%geom_per_vertex_in = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
4388 		"%geom_a3_per_vertex_in = OpTypeArray %geom_per_vertex_in %c_u32_3\n"
4389 		"%geom_ip_a3_per_vertex_in = OpTypePointer Input %geom_a3_per_vertex_in\n"
4390 		"%geom_gl_in = OpVariable %geom_ip_a3_per_vertex_in Input\n"
4391 		"%geom_out_color = OpVariable %op_v4f32 Output\n"
4392 		"%geom_in_color = OpVariable %ip_a3v4f32 Input\n"
4393 		"%geom_out_gl_position = OpVariable %op_v4f32 Output\n"
4394 
4395 		"; Tessellation Control Variables\n"
4396 		"%tessc_out_color = OpVariable %op_a3v4f32 Output\n"
4397 		"%tessc_gl_InvocationID = OpVariable %ip_i32 Input\n"
4398 		"%tessc_in_color = OpVariable %ip_a32v4f32 Input\n"
4399 		"%tessc_out_position = OpVariable %op_a3v4f32 Output\n"
4400 		"%tessc_in_position = OpVariable %ip_a32v4f32 Input\n"
4401 		"%tessc_gl_TessLevelOuter = OpVariable %op_a4f32 Output\n"
4402 		"%tessc_gl_TessLevelInner = OpVariable %op_a2f32 Output\n"
4403 
4404 		"; Tessellation Evaluation Decorations\n"
4405 		"%tesse_per_vertex_out = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
4406 		"%tesse_op_per_vertex_out = OpTypePointer Output %tesse_per_vertex_out\n"
4407 		"%tesse_stream = OpVariable %tesse_op_per_vertex_out Output\n"
4408 		"%tesse_gl_tessCoord = OpVariable %ip_v3f32 Input\n"
4409 		"%tesse_in_position = OpVariable %ip_a32v4f32 Input\n"
4410 		"%tesse_out_color = OpVariable %op_v4f32 Output\n"
4411 		"%tesse_in_color = OpVariable %ip_a32v4f32 Input\n"
4412 
4413 		"; Fragment Variables\n"
4414 		"%frag_fragColor = OpVariable %op_v4f32 Output\n"
4415 		"%frag_vtxColor = OpVariable %ip_v4f32 Input\n"
4416 
4417 		"; Vertex Entry\n"
4418 		"%vert_main = OpFunction %void None %fun\n"
4419 		"%vert_label = OpLabel\n"
4420 		"%vert_tmp_position = OpLoad %v4f32 %vert_Position\n"
4421 		"OpStore %vert_vtxPosition %vert_tmp_position\n"
4422 		"%vert_tmp_color = OpLoad %v4f32 %vert_color\n"
4423 		"OpStore %vert_vtxColor %vert_tmp_color\n"
4424 		"OpReturn\n"
4425 		"OpFunctionEnd\n"
4426 
4427 		"; Geometry Entry\n"
4428 		"%geom_main = OpFunction %void None %fun\n"
4429 		"%geom_label = OpLabel\n"
4430 		"%geom_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %geom_gl_in %c_i32_0 %c_i32_0\n"
4431 		"%geom_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %geom_gl_in %c_i32_1 %c_i32_0\n"
4432 		"%geom_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %geom_gl_in %c_i32_2 %c_i32_0\n"
4433 		"%geom_in_position_0 = OpLoad %v4f32 %geom_gl_in_0_gl_position\n"
4434 		"%geom_in_position_1 = OpLoad %v4f32 %geom_gl_in_1_gl_position\n"
4435 		"%geom_in_position_2 = OpLoad %v4f32 %geom_gl_in_2_gl_position \n"
4436 		"%geom_in_color_0_ptr = OpAccessChain %ip_v4f32 %geom_in_color %c_i32_0\n"
4437 		"%geom_in_color_1_ptr = OpAccessChain %ip_v4f32 %geom_in_color %c_i32_1\n"
4438 		"%geom_in_color_2_ptr = OpAccessChain %ip_v4f32 %geom_in_color %c_i32_2\n"
4439 		"%geom_in_color_0 = OpLoad %v4f32 %geom_in_color_0_ptr\n"
4440 		"%geom_in_color_1 = OpLoad %v4f32 %geom_in_color_1_ptr\n"
4441 		"%geom_in_color_2 = OpLoad %v4f32 %geom_in_color_2_ptr\n"
4442 		"OpStore %geom_out_gl_position %geom_in_position_0\n"
4443 		"OpStore %geom_out_color %geom_in_color_0\n"
4444 		"OpEmitVertex\n"
4445 		"OpStore %geom_out_gl_position %geom_in_position_1\n"
4446 		"OpStore %geom_out_color %geom_in_color_1\n"
4447 		"OpEmitVertex\n"
4448 		"OpStore %geom_out_gl_position %geom_in_position_2\n"
4449 		"OpStore %geom_out_color %geom_in_color_2\n"
4450 		"OpEmitVertex\n"
4451 		"OpEndPrimitive\n"
4452 		"OpReturn\n"
4453 		"OpFunctionEnd\n"
4454 
4455 		"; Tessellation Control Entry\n"
4456 		"%tessc_main = OpFunction %void None %fun\n"
4457 		"%tessc_label = OpLabel\n"
4458 		"%tessc_invocation_id = OpLoad %i32 %tessc_gl_InvocationID\n"
4459 		"%tessc_in_color_ptr = OpAccessChain %ip_v4f32 %tessc_in_color %tessc_invocation_id\n"
4460 		"%tessc_in_position_ptr = OpAccessChain %ip_v4f32 %tessc_in_position %tessc_invocation_id\n"
4461 		"%tessc_in_color_val = OpLoad %v4f32 %tessc_in_color_ptr\n"
4462 		"%tessc_in_position_val = OpLoad %v4f32 %tessc_in_position_ptr\n"
4463 		"%tessc_out_color_ptr = OpAccessChain %op_v4f32 %tessc_out_color %tessc_invocation_id\n"
4464 		"%tessc_out_position_ptr = OpAccessChain %op_v4f32 %tessc_out_position %tessc_invocation_id\n"
4465 		"OpStore %tessc_out_color_ptr %tessc_in_color_val\n"
4466 		"OpStore %tessc_out_position_ptr %tessc_in_position_val\n"
4467 		"%tessc_is_first_invocation = OpIEqual %bool %tessc_invocation_id %c_i32_0\n"
4468 		"OpSelectionMerge %tessc_merge_label None\n"
4469 		"OpBranchConditional %tessc_is_first_invocation %tessc_first_invocation %tessc_merge_label\n"
4470 		"%tessc_first_invocation = OpLabel\n"
4471 		"%tessc_tess_outer_0 = OpAccessChain %op_f32 %tessc_gl_TessLevelOuter %c_i32_0\n"
4472 		"%tessc_tess_outer_1 = OpAccessChain %op_f32 %tessc_gl_TessLevelOuter %c_i32_1\n"
4473 		"%tessc_tess_outer_2 = OpAccessChain %op_f32 %tessc_gl_TessLevelOuter %c_i32_2\n"
4474 		"%tessc_tess_inner = OpAccessChain %op_f32 %tessc_gl_TessLevelInner %c_i32_0\n"
4475 		"OpStore %tessc_tess_outer_0 %c_f32_1\n"
4476 		"OpStore %tessc_tess_outer_1 %c_f32_1\n"
4477 		"OpStore %tessc_tess_outer_2 %c_f32_1\n"
4478 		"OpStore %tessc_tess_inner %c_f32_1\n"
4479 		"OpBranch %tessc_merge_label\n"
4480 		"%tessc_merge_label = OpLabel\n"
4481 		"OpReturn\n"
4482 		"OpFunctionEnd\n"
4483 
4484 		"; Tessellation Evaluation Entry\n"
4485 		"%tesse_main = OpFunction %void None %fun\n"
4486 		"%tesse_label = OpLabel\n"
4487 		"%tesse_tc_0_ptr = OpAccessChain %ip_f32 %tesse_gl_tessCoord %c_u32_0\n"
4488 		"%tesse_tc_1_ptr = OpAccessChain %ip_f32 %tesse_gl_tessCoord %c_u32_1\n"
4489 		"%tesse_tc_2_ptr = OpAccessChain %ip_f32 %tesse_gl_tessCoord %c_u32_2\n"
4490 		"%tesse_tc_0 = OpLoad %f32 %tesse_tc_0_ptr\n"
4491 		"%tesse_tc_1 = OpLoad %f32 %tesse_tc_1_ptr\n"
4492 		"%tesse_tc_2 = OpLoad %f32 %tesse_tc_2_ptr\n"
4493 		"%tesse_in_pos_0_ptr = OpAccessChain %ip_v4f32 %tesse_in_position %c_i32_0\n"
4494 		"%tesse_in_pos_1_ptr = OpAccessChain %ip_v4f32 %tesse_in_position %c_i32_1\n"
4495 		"%tesse_in_pos_2_ptr = OpAccessChain %ip_v4f32 %tesse_in_position %c_i32_2\n"
4496 		"%tesse_in_pos_0 = OpLoad %v4f32 %tesse_in_pos_0_ptr\n"
4497 		"%tesse_in_pos_1 = OpLoad %v4f32 %tesse_in_pos_1_ptr\n"
4498 		"%tesse_in_pos_2 = OpLoad %v4f32 %tesse_in_pos_2_ptr\n"
4499 		"%tesse_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse_in_pos_0 %tesse_tc_0\n"
4500 		"%tesse_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse_in_pos_1 %tesse_tc_1\n"
4501 		"%tesse_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse_in_pos_2 %tesse_tc_2\n"
4502 		"%tesse_out_pos_ptr = OpAccessChain %op_v4f32 %tesse_stream %c_i32_0\n"
4503 		"%tesse_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %tesse_in_pos_0_weighted %tesse_in_pos_1_weighted\n"
4504 		"%tesse_computed_out = OpFAdd %v4f32 %tesse_in_pos_0_plus_pos_1 %tesse_in_pos_2_weighted\n"
4505 		"OpStore %tesse_out_pos_ptr %tesse_computed_out\n"
4506 		"%tesse_in_clr_0_ptr = OpAccessChain %ip_v4f32 %tesse_in_color %c_i32_0\n"
4507 		"%tesse_in_clr_1_ptr = OpAccessChain %ip_v4f32 %tesse_in_color %c_i32_1\n"
4508 		"%tesse_in_clr_2_ptr = OpAccessChain %ip_v4f32 %tesse_in_color %c_i32_2\n"
4509 		"%tesse_in_clr_0 = OpLoad %v4f32 %tesse_in_clr_0_ptr\n"
4510 		"%tesse_in_clr_1 = OpLoad %v4f32 %tesse_in_clr_1_ptr\n"
4511 		"%tesse_in_clr_2 = OpLoad %v4f32 %tesse_in_clr_2_ptr\n"
4512 		"%tesse_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse_in_clr_0 %tesse_tc_0\n"
4513 		"%tesse_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse_in_clr_1 %tesse_tc_1\n"
4514 		"%tesse_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse_in_clr_2 %tesse_tc_2\n"
4515 		"%tesse_in_clr_0_plus_col_1 = OpFAdd %v4f32 %tesse_in_clr_0_weighted %tesse_in_clr_1_weighted\n"
4516 		"%tesse_computed_clr = OpFAdd %v4f32 %tesse_in_clr_0_plus_col_1 %tesse_in_clr_2_weighted\n"
4517 		"OpStore %tesse_out_color %tesse_computed_clr\n"
4518 		"OpReturn\n"
4519 		"OpFunctionEnd\n"
4520 
4521 		"; Fragment Entry\n"
4522 		"%frag_main = OpFunction %void None %fun\n"
4523 		"%frag_label_main = OpLabel\n"
4524 		"%frag_tmp1 = OpLoad %v4f32 %frag_vtxColor\n"
4525 		"OpStore %frag_fragColor %frag_tmp1\n"
4526 		"OpReturn\n"
4527 		"OpFunctionEnd\n";
4528 }
4529 
4530 // This has two shaders of each stage. The first
4531 // is a passthrough, the second inverts the color.
createMultipleEntries(vk::SourceCollections & dst,InstanceContext)4532 void createMultipleEntries(vk::SourceCollections& dst, InstanceContext)
4533 {
4534 	dst.spirvAsmSources.add("vert") <<
4535 	// This module contains 2 vertex shaders. One that is a passthrough
4536 	// and a second that inverts the color of the output (1.0 - color).
4537 		"OpCapability Shader\n"
4538 		"OpMemoryModel Logical GLSL450\n"
4539 		"OpEntryPoint Vertex %main \"vert1\" %Position %vtxColor %color %vtxPosition %vertex_id %instance_id\n"
4540 		"OpEntryPoint Vertex %main2 \"vert2\" %Position %vtxColor %color %vtxPosition %vertex_id %instance_id\n"
4541 
4542 		"OpName %main \"vert1\"\n"
4543 		"OpName %main2 \"vert2\"\n"
4544 		"OpName %vtxPosition \"vtxPosition\"\n"
4545 		"OpName %Position \"position\"\n"
4546 		"OpName %vtxColor \"vtxColor\"\n"
4547 		"OpName %color \"color\"\n"
4548 		"OpName %vertex_id \"gl_VertexIndex\"\n"
4549 		"OpName %instance_id \"gl_InstanceIndex\"\n"
4550 
4551 		"OpDecorate %vtxPosition Location 2\n"
4552 		"OpDecorate %Position Location 0\n"
4553 		"OpDecorate %vtxColor Location 1\n"
4554 		"OpDecorate %color Location 1\n"
4555 		"OpDecorate %vertex_id BuiltIn VertexIndex\n"
4556 		"OpDecorate %instance_id BuiltIn InstanceIndex\n"
4557 		SPIRV_ASSEMBLY_TYPES
4558 		SPIRV_ASSEMBLY_CONSTANTS
4559 		SPIRV_ASSEMBLY_ARRAYS
4560 		"%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
4561 		"%vtxPosition = OpVariable %op_v4f32 Output\n"
4562 		"%Position = OpVariable %ip_v4f32 Input\n"
4563 		"%vtxColor = OpVariable %op_v4f32 Output\n"
4564 		"%color = OpVariable %ip_v4f32 Input\n"
4565 		"%vertex_id = OpVariable %ip_i32 Input\n"
4566 		"%instance_id = OpVariable %ip_i32 Input\n"
4567 
4568 		"%main = OpFunction %void None %fun\n"
4569 		"%label = OpLabel\n"
4570 		"%tmp_position = OpLoad %v4f32 %Position\n"
4571 		"OpStore %vtxPosition %tmp_position\n"
4572 		"%tmp_color = OpLoad %v4f32 %color\n"
4573 		"OpStore %vtxColor %tmp_color\n"
4574 		"OpReturn\n"
4575 		"OpFunctionEnd\n"
4576 
4577 		"%main2 = OpFunction %void None %fun\n"
4578 		"%label2 = OpLabel\n"
4579 		"%tmp_position2 = OpLoad %v4f32 %Position\n"
4580 		"OpStore %vtxPosition %tmp_position2\n"
4581 		"%tmp_color2 = OpLoad %v4f32 %color\n"
4582 		"%tmp_color3 = OpFSub %v4f32 %cval %tmp_color2\n"
4583 		"%tmp_color4 = OpVectorInsertDynamic %v4f32 %tmp_color3 %c_f32_1 %c_i32_3\n"
4584 		"OpStore %vtxColor %tmp_color4\n"
4585 		"OpReturn\n"
4586 		"OpFunctionEnd\n";
4587 
4588 	dst.spirvAsmSources.add("frag") <<
4589 		// This is a single module that contains 2 fragment shaders.
4590 		// One that passes color through and the other that inverts the output
4591 		// color (1.0 - color).
4592 		"OpCapability Shader\n"
4593 		"OpMemoryModel Logical GLSL450\n"
4594 		"OpEntryPoint Fragment %main \"frag1\" %vtxColor %fragColor\n"
4595 		"OpEntryPoint Fragment %main2 \"frag2\" %vtxColor %fragColor\n"
4596 		"OpExecutionMode %main OriginUpperLeft\n"
4597 		"OpExecutionMode %main2 OriginUpperLeft\n"
4598 
4599 		"OpName %main \"frag1\"\n"
4600 		"OpName %main2 \"frag2\"\n"
4601 		"OpName %fragColor \"fragColor\"\n"
4602 		"OpName %vtxColor \"vtxColor\"\n"
4603 		"OpDecorate %fragColor Location 0\n"
4604 		"OpDecorate %vtxColor Location 1\n"
4605 		SPIRV_ASSEMBLY_TYPES
4606 		SPIRV_ASSEMBLY_CONSTANTS
4607 		SPIRV_ASSEMBLY_ARRAYS
4608 		"%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
4609 		"%fragColor = OpVariable %op_v4f32 Output\n"
4610 		"%vtxColor = OpVariable %ip_v4f32 Input\n"
4611 
4612 		"%main = OpFunction %void None %fun\n"
4613 		"%label_main = OpLabel\n"
4614 		"%tmp1 = OpLoad %v4f32 %vtxColor\n"
4615 		"OpStore %fragColor %tmp1\n"
4616 		"OpReturn\n"
4617 		"OpFunctionEnd\n"
4618 
4619 		"%main2 = OpFunction %void None %fun\n"
4620 		"%label_main2 = OpLabel\n"
4621 		"%tmp2 = OpLoad %v4f32 %vtxColor\n"
4622 		"%tmp3 = OpFSub %v4f32 %cval %tmp2\n"
4623 		"%tmp4 = OpVectorInsertDynamic %v4f32 %tmp3 %c_f32_1 %c_i32_3\n"
4624 		"OpStore %fragColor %tmp4\n"
4625 		"OpReturn\n"
4626 		"OpFunctionEnd\n";
4627 
4628 	dst.spirvAsmSources.add("geom") <<
4629 		"OpCapability Geometry\n"
4630 		"OpCapability ClipDistance\n"
4631 		"OpCapability CullDistance\n"
4632 		"OpMemoryModel Logical GLSL450\n"
4633 		"OpEntryPoint Geometry %geom1_main \"geom1\" %out_gl_position %gl_in %out_color %in_color\n"
4634 		"OpEntryPoint Geometry %geom2_main \"geom2\" %out_gl_position %gl_in %out_color %in_color\n"
4635 		"OpExecutionMode %geom1_main Triangles\n"
4636 		"OpExecutionMode %geom2_main Triangles\n"
4637 		"OpExecutionMode %geom1_main OutputTriangleStrip\n"
4638 		"OpExecutionMode %geom2_main OutputTriangleStrip\n"
4639 		"OpExecutionMode %geom1_main OutputVertices 3\n"
4640 		"OpExecutionMode %geom2_main OutputVertices 3\n"
4641 		"OpName %geom1_main \"geom1\"\n"
4642 		"OpName %geom2_main \"geom2\"\n"
4643 		"OpName %per_vertex_in \"gl_PerVertex\"\n"
4644 		"OpMemberName %per_vertex_in 0 \"gl_Position\"\n"
4645 		"OpMemberName %per_vertex_in 1 \"gl_PointSize\"\n"
4646 		"OpMemberName %per_vertex_in 2 \"gl_ClipDistance\"\n"
4647 		"OpMemberName %per_vertex_in 3 \"gl_CullDistance\"\n"
4648 		"OpName %gl_in \"gl_in\"\n"
4649 		"OpName %out_color \"out_color\"\n"
4650 		"OpName %in_color \"in_color\"\n"
4651 		"OpDecorate %out_gl_position BuiltIn Position\n"
4652 		"OpMemberDecorate %per_vertex_in 0 BuiltIn Position\n"
4653 		"OpMemberDecorate %per_vertex_in 1 BuiltIn PointSize\n"
4654 		"OpMemberDecorate %per_vertex_in 2 BuiltIn ClipDistance\n"
4655 		"OpMemberDecorate %per_vertex_in 3 BuiltIn CullDistance\n"
4656 		"OpDecorate %per_vertex_in Block\n"
4657 		"OpDecorate %out_color Location 1\n"
4658 		"OpDecorate %in_color Location 1\n"
4659 		SPIRV_ASSEMBLY_TYPES
4660 		SPIRV_ASSEMBLY_CONSTANTS
4661 		SPIRV_ASSEMBLY_ARRAYS
4662 		"%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
4663 		"%per_vertex_in = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
4664 		"%a3_per_vertex_in = OpTypeArray %per_vertex_in %c_u32_3\n"
4665 		"%ip_a3_per_vertex_in = OpTypePointer Input %a3_per_vertex_in\n"
4666 		"%gl_in = OpVariable %ip_a3_per_vertex_in Input\n"
4667 		"%out_color = OpVariable %op_v4f32 Output\n"
4668 		"%in_color = OpVariable %ip_a3v4f32 Input\n"
4669 		"%out_gl_position = OpVariable %op_v4f32 Output\n"
4670 
4671 		"%geom1_main = OpFunction %void None %fun\n"
4672 		"%geom1_label = OpLabel\n"
4673 		"%geom1_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_0 %c_i32_0\n"
4674 		"%geom1_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_1 %c_i32_0\n"
4675 		"%geom1_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_2 %c_i32_0\n"
4676 		"%geom1_in_position_0 = OpLoad %v4f32 %geom1_gl_in_0_gl_position\n"
4677 		"%geom1_in_position_1 = OpLoad %v4f32 %geom1_gl_in_1_gl_position\n"
4678 		"%geom1_in_position_2 = OpLoad %v4f32 %geom1_gl_in_2_gl_position \n"
4679 		"%geom1_in_color_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
4680 		"%geom1_in_color_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
4681 		"%geom1_in_color_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
4682 		"%geom1_in_color_0 = OpLoad %v4f32 %geom1_in_color_0_ptr\n"
4683 		"%geom1_in_color_1 = OpLoad %v4f32 %geom1_in_color_1_ptr\n"
4684 		"%geom1_in_color_2 = OpLoad %v4f32 %geom1_in_color_2_ptr\n"
4685 		"OpStore %out_gl_position %geom1_in_position_0\n"
4686 		"OpStore %out_color %geom1_in_color_0\n"
4687 		"OpEmitVertex\n"
4688 		"OpStore %out_gl_position %geom1_in_position_1\n"
4689 		"OpStore %out_color %geom1_in_color_1\n"
4690 		"OpEmitVertex\n"
4691 		"OpStore %out_gl_position %geom1_in_position_2\n"
4692 		"OpStore %out_color %geom1_in_color_2\n"
4693 		"OpEmitVertex\n"
4694 		"OpEndPrimitive\n"
4695 		"OpReturn\n"
4696 		"OpFunctionEnd\n"
4697 
4698 		"%geom2_main = OpFunction %void None %fun\n"
4699 		"%geom2_label = OpLabel\n"
4700 		"%geom2_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_0 %c_i32_0\n"
4701 		"%geom2_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_1 %c_i32_0\n"
4702 		"%geom2_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_2 %c_i32_0\n"
4703 		"%geom2_in_position_0 = OpLoad %v4f32 %geom2_gl_in_0_gl_position\n"
4704 		"%geom2_in_position_1 = OpLoad %v4f32 %geom2_gl_in_1_gl_position\n"
4705 		"%geom2_in_position_2 = OpLoad %v4f32 %geom2_gl_in_2_gl_position \n"
4706 		"%geom2_in_color_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
4707 		"%geom2_in_color_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
4708 		"%geom2_in_color_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
4709 		"%geom2_in_color_0 = OpLoad %v4f32 %geom2_in_color_0_ptr\n"
4710 		"%geom2_in_color_1 = OpLoad %v4f32 %geom2_in_color_1_ptr\n"
4711 		"%geom2_in_color_2 = OpLoad %v4f32 %geom2_in_color_2_ptr\n"
4712 		"%geom2_transformed_in_color_0 = OpFSub %v4f32 %cval %geom2_in_color_0\n"
4713 		"%geom2_transformed_in_color_1 = OpFSub %v4f32 %cval %geom2_in_color_1\n"
4714 		"%geom2_transformed_in_color_2 = OpFSub %v4f32 %cval %geom2_in_color_2\n"
4715 		"%geom2_transformed_in_color_0_a = OpVectorInsertDynamic %v4f32 %geom2_transformed_in_color_0 %c_f32_1 %c_i32_3\n"
4716 		"%geom2_transformed_in_color_1_a = OpVectorInsertDynamic %v4f32 %geom2_transformed_in_color_1 %c_f32_1 %c_i32_3\n"
4717 		"%geom2_transformed_in_color_2_a = OpVectorInsertDynamic %v4f32 %geom2_transformed_in_color_2 %c_f32_1 %c_i32_3\n"
4718 		"OpStore %out_gl_position %geom2_in_position_0\n"
4719 		"OpStore %out_color %geom2_transformed_in_color_0_a\n"
4720 		"OpEmitVertex\n"
4721 		"OpStore %out_gl_position %geom2_in_position_1\n"
4722 		"OpStore %out_color %geom2_transformed_in_color_1_a\n"
4723 		"OpEmitVertex\n"
4724 		"OpStore %out_gl_position %geom2_in_position_2\n"
4725 		"OpStore %out_color %geom2_transformed_in_color_2_a\n"
4726 		"OpEmitVertex\n"
4727 		"OpEndPrimitive\n"
4728 		"OpReturn\n"
4729 		"OpFunctionEnd\n";
4730 
4731 	dst.spirvAsmSources.add("tessc") <<
4732 		"OpCapability Tessellation\n"
4733 		"OpMemoryModel Logical GLSL450\n"
4734 		"OpEntryPoint TessellationControl %tessc1_main \"tessc1\" %out_color %gl_InvocationID %in_color %out_position %in_position %gl_TessLevelOuter %gl_TessLevelInner\n"
4735 		"OpEntryPoint TessellationControl %tessc2_main \"tessc2\" %out_color %gl_InvocationID %in_color %out_position %in_position %gl_TessLevelOuter %gl_TessLevelInner\n"
4736 		"OpExecutionMode %tessc1_main OutputVertices 3\n"
4737 		"OpExecutionMode %tessc2_main OutputVertices 3\n"
4738 		"OpName %tessc1_main \"tessc1\"\n"
4739 		"OpName %tessc2_main \"tessc2\"\n"
4740 		"OpName %out_color \"out_color\"\n"
4741 		"OpName %gl_InvocationID \"gl_InvocationID\"\n"
4742 		"OpName %in_color \"in_color\"\n"
4743 		"OpName %out_position \"out_position\"\n"
4744 		"OpName %in_position \"in_position\"\n"
4745 		"OpName %gl_TessLevelOuter \"gl_TessLevelOuter\"\n"
4746 		"OpName %gl_TessLevelInner \"gl_TessLevelInner\"\n"
4747 		"OpDecorate %out_color Location 1\n"
4748 		"OpDecorate %gl_InvocationID BuiltIn InvocationId\n"
4749 		"OpDecorate %in_color Location 1\n"
4750 		"OpDecorate %out_position Location 2\n"
4751 		"OpDecorate %in_position Location 2\n"
4752 		"OpDecorate %gl_TessLevelOuter Patch\n"
4753 		"OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter\n"
4754 		"OpDecorate %gl_TessLevelInner Patch\n"
4755 		"OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner\n"
4756 		SPIRV_ASSEMBLY_TYPES
4757 		SPIRV_ASSEMBLY_CONSTANTS
4758 		SPIRV_ASSEMBLY_ARRAYS
4759 		"%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
4760 		"%out_color = OpVariable %op_a3v4f32 Output\n"
4761 		"%gl_InvocationID = OpVariable %ip_i32 Input\n"
4762 		"%in_color = OpVariable %ip_a32v4f32 Input\n"
4763 		"%out_position = OpVariable %op_a3v4f32 Output\n"
4764 		"%in_position = OpVariable %ip_a32v4f32 Input\n"
4765 		"%gl_TessLevelOuter = OpVariable %op_a4f32 Output\n"
4766 		"%gl_TessLevelInner = OpVariable %op_a2f32 Output\n"
4767 
4768 		"%tessc1_main = OpFunction %void None %fun\n"
4769 		"%tessc1_label = OpLabel\n"
4770 		"%tessc1_invocation_id = OpLoad %i32 %gl_InvocationID\n"
4771 		"%tessc1_in_color_ptr = OpAccessChain %ip_v4f32 %in_color %tessc1_invocation_id\n"
4772 		"%tessc1_in_position_ptr = OpAccessChain %ip_v4f32 %in_position %tessc1_invocation_id\n"
4773 		"%tessc1_in_color_val = OpLoad %v4f32 %tessc1_in_color_ptr\n"
4774 		"%tessc1_in_position_val = OpLoad %v4f32 %tessc1_in_position_ptr\n"
4775 		"%tessc1_out_color_ptr = OpAccessChain %op_v4f32 %out_color %tessc1_invocation_id\n"
4776 		"%tessc1_out_position_ptr = OpAccessChain %op_v4f32 %out_position %tessc1_invocation_id\n"
4777 		"OpStore %tessc1_out_color_ptr %tessc1_in_color_val\n"
4778 		"OpStore %tessc1_out_position_ptr %tessc1_in_position_val\n"
4779 		"%tessc1_is_first_invocation = OpIEqual %bool %tessc1_invocation_id %c_i32_0\n"
4780 		"OpSelectionMerge %tessc1_merge_label None\n"
4781 		"OpBranchConditional %tessc1_is_first_invocation %tessc1_first_invocation %tessc1_merge_label\n"
4782 		"%tessc1_first_invocation = OpLabel\n"
4783 		"%tessc1_tess_outer_0 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_0\n"
4784 		"%tessc1_tess_outer_1 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_1\n"
4785 		"%tessc1_tess_outer_2 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_2\n"
4786 		"%tessc1_tess_inner = OpAccessChain %op_f32 %gl_TessLevelInner %c_i32_0\n"
4787 		"OpStore %tessc1_tess_outer_0 %c_f32_1\n"
4788 		"OpStore %tessc1_tess_outer_1 %c_f32_1\n"
4789 		"OpStore %tessc1_tess_outer_2 %c_f32_1\n"
4790 		"OpStore %tessc1_tess_inner %c_f32_1\n"
4791 		"OpBranch %tessc1_merge_label\n"
4792 		"%tessc1_merge_label = OpLabel\n"
4793 		"OpReturn\n"
4794 		"OpFunctionEnd\n"
4795 
4796 		"%tessc2_main = OpFunction %void None %fun\n"
4797 		"%tessc2_label = OpLabel\n"
4798 		"%tessc2_invocation_id = OpLoad %i32 %gl_InvocationID\n"
4799 		"%tessc2_in_color_ptr = OpAccessChain %ip_v4f32 %in_color %tessc2_invocation_id\n"
4800 		"%tessc2_in_position_ptr = OpAccessChain %ip_v4f32 %in_position %tessc2_invocation_id\n"
4801 		"%tessc2_in_color_val = OpLoad %v4f32 %tessc2_in_color_ptr\n"
4802 		"%tessc2_in_position_val = OpLoad %v4f32 %tessc2_in_position_ptr\n"
4803 		"%tessc2_out_color_ptr = OpAccessChain %op_v4f32 %out_color %tessc2_invocation_id\n"
4804 		"%tessc2_out_position_ptr = OpAccessChain %op_v4f32 %out_position %tessc2_invocation_id\n"
4805 		"%tessc2_transformed_color = OpFSub %v4f32 %cval %tessc2_in_color_val\n"
4806 		"%tessc2_transformed_color_a = OpVectorInsertDynamic %v4f32 %tessc2_transformed_color %c_f32_1 %c_i32_3\n"
4807 		"OpStore %tessc2_out_color_ptr %tessc2_transformed_color_a\n"
4808 		"OpStore %tessc2_out_position_ptr %tessc2_in_position_val\n"
4809 		"%tessc2_is_first_invocation = OpIEqual %bool %tessc2_invocation_id %c_i32_0\n"
4810 		"OpSelectionMerge %tessc2_merge_label None\n"
4811 		"OpBranchConditional %tessc2_is_first_invocation %tessc2_first_invocation %tessc2_merge_label\n"
4812 		"%tessc2_first_invocation = OpLabel\n"
4813 		"%tessc2_tess_outer_0 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_0\n"
4814 		"%tessc2_tess_outer_1 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_1\n"
4815 		"%tessc2_tess_outer_2 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_2\n"
4816 		"%tessc2_tess_inner = OpAccessChain %op_f32 %gl_TessLevelInner %c_i32_0\n"
4817 		"OpStore %tessc2_tess_outer_0 %c_f32_1\n"
4818 		"OpStore %tessc2_tess_outer_1 %c_f32_1\n"
4819 		"OpStore %tessc2_tess_outer_2 %c_f32_1\n"
4820 		"OpStore %tessc2_tess_inner %c_f32_1\n"
4821 		"OpBranch %tessc2_merge_label\n"
4822 		"%tessc2_merge_label = OpLabel\n"
4823 		"OpReturn\n"
4824 		"OpFunctionEnd\n";
4825 
4826 	dst.spirvAsmSources.add("tesse") <<
4827 		"OpCapability Tessellation\n"
4828 		"OpCapability ClipDistance\n"
4829 		"OpCapability CullDistance\n"
4830 		"OpMemoryModel Logical GLSL450\n"
4831 		"OpEntryPoint TessellationEvaluation %tesse1_main \"tesse1\" %stream %gl_tessCoord %in_position %out_color %in_color \n"
4832 		"OpEntryPoint TessellationEvaluation %tesse2_main \"tesse2\" %stream %gl_tessCoord %in_position %out_color %in_color \n"
4833 		"OpExecutionMode %tesse1_main Triangles\n"
4834 		"OpExecutionMode %tesse1_main SpacingEqual\n"
4835 		"OpExecutionMode %tesse1_main VertexOrderCcw\n"
4836 		"OpExecutionMode %tesse2_main Triangles\n"
4837 		"OpExecutionMode %tesse2_main SpacingEqual\n"
4838 		"OpExecutionMode %tesse2_main VertexOrderCcw\n"
4839 		"OpName %tesse1_main \"tesse1\"\n"
4840 		"OpName %tesse2_main \"tesse2\"\n"
4841 		"OpName %per_vertex_out \"gl_PerVertex\"\n"
4842 		"OpMemberName %per_vertex_out 0 \"gl_Position\"\n"
4843 		"OpMemberName %per_vertex_out 1 \"gl_PointSize\"\n"
4844 		"OpMemberName %per_vertex_out 2 \"gl_ClipDistance\"\n"
4845 		"OpMemberName %per_vertex_out 3 \"gl_CullDistance\"\n"
4846 		"OpName %stream \"\"\n"
4847 		"OpName %gl_tessCoord \"gl_TessCoord\"\n"
4848 		"OpName %in_position \"in_position\"\n"
4849 		"OpName %out_color \"out_color\"\n"
4850 		"OpName %in_color \"in_color\"\n"
4851 		"OpMemberDecorate %per_vertex_out 0 BuiltIn Position\n"
4852 		"OpMemberDecorate %per_vertex_out 1 BuiltIn PointSize\n"
4853 		"OpMemberDecorate %per_vertex_out 2 BuiltIn ClipDistance\n"
4854 		"OpMemberDecorate %per_vertex_out 3 BuiltIn CullDistance\n"
4855 		"OpDecorate %per_vertex_out Block\n"
4856 		"OpDecorate %gl_tessCoord BuiltIn TessCoord\n"
4857 		"OpDecorate %in_position Location 2\n"
4858 		"OpDecorate %out_color Location 1\n"
4859 		"OpDecorate %in_color Location 1\n"
4860 		SPIRV_ASSEMBLY_TYPES
4861 		SPIRV_ASSEMBLY_CONSTANTS
4862 		SPIRV_ASSEMBLY_ARRAYS
4863 		"%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
4864 		"%per_vertex_out = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
4865 		"%op_per_vertex_out = OpTypePointer Output %per_vertex_out\n"
4866 		"%stream = OpVariable %op_per_vertex_out Output\n"
4867 		"%gl_tessCoord = OpVariable %ip_v3f32 Input\n"
4868 		"%in_position = OpVariable %ip_a32v4f32 Input\n"
4869 		"%out_color = OpVariable %op_v4f32 Output\n"
4870 		"%in_color = OpVariable %ip_a32v4f32 Input\n"
4871 
4872 		"%tesse1_main = OpFunction %void None %fun\n"
4873 		"%tesse1_label = OpLabel\n"
4874 		"%tesse1_tc_0_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_0\n"
4875 		"%tesse1_tc_1_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_1\n"
4876 		"%tesse1_tc_2_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_2\n"
4877 		"%tesse1_tc_0 = OpLoad %f32 %tesse1_tc_0_ptr\n"
4878 		"%tesse1_tc_1 = OpLoad %f32 %tesse1_tc_1_ptr\n"
4879 		"%tesse1_tc_2 = OpLoad %f32 %tesse1_tc_2_ptr\n"
4880 		"%tesse1_in_pos_0_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_0\n"
4881 		"%tesse1_in_pos_1_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_1\n"
4882 		"%tesse1_in_pos_2_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_2\n"
4883 		"%tesse1_in_pos_0 = OpLoad %v4f32 %tesse1_in_pos_0_ptr\n"
4884 		"%tesse1_in_pos_1 = OpLoad %v4f32 %tesse1_in_pos_1_ptr\n"
4885 		"%tesse1_in_pos_2 = OpLoad %v4f32 %tesse1_in_pos_2_ptr\n"
4886 		"%tesse1_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_pos_0 %tesse1_tc_0\n"
4887 		"%tesse1_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_pos_1 %tesse1_tc_1\n"
4888 		"%tesse1_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_pos_2 %tesse1_tc_2\n"
4889 		"%tesse1_out_pos_ptr = OpAccessChain %op_v4f32 %stream %c_i32_0\n"
4890 		"%tesse1_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %tesse1_in_pos_0_weighted %tesse1_in_pos_1_weighted\n"
4891 		"%tesse1_computed_out = OpFAdd %v4f32 %tesse1_in_pos_0_plus_pos_1 %tesse1_in_pos_2_weighted\n"
4892 		"OpStore %tesse1_out_pos_ptr %tesse1_computed_out\n"
4893 		"%tesse1_in_clr_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
4894 		"%tesse1_in_clr_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
4895 		"%tesse1_in_clr_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
4896 		"%tesse1_in_clr_0 = OpLoad %v4f32 %tesse1_in_clr_0_ptr\n"
4897 		"%tesse1_in_clr_1 = OpLoad %v4f32 %tesse1_in_clr_1_ptr\n"
4898 		"%tesse1_in_clr_2 = OpLoad %v4f32 %tesse1_in_clr_2_ptr\n"
4899 		"%tesse1_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_clr_0 %tesse1_tc_0\n"
4900 		"%tesse1_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_clr_1 %tesse1_tc_1\n"
4901 		"%tesse1_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_clr_2 %tesse1_tc_2\n"
4902 		"%tesse1_in_clr_0_plus_col_1 = OpFAdd %v4f32 %tesse1_in_clr_0_weighted %tesse1_in_clr_1_weighted\n"
4903 		"%tesse1_computed_clr = OpFAdd %v4f32 %tesse1_in_clr_0_plus_col_1 %tesse1_in_clr_2_weighted\n"
4904 		"OpStore %out_color %tesse1_computed_clr\n"
4905 		"OpReturn\n"
4906 		"OpFunctionEnd\n"
4907 
4908 		"%tesse2_main = OpFunction %void None %fun\n"
4909 		"%tesse2_label = OpLabel\n"
4910 		"%tesse2_tc_0_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_0\n"
4911 		"%tesse2_tc_1_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_1\n"
4912 		"%tesse2_tc_2_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_2\n"
4913 		"%tesse2_tc_0 = OpLoad %f32 %tesse2_tc_0_ptr\n"
4914 		"%tesse2_tc_1 = OpLoad %f32 %tesse2_tc_1_ptr\n"
4915 		"%tesse2_tc_2 = OpLoad %f32 %tesse2_tc_2_ptr\n"
4916 		"%tesse2_in_pos_0_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_0\n"
4917 		"%tesse2_in_pos_1_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_1\n"
4918 		"%tesse2_in_pos_2_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_2\n"
4919 		"%tesse2_in_pos_0 = OpLoad %v4f32 %tesse2_in_pos_0_ptr\n"
4920 		"%tesse2_in_pos_1 = OpLoad %v4f32 %tesse2_in_pos_1_ptr\n"
4921 		"%tesse2_in_pos_2 = OpLoad %v4f32 %tesse2_in_pos_2_ptr\n"
4922 		"%tesse2_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_pos_0 %tesse2_tc_0\n"
4923 		"%tesse2_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_pos_1 %tesse2_tc_1\n"
4924 		"%tesse2_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_pos_2 %tesse2_tc_2\n"
4925 		"%tesse2_out_pos_ptr = OpAccessChain %op_v4f32 %stream %c_i32_0\n"
4926 		"%tesse2_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %tesse2_in_pos_0_weighted %tesse2_in_pos_1_weighted\n"
4927 		"%tesse2_computed_out = OpFAdd %v4f32 %tesse2_in_pos_0_plus_pos_1 %tesse2_in_pos_2_weighted\n"
4928 		"OpStore %tesse2_out_pos_ptr %tesse2_computed_out\n"
4929 		"%tesse2_in_clr_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
4930 		"%tesse2_in_clr_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
4931 		"%tesse2_in_clr_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
4932 		"%tesse2_in_clr_0 = OpLoad %v4f32 %tesse2_in_clr_0_ptr\n"
4933 		"%tesse2_in_clr_1 = OpLoad %v4f32 %tesse2_in_clr_1_ptr\n"
4934 		"%tesse2_in_clr_2 = OpLoad %v4f32 %tesse2_in_clr_2_ptr\n"
4935 		"%tesse2_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_clr_0 %tesse2_tc_0\n"
4936 		"%tesse2_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_clr_1 %tesse2_tc_1\n"
4937 		"%tesse2_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_clr_2 %tesse2_tc_2\n"
4938 		"%tesse2_in_clr_0_plus_col_1 = OpFAdd %v4f32 %tesse2_in_clr_0_weighted %tesse2_in_clr_1_weighted\n"
4939 		"%tesse2_computed_clr = OpFAdd %v4f32 %tesse2_in_clr_0_plus_col_1 %tesse2_in_clr_2_weighted\n"
4940 		"%tesse2_clr_transformed = OpFSub %v4f32 %cval %tesse2_computed_clr\n"
4941 		"%tesse2_clr_transformed_a = OpVectorInsertDynamic %v4f32 %tesse2_clr_transformed %c_f32_1 %c_i32_3\n"
4942 		"OpStore %out_color %tesse2_clr_transformed_a\n"
4943 		"OpReturn\n"
4944 		"OpFunctionEnd\n";
4945 }
4946 
4947 // Sets up and runs a Vulkan pipeline, then spot-checks the resulting image.
4948 // Feeds the pipeline a set of colored triangles, which then must occur in the
4949 // rendered image.  The surface is cleared before executing the pipeline, so
4950 // whatever the shaders draw can be directly spot-checked.
runAndVerifyDefaultPipeline(Context & context,InstanceContext instance)4951 TestStatus runAndVerifyDefaultPipeline (Context& context, InstanceContext instance)
4952 {
4953 	const VkDevice								vkDevice				= context.getDevice();
4954 	const DeviceInterface&						vk						= context.getDeviceInterface();
4955 	const VkQueue								queue					= context.getUniversalQueue();
4956 	const deUint32								queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
4957 	const tcu::UVec2							renderSize				(256, 256);
4958 	vector<ModuleHandleSp>						modules;
4959 	map<VkShaderStageFlagBits, VkShaderModule>	moduleByStage;
4960 	const int									testSpecificSeed		= 31354125;
4961 	const int									seed					= context.getTestContext().getCommandLine().getBaseSeed() ^ testSpecificSeed;
4962 	bool										supportsGeometry		= false;
4963 	bool										supportsTessellation	= false;
4964 	bool										hasTessellation         = false;
4965 
4966 	const VkPhysicalDeviceFeatures&				features				= context.getDeviceFeatures();
4967 	supportsGeometry		= features.geometryShader == VK_TRUE;
4968 	supportsTessellation	= features.tessellationShader == VK_TRUE;
4969 	hasTessellation			= (instance.requiredStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) ||
4970 								(instance.requiredStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
4971 
4972 	if (hasTessellation && !supportsTessellation)
4973 	{
4974 		throw tcu::NotSupportedError(std::string("Tessellation not supported"));
4975 	}
4976 
4977 	if ((instance.requiredStages & VK_SHADER_STAGE_GEOMETRY_BIT) &&
4978 		!supportsGeometry)
4979 	{
4980 		throw tcu::NotSupportedError(std::string("Geometry not supported"));
4981 	}
4982 
4983 	de::Random(seed).shuffle(instance.inputColors, instance.inputColors+4);
4984 	de::Random(seed).shuffle(instance.outputColors, instance.outputColors+4);
4985 	const Vec4								vertexData[]			=
4986 	{
4987 		// Upper left corner:
4988 		Vec4(-1.0f, -1.0f, 0.0f, 1.0f), instance.inputColors[0].toVec(),
4989 		Vec4(-0.5f, -1.0f, 0.0f, 1.0f), instance.inputColors[0].toVec(),
4990 		Vec4(-1.0f, -0.5f, 0.0f, 1.0f), instance.inputColors[0].toVec(),
4991 
4992 		// Upper right corner:
4993 		Vec4(+0.5f, -1.0f, 0.0f, 1.0f), instance.inputColors[1].toVec(),
4994 		Vec4(+1.0f, -1.0f, 0.0f, 1.0f), instance.inputColors[1].toVec(),
4995 		Vec4(+1.0f, -0.5f, 0.0f, 1.0f), instance.inputColors[1].toVec(),
4996 
4997 		// Lower left corner:
4998 		Vec4(-1.0f, +0.5f, 0.0f, 1.0f), instance.inputColors[2].toVec(),
4999 		Vec4(-0.5f, +1.0f, 0.0f, 1.0f), instance.inputColors[2].toVec(),
5000 		Vec4(-1.0f, +1.0f, 0.0f, 1.0f), instance.inputColors[2].toVec(),
5001 
5002 		// Lower right corner:
5003 		Vec4(+1.0f, +0.5f, 0.0f, 1.0f), instance.inputColors[3].toVec(),
5004 		Vec4(+1.0f, +1.0f, 0.0f, 1.0f), instance.inputColors[3].toVec(),
5005 		Vec4(+0.5f, +1.0f, 0.0f, 1.0f), instance.inputColors[3].toVec()
5006 	};
5007 	const size_t							singleVertexDataSize	= 2 * sizeof(Vec4);
5008 	const size_t							vertexCount				= sizeof(vertexData) / singleVertexDataSize;
5009 
5010 	const VkBufferCreateInfo				vertexBufferParams		=
5011 	{
5012 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	//	VkStructureType		sType;
5013 		DE_NULL,								//	const void*			pNext;
5014 		0u,										//	VkBufferCreateFlags	flags;
5015 		(VkDeviceSize)sizeof(vertexData),		//	VkDeviceSize		size;
5016 		VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,		//	VkBufferUsageFlags	usage;
5017 		VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode		sharingMode;
5018 		1u,										//	deUint32			queueFamilyCount;
5019 		&queueFamilyIndex,						//	const deUint32*		pQueueFamilyIndices;
5020 	};
5021 	const Unique<VkBuffer>					vertexBuffer			(createBuffer(vk, vkDevice, &vertexBufferParams));
5022 	const UniquePtr<Allocation>				vertexBufferMemory		(context.getDefaultAllocator().allocate(getBufferMemoryRequirements(vk, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible));
5023 
5024 	VK_CHECK(vk.bindBufferMemory(vkDevice, *vertexBuffer, vertexBufferMemory->getMemory(), vertexBufferMemory->getOffset()));
5025 
5026 	const VkDeviceSize						imageSizeBytes			= (VkDeviceSize)(sizeof(deUint32)*renderSize.x()*renderSize.y());
5027 	const VkBufferCreateInfo				readImageBufferParams	=
5028 	{
5029 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		//	VkStructureType		sType;
5030 		DE_NULL,									//	const void*			pNext;
5031 		0u,											//	VkBufferCreateFlags	flags;
5032 		imageSizeBytes,								//	VkDeviceSize		size;
5033 		VK_BUFFER_USAGE_TRANSFER_DST_BIT,			//	VkBufferUsageFlags	usage;
5034 		VK_SHARING_MODE_EXCLUSIVE,					//	VkSharingMode		sharingMode;
5035 		1u,											//	deUint32			queueFamilyCount;
5036 		&queueFamilyIndex,							//	const deUint32*		pQueueFamilyIndices;
5037 	};
5038 	const Unique<VkBuffer>					readImageBuffer			(createBuffer(vk, vkDevice, &readImageBufferParams));
5039 	const UniquePtr<Allocation>				readImageBufferMemory	(context.getDefaultAllocator().allocate(getBufferMemoryRequirements(vk, vkDevice, *readImageBuffer), MemoryRequirement::HostVisible));
5040 
5041 	VK_CHECK(vk.bindBufferMemory(vkDevice, *readImageBuffer, readImageBufferMemory->getMemory(), readImageBufferMemory->getOffset()));
5042 
5043 	const VkImageCreateInfo					imageParams				=
5044 	{
5045 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,									//	VkStructureType		sType;
5046 		DE_NULL,																//	const void*			pNext;
5047 		0u,																		//	VkImageCreateFlags	flags;
5048 		VK_IMAGE_TYPE_2D,														//	VkImageType			imageType;
5049 		VK_FORMAT_R8G8B8A8_UNORM,												//	VkFormat			format;
5050 		{ renderSize.x(), renderSize.y(), 1 },									//	VkExtent3D			extent;
5051 		1u,																		//	deUint32			mipLevels;
5052 		1u,																		//	deUint32			arraySize;
5053 		VK_SAMPLE_COUNT_1_BIT,													//	deUint32			samples;
5054 		VK_IMAGE_TILING_OPTIMAL,												//	VkImageTiling		tiling;
5055 		VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT,	//	VkImageUsageFlags	usage;
5056 		VK_SHARING_MODE_EXCLUSIVE,												//	VkSharingMode		sharingMode;
5057 		1u,																		//	deUint32			queueFamilyCount;
5058 		&queueFamilyIndex,														//	const deUint32*		pQueueFamilyIndices;
5059 		VK_IMAGE_LAYOUT_UNDEFINED,												//	VkImageLayout		initialLayout;
5060 	};
5061 
5062 	const Unique<VkImage>					image					(createImage(vk, vkDevice, &imageParams));
5063 	const UniquePtr<Allocation>				imageMemory				(context.getDefaultAllocator().allocate(getImageMemoryRequirements(vk, vkDevice, *image), MemoryRequirement::Any));
5064 
5065 	VK_CHECK(vk.bindImageMemory(vkDevice, *image, imageMemory->getMemory(), imageMemory->getOffset()));
5066 
5067 	const VkAttachmentDescription			colorAttDesc			=
5068 	{
5069 		0u,												//	VkAttachmentDescriptionFlags	flags;
5070 		VK_FORMAT_R8G8B8A8_UNORM,						//	VkFormat						format;
5071 		VK_SAMPLE_COUNT_1_BIT,							//	deUint32						samples;
5072 		VK_ATTACHMENT_LOAD_OP_CLEAR,					//	VkAttachmentLoadOp				loadOp;
5073 		VK_ATTACHMENT_STORE_OP_STORE,					//	VkAttachmentStoreOp				storeOp;
5074 		VK_ATTACHMENT_LOAD_OP_DONT_CARE,				//	VkAttachmentLoadOp				stencilLoadOp;
5075 		VK_ATTACHMENT_STORE_OP_DONT_CARE,				//	VkAttachmentStoreOp				stencilStoreOp;
5076 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,		//	VkImageLayout					initialLayout;
5077 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,		//	VkImageLayout					finalLayout;
5078 	};
5079 	const VkAttachmentReference				colorAttRef				=
5080 	{
5081 		0u,												//	deUint32		attachment;
5082 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,		//	VkImageLayout	layout;
5083 	};
5084 	const VkSubpassDescription				subpassDesc				=
5085 	{
5086 		0u,												//	VkSubpassDescriptionFlags		flags;
5087 		VK_PIPELINE_BIND_POINT_GRAPHICS,				//	VkPipelineBindPoint				pipelineBindPoint;
5088 		0u,												//	deUint32						inputCount;
5089 		DE_NULL,										//	const VkAttachmentReference*	pInputAttachments;
5090 		1u,												//	deUint32						colorCount;
5091 		&colorAttRef,									//	const VkAttachmentReference*	pColorAttachments;
5092 		DE_NULL,										//	const VkAttachmentReference*	pResolveAttachments;
5093 		DE_NULL,										//	const VkAttachmentReference*	pDepthStencilAttachment;
5094 		0u,												//	deUint32						preserveCount;
5095 		DE_NULL,										//	const VkAttachmentReference*	pPreserveAttachments;
5096 
5097 	};
5098 	const VkRenderPassCreateInfo			renderPassParams		=
5099 	{
5100 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,		//	VkStructureType					sType;
5101 		DE_NULL,										//	const void*						pNext;
5102 		(VkRenderPassCreateFlags)0,
5103 		1u,												//	deUint32						attachmentCount;
5104 		&colorAttDesc,									//	const VkAttachmentDescription*	pAttachments;
5105 		1u,												//	deUint32						subpassCount;
5106 		&subpassDesc,									//	const VkSubpassDescription*		pSubpasses;
5107 		0u,												//	deUint32						dependencyCount;
5108 		DE_NULL,										//	const VkSubpassDependency*		pDependencies;
5109 	};
5110 	const Unique<VkRenderPass>				renderPass				(createRenderPass(vk, vkDevice, &renderPassParams));
5111 
5112 	const VkImageViewCreateInfo				colorAttViewParams		=
5113 	{
5114 		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,		//	VkStructureType				sType;
5115 		DE_NULL,										//	const void*					pNext;
5116 		0u,												//	VkImageViewCreateFlags		flags;
5117 		*image,											//	VkImage						image;
5118 		VK_IMAGE_VIEW_TYPE_2D,							//	VkImageViewType				viewType;
5119 		VK_FORMAT_R8G8B8A8_UNORM,						//	VkFormat					format;
5120 		{
5121 			VK_COMPONENT_SWIZZLE_R,
5122 			VK_COMPONENT_SWIZZLE_G,
5123 			VK_COMPONENT_SWIZZLE_B,
5124 			VK_COMPONENT_SWIZZLE_A
5125 		},												//	VkChannelMapping			channels;
5126 		{
5127 			VK_IMAGE_ASPECT_COLOR_BIT,						//	VkImageAspectFlags	aspectMask;
5128 			0u,												//	deUint32			baseMipLevel;
5129 			1u,												//	deUint32			mipLevels;
5130 			0u,												//	deUint32			baseArrayLayer;
5131 			1u,												//	deUint32			arraySize;
5132 		},												//	VkImageSubresourceRange		subresourceRange;
5133 	};
5134 	const Unique<VkImageView>				colorAttView			(createImageView(vk, vkDevice, &colorAttViewParams));
5135 
5136 
5137 	// Pipeline layout
5138 	const VkPipelineLayoutCreateInfo		pipelineLayoutParams	=
5139 	{
5140 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,			//	VkStructureType					sType;
5141 		DE_NULL,												//	const void*						pNext;
5142 		(VkPipelineLayoutCreateFlags)0,
5143 		0u,														//	deUint32						descriptorSetCount;
5144 		DE_NULL,												//	const VkDescriptorSetLayout*	pSetLayouts;
5145 		0u,														//	deUint32						pushConstantRangeCount;
5146 		DE_NULL,												//	const VkPushConstantRange*		pPushConstantRanges;
5147 	};
5148 	const Unique<VkPipelineLayout>			pipelineLayout			(createPipelineLayout(vk, vkDevice, &pipelineLayoutParams));
5149 
5150 	// Pipeline
5151 	vector<VkPipelineShaderStageCreateInfo>		shaderStageParams;
5152 	// We need these vectors to make sure that information about specialization constants for each stage can outlive createGraphicsPipeline().
5153 	vector<vector<VkSpecializationMapEntry> >	specConstantEntries;
5154 	vector<VkSpecializationInfo>				specializationInfos;
5155 	createPipelineShaderStages(vk, vkDevice, instance, context, modules, shaderStageParams);
5156 
5157 	// And we don't want the reallocation of these vectors to invalidate pointers pointing to their contents.
5158 	specConstantEntries.reserve(shaderStageParams.size());
5159 	specializationInfos.reserve(shaderStageParams.size());
5160 
5161 	// Patch the specialization info field in PipelineShaderStageCreateInfos.
5162 	for (vector<VkPipelineShaderStageCreateInfo>::iterator stageInfo = shaderStageParams.begin(); stageInfo != shaderStageParams.end(); ++stageInfo)
5163 	{
5164 		const StageToSpecConstantMap::const_iterator stageIt = instance.specConstants.find(stageInfo->stage);
5165 
5166 		if (stageIt != instance.specConstants.end())
5167 		{
5168 			const size_t						numSpecConstants	= stageIt->second.size();
5169 			vector<VkSpecializationMapEntry>	entries;
5170 			VkSpecializationInfo				specInfo;
5171 
5172 			entries.resize(numSpecConstants);
5173 
5174 			// Only support 32-bit integers as spec constants now. And their constant IDs are numbered sequentially starting from 0.
5175 			for (size_t ndx = 0; ndx < numSpecConstants; ++ndx)
5176 			{
5177 				entries[ndx].constantID	= (deUint32)ndx;
5178 				entries[ndx].offset		= deUint32(ndx * sizeof(deInt32));
5179 				entries[ndx].size		= sizeof(deInt32);
5180 			}
5181 
5182 			specConstantEntries.push_back(entries);
5183 
5184 			specInfo.mapEntryCount	= (deUint32)numSpecConstants;
5185 			specInfo.pMapEntries	= specConstantEntries.back().data();
5186 			specInfo.dataSize		= numSpecConstants * sizeof(deInt32);
5187 			specInfo.pData			= stageIt->second.data();
5188 			specializationInfos.push_back(specInfo);
5189 
5190 			stageInfo->pSpecializationInfo = &specializationInfos.back();
5191 		}
5192 	}
5193 	const VkPipelineDepthStencilStateCreateInfo	depthStencilParams		=
5194 	{
5195 		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,	//	VkStructureType		sType;
5196 		DE_NULL,													//	const void*			pNext;
5197 		(VkPipelineDepthStencilStateCreateFlags)0,
5198 		DE_FALSE,													//	deUint32			depthTestEnable;
5199 		DE_FALSE,													//	deUint32			depthWriteEnable;
5200 		VK_COMPARE_OP_ALWAYS,										//	VkCompareOp			depthCompareOp;
5201 		DE_FALSE,													//	deUint32			depthBoundsTestEnable;
5202 		DE_FALSE,													//	deUint32			stencilTestEnable;
5203 		{
5204 			VK_STENCIL_OP_KEEP,											//	VkStencilOp	stencilFailOp;
5205 			VK_STENCIL_OP_KEEP,											//	VkStencilOp	stencilPassOp;
5206 			VK_STENCIL_OP_KEEP,											//	VkStencilOp	stencilDepthFailOp;
5207 			VK_COMPARE_OP_ALWAYS,										//	VkCompareOp	stencilCompareOp;
5208 			0u,															//	deUint32	stencilCompareMask;
5209 			0u,															//	deUint32	stencilWriteMask;
5210 			0u,															//	deUint32	stencilReference;
5211 		},															//	VkStencilOpState	front;
5212 		{
5213 			VK_STENCIL_OP_KEEP,											//	VkStencilOp	stencilFailOp;
5214 			VK_STENCIL_OP_KEEP,											//	VkStencilOp	stencilPassOp;
5215 			VK_STENCIL_OP_KEEP,											//	VkStencilOp	stencilDepthFailOp;
5216 			VK_COMPARE_OP_ALWAYS,										//	VkCompareOp	stencilCompareOp;
5217 			0u,															//	deUint32	stencilCompareMask;
5218 			0u,															//	deUint32	stencilWriteMask;
5219 			0u,															//	deUint32	stencilReference;
5220 		},															//	VkStencilOpState	back;
5221 		-1.0f,														//	float				minDepthBounds;
5222 		+1.0f,														//	float				maxDepthBounds;
5223 	};
5224 	const VkViewport						viewport0				=
5225 	{
5226 		0.0f,														//	float	originX;
5227 		0.0f,														//	float	originY;
5228 		(float)renderSize.x(),										//	float	width;
5229 		(float)renderSize.y(),										//	float	height;
5230 		0.0f,														//	float	minDepth;
5231 		1.0f,														//	float	maxDepth;
5232 	};
5233 	const VkRect2D							scissor0				=
5234 	{
5235 		{
5236 			0u,															//	deInt32	x;
5237 			0u,															//	deInt32	y;
5238 		},															//	VkOffset2D	offset;
5239 		{
5240 			renderSize.x(),												//	deInt32	width;
5241 			renderSize.y(),												//	deInt32	height;
5242 		},															//	VkExtent2D	extent;
5243 	};
5244 	const VkPipelineViewportStateCreateInfo		viewportParams			=
5245 	{
5246 		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,		//	VkStructureType		sType;
5247 		DE_NULL,													//	const void*			pNext;
5248 		(VkPipelineViewportStateCreateFlags)0,
5249 		1u,															//	deUint32			viewportCount;
5250 		&viewport0,
5251 		1u,
5252 		&scissor0
5253 	};
5254 	const VkSampleMask							sampleMask				= ~0u;
5255 	const VkPipelineMultisampleStateCreateInfo	multisampleParams		=
5256 	{
5257 		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	//	VkStructureType			sType;
5258 		DE_NULL,													//	const void*				pNext;
5259 		(VkPipelineMultisampleStateCreateFlags)0,
5260 		VK_SAMPLE_COUNT_1_BIT,										//	VkSampleCountFlagBits	rasterSamples;
5261 		DE_FALSE,													//	deUint32				sampleShadingEnable;
5262 		0.0f,														//	float					minSampleShading;
5263 		&sampleMask,												//	const VkSampleMask*		pSampleMask;
5264 		DE_FALSE,													//	VkBool32				alphaToCoverageEnable;
5265 		DE_FALSE,													//	VkBool32				alphaToOneEnable;
5266 	};
5267 	const VkPipelineRasterizationStateCreateInfo	rasterParams		=
5268 	{
5269 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,	//	VkStructureType	sType;
5270 		DE_NULL,													//	const void*		pNext;
5271 		(VkPipelineRasterizationStateCreateFlags)0,
5272 		DE_TRUE,													//	deUint32		depthClipEnable;
5273 		DE_FALSE,													//	deUint32		rasterizerDiscardEnable;
5274 		VK_POLYGON_MODE_FILL,										//	VkFillMode		fillMode;
5275 		VK_CULL_MODE_NONE,											//	VkCullMode		cullMode;
5276 		VK_FRONT_FACE_COUNTER_CLOCKWISE,							//	VkFrontFace		frontFace;
5277 		VK_FALSE,													//	VkBool32		depthBiasEnable;
5278 		0.0f,														//	float			depthBias;
5279 		0.0f,														//	float			depthBiasClamp;
5280 		0.0f,														//	float			slopeScaledDepthBias;
5281 		1.0f,														//	float			lineWidth;
5282 	};
5283 	const VkPrimitiveTopology topology = hasTessellation? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST: VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
5284 	const VkPipelineInputAssemblyStateCreateInfo	inputAssemblyParams	=
5285 	{
5286 		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	//	VkStructureType		sType;
5287 		DE_NULL,														//	const void*			pNext;
5288 		(VkPipelineInputAssemblyStateCreateFlags)0,
5289 		topology,														//	VkPrimitiveTopology	topology;
5290 		DE_FALSE,														//	deUint32			primitiveRestartEnable;
5291 	};
5292 	const VkVertexInputBindingDescription		vertexBinding0 =
5293 	{
5294 		0u,									// deUint32					binding;
5295 		deUint32(singleVertexDataSize),		// deUint32					strideInBytes;
5296 		VK_VERTEX_INPUT_RATE_VERTEX			// VkVertexInputStepRate	stepRate;
5297 	};
5298 	const VkVertexInputAttributeDescription		vertexAttrib0[2] =
5299 	{
5300 		{
5301 			0u,									// deUint32	location;
5302 			0u,									// deUint32	binding;
5303 			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat	format;
5304 			0u									// deUint32	offsetInBytes;
5305 		},
5306 		{
5307 			1u,									// deUint32	location;
5308 			0u,									// deUint32	binding;
5309 			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat	format;
5310 			sizeof(Vec4),						// deUint32	offsetInBytes;
5311 		}
5312 	};
5313 
5314 	const VkPipelineVertexInputStateCreateInfo	vertexInputStateParams	=
5315 	{
5316 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	VkStructureType								sType;
5317 		DE_NULL,													//	const void*									pNext;
5318 		(VkPipelineVertexInputStateCreateFlags)0,
5319 		1u,															//	deUint32									bindingCount;
5320 		&vertexBinding0,											//	const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
5321 		2u,															//	deUint32									attributeCount;
5322 		vertexAttrib0,												//	const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
5323 	};
5324 	const VkPipelineColorBlendAttachmentState	attBlendParams			=
5325 	{
5326 		DE_FALSE,													//	deUint32		blendEnable;
5327 		VK_BLEND_FACTOR_ONE,										//	VkBlend			srcBlendColor;
5328 		VK_BLEND_FACTOR_ZERO,										//	VkBlend			destBlendColor;
5329 		VK_BLEND_OP_ADD,											//	VkBlendOp		blendOpColor;
5330 		VK_BLEND_FACTOR_ONE,										//	VkBlend			srcBlendAlpha;
5331 		VK_BLEND_FACTOR_ZERO,										//	VkBlend			destBlendAlpha;
5332 		VK_BLEND_OP_ADD,											//	VkBlendOp		blendOpAlpha;
5333 		(VK_COLOR_COMPONENT_R_BIT|
5334 		 VK_COLOR_COMPONENT_G_BIT|
5335 		 VK_COLOR_COMPONENT_B_BIT|
5336 		 VK_COLOR_COMPONENT_A_BIT),									//	VkChannelFlags	channelWriteMask;
5337 	};
5338 	const VkPipelineColorBlendStateCreateInfo	blendParams				=
5339 	{
5340 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	//	VkStructureType								sType;
5341 		DE_NULL,													//	const void*									pNext;
5342 		(VkPipelineColorBlendStateCreateFlags)0,
5343 		DE_FALSE,													//	VkBool32									logicOpEnable;
5344 		VK_LOGIC_OP_COPY,											//	VkLogicOp									logicOp;
5345 		1u,															//	deUint32									attachmentCount;
5346 		&attBlendParams,											//	const VkPipelineColorBlendAttachmentState*	pAttachments;
5347 		{ 0.0f, 0.0f, 0.0f, 0.0f },									//	float										blendConst[4];
5348 	};
5349 	const VkPipelineTessellationStateCreateInfo	tessellationState	=
5350 	{
5351 		VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,
5352 		DE_NULL,
5353 		(VkPipelineTessellationStateCreateFlags)0,
5354 		3u
5355 	};
5356 
5357 	const VkPipelineTessellationStateCreateInfo* tessellationInfo	=	hasTessellation ? &tessellationState: DE_NULL;
5358 	const VkGraphicsPipelineCreateInfo		pipelineParams			=
5359 	{
5360 		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,		//	VkStructureType									sType;
5361 		DE_NULL,												//	const void*										pNext;
5362 		0u,														//	VkPipelineCreateFlags							flags;
5363 		(deUint32)shaderStageParams.size(),						//	deUint32										stageCount;
5364 		&shaderStageParams[0],									//	const VkPipelineShaderStageCreateInfo*			pStages;
5365 		&vertexInputStateParams,								//	const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
5366 		&inputAssemblyParams,									//	const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
5367 		tessellationInfo,										//	const VkPipelineTessellationStateCreateInfo*	pTessellationState;
5368 		&viewportParams,										//	const VkPipelineViewportStateCreateInfo*		pViewportState;
5369 		&rasterParams,											//	const VkPipelineRasterStateCreateInfo*			pRasterState;
5370 		&multisampleParams,										//	const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
5371 		&depthStencilParams,									//	const VkPipelineDepthStencilStateCreateInfo*	pDepthStencilState;
5372 		&blendParams,											//	const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
5373 		(const VkPipelineDynamicStateCreateInfo*)DE_NULL,		//	const VkPipelineDynamicStateCreateInfo*			pDynamicState;
5374 		*pipelineLayout,										//	VkPipelineLayout								layout;
5375 		*renderPass,											//	VkRenderPass									renderPass;
5376 		0u,														//	deUint32										subpass;
5377 		DE_NULL,												//	VkPipeline										basePipelineHandle;
5378 		0u,														//	deInt32											basePipelineIndex;
5379 	};
5380 
5381 	const Unique<VkPipeline>				pipeline				(createGraphicsPipeline(vk, vkDevice, DE_NULL, &pipelineParams));
5382 
5383 	// Framebuffer
5384 	const VkFramebufferCreateInfo			framebufferParams		=
5385 	{
5386 		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,				//	VkStructureType		sType;
5387 		DE_NULL,												//	const void*			pNext;
5388 		(VkFramebufferCreateFlags)0,
5389 		*renderPass,											//	VkRenderPass		renderPass;
5390 		1u,														//	deUint32			attachmentCount;
5391 		&*colorAttView,											//	const VkImageView*	pAttachments;
5392 		(deUint32)renderSize.x(),								//	deUint32			width;
5393 		(deUint32)renderSize.y(),								//	deUint32			height;
5394 		1u,														//	deUint32			layers;
5395 	};
5396 	const Unique<VkFramebuffer>				framebuffer				(createFramebuffer(vk, vkDevice, &framebufferParams));
5397 
5398 	const VkCommandPoolCreateInfo			cmdPoolParams			=
5399 	{
5400 		VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,					//	VkStructureType			sType;
5401 		DE_NULL,													//	const void*				pNext;
5402 		VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,				//	VkCmdPoolCreateFlags	flags;
5403 		queueFamilyIndex,											//	deUint32				queueFamilyIndex;
5404 	};
5405 	const Unique<VkCommandPool>				cmdPool					(createCommandPool(vk, vkDevice, &cmdPoolParams));
5406 
5407 	// Command buffer
5408 	const VkCommandBufferAllocateInfo		cmdBufParams			=
5409 	{
5410 		VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,			//	VkStructureType			sType;
5411 		DE_NULL,												//	const void*				pNext;
5412 		*cmdPool,												//	VkCmdPool				pool;
5413 		VK_COMMAND_BUFFER_LEVEL_PRIMARY,						//	VkCmdBufferLevel		level;
5414 		1u,														//	deUint32				count;
5415 	};
5416 	const Unique<VkCommandBuffer>			cmdBuf					(allocateCommandBuffer(vk, vkDevice, &cmdBufParams));
5417 
5418 	const VkCommandBufferBeginInfo			cmdBufBeginParams		=
5419 	{
5420 		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,			//	VkStructureType				sType;
5421 		DE_NULL,												//	const void*					pNext;
5422 		(VkCommandBufferUsageFlags)0,
5423 		(const VkCommandBufferInheritanceInfo*)DE_NULL,
5424 	};
5425 
5426 	// Record commands
5427 	VK_CHECK(vk.beginCommandBuffer(*cmdBuf, &cmdBufBeginParams));
5428 
5429 	{
5430 		const VkMemoryBarrier		vertFlushBarrier	=
5431 		{
5432 			VK_STRUCTURE_TYPE_MEMORY_BARRIER,			//	VkStructureType		sType;
5433 			DE_NULL,									//	const void*			pNext;
5434 			VK_ACCESS_HOST_WRITE_BIT,					//	VkMemoryOutputFlags	outputMask;
5435 			VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,		//	VkMemoryInputFlags	inputMask;
5436 		};
5437 		const VkImageMemoryBarrier	colorAttBarrier		=
5438 		{
5439 			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		//	VkStructureType			sType;
5440 			DE_NULL,									//	const void*				pNext;
5441 			0u,											//	VkMemoryOutputFlags		outputMask;
5442 			VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,		//	VkMemoryInputFlags		inputMask;
5443 			VK_IMAGE_LAYOUT_UNDEFINED,					//	VkImageLayout			oldLayout;
5444 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout			newLayout;
5445 			queueFamilyIndex,							//	deUint32				srcQueueFamilyIndex;
5446 			queueFamilyIndex,							//	deUint32				destQueueFamilyIndex;
5447 			*image,										//	VkImage					image;
5448 			{
5449 				VK_IMAGE_ASPECT_COLOR_BIT,					//	VkImageAspect	aspect;
5450 				0u,											//	deUint32		baseMipLevel;
5451 				1u,											//	deUint32		mipLevels;
5452 				0u,											//	deUint32		baseArraySlice;
5453 				1u,											//	deUint32		arraySize;
5454 			}											//	VkImageSubresourceRange	subresourceRange;
5455 		};
5456 		vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, (VkDependencyFlags)0, 1, &vertFlushBarrier, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &colorAttBarrier);
5457 	}
5458 
5459 	{
5460 		const VkClearValue			clearValue		= makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f);
5461 		const VkRenderPassBeginInfo	passBeginParams	=
5462 		{
5463 			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,			//	VkStructureType		sType;
5464 			DE_NULL,											//	const void*			pNext;
5465 			*renderPass,										//	VkRenderPass		renderPass;
5466 			*framebuffer,										//	VkFramebuffer		framebuffer;
5467 			{ { 0, 0 }, { renderSize.x(), renderSize.y() } },	//	VkRect2D			renderArea;
5468 			1u,													//	deUint32			clearValueCount;
5469 			&clearValue,										//	const VkClearValue*	pClearValues;
5470 		};
5471 		vk.cmdBeginRenderPass(*cmdBuf, &passBeginParams, VK_SUBPASS_CONTENTS_INLINE);
5472 	}
5473 
5474 	vk.cmdBindPipeline(*cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
5475 	{
5476 		const VkDeviceSize bindingOffset = 0;
5477 		vk.cmdBindVertexBuffers(*cmdBuf, 0u, 1u, &vertexBuffer.get(), &bindingOffset);
5478 	}
5479 	vk.cmdDraw(*cmdBuf, deUint32(vertexCount), 1u /*run pipeline once*/, 0u /*first vertex*/, 0u /*first instanceIndex*/);
5480 	vk.cmdEndRenderPass(*cmdBuf);
5481 
5482 	{
5483 		const VkImageMemoryBarrier	renderFinishBarrier	=
5484 		{
5485 			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		//	VkStructureType			sType;
5486 			DE_NULL,									//	const void*				pNext;
5487 			VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,		//	VkMemoryOutputFlags		outputMask;
5488 			VK_ACCESS_TRANSFER_READ_BIT,				//	VkMemoryInputFlags		inputMask;
5489 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout			oldLayout;
5490 			VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,		//	VkImageLayout			newLayout;
5491 			queueFamilyIndex,							//	deUint32				srcQueueFamilyIndex;
5492 			queueFamilyIndex,							//	deUint32				destQueueFamilyIndex;
5493 			*image,										//	VkImage					image;
5494 			{
5495 				VK_IMAGE_ASPECT_COLOR_BIT,					//	VkImageAspectFlags	aspectMask;
5496 				0u,											//	deUint32			baseMipLevel;
5497 				1u,											//	deUint32			mipLevels;
5498 				0u,											//	deUint32			baseArraySlice;
5499 				1u,											//	deUint32			arraySize;
5500 			}											//	VkImageSubresourceRange	subresourceRange;
5501 		};
5502 		vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &renderFinishBarrier);
5503 	}
5504 
5505 	{
5506 		const VkBufferImageCopy	copyParams	=
5507 		{
5508 			(VkDeviceSize)0u,						//	VkDeviceSize			bufferOffset;
5509 			(deUint32)renderSize.x(),				//	deUint32				bufferRowLength;
5510 			(deUint32)renderSize.y(),				//	deUint32				bufferImageHeight;
5511 			{
5512 				VK_IMAGE_ASPECT_COLOR_BIT,				//	VkImageAspect		aspect;
5513 				0u,										//	deUint32			mipLevel;
5514 				0u,										//	deUint32			arrayLayer;
5515 				1u,										//	deUint32			arraySize;
5516 			},										//	VkImageSubresourceCopy	imageSubresource;
5517 			{ 0u, 0u, 0u },							//	VkOffset3D				imageOffset;
5518 			{ renderSize.x(), renderSize.y(), 1u }	//	VkExtent3D				imageExtent;
5519 		};
5520 		vk.cmdCopyImageToBuffer(*cmdBuf, *image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *readImageBuffer, 1u, &copyParams);
5521 	}
5522 
5523 	{
5524 		const VkBufferMemoryBarrier	copyFinishBarrier	=
5525 		{
5526 			VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	//	VkStructureType		sType;
5527 			DE_NULL,									//	const void*			pNext;
5528 			VK_ACCESS_TRANSFER_WRITE_BIT,				//	VkMemoryOutputFlags	outputMask;
5529 			VK_ACCESS_HOST_READ_BIT,					//	VkMemoryInputFlags	inputMask;
5530 			queueFamilyIndex,							//	deUint32			srcQueueFamilyIndex;
5531 			queueFamilyIndex,							//	deUint32			destQueueFamilyIndex;
5532 			*readImageBuffer,							//	VkBuffer			buffer;
5533 			0u,											//	VkDeviceSize		offset;
5534 			imageSizeBytes								//	VkDeviceSize		size;
5535 		};
5536 		vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &copyFinishBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
5537 	}
5538 
5539 	VK_CHECK(vk.endCommandBuffer(*cmdBuf));
5540 
5541 	// Upload vertex data
5542 	{
5543 		const VkMappedMemoryRange	range			=
5544 		{
5545 			VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,	//	VkStructureType	sType;
5546 			DE_NULL,								//	const void*		pNext;
5547 			vertexBufferMemory->getMemory(),		//	VkDeviceMemory	mem;
5548 			0,										//	VkDeviceSize	offset;
5549 			(VkDeviceSize)sizeof(vertexData),		//	VkDeviceSize	size;
5550 		};
5551 		void*						vertexBufPtr	= vertexBufferMemory->getHostPtr();
5552 
5553 		deMemcpy(vertexBufPtr, &vertexData[0], sizeof(vertexData));
5554 		VK_CHECK(vk.flushMappedMemoryRanges(vkDevice, 1u, &range));
5555 	}
5556 
5557 	// Submit & wait for completion
5558 	{
5559 		const VkFenceCreateInfo	fenceParams	=
5560 		{
5561 			VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,	//	VkStructureType		sType;
5562 			DE_NULL,								//	const void*			pNext;
5563 			0u,										//	VkFenceCreateFlags	flags;
5564 		};
5565 		const Unique<VkFence>	fence		(createFence(vk, vkDevice, &fenceParams));
5566 		const VkSubmitInfo		submitInfo	=
5567 		{
5568 			VK_STRUCTURE_TYPE_SUBMIT_INFO,
5569 			DE_NULL,
5570 			0u,
5571 			(const VkSemaphore*)DE_NULL,
5572 			(const VkPipelineStageFlags*)DE_NULL,
5573 			1u,
5574 			&cmdBuf.get(),
5575 			0u,
5576 			(const VkSemaphore*)DE_NULL,
5577 		};
5578 
5579 		VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, *fence));
5580 		VK_CHECK(vk.waitForFences(vkDevice, 1u, &fence.get(), DE_TRUE, ~0ull));
5581 	}
5582 
5583 	const void* imagePtr	= readImageBufferMemory->getHostPtr();
5584 	const tcu::ConstPixelBufferAccess pixelBuffer(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8),
5585 												  renderSize.x(), renderSize.y(), 1, imagePtr);
5586 	// Log image
5587 	{
5588 		const VkMappedMemoryRange	range		=
5589 		{
5590 			VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,	//	VkStructureType	sType;
5591 			DE_NULL,								//	const void*		pNext;
5592 			readImageBufferMemory->getMemory(),		//	VkDeviceMemory	mem;
5593 			0,										//	VkDeviceSize	offset;
5594 			imageSizeBytes,							//	VkDeviceSize	size;
5595 		};
5596 
5597 		VK_CHECK(vk.invalidateMappedMemoryRanges(vkDevice, 1u, &range));
5598 		context.getTestContext().getLog() << TestLog::Image("Result", "Result", pixelBuffer);
5599 	}
5600 
5601 	const RGBA threshold(1, 1, 1, 1);
5602 	const RGBA upperLeft(pixelBuffer.getPixel(1, 1));
5603 	if (!tcu::compareThreshold(upperLeft, instance.outputColors[0], threshold))
5604 		return TestStatus::fail("Upper left corner mismatch");
5605 
5606 	const RGBA upperRight(pixelBuffer.getPixel(pixelBuffer.getWidth() - 1, 1));
5607 	if (!tcu::compareThreshold(upperRight, instance.outputColors[1], threshold))
5608 		return TestStatus::fail("Upper right corner mismatch");
5609 
5610 	const RGBA lowerLeft(pixelBuffer.getPixel(1, pixelBuffer.getHeight() - 1));
5611 	if (!tcu::compareThreshold(lowerLeft, instance.outputColors[2], threshold))
5612 		return TestStatus::fail("Lower left corner mismatch");
5613 
5614 	const RGBA lowerRight(pixelBuffer.getPixel(pixelBuffer.getWidth() - 1, pixelBuffer.getHeight() - 1));
5615 	if (!tcu::compareThreshold(lowerRight, instance.outputColors[3], threshold))
5616 		return TestStatus::fail("Lower right corner mismatch");
5617 
5618 	return TestStatus::pass("Rendered output matches input");
5619 }
5620 
createTestsForAllStages(const std::string & name,const RGBA (& inputColors)[4],const RGBA (& outputColors)[4],const map<string,string> & testCodeFragments,const vector<deInt32> & specConstants,tcu::TestCaseGroup * tests)5621 void createTestsForAllStages (const std::string& name, const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map<string, string>& testCodeFragments, const vector<deInt32>& specConstants, tcu::TestCaseGroup* tests)
5622 {
5623 	const ShaderElement		vertFragPipelineStages[]		=
5624 	{
5625 		ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT),
5626 		ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
5627 	};
5628 
5629 	const ShaderElement		tessPipelineStages[]			=
5630 	{
5631 		ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT),
5632 		ShaderElement("tessc", "main", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT),
5633 		ShaderElement("tesse", "main", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT),
5634 		ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
5635 	};
5636 
5637 	const ShaderElement		geomPipelineStages[]				=
5638 	{
5639 		ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT),
5640 		ShaderElement("geom", "main", VK_SHADER_STAGE_GEOMETRY_BIT),
5641 		ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
5642 	};
5643 
5644 	StageToSpecConstantMap	specConstantMap;
5645 
5646 	specConstantMap[VK_SHADER_STAGE_VERTEX_BIT] = specConstants;
5647 	addFunctionCaseWithPrograms<InstanceContext>(tests, name + "_vert", "", addShaderCodeCustomVertex, runAndVerifyDefaultPipeline,
5648 												 createInstanceContext(vertFragPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
5649 
5650 	specConstantMap.clear();
5651 	specConstantMap[VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT] = specConstants;
5652 	addFunctionCaseWithPrograms<InstanceContext>(tests, name + "_tessc", "", addShaderCodeCustomTessControl, runAndVerifyDefaultPipeline,
5653 												 createInstanceContext(tessPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
5654 
5655 	specConstantMap.clear();
5656 	specConstantMap[VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT] = specConstants;
5657 	addFunctionCaseWithPrograms<InstanceContext>(tests, name + "_tesse", "", addShaderCodeCustomTessEval, runAndVerifyDefaultPipeline,
5658 												 createInstanceContext(tessPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
5659 
5660 	specConstantMap.clear();
5661 	specConstantMap[VK_SHADER_STAGE_GEOMETRY_BIT] = specConstants;
5662 	addFunctionCaseWithPrograms<InstanceContext>(tests, name + "_geom", "", addShaderCodeCustomGeometry, runAndVerifyDefaultPipeline,
5663 												 createInstanceContext(geomPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
5664 
5665 	specConstantMap.clear();
5666 	specConstantMap[VK_SHADER_STAGE_FRAGMENT_BIT] = specConstants;
5667 	addFunctionCaseWithPrograms<InstanceContext>(tests, name + "_frag", "", addShaderCodeCustomFragment, runAndVerifyDefaultPipeline,
5668 												 createInstanceContext(vertFragPipelineStages, inputColors, outputColors, testCodeFragments, specConstantMap));
5669 }
5670 
createTestsForAllStages(const std::string & name,const RGBA (& inputColors)[4],const RGBA (& outputColors)[4],const map<string,string> & testCodeFragments,tcu::TestCaseGroup * tests)5671 inline void createTestsForAllStages (const std::string& name, const RGBA (&inputColors)[4], const RGBA (&outputColors)[4], const map<string, string>& testCodeFragments, tcu::TestCaseGroup* tests)
5672 {
5673 	vector<deInt32> noSpecConstants;
5674 	createTestsForAllStages(name, inputColors, outputColors, testCodeFragments, noSpecConstants, tests);
5675 }
5676 
5677 } // anonymous
5678 
createOpSourceTests(tcu::TestContext & testCtx)5679 tcu::TestCaseGroup* createOpSourceTests (tcu::TestContext& testCtx)
5680 {
5681 	struct NameCodePair { string name, code; };
5682 	RGBA							defaultColors[4];
5683 	de::MovePtr<tcu::TestCaseGroup> opSourceTests			(new tcu::TestCaseGroup(testCtx, "opsource", "OpSource instruction"));
5684 	const std::string				opsourceGLSLWithFile	= "%opsrcfile = OpString \"foo.vert\"\nOpSource GLSL 450 %opsrcfile ";
5685 	map<string, string>				fragments				= passthruFragments();
5686 	const NameCodePair				tests[]					=
5687 	{
5688 		{"unknown", "OpSource Unknown 321"},
5689 		{"essl", "OpSource ESSL 310"},
5690 		{"glsl", "OpSource GLSL 450"},
5691 		{"opencl_cpp", "OpSource OpenCL_CPP 120"},
5692 		{"opencl_c", "OpSource OpenCL_C 120"},
5693 		{"multiple", "OpSource GLSL 450\nOpSource GLSL 450"},
5694 		{"file", opsourceGLSLWithFile},
5695 		{"source", opsourceGLSLWithFile + "\"void main(){}\""},
5696 		// Longest possible source string: SPIR-V limits instructions to 65535
5697 		// words, of which the first 4 are opsourceGLSLWithFile; the rest will
5698 		// contain 65530 UTF8 characters (one word each) plus one last word
5699 		// containing 3 ASCII characters and \0.
5700 		{"longsource", opsourceGLSLWithFile + '"' + makeLongUTF8String(65530) + "ccc" + '"'}
5701 	};
5702 
5703 	getDefaultColors(defaultColors);
5704 	for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameCodePair); ++testNdx)
5705 	{
5706 		fragments["debug"] = tests[testNdx].code;
5707 		createTestsForAllStages(tests[testNdx].name, defaultColors, defaultColors, fragments, opSourceTests.get());
5708 	}
5709 
5710 	return opSourceTests.release();
5711 }
5712 
createOpSourceContinuedTests(tcu::TestContext & testCtx)5713 tcu::TestCaseGroup* createOpSourceContinuedTests (tcu::TestContext& testCtx)
5714 {
5715 	struct NameCodePair { string name, code; };
5716 	RGBA								defaultColors[4];
5717 	de::MovePtr<tcu::TestCaseGroup>		opSourceTests		(new tcu::TestCaseGroup(testCtx, "opsourcecontinued", "OpSourceContinued instruction"));
5718 	map<string, string>					fragments			= passthruFragments();
5719 	const std::string					opsource			= "%opsrcfile = OpString \"foo.vert\"\nOpSource GLSL 450 %opsrcfile \"void main(){}\"\n";
5720 	const NameCodePair					tests[]				=
5721 	{
5722 		{"empty", opsource + "OpSourceContinued \"\""},
5723 		{"short", opsource + "OpSourceContinued \"abcde\""},
5724 		{"multiple", opsource + "OpSourceContinued \"abcde\"\nOpSourceContinued \"fghij\""},
5725 		// Longest possible source string: SPIR-V limits instructions to 65535
5726 		// words, of which the first one is OpSourceContinued/length; the rest
5727 		// will contain 65533 UTF8 characters (one word each) plus one last word
5728 		// containing 3 ASCII characters and \0.
5729 		{"long", opsource + "OpSourceContinued \"" + makeLongUTF8String(65533) + "ccc\""}
5730 	};
5731 
5732 	getDefaultColors(defaultColors);
5733 	for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameCodePair); ++testNdx)
5734 	{
5735 		fragments["debug"] = tests[testNdx].code;
5736 		createTestsForAllStages(tests[testNdx].name, defaultColors, defaultColors, fragments, opSourceTests.get());
5737 	}
5738 
5739 	return opSourceTests.release();
5740 }
5741 
createOpNoLineTests(tcu::TestContext & testCtx)5742 tcu::TestCaseGroup* createOpNoLineTests(tcu::TestContext& testCtx)
5743 {
5744 	RGBA								 defaultColors[4];
5745 	de::MovePtr<tcu::TestCaseGroup>		 opLineTests		 (new tcu::TestCaseGroup(testCtx, "opnoline", "OpNoLine instruction"));
5746 	map<string, string>					 fragments;
5747 	getDefaultColors(defaultColors);
5748 	fragments["debug"]			=
5749 		"%name = OpString \"name\"\n";
5750 
5751 	fragments["pre_main"]	=
5752 		"OpNoLine\n"
5753 		"OpNoLine\n"
5754 		"OpLine %name 1 1\n"
5755 		"OpNoLine\n"
5756 		"OpLine %name 1 1\n"
5757 		"OpLine %name 1 1\n"
5758 		"%second_function = OpFunction %v4f32 None %v4f32_function\n"
5759 		"OpNoLine\n"
5760 		"OpLine %name 1 1\n"
5761 		"OpNoLine\n"
5762 		"OpLine %name 1 1\n"
5763 		"OpLine %name 1 1\n"
5764 		"%second_param1 = OpFunctionParameter %v4f32\n"
5765 		"OpNoLine\n"
5766 		"OpNoLine\n"
5767 		"%label_secondfunction = OpLabel\n"
5768 		"OpNoLine\n"
5769 		"OpReturnValue %second_param1\n"
5770 		"OpFunctionEnd\n"
5771 		"OpNoLine\n"
5772 		"OpNoLine\n";
5773 
5774 	fragments["testfun"]		=
5775 		// A %test_code function that returns its argument unchanged.
5776 		"OpNoLine\n"
5777 		"OpNoLine\n"
5778 		"OpLine %name 1 1\n"
5779 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
5780 		"OpNoLine\n"
5781 		"%param1 = OpFunctionParameter %v4f32\n"
5782 		"OpNoLine\n"
5783 		"OpNoLine\n"
5784 		"%label_testfun = OpLabel\n"
5785 		"OpNoLine\n"
5786 		"%val1 = OpFunctionCall %v4f32 %second_function %param1\n"
5787 		"OpReturnValue %val1\n"
5788 		"OpFunctionEnd\n"
5789 		"OpLine %name 1 1\n"
5790 		"OpNoLine\n";
5791 
5792 	createTestsForAllStages("opnoline", defaultColors, defaultColors, fragments, opLineTests.get());
5793 
5794 	return opLineTests.release();
5795 }
5796 
5797 
createOpLineTests(tcu::TestContext & testCtx)5798 tcu::TestCaseGroup* createOpLineTests(tcu::TestContext& testCtx)
5799 {
5800 	RGBA													defaultColors[4];
5801 	de::MovePtr<tcu::TestCaseGroup>							opLineTests			(new tcu::TestCaseGroup(testCtx, "opline", "OpLine instruction"));
5802 	map<string, string>										fragments;
5803 	std::vector<std::pair<std::string, std::string> >		problemStrings;
5804 
5805 	problemStrings.push_back(std::make_pair<std::string, std::string>("empty_name", ""));
5806 	problemStrings.push_back(std::make_pair<std::string, std::string>("short_name", "short_name"));
5807 	problemStrings.push_back(std::make_pair<std::string, std::string>("long_name", makeLongUTF8String(65530) + "ccc"));
5808 	getDefaultColors(defaultColors);
5809 
5810 	fragments["debug"]			=
5811 		"%other_name = OpString \"other_name\"\n";
5812 
5813 	fragments["pre_main"]	=
5814 		"OpLine %file_name 32 0\n"
5815 		"OpLine %file_name 32 32\n"
5816 		"OpLine %file_name 32 40\n"
5817 		"OpLine %other_name 32 40\n"
5818 		"OpLine %other_name 0 100\n"
5819 		"OpLine %other_name 0 4294967295\n"
5820 		"OpLine %other_name 4294967295 0\n"
5821 		"OpLine %other_name 32 40\n"
5822 		"OpLine %file_name 0 0\n"
5823 		"%second_function = OpFunction %v4f32 None %v4f32_function\n"
5824 		"OpLine %file_name 1 0\n"
5825 		"%second_param1 = OpFunctionParameter %v4f32\n"
5826 		"OpLine %file_name 1 3\n"
5827 		"OpLine %file_name 1 2\n"
5828 		"%label_secondfunction = OpLabel\n"
5829 		"OpLine %file_name 0 2\n"
5830 		"OpReturnValue %second_param1\n"
5831 		"OpFunctionEnd\n"
5832 		"OpLine %file_name 0 2\n"
5833 		"OpLine %file_name 0 2\n";
5834 
5835 	fragments["testfun"]		=
5836 		// A %test_code function that returns its argument unchanged.
5837 		"OpLine %file_name 1 0\n"
5838 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
5839 		"OpLine %file_name 16 330\n"
5840 		"%param1 = OpFunctionParameter %v4f32\n"
5841 		"OpLine %file_name 14 442\n"
5842 		"%label_testfun = OpLabel\n"
5843 		"OpLine %file_name 11 1024\n"
5844 		"%val1 = OpFunctionCall %v4f32 %second_function %param1\n"
5845 		"OpLine %file_name 2 97\n"
5846 		"OpReturnValue %val1\n"
5847 		"OpFunctionEnd\n"
5848 		"OpLine %file_name 5 32\n";
5849 
5850 	for (size_t i = 0; i < problemStrings.size(); ++i)
5851 	{
5852 		map<string, string> testFragments = fragments;
5853 		testFragments["debug"] += "%file_name = OpString \"" + problemStrings[i].second + "\"\n";
5854 		createTestsForAllStages(string("opline") + "_" + problemStrings[i].first, defaultColors, defaultColors, testFragments, opLineTests.get());
5855 	}
5856 
5857 	return opLineTests.release();
5858 }
5859 
createOpConstantNullTests(tcu::TestContext & testCtx)5860 tcu::TestCaseGroup* createOpConstantNullTests(tcu::TestContext& testCtx)
5861 {
5862 	de::MovePtr<tcu::TestCaseGroup> opConstantNullTests		(new tcu::TestCaseGroup(testCtx, "opconstantnull", "OpConstantNull instruction"));
5863 	RGBA							colors[4];
5864 
5865 
5866 	const char						functionStart[] =
5867 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
5868 		"%param1 = OpFunctionParameter %v4f32\n"
5869 		"%lbl    = OpLabel\n";
5870 
5871 	const char						functionEnd[]	=
5872 		"OpReturnValue %transformed_param\n"
5873 		"OpFunctionEnd\n";
5874 
5875 	struct NameConstantsCode
5876 	{
5877 		string name;
5878 		string constants;
5879 		string code;
5880 	};
5881 
5882 	NameConstantsCode tests[] =
5883 	{
5884 		{
5885 			"vec4",
5886 			"%cnull = OpConstantNull %v4f32\n",
5887 			"%transformed_param = OpFAdd %v4f32 %param1 %cnull\n"
5888 		},
5889 		{
5890 			"float",
5891 			"%cnull = OpConstantNull %f32\n",
5892 			"%vp = OpVariable %fp_v4f32 Function\n"
5893 			"%v  = OpLoad %v4f32 %vp\n"
5894 			"%v0 = OpVectorInsertDynamic %v4f32 %v %cnull %c_i32_0\n"
5895 			"%v1 = OpVectorInsertDynamic %v4f32 %v0 %cnull %c_i32_1\n"
5896 			"%v2 = OpVectorInsertDynamic %v4f32 %v1 %cnull %c_i32_2\n"
5897 			"%v3 = OpVectorInsertDynamic %v4f32 %v2 %cnull %c_i32_3\n"
5898 			"%transformed_param = OpFAdd %v4f32 %param1 %v3\n"
5899 		},
5900 		{
5901 			"bool",
5902 			"%cnull             = OpConstantNull %bool\n",
5903 			"%v                 = OpVariable %fp_v4f32 Function\n"
5904 			"                     OpStore %v %param1\n"
5905 			"                     OpSelectionMerge %false_label None\n"
5906 			"                     OpBranchConditional %cnull %true_label %false_label\n"
5907 			"%true_label        = OpLabel\n"
5908 			"                     OpStore %v %c_v4f32_0_5_0_5_0_5_0_5\n"
5909 			"                     OpBranch %false_label\n"
5910 			"%false_label       = OpLabel\n"
5911 			"%transformed_param = OpLoad %v4f32 %v\n"
5912 		},
5913 		{
5914 			"i32",
5915 			"%cnull             = OpConstantNull %i32\n",
5916 			"%v                 = OpVariable %fp_v4f32 Function %c_v4f32_0_5_0_5_0_5_0_5\n"
5917 			"%b                 = OpIEqual %bool %cnull %c_i32_0\n"
5918 			"                     OpSelectionMerge %false_label None\n"
5919 			"                     OpBranchConditional %b %true_label %false_label\n"
5920 			"%true_label        = OpLabel\n"
5921 			"                     OpStore %v %param1\n"
5922 			"                     OpBranch %false_label\n"
5923 			"%false_label       = OpLabel\n"
5924 			"%transformed_param = OpLoad %v4f32 %v\n"
5925 		},
5926 		{
5927 			"struct",
5928 			"%stype             = OpTypeStruct %f32 %v4f32\n"
5929 			"%fp_stype          = OpTypePointer Function %stype\n"
5930 			"%cnull             = OpConstantNull %stype\n",
5931 			"%v                 = OpVariable %fp_stype Function %cnull\n"
5932 			"%f                 = OpAccessChain %fp_v4f32 %v %c_i32_1\n"
5933 			"%f_val             = OpLoad %v4f32 %f\n"
5934 			"%transformed_param = OpFAdd %v4f32 %param1 %f_val\n"
5935 		},
5936 		{
5937 			"array",
5938 			"%a4_v4f32          = OpTypeArray %v4f32 %c_u32_4\n"
5939 			"%fp_a4_v4f32       = OpTypePointer Function %a4_v4f32\n"
5940 			"%cnull             = OpConstantNull %a4_v4f32\n",
5941 			"%v                 = OpVariable %fp_a4_v4f32 Function %cnull\n"
5942 			"%f                 = OpAccessChain %fp_v4f32 %v %c_u32_0\n"
5943 			"%f1                = OpAccessChain %fp_v4f32 %v %c_u32_1\n"
5944 			"%f2                = OpAccessChain %fp_v4f32 %v %c_u32_2\n"
5945 			"%f3                = OpAccessChain %fp_v4f32 %v %c_u32_3\n"
5946 			"%f_val             = OpLoad %v4f32 %f\n"
5947 			"%f1_val            = OpLoad %v4f32 %f1\n"
5948 			"%f2_val            = OpLoad %v4f32 %f2\n"
5949 			"%f3_val            = OpLoad %v4f32 %f3\n"
5950 			"%t0                = OpFAdd %v4f32 %param1 %f_val\n"
5951 			"%t1                = OpFAdd %v4f32 %t0 %f1_val\n"
5952 			"%t2                = OpFAdd %v4f32 %t1 %f2_val\n"
5953 			"%transformed_param = OpFAdd %v4f32 %t2 %f3_val\n"
5954 		},
5955 		{
5956 			"matrix",
5957 			"%mat4x4_f32        = OpTypeMatrix %v4f32 4\n"
5958 			"%cnull             = OpConstantNull %mat4x4_f32\n",
5959 			// Our null matrix * any vector should result in a zero vector.
5960 			"%v                 = OpVectorTimesMatrix %v4f32 %param1 %cnull\n"
5961 			"%transformed_param = OpFAdd %v4f32 %param1 %v\n"
5962 		}
5963 	};
5964 
5965 	getHalfColorsFullAlpha(colors);
5966 
5967 	for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameConstantsCode); ++testNdx)
5968 	{
5969 		map<string, string> fragments;
5970 		fragments["pre_main"] = tests[testNdx].constants;
5971 		fragments["testfun"] = string(functionStart) + tests[testNdx].code + functionEnd;
5972 		createTestsForAllStages(tests[testNdx].name, colors, colors, fragments, opConstantNullTests.get());
5973 	}
5974 	return opConstantNullTests.release();
5975 }
createOpConstantCompositeTests(tcu::TestContext & testCtx)5976 tcu::TestCaseGroup* createOpConstantCompositeTests(tcu::TestContext& testCtx)
5977 {
5978 	de::MovePtr<tcu::TestCaseGroup> opConstantCompositeTests		(new tcu::TestCaseGroup(testCtx, "opconstantcomposite", "OpConstantComposite instruction"));
5979 	RGBA							inputColors[4];
5980 	RGBA							outputColors[4];
5981 
5982 
5983 	const char						functionStart[]	 =
5984 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
5985 		"%param1 = OpFunctionParameter %v4f32\n"
5986 		"%lbl    = OpLabel\n";
5987 
5988 	const char						functionEnd[]		=
5989 		"OpReturnValue %transformed_param\n"
5990 		"OpFunctionEnd\n";
5991 
5992 	struct NameConstantsCode
5993 	{
5994 		string name;
5995 		string constants;
5996 		string code;
5997 	};
5998 
5999 	NameConstantsCode tests[] =
6000 	{
6001 		{
6002 			"vec4",
6003 
6004 			"%cval              = OpConstantComposite %v4f32 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5 %c_f32_0\n",
6005 			"%transformed_param = OpFAdd %v4f32 %param1 %cval\n"
6006 		},
6007 		{
6008 			"struct",
6009 
6010 			"%stype             = OpTypeStruct %v4f32 %f32\n"
6011 			"%fp_stype          = OpTypePointer Function %stype\n"
6012 			"%f32_n_1           = OpConstant %f32 -1.0\n"
6013 			"%f32_1_5           = OpConstant %f32 !0x3fc00000\n" // +1.5
6014 			"%cvec              = OpConstantComposite %v4f32 %f32_1_5 %f32_1_5 %f32_1_5 %c_f32_1\n"
6015 			"%cval              = OpConstantComposite %stype %cvec %f32_n_1\n",
6016 
6017 			"%v                 = OpVariable %fp_stype Function %cval\n"
6018 			"%vec_ptr           = OpAccessChain %fp_v4f32 %v %c_u32_0\n"
6019 			"%f32_ptr           = OpAccessChain %fp_f32 %v %c_u32_1\n"
6020 			"%vec_val           = OpLoad %v4f32 %vec_ptr\n"
6021 			"%f32_val           = OpLoad %f32 %f32_ptr\n"
6022 			"%tmp1              = OpVectorTimesScalar %v4f32 %c_v4f32_1_1_1_1 %f32_val\n" // vec4(-1)
6023 			"%tmp2              = OpFAdd %v4f32 %tmp1 %param1\n" // param1 + vec4(-1)
6024 			"%transformed_param = OpFAdd %v4f32 %tmp2 %vec_val\n" // param1 + vec4(-1) + vec4(1.5, 1.5, 1.5, 1.0)
6025 		},
6026 		{
6027 			// [1|0|0|0.5] [x] = x + 0.5
6028 			// [0|1|0|0.5] [y] = y + 0.5
6029 			// [0|0|1|0.5] [z] = z + 0.5
6030 			// [0|0|0|1  ] [1] = 1
6031 			"matrix",
6032 
6033 			"%mat4x4_f32          = OpTypeMatrix %v4f32 4\n"
6034 		    "%v4f32_1_0_0_0       = OpConstantComposite %v4f32 %c_f32_1 %c_f32_0 %c_f32_0 %c_f32_0\n"
6035 		    "%v4f32_0_1_0_0       = OpConstantComposite %v4f32 %c_f32_0 %c_f32_1 %c_f32_0 %c_f32_0\n"
6036 		    "%v4f32_0_0_1_0       = OpConstantComposite %v4f32 %c_f32_0 %c_f32_0 %c_f32_1 %c_f32_0\n"
6037 		    "%v4f32_0_5_0_5_0_5_1 = OpConstantComposite %v4f32 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5 %c_f32_1\n"
6038 			"%cval                = OpConstantComposite %mat4x4_f32 %v4f32_1_0_0_0 %v4f32_0_1_0_0 %v4f32_0_0_1_0 %v4f32_0_5_0_5_0_5_1\n",
6039 
6040 			"%transformed_param   = OpMatrixTimesVector %v4f32 %cval %param1\n"
6041 		},
6042 		{
6043 			"array",
6044 
6045 			"%c_v4f32_1_1_1_0     = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
6046 			"%fp_a4f32            = OpTypePointer Function %a4f32\n"
6047 			"%f32_n_1             = OpConstant %f32 -1.0\n"
6048 			"%f32_1_5             = OpConstant %f32 !0x3fc00000\n" // +1.5
6049 			"%carr                = OpConstantComposite %a4f32 %c_f32_0 %f32_n_1 %f32_1_5 %c_f32_0\n",
6050 
6051 			"%v                   = OpVariable %fp_a4f32 Function %carr\n"
6052 			"%f                   = OpAccessChain %fp_f32 %v %c_u32_0\n"
6053 			"%f1                  = OpAccessChain %fp_f32 %v %c_u32_1\n"
6054 			"%f2                  = OpAccessChain %fp_f32 %v %c_u32_2\n"
6055 			"%f3                  = OpAccessChain %fp_f32 %v %c_u32_3\n"
6056 			"%f_val               = OpLoad %f32 %f\n"
6057 			"%f1_val              = OpLoad %f32 %f1\n"
6058 			"%f2_val              = OpLoad %f32 %f2\n"
6059 			"%f3_val              = OpLoad %f32 %f3\n"
6060 			"%ftot1               = OpFAdd %f32 %f_val %f1_val\n"
6061 			"%ftot2               = OpFAdd %f32 %ftot1 %f2_val\n"
6062 			"%ftot3               = OpFAdd %f32 %ftot2 %f3_val\n"  // 0 - 1 + 1.5 + 0
6063 			"%add_vec             = OpVectorTimesScalar %v4f32 %c_v4f32_1_1_1_0 %ftot3\n"
6064 			"%transformed_param   = OpFAdd %v4f32 %param1 %add_vec\n"
6065 		},
6066 		{
6067 			//
6068 			// [
6069 			//   {
6070 			//      0.0,
6071 			//      [ 1.0, 1.0, 1.0, 1.0]
6072 			//   },
6073 			//   {
6074 			//      1.0,
6075 			//      [ 0.0, 0.5, 0.0, 0.0]
6076 			//   }, //     ^^^
6077 			//   {
6078 			//      0.0,
6079 			//      [ 1.0, 1.0, 1.0, 1.0]
6080 			//   }
6081 			// ]
6082 			"array_of_struct_of_array",
6083 
6084 			"%c_v4f32_1_1_1_0     = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
6085 			"%fp_a4f32            = OpTypePointer Function %a4f32\n"
6086 			"%stype               = OpTypeStruct %f32 %a4f32\n"
6087 			"%a3stype             = OpTypeArray %stype %c_u32_3\n"
6088 			"%fp_a3stype          = OpTypePointer Function %a3stype\n"
6089 			"%ca4f32_0            = OpConstantComposite %a4f32 %c_f32_0 %c_f32_0_5 %c_f32_0 %c_f32_0\n"
6090 			"%ca4f32_1            = OpConstantComposite %a4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_1\n"
6091 			"%cstype1             = OpConstantComposite %stype %c_f32_0 %ca4f32_1\n"
6092 			"%cstype2             = OpConstantComposite %stype %c_f32_1 %ca4f32_0\n"
6093 			"%carr                = OpConstantComposite %a3stype %cstype1 %cstype2 %cstype1",
6094 
6095 			"%v                   = OpVariable %fp_a3stype Function %carr\n"
6096 			"%f                   = OpAccessChain %fp_f32 %v %c_u32_1 %c_u32_1 %c_u32_1\n"
6097 			"%f_l                 = OpLoad %f32 %f\n"
6098 			"%add_vec             = OpVectorTimesScalar %v4f32 %c_v4f32_1_1_1_0 %f_l\n"
6099 			"%transformed_param   = OpFAdd %v4f32 %param1 %add_vec\n"
6100 		}
6101 	};
6102 
6103 	getHalfColorsFullAlpha(inputColors);
6104 	outputColors[0] = RGBA(255, 255, 255, 255);
6105 	outputColors[1] = RGBA(255, 127, 127, 255);
6106 	outputColors[2] = RGBA(127, 255, 127, 255);
6107 	outputColors[3] = RGBA(127, 127, 255, 255);
6108 
6109 	for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameConstantsCode); ++testNdx)
6110 	{
6111 		map<string, string> fragments;
6112 		fragments["pre_main"] = tests[testNdx].constants;
6113 		fragments["testfun"] = string(functionStart) + tests[testNdx].code + functionEnd;
6114 		createTestsForAllStages(tests[testNdx].name, inputColors, outputColors, fragments, opConstantCompositeTests.get());
6115 	}
6116 	return opConstantCompositeTests.release();
6117 }
6118 
createSelectionBlockOrderTests(tcu::TestContext & testCtx)6119 tcu::TestCaseGroup* createSelectionBlockOrderTests(tcu::TestContext& testCtx)
6120 {
6121 	de::MovePtr<tcu::TestCaseGroup> group				(new tcu::TestCaseGroup(testCtx, "selection_block_order", "Out-of-order blocks for selection"));
6122 	RGBA							inputColors[4];
6123 	RGBA							outputColors[4];
6124 	map<string, string>				fragments;
6125 
6126 	// vec4 test_code(vec4 param) {
6127 	//   vec4 result = param;
6128 	//   for (int i = 0; i < 4; ++i) {
6129 	//     if (i == 0) result[i] = 0.;
6130 	//     else        result[i] = 1. - result[i];
6131 	//   }
6132 	//   return result;
6133 	// }
6134 	const char						function[]			=
6135 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
6136 		"%param1    = OpFunctionParameter %v4f32\n"
6137 		"%lbl       = OpLabel\n"
6138 		"%iptr      = OpVariable %fp_i32 Function\n"
6139 		"%result    = OpVariable %fp_v4f32 Function\n"
6140 		"             OpStore %iptr %c_i32_0\n"
6141 		"             OpStore %result %param1\n"
6142 		"             OpBranch %loop\n"
6143 
6144 		// Loop entry block.
6145 		"%loop      = OpLabel\n"
6146 		"%ival      = OpLoad %i32 %iptr\n"
6147 		"%lt_4      = OpSLessThan %bool %ival %c_i32_4\n"
6148 		"             OpLoopMerge %exit %if_entry None\n"
6149 		"             OpBranchConditional %lt_4 %if_entry %exit\n"
6150 
6151 		// Merge block for loop.
6152 		"%exit      = OpLabel\n"
6153 		"%ret       = OpLoad %v4f32 %result\n"
6154 		"             OpReturnValue %ret\n"
6155 
6156 		// If-statement entry block.
6157 		"%if_entry  = OpLabel\n"
6158 		"%loc       = OpAccessChain %fp_f32 %result %ival\n"
6159 		"%eq_0      = OpIEqual %bool %ival %c_i32_0\n"
6160 		"             OpSelectionMerge %if_exit None\n"
6161 		"             OpBranchConditional %eq_0 %if_true %if_false\n"
6162 
6163 		// False branch for if-statement.
6164 		"%if_false  = OpLabel\n"
6165 		"%val       = OpLoad %f32 %loc\n"
6166 		"%sub       = OpFSub %f32 %c_f32_1 %val\n"
6167 		"             OpStore %loc %sub\n"
6168 		"             OpBranch %if_exit\n"
6169 
6170 		// Merge block for if-statement.
6171 		"%if_exit   = OpLabel\n"
6172 		"%ival_next = OpIAdd %i32 %ival %c_i32_1\n"
6173 		"             OpStore %iptr %ival_next\n"
6174 		"             OpBranch %loop\n"
6175 
6176 		// True branch for if-statement.
6177 		"%if_true   = OpLabel\n"
6178 		"             OpStore %loc %c_f32_0\n"
6179 		"             OpBranch %if_exit\n"
6180 
6181 		"             OpFunctionEnd\n";
6182 
6183 	fragments["testfun"]	= function;
6184 
6185 	inputColors[0]			= RGBA(127, 127, 127, 0);
6186 	inputColors[1]			= RGBA(127, 0,   0,   0);
6187 	inputColors[2]			= RGBA(0,   127, 0,   0);
6188 	inputColors[3]			= RGBA(0,   0,   127, 0);
6189 
6190 	outputColors[0]			= RGBA(0, 128, 128, 255);
6191 	outputColors[1]			= RGBA(0, 255, 255, 255);
6192 	outputColors[2]			= RGBA(0, 128, 255, 255);
6193 	outputColors[3]			= RGBA(0, 255, 128, 255);
6194 
6195 	createTestsForAllStages("out_of_order", inputColors, outputColors, fragments, group.get());
6196 
6197 	return group.release();
6198 }
6199 
createSwitchBlockOrderTests(tcu::TestContext & testCtx)6200 tcu::TestCaseGroup* createSwitchBlockOrderTests(tcu::TestContext& testCtx)
6201 {
6202 	de::MovePtr<tcu::TestCaseGroup> group				(new tcu::TestCaseGroup(testCtx, "switch_block_order", "Out-of-order blocks for switch"));
6203 	RGBA							inputColors[4];
6204 	RGBA							outputColors[4];
6205 	map<string, string>				fragments;
6206 
6207 	const char						typesAndConstants[]	=
6208 		"%c_f32_p2  = OpConstant %f32 0.2\n"
6209 		"%c_f32_p4  = OpConstant %f32 0.4\n"
6210 		"%c_f32_p6  = OpConstant %f32 0.6\n"
6211 		"%c_f32_p8  = OpConstant %f32 0.8\n";
6212 
6213 	// vec4 test_code(vec4 param) {
6214 	//   vec4 result = param;
6215 	//   for (int i = 0; i < 4; ++i) {
6216 	//     switch (i) {
6217 	//       case 0: result[i] += .2; break;
6218 	//       case 1: result[i] += .6; break;
6219 	//       case 2: result[i] += .4; break;
6220 	//       case 3: result[i] += .8; break;
6221 	//       default: break; // unreachable
6222 	//     }
6223 	//   }
6224 	//   return result;
6225 	// }
6226 	const char						function[]			=
6227 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
6228 		"%param1    = OpFunctionParameter %v4f32\n"
6229 		"%lbl       = OpLabel\n"
6230 		"%iptr      = OpVariable %fp_i32 Function\n"
6231 		"%result    = OpVariable %fp_v4f32 Function\n"
6232 		"             OpStore %iptr %c_i32_0\n"
6233 		"             OpStore %result %param1\n"
6234 		"             OpBranch %loop\n"
6235 
6236 		// Loop entry block.
6237 		"%loop      = OpLabel\n"
6238 		"%ival      = OpLoad %i32 %iptr\n"
6239 		"%lt_4      = OpSLessThan %bool %ival %c_i32_4\n"
6240 		"             OpLoopMerge %exit %switch_exit None\n"
6241 		"             OpBranchConditional %lt_4 %switch_entry %exit\n"
6242 
6243 		// Merge block for loop.
6244 		"%exit      = OpLabel\n"
6245 		"%ret       = OpLoad %v4f32 %result\n"
6246 		"             OpReturnValue %ret\n"
6247 
6248 		// Switch-statement entry block.
6249 		"%switch_entry   = OpLabel\n"
6250 		"%loc            = OpAccessChain %fp_f32 %result %ival\n"
6251 		"%val            = OpLoad %f32 %loc\n"
6252 		"                  OpSelectionMerge %switch_exit None\n"
6253 		"                  OpSwitch %ival %switch_default 0 %case0 1 %case1 2 %case2 3 %case3\n"
6254 
6255 		"%case2          = OpLabel\n"
6256 		"%addp4          = OpFAdd %f32 %val %c_f32_p4\n"
6257 		"                  OpStore %loc %addp4\n"
6258 		"                  OpBranch %switch_exit\n"
6259 
6260 		"%switch_default = OpLabel\n"
6261 		"                  OpUnreachable\n"
6262 
6263 		"%case3          = OpLabel\n"
6264 		"%addp8          = OpFAdd %f32 %val %c_f32_p8\n"
6265 		"                  OpStore %loc %addp8\n"
6266 		"                  OpBranch %switch_exit\n"
6267 
6268 		"%case0          = OpLabel\n"
6269 		"%addp2          = OpFAdd %f32 %val %c_f32_p2\n"
6270 		"                  OpStore %loc %addp2\n"
6271 		"                  OpBranch %switch_exit\n"
6272 
6273 		// Merge block for switch-statement.
6274 		"%switch_exit    = OpLabel\n"
6275 		"%ival_next      = OpIAdd %i32 %ival %c_i32_1\n"
6276 		"                  OpStore %iptr %ival_next\n"
6277 		"                  OpBranch %loop\n"
6278 
6279 		"%case1          = OpLabel\n"
6280 		"%addp6          = OpFAdd %f32 %val %c_f32_p6\n"
6281 		"                  OpStore %loc %addp6\n"
6282 		"                  OpBranch %switch_exit\n"
6283 
6284 		"                  OpFunctionEnd\n";
6285 
6286 	fragments["pre_main"]	= typesAndConstants;
6287 	fragments["testfun"]	= function;
6288 
6289 	inputColors[0]			= RGBA(127, 27,  127, 51);
6290 	inputColors[1]			= RGBA(127, 0,   0,   51);
6291 	inputColors[2]			= RGBA(0,   27,  0,   51);
6292 	inputColors[3]			= RGBA(0,   0,   127, 51);
6293 
6294 	outputColors[0]			= RGBA(178, 180, 229, 255);
6295 	outputColors[1]			= RGBA(178, 153, 102, 255);
6296 	outputColors[2]			= RGBA(51,  180, 102, 255);
6297 	outputColors[3]			= RGBA(51,  153, 229, 255);
6298 
6299 	createTestsForAllStages("out_of_order", inputColors, outputColors, fragments, group.get());
6300 
6301 	return group.release();
6302 }
6303 
createDecorationGroupTests(tcu::TestContext & testCtx)6304 tcu::TestCaseGroup* createDecorationGroupTests(tcu::TestContext& testCtx)
6305 {
6306 	de::MovePtr<tcu::TestCaseGroup> group				(new tcu::TestCaseGroup(testCtx, "decoration_group", "Decoration group tests"));
6307 	RGBA							inputColors[4];
6308 	RGBA							outputColors[4];
6309 	map<string, string>				fragments;
6310 
6311 	const char						decorations[]		=
6312 		"OpDecorate %array_group         ArrayStride 4\n"
6313 		"OpDecorate %struct_member_group Offset 0\n"
6314 		"%array_group         = OpDecorationGroup\n"
6315 		"%struct_member_group = OpDecorationGroup\n"
6316 
6317 		"OpDecorate %group1 RelaxedPrecision\n"
6318 		"OpDecorate %group3 RelaxedPrecision\n"
6319 		"OpDecorate %group3 Invariant\n"
6320 		"OpDecorate %group3 Restrict\n"
6321 		"%group0 = OpDecorationGroup\n"
6322 		"%group1 = OpDecorationGroup\n"
6323 		"%group3 = OpDecorationGroup\n";
6324 
6325 	const char						typesAndConstants[]	=
6326 		"%a3f32     = OpTypeArray %f32 %c_u32_3\n"
6327 		"%struct1   = OpTypeStruct %a3f32\n"
6328 		"%struct2   = OpTypeStruct %a3f32\n"
6329 		"%fp_struct1 = OpTypePointer Function %struct1\n"
6330 		"%fp_struct2 = OpTypePointer Function %struct2\n"
6331 		"%c_f32_2    = OpConstant %f32 2.\n"
6332 		"%c_f32_n2   = OpConstant %f32 -2.\n"
6333 
6334 		"%c_a3f32_1 = OpConstantComposite %a3f32 %c_f32_1 %c_f32_2 %c_f32_1\n"
6335 		"%c_a3f32_2 = OpConstantComposite %a3f32 %c_f32_n1 %c_f32_n2 %c_f32_n1\n"
6336 		"%c_struct1 = OpConstantComposite %struct1 %c_a3f32_1\n"
6337 		"%c_struct2 = OpConstantComposite %struct2 %c_a3f32_2\n";
6338 
6339 	const char						function[]			=
6340 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
6341 		"%param     = OpFunctionParameter %v4f32\n"
6342 		"%entry     = OpLabel\n"
6343 		"%result    = OpVariable %fp_v4f32 Function\n"
6344 		"%v_struct1 = OpVariable %fp_struct1 Function\n"
6345 		"%v_struct2 = OpVariable %fp_struct2 Function\n"
6346 		"             OpStore %result %param\n"
6347 		"             OpStore %v_struct1 %c_struct1\n"
6348 		"             OpStore %v_struct2 %c_struct2\n"
6349 		"%ptr1      = OpAccessChain %fp_f32 %v_struct1 %c_i32_0 %c_i32_2\n"
6350 		"%val1      = OpLoad %f32 %ptr1\n"
6351 		"%ptr2      = OpAccessChain %fp_f32 %v_struct2 %c_i32_0 %c_i32_2\n"
6352 		"%val2      = OpLoad %f32 %ptr2\n"
6353 		"%addvalues = OpFAdd %f32 %val1 %val2\n"
6354 		"%ptr       = OpAccessChain %fp_f32 %result %c_i32_1\n"
6355 		"%val       = OpLoad %f32 %ptr\n"
6356 		"%addresult = OpFAdd %f32 %addvalues %val\n"
6357 		"             OpStore %ptr %addresult\n"
6358 		"%ret       = OpLoad %v4f32 %result\n"
6359 		"             OpReturnValue %ret\n"
6360 		"             OpFunctionEnd\n";
6361 
6362 	struct CaseNameDecoration
6363 	{
6364 		string name;
6365 		string decoration;
6366 	};
6367 
6368 	CaseNameDecoration tests[] =
6369 	{
6370 		{
6371 			"same_decoration_group_on_multiple_types",
6372 			"OpGroupMemberDecorate %struct_member_group %struct1 0 %struct2 0\n"
6373 		},
6374 		{
6375 			"empty_decoration_group",
6376 			"OpGroupDecorate %group0      %a3f32\n"
6377 			"OpGroupDecorate %group0      %result\n"
6378 		},
6379 		{
6380 			"one_element_decoration_group",
6381 			"OpGroupDecorate %array_group %a3f32\n"
6382 		},
6383 		{
6384 			"multiple_elements_decoration_group",
6385 			"OpGroupDecorate %group3      %v_struct1\n"
6386 		},
6387 		{
6388 			"multiple_decoration_groups_on_same_variable",
6389 			"OpGroupDecorate %group0      %v_struct2\n"
6390 			"OpGroupDecorate %group1      %v_struct2\n"
6391 			"OpGroupDecorate %group3      %v_struct2\n"
6392 		},
6393 		{
6394 			"same_decoration_group_multiple_times",
6395 			"OpGroupDecorate %group1      %addvalues\n"
6396 			"OpGroupDecorate %group1      %addvalues\n"
6397 			"OpGroupDecorate %group1      %addvalues\n"
6398 		},
6399 
6400 	};
6401 
6402 	getHalfColorsFullAlpha(inputColors);
6403 	getHalfColorsFullAlpha(outputColors);
6404 
6405 	for (size_t idx = 0; idx < (sizeof(tests) / sizeof(tests[0])); ++idx)
6406 	{
6407 		fragments["decoration"]	= decorations + tests[idx].decoration;
6408 		fragments["pre_main"]	= typesAndConstants;
6409 		fragments["testfun"]	= function;
6410 
6411 		createTestsForAllStages(tests[idx].name, inputColors, outputColors, fragments, group.get());
6412 	}
6413 
6414 	return group.release();
6415 }
6416 
6417 struct SpecConstantTwoIntGraphicsCase
6418 {
6419 	const char*		caseName;
6420 	const char*		scDefinition0;
6421 	const char*		scDefinition1;
6422 	const char*		scResultType;
6423 	const char*		scOperation;
6424 	deInt32			scActualValue0;
6425 	deInt32			scActualValue1;
6426 	const char*		resultOperation;
6427 	RGBA			expectedColors[4];
6428 
SpecConstantTwoIntGraphicsCasevkt::SpirVAssembly::SpecConstantTwoIntGraphicsCase6429 					SpecConstantTwoIntGraphicsCase (const char* name,
6430 											const char* definition0,
6431 											const char* definition1,
6432 											const char* resultType,
6433 											const char* operation,
6434 											deInt32		value0,
6435 											deInt32		value1,
6436 											const char* resultOp,
6437 											const RGBA	(&output)[4])
6438 						: caseName			(name)
6439 						, scDefinition0		(definition0)
6440 						, scDefinition1		(definition1)
6441 						, scResultType		(resultType)
6442 						, scOperation		(operation)
6443 						, scActualValue0	(value0)
6444 						, scActualValue1	(value1)
6445 						, resultOperation	(resultOp)
6446 	{
6447 		expectedColors[0] = output[0];
6448 		expectedColors[1] = output[1];
6449 		expectedColors[2] = output[2];
6450 		expectedColors[3] = output[3];
6451 	}
6452 };
6453 
createSpecConstantTests(tcu::TestContext & testCtx)6454 tcu::TestCaseGroup* createSpecConstantTests (tcu::TestContext& testCtx)
6455 {
6456 	de::MovePtr<tcu::TestCaseGroup> group				(new tcu::TestCaseGroup(testCtx, "opspecconstantop", "Test the OpSpecConstantOp instruction"));
6457 	vector<SpecConstantTwoIntGraphicsCase>	cases;
6458 	RGBA							inputColors[4];
6459 	RGBA							outputColors0[4];
6460 	RGBA							outputColors1[4];
6461 	RGBA							outputColors2[4];
6462 
6463 	const char	decorations1[]			=
6464 		"OpDecorate %sc_0  SpecId 0\n"
6465 		"OpDecorate %sc_1  SpecId 1\n";
6466 
6467 	const char	typesAndConstants1[]	=
6468 		"%sc_0      = OpSpecConstant${SC_DEF0}\n"
6469 		"%sc_1      = OpSpecConstant${SC_DEF1}\n"
6470 		"%sc_op     = OpSpecConstantOp ${SC_RESULT_TYPE} ${SC_OP}\n";
6471 
6472 	const char	function1[]				=
6473 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
6474 		"%param     = OpFunctionParameter %v4f32\n"
6475 		"%label     = OpLabel\n"
6476 		"%result    = OpVariable %fp_v4f32 Function\n"
6477 		"             OpStore %result %param\n"
6478 		"%gen       = ${GEN_RESULT}\n"
6479 		"%index     = OpIAdd %i32 %gen %c_i32_1\n"
6480 		"%loc       = OpAccessChain %fp_f32 %result %index\n"
6481 		"%val       = OpLoad %f32 %loc\n"
6482 		"%add       = OpFAdd %f32 %val %c_f32_0_5\n"
6483 		"             OpStore %loc %add\n"
6484 		"%ret       = OpLoad %v4f32 %result\n"
6485 		"             OpReturnValue %ret\n"
6486 		"             OpFunctionEnd\n";
6487 
6488 	inputColors[0] = RGBA(127, 127, 127, 255);
6489 	inputColors[1] = RGBA(127, 0,   0,   255);
6490 	inputColors[2] = RGBA(0,   127, 0,   255);
6491 	inputColors[3] = RGBA(0,   0,   127, 255);
6492 
6493 	// Derived from inputColors[x] by adding 128 to inputColors[x][0].
6494 	outputColors0[0] = RGBA(255, 127, 127, 255);
6495 	outputColors0[1] = RGBA(255, 0,   0,   255);
6496 	outputColors0[2] = RGBA(128, 127, 0,   255);
6497 	outputColors0[3] = RGBA(128, 0,   127, 255);
6498 
6499 	// Derived from inputColors[x] by adding 128 to inputColors[x][1].
6500 	outputColors1[0] = RGBA(127, 255, 127, 255);
6501 	outputColors1[1] = RGBA(127, 128, 0,   255);
6502 	outputColors1[2] = RGBA(0,   255, 0,   255);
6503 	outputColors1[3] = RGBA(0,   128, 127, 255);
6504 
6505 	// Derived from inputColors[x] by adding 128 to inputColors[x][2].
6506 	outputColors2[0] = RGBA(127, 127, 255, 255);
6507 	outputColors2[1] = RGBA(127, 0,   128, 255);
6508 	outputColors2[2] = RGBA(0,   127, 128, 255);
6509 	outputColors2[3] = RGBA(0,   0,   255, 255);
6510 
6511 	const char addZeroToSc[]		= "OpIAdd %i32 %c_i32_0 %sc_op";
6512 	const char selectTrueUsingSc[]	= "OpSelect %i32 %sc_op %c_i32_1 %c_i32_0";
6513 	const char selectFalseUsingSc[]	= "OpSelect %i32 %sc_op %c_i32_0 %c_i32_1";
6514 
6515 	cases.push_back(SpecConstantTwoIntGraphicsCase("iadd",					" %i32 0",		" %i32 0",		"%i32",		"IAdd                 %sc_0 %sc_1",				19,		-20,	addZeroToSc,		outputColors0));
6516 	cases.push_back(SpecConstantTwoIntGraphicsCase("isub",					" %i32 0",		" %i32 0",		"%i32",		"ISub                 %sc_0 %sc_1",				19,		20,		addZeroToSc,		outputColors0));
6517 	cases.push_back(SpecConstantTwoIntGraphicsCase("imul",					" %i32 0",		" %i32 0",		"%i32",		"IMul                 %sc_0 %sc_1",				-1,		-1,		addZeroToSc,		outputColors2));
6518 	cases.push_back(SpecConstantTwoIntGraphicsCase("sdiv",					" %i32 0",		" %i32 0",		"%i32",		"SDiv                 %sc_0 %sc_1",				-126,	126,	addZeroToSc,		outputColors0));
6519 	cases.push_back(SpecConstantTwoIntGraphicsCase("udiv",					" %i32 0",		" %i32 0",		"%i32",		"UDiv                 %sc_0 %sc_1",				126,	126,	addZeroToSc,		outputColors2));
6520 	cases.push_back(SpecConstantTwoIntGraphicsCase("srem",					" %i32 0",		" %i32 0",		"%i32",		"SRem                 %sc_0 %sc_1",				3,		2,		addZeroToSc,		outputColors2));
6521 	cases.push_back(SpecConstantTwoIntGraphicsCase("smod",					" %i32 0",		" %i32 0",		"%i32",		"SMod                 %sc_0 %sc_1",				3,		2,		addZeroToSc,		outputColors2));
6522 	cases.push_back(SpecConstantTwoIntGraphicsCase("umod",					" %i32 0",		" %i32 0",		"%i32",		"UMod                 %sc_0 %sc_1",				1001,	500,	addZeroToSc,		outputColors2));
6523 	cases.push_back(SpecConstantTwoIntGraphicsCase("bitwiseand",			" %i32 0",		" %i32 0",		"%i32",		"BitwiseAnd           %sc_0 %sc_1",				0x33,	0x0d,	addZeroToSc,		outputColors2));
6524 	cases.push_back(SpecConstantTwoIntGraphicsCase("bitwiseor",				" %i32 0",		" %i32 0",		"%i32",		"BitwiseOr            %sc_0 %sc_1",				0,		1,		addZeroToSc,		outputColors2));
6525 	cases.push_back(SpecConstantTwoIntGraphicsCase("bitwisexor",			" %i32 0",		" %i32 0",		"%i32",		"BitwiseXor           %sc_0 %sc_1",				0x2e,	0x2f,	addZeroToSc,		outputColors2));
6526 	cases.push_back(SpecConstantTwoIntGraphicsCase("shiftrightlogical",		" %i32 0",		" %i32 0",		"%i32",		"ShiftRightLogical    %sc_0 %sc_1",				2,		1,		addZeroToSc,		outputColors2));
6527 	cases.push_back(SpecConstantTwoIntGraphicsCase("shiftrightarithmetic",	" %i32 0",		" %i32 0",		"%i32",		"ShiftRightArithmetic %sc_0 %sc_1",				-4,		2,		addZeroToSc,		outputColors0));
6528 	cases.push_back(SpecConstantTwoIntGraphicsCase("shiftleftlogical",		" %i32 0",		" %i32 0",		"%i32",		"ShiftLeftLogical     %sc_0 %sc_1",				1,		0,		addZeroToSc,		outputColors2));
6529 	cases.push_back(SpecConstantTwoIntGraphicsCase("slessthan",				" %i32 0",		" %i32 0",		"%bool",	"SLessThan            %sc_0 %sc_1",				-20,	-10,	selectTrueUsingSc,	outputColors2));
6530 	cases.push_back(SpecConstantTwoIntGraphicsCase("ulessthan",				" %i32 0",		" %i32 0",		"%bool",	"ULessThan            %sc_0 %sc_1",				10,		20,		selectTrueUsingSc,	outputColors2));
6531 	cases.push_back(SpecConstantTwoIntGraphicsCase("sgreaterthan",			" %i32 0",		" %i32 0",		"%bool",	"SGreaterThan         %sc_0 %sc_1",				-1000,	50,		selectFalseUsingSc,	outputColors2));
6532 	cases.push_back(SpecConstantTwoIntGraphicsCase("ugreaterthan",			" %i32 0",		" %i32 0",		"%bool",	"UGreaterThan         %sc_0 %sc_1",				10,		5,		selectTrueUsingSc,	outputColors2));
6533 	cases.push_back(SpecConstantTwoIntGraphicsCase("slessthanequal",		" %i32 0",		" %i32 0",		"%bool",	"SLessThanEqual       %sc_0 %sc_1",				-10,	-10,	selectTrueUsingSc,	outputColors2));
6534 	cases.push_back(SpecConstantTwoIntGraphicsCase("ulessthanequal",		" %i32 0",		" %i32 0",		"%bool",	"ULessThanEqual       %sc_0 %sc_1",				50,		100,	selectTrueUsingSc,	outputColors2));
6535 	cases.push_back(SpecConstantTwoIntGraphicsCase("sgreaterthanequal",		" %i32 0",		" %i32 0",		"%bool",	"SGreaterThanEqual    %sc_0 %sc_1",				-1000,	50,		selectFalseUsingSc,	outputColors2));
6536 	cases.push_back(SpecConstantTwoIntGraphicsCase("ugreaterthanequal",		" %i32 0",		" %i32 0",		"%bool",	"UGreaterThanEqual    %sc_0 %sc_1",				10,		10,		selectTrueUsingSc,	outputColors2));
6537 	cases.push_back(SpecConstantTwoIntGraphicsCase("iequal",				" %i32 0",		" %i32 0",		"%bool",	"IEqual               %sc_0 %sc_1",				42,		24,		selectFalseUsingSc,	outputColors2));
6538 	cases.push_back(SpecConstantTwoIntGraphicsCase("logicaland",			"True %bool",	"True %bool",	"%bool",	"LogicalAnd           %sc_0 %sc_1",				0,		1,		selectFalseUsingSc,	outputColors2));
6539 	cases.push_back(SpecConstantTwoIntGraphicsCase("logicalor",				"False %bool",	"False %bool",	"%bool",	"LogicalOr            %sc_0 %sc_1",				1,		0,		selectTrueUsingSc,	outputColors2));
6540 	cases.push_back(SpecConstantTwoIntGraphicsCase("logicalequal",			"True %bool",	"True %bool",	"%bool",	"LogicalEqual         %sc_0 %sc_1",				0,		1,		selectFalseUsingSc,	outputColors2));
6541 	cases.push_back(SpecConstantTwoIntGraphicsCase("logicalnotequal",		"False %bool",	"False %bool",	"%bool",	"LogicalNotEqual      %sc_0 %sc_1",				1,		0,		selectTrueUsingSc,	outputColors2));
6542 	cases.push_back(SpecConstantTwoIntGraphicsCase("snegate",				" %i32 0",		" %i32 0",		"%i32",		"SNegate              %sc_0",					-1,		0,		addZeroToSc,		outputColors2));
6543 	cases.push_back(SpecConstantTwoIntGraphicsCase("not",					" %i32 0",		" %i32 0",		"%i32",		"Not                  %sc_0",					-2,		0,		addZeroToSc,		outputColors2));
6544 	cases.push_back(SpecConstantTwoIntGraphicsCase("logicalnot",			"False %bool",	"False %bool",	"%bool",	"LogicalNot           %sc_0",					1,		0,		selectFalseUsingSc,	outputColors2));
6545 	cases.push_back(SpecConstantTwoIntGraphicsCase("select",				"False %bool",	" %i32 0",		"%i32",		"Select               %sc_0 %sc_1 %c_i32_0",	1,		1,		addZeroToSc,		outputColors2));
6546 	// OpSConvert, OpFConvert: these two instructions involve ints/floats of different bitwidths.
6547 	// \todo[2015-12-1 antiagainst] OpQuantizeToF16
6548 
6549 	for (size_t caseNdx = 0; caseNdx < cases.size(); ++caseNdx)
6550 	{
6551 		map<string, string>	specializations;
6552 		map<string, string>	fragments;
6553 		vector<deInt32>		specConstants;
6554 
6555 		specializations["SC_DEF0"]			= cases[caseNdx].scDefinition0;
6556 		specializations["SC_DEF1"]			= cases[caseNdx].scDefinition1;
6557 		specializations["SC_RESULT_TYPE"]	= cases[caseNdx].scResultType;
6558 		specializations["SC_OP"]			= cases[caseNdx].scOperation;
6559 		specializations["GEN_RESULT"]		= cases[caseNdx].resultOperation;
6560 
6561 		fragments["decoration"]				= tcu::StringTemplate(decorations1).specialize(specializations);
6562 		fragments["pre_main"]				= tcu::StringTemplate(typesAndConstants1).specialize(specializations);
6563 		fragments["testfun"]				= tcu::StringTemplate(function1).specialize(specializations);
6564 
6565 		specConstants.push_back(cases[caseNdx].scActualValue0);
6566 		specConstants.push_back(cases[caseNdx].scActualValue1);
6567 
6568 		createTestsForAllStages(cases[caseNdx].caseName, inputColors, cases[caseNdx].expectedColors, fragments, specConstants, group.get());
6569 	}
6570 
6571 	const char	decorations2[]			=
6572 		"OpDecorate %sc_0  SpecId 0\n"
6573 		"OpDecorate %sc_1  SpecId 1\n"
6574 		"OpDecorate %sc_2  SpecId 2\n";
6575 
6576 	const char	typesAndConstants2[]	=
6577 		"%v3i32     = OpTypeVector %i32 3\n"
6578 
6579 		"%sc_0      = OpSpecConstant %i32 0\n"
6580 		"%sc_1      = OpSpecConstant %i32 0\n"
6581 		"%sc_2      = OpSpecConstant %i32 0\n"
6582 
6583 		"%vec3_0      = OpConstantComposite %v3i32 %c_i32_0 %c_i32_0 %c_i32_0\n"
6584 		"%sc_vec3_0   = OpSpecConstantOp %v3i32 CompositeInsert  %sc_0        %vec3_0    0\n"     // (sc_0, 0, 0)
6585 		"%sc_vec3_1   = OpSpecConstantOp %v3i32 CompositeInsert  %sc_1        %vec3_0    1\n"     // (0, sc_1, 0)
6586 		"%sc_vec3_2   = OpSpecConstantOp %v3i32 CompositeInsert  %sc_2        %vec3_0    2\n"     // (0, 0, sc_2)
6587 		"%sc_vec3_01  = OpSpecConstantOp %v3i32 VectorShuffle    %sc_vec3_0   %sc_vec3_1 1 0 4\n" // (0,    sc_0, sc_1)
6588 		"%sc_vec3_012 = OpSpecConstantOp %v3i32 VectorShuffle    %sc_vec3_01  %sc_vec3_2 5 1 2\n" // (sc_2, sc_0, sc_1)
6589 		"%sc_ext_0    = OpSpecConstantOp %i32   CompositeExtract %sc_vec3_012            0\n"     // sc_2
6590 		"%sc_ext_1    = OpSpecConstantOp %i32   CompositeExtract %sc_vec3_012            1\n"     // sc_0
6591 		"%sc_ext_2    = OpSpecConstantOp %i32   CompositeExtract %sc_vec3_012            2\n"     // sc_1
6592 		"%sc_sub      = OpSpecConstantOp %i32   ISub             %sc_ext_0    %sc_ext_1\n"        // (sc_2 - sc_0)
6593 		"%sc_final    = OpSpecConstantOp %i32   IMul             %sc_sub      %sc_ext_2\n";       // (sc_2 - sc_0) * sc_1
6594 
6595 	const char	function2[]				=
6596 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
6597 		"%param     = OpFunctionParameter %v4f32\n"
6598 		"%label     = OpLabel\n"
6599 		"%result    = OpVariable %fp_v4f32 Function\n"
6600 		"             OpStore %result %param\n"
6601 		"%loc       = OpAccessChain %fp_f32 %result %sc_final\n"
6602 		"%val       = OpLoad %f32 %loc\n"
6603 		"%add       = OpFAdd %f32 %val %c_f32_0_5\n"
6604 		"             OpStore %loc %add\n"
6605 		"%ret       = OpLoad %v4f32 %result\n"
6606 		"             OpReturnValue %ret\n"
6607 		"             OpFunctionEnd\n";
6608 
6609 	map<string, string>	fragments;
6610 	vector<deInt32>		specConstants;
6611 
6612 	fragments["decoration"]	= decorations2;
6613 	fragments["pre_main"]	= typesAndConstants2;
6614 	fragments["testfun"]	= function2;
6615 
6616 	specConstants.push_back(56789);
6617 	specConstants.push_back(-2);
6618 	specConstants.push_back(56788);
6619 
6620 	createTestsForAllStages("vector_related", inputColors, outputColors2, fragments, specConstants, group.get());
6621 
6622 	return group.release();
6623 }
6624 
createOpPhiTests(tcu::TestContext & testCtx)6625 tcu::TestCaseGroup* createOpPhiTests(tcu::TestContext& testCtx)
6626 {
6627 	de::MovePtr<tcu::TestCaseGroup> group				(new tcu::TestCaseGroup(testCtx, "opphi", "Test the OpPhi instruction"));
6628 	RGBA							inputColors[4];
6629 	RGBA							outputColors1[4];
6630 	RGBA							outputColors2[4];
6631 	RGBA							outputColors3[4];
6632 	map<string, string>				fragments1;
6633 	map<string, string>				fragments2;
6634 	map<string, string>				fragments3;
6635 
6636 	const char	typesAndConstants1[]	=
6637 		"%c_f32_p2  = OpConstant %f32 0.2\n"
6638 		"%c_f32_p4  = OpConstant %f32 0.4\n"
6639 		"%c_f32_p5  = OpConstant %f32 0.5\n"
6640 		"%c_f32_p8  = OpConstant %f32 0.8\n";
6641 
6642 	// vec4 test_code(vec4 param) {
6643 	//   vec4 result = param;
6644 	//   for (int i = 0; i < 4; ++i) {
6645 	//     float operand;
6646 	//     switch (i) {
6647 	//       case 0: operand = .2; break;
6648 	//       case 1: operand = .5; break;
6649 	//       case 2: operand = .4; break;
6650 	//       case 3: operand = .0; break;
6651 	//       default: break; // unreachable
6652 	//     }
6653 	//     result[i] += operand;
6654 	//   }
6655 	//   return result;
6656 	// }
6657 	const char	function1[]				=
6658 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
6659 		"%param1    = OpFunctionParameter %v4f32\n"
6660 		"%lbl       = OpLabel\n"
6661 		"%iptr      = OpVariable %fp_i32 Function\n"
6662 		"%result    = OpVariable %fp_v4f32 Function\n"
6663 		"             OpStore %iptr %c_i32_0\n"
6664 		"             OpStore %result %param1\n"
6665 		"             OpBranch %loop\n"
6666 
6667 		"%loop      = OpLabel\n"
6668 		"%ival      = OpLoad %i32 %iptr\n"
6669 		"%lt_4      = OpSLessThan %bool %ival %c_i32_4\n"
6670 		"             OpLoopMerge %exit %phi None\n"
6671 		"             OpBranchConditional %lt_4 %entry %exit\n"
6672 
6673 		"%entry     = OpLabel\n"
6674 		"%loc       = OpAccessChain %fp_f32 %result %ival\n"
6675 		"%val       = OpLoad %f32 %loc\n"
6676 		"             OpSelectionMerge %phi None\n"
6677 		"             OpSwitch %ival %default 0 %case0 1 %case1 2 %case2 3 %case3\n"
6678 
6679 		"%case0     = OpLabel\n"
6680 		"             OpBranch %phi\n"
6681 		"%case1     = OpLabel\n"
6682 		"             OpBranch %phi\n"
6683 		"%case2     = OpLabel\n"
6684 		"             OpBranch %phi\n"
6685 		"%case3     = OpLabel\n"
6686 		"             OpBranch %phi\n"
6687 
6688 		"%default   = OpLabel\n"
6689 		"             OpUnreachable\n"
6690 
6691 		"%phi       = OpLabel\n"
6692 		"%operand   = OpPhi %f32 %c_f32_p4 %case2 %c_f32_p5 %case1 %c_f32_p2 %case0 %c_f32_0 %case3\n" // not in the order of blocks
6693 		"%add       = OpFAdd %f32 %val %operand\n"
6694 		"             OpStore %loc %add\n"
6695 		"%ival_next = OpIAdd %i32 %ival %c_i32_1\n"
6696 		"             OpStore %iptr %ival_next\n"
6697 		"             OpBranch %loop\n"
6698 
6699 		"%exit      = OpLabel\n"
6700 		"%ret       = OpLoad %v4f32 %result\n"
6701 		"             OpReturnValue %ret\n"
6702 
6703 		"             OpFunctionEnd\n";
6704 
6705 	fragments1["pre_main"]	= typesAndConstants1;
6706 	fragments1["testfun"]	= function1;
6707 
6708 	getHalfColorsFullAlpha(inputColors);
6709 
6710 	outputColors1[0]		= RGBA(178, 255, 229, 255);
6711 	outputColors1[1]		= RGBA(178, 127, 102, 255);
6712 	outputColors1[2]		= RGBA(51,  255, 102, 255);
6713 	outputColors1[3]		= RGBA(51,  127, 229, 255);
6714 
6715 	createTestsForAllStages("out_of_order", inputColors, outputColors1, fragments1, group.get());
6716 
6717 	const char	typesAndConstants2[]	=
6718 		"%c_f32_p2  = OpConstant %f32 0.2\n";
6719 
6720 	// Add .4 to the second element of the given parameter.
6721 	const char	function2[]				=
6722 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
6723 		"%param     = OpFunctionParameter %v4f32\n"
6724 		"%entry     = OpLabel\n"
6725 		"%result    = OpVariable %fp_v4f32 Function\n"
6726 		"             OpStore %result %param\n"
6727 		"%loc       = OpAccessChain %fp_f32 %result %c_i32_1\n"
6728 		"%val       = OpLoad %f32 %loc\n"
6729 		"             OpBranch %phi\n"
6730 
6731 		"%phi        = OpLabel\n"
6732 		"%step       = OpPhi %i32 %c_i32_0  %entry %step_next  %phi\n"
6733 		"%accum      = OpPhi %f32 %val      %entry %accum_next %phi\n"
6734 		"%step_next  = OpIAdd %i32 %step  %c_i32_1\n"
6735 		"%accum_next = OpFAdd %f32 %accum %c_f32_p2\n"
6736 		"%still_loop = OpSLessThan %bool %step %c_i32_2\n"
6737 		"              OpLoopMerge %exit %phi None\n"
6738 		"              OpBranchConditional %still_loop %phi %exit\n"
6739 
6740 		"%exit       = OpLabel\n"
6741 		"              OpStore %loc %accum\n"
6742 		"%ret        = OpLoad %v4f32 %result\n"
6743 		"              OpReturnValue %ret\n"
6744 
6745 		"              OpFunctionEnd\n";
6746 
6747 	fragments2["pre_main"]	= typesAndConstants2;
6748 	fragments2["testfun"]	= function2;
6749 
6750 	outputColors2[0]			= RGBA(127, 229, 127, 255);
6751 	outputColors2[1]			= RGBA(127, 102, 0,   255);
6752 	outputColors2[2]			= RGBA(0,   229, 0,   255);
6753 	outputColors2[3]			= RGBA(0,   102, 127, 255);
6754 
6755 	createTestsForAllStages("induction", inputColors, outputColors2, fragments2, group.get());
6756 
6757 	const char	typesAndConstants3[]	=
6758 		"%true      = OpConstantTrue %bool\n"
6759 		"%false     = OpConstantFalse %bool\n"
6760 		"%c_f32_p2  = OpConstant %f32 0.2\n";
6761 
6762 	// Swap the second and the third element of the given parameter.
6763 	const char	function3[]				=
6764 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
6765 		"%param     = OpFunctionParameter %v4f32\n"
6766 		"%entry     = OpLabel\n"
6767 		"%result    = OpVariable %fp_v4f32 Function\n"
6768 		"             OpStore %result %param\n"
6769 		"%a_loc     = OpAccessChain %fp_f32 %result %c_i32_1\n"
6770 		"%a_init    = OpLoad %f32 %a_loc\n"
6771 		"%b_loc     = OpAccessChain %fp_f32 %result %c_i32_2\n"
6772 		"%b_init    = OpLoad %f32 %b_loc\n"
6773 		"             OpBranch %phi\n"
6774 
6775 		"%phi        = OpLabel\n"
6776 		"%still_loop = OpPhi %bool %true   %entry %false  %phi\n"
6777 		"%a_next     = OpPhi %f32  %a_init %entry %b_next %phi\n"
6778 		"%b_next     = OpPhi %f32  %b_init %entry %a_next %phi\n"
6779 		"              OpLoopMerge %exit %phi None\n"
6780 		"              OpBranchConditional %still_loop %phi %exit\n"
6781 
6782 		"%exit       = OpLabel\n"
6783 		"              OpStore %a_loc %a_next\n"
6784 		"              OpStore %b_loc %b_next\n"
6785 		"%ret        = OpLoad %v4f32 %result\n"
6786 		"              OpReturnValue %ret\n"
6787 
6788 		"              OpFunctionEnd\n";
6789 
6790 	fragments3["pre_main"]	= typesAndConstants3;
6791 	fragments3["testfun"]	= function3;
6792 
6793 	outputColors3[0]			= RGBA(127, 127, 127, 255);
6794 	outputColors3[1]			= RGBA(127, 0,   0,   255);
6795 	outputColors3[2]			= RGBA(0,   0,   127, 255);
6796 	outputColors3[3]			= RGBA(0,   127, 0,   255);
6797 
6798 	createTestsForAllStages("swap", inputColors, outputColors3, fragments3, group.get());
6799 
6800 	return group.release();
6801 }
6802 
createNoContractionTests(tcu::TestContext & testCtx)6803 tcu::TestCaseGroup* createNoContractionTests(tcu::TestContext& testCtx)
6804 {
6805 	de::MovePtr<tcu::TestCaseGroup> group			(new tcu::TestCaseGroup(testCtx, "nocontraction", "Test the NoContraction decoration"));
6806 	RGBA							inputColors[4];
6807 	RGBA							outputColors[4];
6808 
6809 	// With NoContraction, (1 + 2^-23) * (1 - 2^-23) - 1 should be conducted as a multiplication and an addition separately.
6810 	// For the multiplication, the result is 1 - 2^-46, which is out of the precision range for 32-bit float. (32-bit float
6811 	// only have 23-bit fraction.) So it will be rounded to 1. Or 0x1.fffffc. Then the final result is 0 or -0x1p-24.
6812 	// On the contrary, the result will be 2^-46, which is a normalized number perfectly representable as 32-bit float.
6813 	const char						constantsAndTypes[]	 =
6814 		"%c_vec4_0       = OpConstantComposite %v4f32 %c_f32_0 %c_f32_0 %c_f32_0 %c_f32_1\n"
6815 		"%c_vec4_1       = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_1\n"
6816 		"%c_f32_1pl2_23  = OpConstant %f32 0x1.000002p+0\n" // 1 + 2^-23
6817 		"%c_f32_1mi2_23  = OpConstant %f32 0x1.fffffcp-1\n" // 1 - 2^-23
6818 		"%c_f32_n1pn24   = OpConstant %f32 -0x1p-24\n"
6819 		;
6820 
6821 	const char						function[]	 =
6822 		"%test_code      = OpFunction %v4f32 None %v4f32_function\n"
6823 		"%param          = OpFunctionParameter %v4f32\n"
6824 		"%label          = OpLabel\n"
6825 		"%var1           = OpVariable %fp_f32 Function %c_f32_1pl2_23\n"
6826 		"%var2           = OpVariable %fp_f32 Function\n"
6827 		"%red            = OpCompositeExtract %f32 %param 0\n"
6828 		"%plus_red       = OpFAdd %f32 %c_f32_1mi2_23 %red\n"
6829 		"                  OpStore %var2 %plus_red\n"
6830 		"%val1           = OpLoad %f32 %var1\n"
6831 		"%val2           = OpLoad %f32 %var2\n"
6832 		"%mul            = OpFMul %f32 %val1 %val2\n"
6833 		"%add            = OpFAdd %f32 %mul %c_f32_n1\n"
6834 		"%is0            = OpFOrdEqual %bool %add %c_f32_0\n"
6835 		"%isn1n24         = OpFOrdEqual %bool %add %c_f32_n1pn24\n"
6836 		"%success        = OpLogicalOr %bool %is0 %isn1n24\n"
6837 		"%v4success      = OpCompositeConstruct %v4bool %success %success %success %success\n"
6838 		"%ret            = OpSelect %v4f32 %v4success %c_vec4_0 %c_vec4_1\n"
6839 		"                  OpReturnValue %ret\n"
6840 		"                  OpFunctionEnd\n";
6841 
6842 	struct CaseNameDecoration
6843 	{
6844 		string name;
6845 		string decoration;
6846 	};
6847 
6848 
6849 	CaseNameDecoration tests[] = {
6850 		{"multiplication",	"OpDecorate %mul NoContraction"},
6851 		{"addition",		"OpDecorate %add NoContraction"},
6852 		{"both",			"OpDecorate %mul NoContraction\nOpDecorate %add NoContraction"},
6853 	};
6854 
6855 	getHalfColorsFullAlpha(inputColors);
6856 
6857 	for (deUint8 idx = 0; idx < 4; ++idx)
6858 	{
6859 		inputColors[idx].setRed(0);
6860 		outputColors[idx] = RGBA(0, 0, 0, 255);
6861 	}
6862 
6863 	for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(CaseNameDecoration); ++testNdx)
6864 	{
6865 		map<string, string> fragments;
6866 
6867 		fragments["decoration"] = tests[testNdx].decoration;
6868 		fragments["pre_main"] = constantsAndTypes;
6869 		fragments["testfun"] = function;
6870 
6871 		createTestsForAllStages(tests[testNdx].name, inputColors, outputColors, fragments, group.get());
6872 	}
6873 
6874 	return group.release();
6875 }
6876 
createMemoryAccessTests(tcu::TestContext & testCtx)6877 tcu::TestCaseGroup* createMemoryAccessTests(tcu::TestContext& testCtx)
6878 {
6879 	de::MovePtr<tcu::TestCaseGroup> memoryAccessTests (new tcu::TestCaseGroup(testCtx, "opmemoryaccess", "Memory Semantics"));
6880 	RGBA							colors[4];
6881 
6882 	const char						constantsAndTypes[]	 =
6883 		"%c_a2f32_1         = OpConstantComposite %a2f32 %c_f32_1 %c_f32_1\n"
6884 		"%fp_a2f32          = OpTypePointer Function %a2f32\n"
6885 		"%stype             = OpTypeStruct  %v4f32 %a2f32 %f32\n"
6886 		"%fp_stype          = OpTypePointer Function %stype\n";
6887 
6888 	const char						function[]	 =
6889 		"%test_code         = OpFunction %v4f32 None %v4f32_function\n"
6890 		"%param1            = OpFunctionParameter %v4f32\n"
6891 		"%lbl               = OpLabel\n"
6892 		"%v1                = OpVariable %fp_v4f32 Function\n"
6893 		"%v2                = OpVariable %fp_a2f32 Function\n"
6894 		"%v3                = OpVariable %fp_f32 Function\n"
6895 		"%v                 = OpVariable %fp_stype Function\n"
6896 		"%vv                = OpVariable %fp_stype Function\n"
6897 		"%vvv               = OpVariable %fp_f32 Function\n"
6898 
6899 		"                     OpStore %v1 %c_v4f32_1_1_1_1\n"
6900 		"                     OpStore %v2 %c_a2f32_1\n"
6901 		"                     OpStore %v3 %c_f32_1\n"
6902 
6903 		"%p_v4f32          = OpAccessChain %fp_v4f32 %v %c_u32_0\n"
6904 		"%p_a2f32          = OpAccessChain %fp_a2f32 %v %c_u32_1\n"
6905 		"%p_f32            = OpAccessChain %fp_f32 %v %c_u32_2\n"
6906 		"%v1_v             = OpLoad %v4f32 %v1 ${access_type}\n"
6907 		"%v2_v             = OpLoad %a2f32 %v2 ${access_type}\n"
6908 		"%v3_v             = OpLoad %f32 %v3 ${access_type}\n"
6909 
6910 		"                    OpStore %p_v4f32 %v1_v ${access_type}\n"
6911 		"                    OpStore %p_a2f32 %v2_v ${access_type}\n"
6912 		"                    OpStore %p_f32 %v3_v ${access_type}\n"
6913 
6914 		"                    OpCopyMemory %vv %v ${access_type}\n"
6915 		"                    OpCopyMemory %vvv %p_f32 ${access_type}\n"
6916 
6917 		"%p_f32_2          = OpAccessChain %fp_f32 %vv %c_u32_2\n"
6918 		"%v_f32_2          = OpLoad %f32 %p_f32_2\n"
6919 		"%v_f32_3          = OpLoad %f32 %vvv\n"
6920 
6921 		"%ret1             = OpVectorTimesScalar %v4f32 %param1 %v_f32_2\n"
6922 		"%ret2             = OpVectorTimesScalar %v4f32 %ret1 %v_f32_3\n"
6923 		"                    OpReturnValue %ret2\n"
6924 		"                    OpFunctionEnd\n";
6925 
6926 	struct NameMemoryAccess
6927 	{
6928 		string name;
6929 		string accessType;
6930 	};
6931 
6932 
6933 	NameMemoryAccess tests[] =
6934 	{
6935 		{ "none", "" },
6936 		{ "volatile", "Volatile" },
6937 		{ "aligned",  "Aligned 1" },
6938 		{ "volatile_aligned",  "Volatile|Aligned 1" },
6939 		{ "nontemporal_aligned",  "Nontemporal|Aligned 1" },
6940 		{ "volatile_nontemporal",  "Volatile|Nontemporal" },
6941 		{ "volatile_nontermporal_aligned",  "Volatile|Nontemporal|Aligned 1" },
6942 	};
6943 
6944 	getHalfColorsFullAlpha(colors);
6945 
6946 	for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameMemoryAccess); ++testNdx)
6947 	{
6948 		map<string, string> fragments;
6949 		map<string, string> memoryAccess;
6950 		memoryAccess["access_type"] = tests[testNdx].accessType;
6951 
6952 		fragments["pre_main"] = constantsAndTypes;
6953 		fragments["testfun"] = tcu::StringTemplate(function).specialize(memoryAccess);
6954 		createTestsForAllStages(tests[testNdx].name, colors, colors, fragments, memoryAccessTests.get());
6955 	}
6956 	return memoryAccessTests.release();
6957 }
createOpUndefTests(tcu::TestContext & testCtx)6958 tcu::TestCaseGroup* createOpUndefTests(tcu::TestContext& testCtx)
6959 {
6960 	de::MovePtr<tcu::TestCaseGroup>		opUndefTests		 (new tcu::TestCaseGroup(testCtx, "opundef", "Test OpUndef"));
6961 	RGBA								defaultColors[4];
6962 	map<string, string>					fragments;
6963 	getDefaultColors(defaultColors);
6964 
6965 	// First, simple cases that don't do anything with the OpUndef result.
6966 	struct NameCodePair { string name, decl, type; };
6967 	const NameCodePair tests[] =
6968 	{
6969 		{"bool", "", "%bool"},
6970 		{"vec2uint32", "%type = OpTypeVector %u32 2", "%type"},
6971 		{"image", "%type = OpTypeImage %f32 2D 0 0 0 1 Unknown", "%type"},
6972 		{"sampler", "%type = OpTypeSampler", "%type"},
6973 		{"sampledimage", "%img = OpTypeImage %f32 2D 0 0 0 1 Unknown\n" "%type = OpTypeSampledImage %img", "%type"},
6974 		{"pointer", "", "%fp_i32"},
6975 		{"runtimearray", "%type = OpTypeRuntimeArray %f32", "%type"},
6976 		{"array", "%c_u32_100 = OpConstant %u32 100\n" "%type = OpTypeArray %i32 %c_u32_100", "%type"},
6977 		{"struct", "%type = OpTypeStruct %f32 %i32 %u32", "%type"}};
6978 	for (size_t testNdx = 0; testNdx < sizeof(tests) / sizeof(NameCodePair); ++testNdx)
6979 	{
6980 		fragments["undef_type"] = tests[testNdx].type;
6981 		fragments["testfun"] = StringTemplate(
6982 			"%test_code = OpFunction %v4f32 None %v4f32_function\n"
6983 			"%param1 = OpFunctionParameter %v4f32\n"
6984 			"%label_testfun = OpLabel\n"
6985 			"%undef = OpUndef ${undef_type}\n"
6986 			"OpReturnValue %param1\n"
6987 			"OpFunctionEnd\n").specialize(fragments);
6988 		fragments["pre_main"] = tests[testNdx].decl;
6989 		createTestsForAllStages(tests[testNdx].name, defaultColors, defaultColors, fragments, opUndefTests.get());
6990 	}
6991 	fragments.clear();
6992 
6993 	fragments["testfun"] =
6994 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
6995 		"%param1 = OpFunctionParameter %v4f32\n"
6996 		"%label_testfun = OpLabel\n"
6997 		"%undef = OpUndef %f32\n"
6998 		"%zero = OpFMul %f32 %undef %c_f32_0\n"
6999 		"%is_nan = OpIsNan %bool %zero\n" //OpUndef may result in NaN which may turn %zero into Nan.
7000 		"%actually_zero = OpSelect %f32 %is_nan %c_f32_0 %zero\n"
7001 		"%a = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
7002 		"%b = OpFAdd %f32 %a %actually_zero\n"
7003 		"%ret = OpVectorInsertDynamic %v4f32 %param1 %b %c_i32_0\n"
7004 		"OpReturnValue %ret\n"
7005 		"OpFunctionEnd\n"
7006 		;
7007 	createTestsForAllStages("float32", defaultColors, defaultColors, fragments, opUndefTests.get());
7008 
7009 	fragments["testfun"] =
7010 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
7011 		"%param1 = OpFunctionParameter %v4f32\n"
7012 		"%label_testfun = OpLabel\n"
7013 		"%undef = OpUndef %i32\n"
7014 		"%zero = OpIMul %i32 %undef %c_i32_0\n"
7015 		"%a = OpVectorExtractDynamic %f32 %param1 %zero\n"
7016 		"%ret = OpVectorInsertDynamic %v4f32 %param1 %a %c_i32_0\n"
7017 		"OpReturnValue %ret\n"
7018 		"OpFunctionEnd\n"
7019 		;
7020 	createTestsForAllStages("sint32", defaultColors, defaultColors, fragments, opUndefTests.get());
7021 
7022 	fragments["testfun"] =
7023 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
7024 		"%param1 = OpFunctionParameter %v4f32\n"
7025 		"%label_testfun = OpLabel\n"
7026 		"%undef = OpUndef %u32\n"
7027 		"%zero = OpIMul %u32 %undef %c_i32_0\n"
7028 		"%a = OpVectorExtractDynamic %f32 %param1 %zero\n"
7029 		"%ret = OpVectorInsertDynamic %v4f32 %param1 %a %c_i32_0\n"
7030 		"OpReturnValue %ret\n"
7031 		"OpFunctionEnd\n"
7032 		;
7033 	createTestsForAllStages("uint32", defaultColors, defaultColors, fragments, opUndefTests.get());
7034 
7035 	fragments["testfun"] =
7036 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
7037 		"%param1 = OpFunctionParameter %v4f32\n"
7038 		"%label_testfun = OpLabel\n"
7039 		"%undef = OpUndef %v4f32\n"
7040 		"%vzero = OpVectorTimesScalar %v4f32 %undef %c_f32_0\n"
7041 		"%zero_0 = OpVectorExtractDynamic %f32 %vzero %c_i32_0\n"
7042 		"%zero_1 = OpVectorExtractDynamic %f32 %vzero %c_i32_1\n"
7043 		"%zero_2 = OpVectorExtractDynamic %f32 %vzero %c_i32_2\n"
7044 		"%zero_3 = OpVectorExtractDynamic %f32 %vzero %c_i32_3\n"
7045 		"%is_nan_0 = OpIsNan %bool %zero_0\n"
7046 		"%is_nan_1 = OpIsNan %bool %zero_1\n"
7047 		"%is_nan_2 = OpIsNan %bool %zero_2\n"
7048 		"%is_nan_3 = OpIsNan %bool %zero_3\n"
7049 		"%actually_zero_0 = OpSelect %f32 %is_nan_0 %c_f32_0 %zero_0\n"
7050 		"%actually_zero_1 = OpSelect %f32 %is_nan_0 %c_f32_0 %zero_1\n"
7051 		"%actually_zero_2 = OpSelect %f32 %is_nan_0 %c_f32_0 %zero_2\n"
7052 		"%actually_zero_3 = OpSelect %f32 %is_nan_0 %c_f32_0 %zero_3\n"
7053 		"%param1_0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
7054 		"%param1_1 = OpVectorExtractDynamic %f32 %param1 %c_i32_1\n"
7055 		"%param1_2 = OpVectorExtractDynamic %f32 %param1 %c_i32_2\n"
7056 		"%param1_3 = OpVectorExtractDynamic %f32 %param1 %c_i32_3\n"
7057 		"%sum_0 = OpFAdd %f32 %param1_0 %actually_zero_0\n"
7058 		"%sum_1 = OpFAdd %f32 %param1_1 %actually_zero_1\n"
7059 		"%sum_2 = OpFAdd %f32 %param1_2 %actually_zero_2\n"
7060 		"%sum_3 = OpFAdd %f32 %param1_3 %actually_zero_3\n"
7061 		"%ret3 = OpVectorInsertDynamic %v4f32 %param1 %sum_3 %c_i32_3\n"
7062 		"%ret2 = OpVectorInsertDynamic %v4f32 %ret3 %sum_2 %c_i32_2\n"
7063 		"%ret1 = OpVectorInsertDynamic %v4f32 %ret2 %sum_1 %c_i32_1\n"
7064 		"%ret = OpVectorInsertDynamic %v4f32 %ret1 %sum_0 %c_i32_0\n"
7065 		"OpReturnValue %ret\n"
7066 		"OpFunctionEnd\n"
7067 		;
7068 	createTestsForAllStages("vec4float32", defaultColors, defaultColors, fragments, opUndefTests.get());
7069 
7070 	fragments["pre_main"] =
7071 		"%v2f32 = OpTypeVector %f32 2\n"
7072 		"%m2x2f32 = OpTypeMatrix %v2f32 2\n";
7073 	fragments["testfun"] =
7074 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
7075 		"%param1 = OpFunctionParameter %v4f32\n"
7076 		"%label_testfun = OpLabel\n"
7077 		"%undef = OpUndef %m2x2f32\n"
7078 		"%mzero = OpMatrixTimesScalar %m2x2f32 %undef %c_f32_0\n"
7079 		"%zero_0 = OpCompositeExtract %f32 %mzero 0 0\n"
7080 		"%zero_1 = OpCompositeExtract %f32 %mzero 0 1\n"
7081 		"%zero_2 = OpCompositeExtract %f32 %mzero 1 0\n"
7082 		"%zero_3 = OpCompositeExtract %f32 %mzero 1 1\n"
7083 		"%is_nan_0 = OpIsNan %bool %zero_0\n"
7084 		"%is_nan_1 = OpIsNan %bool %zero_1\n"
7085 		"%is_nan_2 = OpIsNan %bool %zero_2\n"
7086 		"%is_nan_3 = OpIsNan %bool %zero_3\n"
7087 		"%actually_zero_0 = OpSelect %f32 %is_nan_0 %c_f32_0 %zero_0\n"
7088 		"%actually_zero_1 = OpSelect %f32 %is_nan_0 %c_f32_0 %zero_1\n"
7089 		"%actually_zero_2 = OpSelect %f32 %is_nan_0 %c_f32_0 %zero_2\n"
7090 		"%actually_zero_3 = OpSelect %f32 %is_nan_0 %c_f32_0 %zero_3\n"
7091 		"%param1_0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
7092 		"%param1_1 = OpVectorExtractDynamic %f32 %param1 %c_i32_1\n"
7093 		"%param1_2 = OpVectorExtractDynamic %f32 %param1 %c_i32_2\n"
7094 		"%param1_3 = OpVectorExtractDynamic %f32 %param1 %c_i32_3\n"
7095 		"%sum_0 = OpFAdd %f32 %param1_0 %actually_zero_0\n"
7096 		"%sum_1 = OpFAdd %f32 %param1_1 %actually_zero_1\n"
7097 		"%sum_2 = OpFAdd %f32 %param1_2 %actually_zero_2\n"
7098 		"%sum_3 = OpFAdd %f32 %param1_3 %actually_zero_3\n"
7099 		"%ret3 = OpVectorInsertDynamic %v4f32 %param1 %sum_3 %c_i32_3\n"
7100 		"%ret2 = OpVectorInsertDynamic %v4f32 %ret3 %sum_2 %c_i32_2\n"
7101 		"%ret1 = OpVectorInsertDynamic %v4f32 %ret2 %sum_1 %c_i32_1\n"
7102 		"%ret = OpVectorInsertDynamic %v4f32 %ret1 %sum_0 %c_i32_0\n"
7103 		"OpReturnValue %ret\n"
7104 		"OpFunctionEnd\n"
7105 		;
7106 	createTestsForAllStages("matrix", defaultColors, defaultColors, fragments, opUndefTests.get());
7107 
7108 	return opUndefTests.release();
7109 }
7110 
createOpQuantizeSingleOptionTests(tcu::TestCaseGroup * testCtx)7111 void createOpQuantizeSingleOptionTests(tcu::TestCaseGroup* testCtx)
7112 {
7113 	const RGBA		inputColors[4]		=
7114 	{
7115 		RGBA(0,		0,		0,		255),
7116 		RGBA(0,		0,		255,	255),
7117 		RGBA(0,		255,	0,		255),
7118 		RGBA(0,		255,	255,	255)
7119 	};
7120 
7121 	const RGBA		expectedColors[4]	=
7122 	{
7123 		RGBA(255,	 0,		 0,		 255),
7124 		RGBA(255,	 0,		 0,		 255),
7125 		RGBA(255,	 0,		 0,		 255),
7126 		RGBA(255,	 0,		 0,		 255)
7127 	};
7128 
7129 	const struct SingleFP16Possibility
7130 	{
7131 		const char* name;
7132 		const char* constant;  // Value to assign to %test_constant.
7133 		float		valueAsFloat;
7134 		const char* condition; // Must assign to %cond an expression that evaluates to true after %c = OpQuantizeToF16(%test_constant + 0).
7135 	}				tests[]				=
7136 	{
7137 		{
7138 			"negative",
7139 			"-0x1.3p1\n",
7140 			-constructNormalizedFloat(1, 0x300000),
7141 			"%cond = OpFOrdEqual %bool %c %test_constant\n"
7142 		}, // -19
7143 		{
7144 			"positive",
7145 			"0x1.0p7\n",
7146 			constructNormalizedFloat(7, 0x000000),
7147 			"%cond = OpFOrdEqual %bool %c %test_constant\n"
7148 		},  // +128
7149 		// SPIR-V requires that OpQuantizeToF16 flushes
7150 		// any numbers that would end up denormalized in F16 to zero.
7151 		{
7152 			"denorm",
7153 			"0x0.0006p-126\n",
7154 			std::ldexp(1.5f, -140),
7155 			"%cond = OpFOrdEqual %bool %c %c_f32_0\n"
7156 		},  // denorm
7157 		{
7158 			"negative_denorm",
7159 			"-0x0.0006p-126\n",
7160 			-std::ldexp(1.5f, -140),
7161 			"%cond = OpFOrdEqual %bool %c %c_f32_0\n"
7162 		}, // -denorm
7163 		{
7164 			"too_small",
7165 			"0x1.0p-16\n",
7166 			std::ldexp(1.0f, -16),
7167 			"%cond = OpFOrdEqual %bool %c %c_f32_0\n"
7168 		},     // too small positive
7169 		{
7170 			"negative_too_small",
7171 			"-0x1.0p-32\n",
7172 			-std::ldexp(1.0f, -32),
7173 			"%cond = OpFOrdEqual %bool %c %c_f32_0\n"
7174 		},      // too small negative
7175 		{
7176 			"negative_inf",
7177 			"-0x1.0p128\n",
7178 			-std::ldexp(1.0f, 128),
7179 
7180 			"%gz = OpFOrdLessThan %bool %c %c_f32_0\n"
7181 			"%inf = OpIsInf %bool %c\n"
7182 			"%cond = OpLogicalAnd %bool %gz %inf\n"
7183 		},     // -inf to -inf
7184 		{
7185 			"inf",
7186 			"0x1.0p128\n",
7187 			std::ldexp(1.0f, 128),
7188 
7189 			"%gz = OpFOrdGreaterThan %bool %c %c_f32_0\n"
7190 			"%inf = OpIsInf %bool %c\n"
7191 			"%cond = OpLogicalAnd %bool %gz %inf\n"
7192 		},     // +inf to +inf
7193 		{
7194 			"round_to_negative_inf",
7195 			"-0x1.0p32\n",
7196 			-std::ldexp(1.0f, 32),
7197 
7198 			"%gz = OpFOrdLessThan %bool %c %c_f32_0\n"
7199 			"%inf = OpIsInf %bool %c\n"
7200 			"%cond = OpLogicalAnd %bool %gz %inf\n"
7201 		},     // round to -inf
7202 		{
7203 			"round_to_inf",
7204 			"0x1.0p16\n",
7205 			std::ldexp(1.0f, 16),
7206 
7207 			"%gz = OpFOrdGreaterThan %bool %c %c_f32_0\n"
7208 			"%inf = OpIsInf %bool %c\n"
7209 			"%cond = OpLogicalAnd %bool %gz %inf\n"
7210 		},     // round to +inf
7211 		{
7212 			"nan",
7213 			"0x1.1p128\n",
7214 			std::numeric_limits<float>::quiet_NaN(),
7215 
7216 			// Test for any NaN value, as NaNs are not preserved
7217 			"%direct_quant = OpQuantizeToF16 %f32 %test_constant\n"
7218 			"%cond = OpIsNan %bool %direct_quant\n"
7219 		}, // nan
7220 		{
7221 			"negative_nan",
7222 			"-0x1.0001p128\n",
7223 			std::numeric_limits<float>::quiet_NaN(),
7224 
7225 			// Test for any NaN value, as NaNs are not preserved
7226 			"%direct_quant = OpQuantizeToF16 %f32 %test_constant\n"
7227 			"%cond = OpIsNan %bool %direct_quant\n"
7228 		} // -nan
7229 	};
7230 	const char*		constants			=
7231 		"%test_constant = OpConstant %f32 ";  // The value will be test.constant.
7232 
7233 	StringTemplate	function			(
7234 		"%test_code     = OpFunction %v4f32 None %v4f32_function\n"
7235 		"%param1        = OpFunctionParameter %v4f32\n"
7236 		"%label_testfun = OpLabel\n"
7237 		"%a             = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
7238 		"%b             = OpFAdd %f32 %test_constant %a\n"
7239 		"%c             = OpQuantizeToF16 %f32 %b\n"
7240 		"${condition}\n"
7241 		"%v4cond        = OpCompositeConstruct %v4bool %cond %cond %cond %cond\n"
7242 		"%retval        = OpSelect %v4f32 %v4cond %c_v4f32_1_0_0_1 %param1\n"
7243 		"                 OpReturnValue %retval\n"
7244 		"OpFunctionEnd\n"
7245 	);
7246 
7247 	const char*		specDecorations		= "OpDecorate %test_constant SpecId 0\n";
7248 	const char*		specConstants		=
7249 			"%test_constant = OpSpecConstant %f32 0.\n"
7250 			"%c             = OpSpecConstantOp %f32 QuantizeToF16 %test_constant\n";
7251 
7252 	StringTemplate	specConstantFunction(
7253 		"%test_code     = OpFunction %v4f32 None %v4f32_function\n"
7254 		"%param1        = OpFunctionParameter %v4f32\n"
7255 		"%label_testfun = OpLabel\n"
7256 		"${condition}\n"
7257 		"%v4cond        = OpCompositeConstruct %v4bool %cond %cond %cond %cond\n"
7258 		"%retval        = OpSelect %v4f32 %v4cond %c_v4f32_1_0_0_1 %param1\n"
7259 		"                 OpReturnValue %retval\n"
7260 		"OpFunctionEnd\n"
7261 	);
7262 
7263 	for (size_t idx = 0; idx < (sizeof(tests)/sizeof(tests[0])); ++idx)
7264 	{
7265 		map<string, string>								codeSpecialization;
7266 		map<string, string>								fragments;
7267 		codeSpecialization["condition"]					= tests[idx].condition;
7268 		fragments["testfun"]							= function.specialize(codeSpecialization);
7269 		fragments["pre_main"]							= string(constants) + tests[idx].constant + "\n";
7270 		createTestsForAllStages(tests[idx].name, inputColors, expectedColors, fragments, testCtx);
7271 	}
7272 
7273 	for (size_t idx = 0; idx < (sizeof(tests)/sizeof(tests[0])); ++idx)
7274 	{
7275 		map<string, string>								codeSpecialization;
7276 		map<string, string>								fragments;
7277 		vector<deInt32>									passConstants;
7278 		deInt32											specConstant;
7279 
7280 		codeSpecialization["condition"]					= tests[idx].condition;
7281 		fragments["testfun"]							= specConstantFunction.specialize(codeSpecialization);
7282 		fragments["decoration"]							= specDecorations;
7283 		fragments["pre_main"]							= specConstants;
7284 
7285 		memcpy(&specConstant, &tests[idx].valueAsFloat, sizeof(float));
7286 		passConstants.push_back(specConstant);
7287 
7288 		createTestsForAllStages(string("spec_const_") + tests[idx].name, inputColors, expectedColors, fragments, passConstants, testCtx);
7289 	}
7290 }
7291 
createOpQuantizeTwoPossibilityTests(tcu::TestCaseGroup * testCtx)7292 void createOpQuantizeTwoPossibilityTests(tcu::TestCaseGroup* testCtx)
7293 {
7294 	RGBA inputColors[4] =  {
7295 		RGBA(0,		0,		0,		255),
7296 		RGBA(0,		0,		255,	255),
7297 		RGBA(0,		255,	0,		255),
7298 		RGBA(0,		255,	255,	255)
7299 	};
7300 
7301 	RGBA expectedColors[4] =
7302 	{
7303 		RGBA(255,	 0,		 0,		 255),
7304 		RGBA(255,	 0,		 0,		 255),
7305 		RGBA(255,	 0,		 0,		 255),
7306 		RGBA(255,	 0,		 0,		 255)
7307 	};
7308 
7309 	struct DualFP16Possibility
7310 	{
7311 		const char* name;
7312 		const char* input;
7313 		float		inputAsFloat;
7314 		const char* possibleOutput1;
7315 		const char* possibleOutput2;
7316 	} tests[] = {
7317 		{
7318 			"positive_round_up_or_round_down",
7319 			"0x1.3003p8",
7320 			constructNormalizedFloat(8, 0x300300),
7321 			"0x1.304p8",
7322 			"0x1.3p8"
7323 		},
7324 		{
7325 			"negative_round_up_or_round_down",
7326 			"-0x1.6008p-7",
7327 			-constructNormalizedFloat(-7, 0x600800),
7328 			"-0x1.6p-7",
7329 			"-0x1.604p-7"
7330 		},
7331 		{
7332 			"carry_bit",
7333 			"0x1.01ep2",
7334 			constructNormalizedFloat(2, 0x01e000),
7335 			"0x1.01cp2",
7336 			"0x1.02p2"
7337 		},
7338 		{
7339 			"carry_to_exponent",
7340 			"0x1.ffep1",
7341 			constructNormalizedFloat(1, 0xffe000),
7342 			"0x1.ffcp1",
7343 			"0x1.0p2"
7344 		},
7345 	};
7346 	StringTemplate constants (
7347 		"%input_const = OpConstant %f32 ${input}\n"
7348 		"%possible_solution1 = OpConstant %f32 ${output1}\n"
7349 		"%possible_solution2 = OpConstant %f32 ${output2}\n"
7350 		);
7351 
7352 	StringTemplate specConstants (
7353 		"%input_const = OpSpecConstant %f32 0.\n"
7354 		"%possible_solution1 = OpConstant %f32 ${output1}\n"
7355 		"%possible_solution2 = OpConstant %f32 ${output2}\n"
7356 	);
7357 
7358 	const char* specDecorations = "OpDecorate %input_const  SpecId 0\n";
7359 
7360 	const char* function  =
7361 		"%test_code     = OpFunction %v4f32 None %v4f32_function\n"
7362 		"%param1        = OpFunctionParameter %v4f32\n"
7363 		"%label_testfun = OpLabel\n"
7364 		"%a             = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
7365 		// For the purposes of this test we assume that 0.f will always get
7366 		// faithfully passed through the pipeline stages.
7367 		"%b             = OpFAdd %f32 %input_const %a\n"
7368 		"%c             = OpQuantizeToF16 %f32 %b\n"
7369 		"%eq_1          = OpFOrdEqual %bool %c %possible_solution1\n"
7370 		"%eq_2          = OpFOrdEqual %bool %c %possible_solution2\n"
7371 		"%cond          = OpLogicalOr %bool %eq_1 %eq_2\n"
7372 		"%v4cond        = OpCompositeConstruct %v4bool %cond %cond %cond %cond\n"
7373 		"%retval        = OpSelect %v4f32 %v4cond %c_v4f32_1_0_0_1 %param1"
7374 		"                 OpReturnValue %retval\n"
7375 		"OpFunctionEnd\n";
7376 
7377 	for(size_t idx = 0; idx < (sizeof(tests)/sizeof(tests[0])); ++idx) {
7378 		map<string, string>									fragments;
7379 		map<string, string>									constantSpecialization;
7380 
7381 		constantSpecialization["input"]						= tests[idx].input;
7382 		constantSpecialization["output1"]					= tests[idx].possibleOutput1;
7383 		constantSpecialization["output2"]					= tests[idx].possibleOutput2;
7384 		fragments["testfun"]								= function;
7385 		fragments["pre_main"]								= constants.specialize(constantSpecialization);
7386 		createTestsForAllStages(tests[idx].name, inputColors, expectedColors, fragments, testCtx);
7387 	}
7388 
7389 	for(size_t idx = 0; idx < (sizeof(tests)/sizeof(tests[0])); ++idx) {
7390 		map<string, string>									fragments;
7391 		map<string, string>									constantSpecialization;
7392 		vector<deInt32>										passConstants;
7393 		deInt32												specConstant;
7394 
7395 		constantSpecialization["output1"]					= tests[idx].possibleOutput1;
7396 		constantSpecialization["output2"]					= tests[idx].possibleOutput2;
7397 		fragments["testfun"]								= function;
7398 		fragments["decoration"]								= specDecorations;
7399 		fragments["pre_main"]								= specConstants.specialize(constantSpecialization);
7400 
7401 		memcpy(&specConstant, &tests[idx].inputAsFloat, sizeof(float));
7402 		passConstants.push_back(specConstant);
7403 
7404 		createTestsForAllStages(string("spec_const_") + tests[idx].name, inputColors, expectedColors, fragments, passConstants, testCtx);
7405 	}
7406 }
7407 
createOpQuantizeTests(tcu::TestContext & testCtx)7408 tcu::TestCaseGroup* createOpQuantizeTests(tcu::TestContext& testCtx)
7409 {
7410 	de::MovePtr<tcu::TestCaseGroup> opQuantizeTests (new tcu::TestCaseGroup(testCtx, "opquantize", "Test OpQuantizeToF16"));
7411 	createOpQuantizeSingleOptionTests(opQuantizeTests.get());
7412 	createOpQuantizeTwoPossibilityTests(opQuantizeTests.get());
7413 	return opQuantizeTests.release();
7414 }
7415 
7416 struct ShaderPermutation
7417 {
7418 	deUint8 vertexPermutation;
7419 	deUint8 geometryPermutation;
7420 	deUint8 tesscPermutation;
7421 	deUint8 tessePermutation;
7422 	deUint8 fragmentPermutation;
7423 };
7424 
getShaderPermutation(deUint8 inputValue)7425 ShaderPermutation getShaderPermutation(deUint8 inputValue)
7426 {
7427 	ShaderPermutation	permutation =
7428 	{
7429 		static_cast<deUint8>(inputValue & 0x10? 1u: 0u),
7430 		static_cast<deUint8>(inputValue & 0x08? 1u: 0u),
7431 		static_cast<deUint8>(inputValue & 0x04? 1u: 0u),
7432 		static_cast<deUint8>(inputValue & 0x02? 1u: 0u),
7433 		static_cast<deUint8>(inputValue & 0x01? 1u: 0u)
7434 	};
7435 	return permutation;
7436 }
7437 
createModuleTests(tcu::TestContext & testCtx)7438 tcu::TestCaseGroup* createModuleTests(tcu::TestContext& testCtx)
7439 {
7440 	RGBA								defaultColors[4];
7441 	RGBA								invertedColors[4];
7442 	de::MovePtr<tcu::TestCaseGroup>		moduleTests			(new tcu::TestCaseGroup(testCtx, "module", "Multiple entry points into shaders"));
7443 
7444 	const ShaderElement					combinedPipeline[]	=
7445 	{
7446 		ShaderElement("module", "main", VK_SHADER_STAGE_VERTEX_BIT),
7447 		ShaderElement("module", "main", VK_SHADER_STAGE_GEOMETRY_BIT),
7448 		ShaderElement("module", "main", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT),
7449 		ShaderElement("module", "main", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT),
7450 		ShaderElement("module", "main", VK_SHADER_STAGE_FRAGMENT_BIT)
7451 	};
7452 
7453 	getDefaultColors(defaultColors);
7454 	getInvertedDefaultColors(invertedColors);
7455 	addFunctionCaseWithPrograms<InstanceContext>(moduleTests.get(), "same_module", "", createCombinedModule, runAndVerifyDefaultPipeline, createInstanceContext(combinedPipeline, map<string, string>()));
7456 
7457 	const char* numbers[] =
7458 	{
7459 		"1", "2"
7460 	};
7461 
7462 	for (deInt8 idx = 0; idx < 32; ++idx)
7463 	{
7464 		ShaderPermutation			permutation		= getShaderPermutation(idx);
7465 		string						name			= string("vert") + numbers[permutation.vertexPermutation] + "_geom" + numbers[permutation.geometryPermutation] + "_tessc" + numbers[permutation.tesscPermutation] + "_tesse" + numbers[permutation.tessePermutation] + "_frag" + numbers[permutation.fragmentPermutation];
7466 		const ShaderElement			pipeline[]		=
7467 		{
7468 			ShaderElement("vert",	string("vert") +	numbers[permutation.vertexPermutation],		VK_SHADER_STAGE_VERTEX_BIT),
7469 			ShaderElement("geom",	string("geom") +	numbers[permutation.geometryPermutation],	VK_SHADER_STAGE_GEOMETRY_BIT),
7470 			ShaderElement("tessc",	string("tessc") +	numbers[permutation.tesscPermutation],		VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT),
7471 			ShaderElement("tesse",	string("tesse") +	numbers[permutation.tessePermutation],		VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT),
7472 			ShaderElement("frag",	string("frag") +	numbers[permutation.fragmentPermutation],	VK_SHADER_STAGE_FRAGMENT_BIT)
7473 		};
7474 
7475 		// If there are an even number of swaps, then it should be no-op.
7476 		// If there are an odd number, the color should be flipped.
7477 		if ((permutation.vertexPermutation + permutation.geometryPermutation + permutation.tesscPermutation + permutation.tessePermutation + permutation.fragmentPermutation) % 2 == 0)
7478 		{
7479 			addFunctionCaseWithPrograms<InstanceContext>(moduleTests.get(), name, "", createMultipleEntries, runAndVerifyDefaultPipeline, createInstanceContext(pipeline, defaultColors, defaultColors, map<string, string>()));
7480 		}
7481 		else
7482 		{
7483 			addFunctionCaseWithPrograms<InstanceContext>(moduleTests.get(), name, "", createMultipleEntries, runAndVerifyDefaultPipeline, createInstanceContext(pipeline, defaultColors, invertedColors, map<string, string>()));
7484 		}
7485 	}
7486 	return moduleTests.release();
7487 }
7488 
createLoopTests(tcu::TestContext & testCtx)7489 tcu::TestCaseGroup* createLoopTests(tcu::TestContext& testCtx)
7490 {
7491 	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "loop", "Looping control flow"));
7492 	RGBA defaultColors[4];
7493 	getDefaultColors(defaultColors);
7494 	map<string, string> fragments;
7495 	fragments["pre_main"] =
7496 		"%c_f32_5 = OpConstant %f32 5.\n";
7497 
7498 	// A loop with a single block. The Continue Target is the loop block
7499 	// itself. In SPIR-V terms, the "loop construct" contains no blocks at all
7500 	// -- the "continue construct" forms the entire loop.
7501 	fragments["testfun"] =
7502 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
7503 		"%param1 = OpFunctionParameter %v4f32\n"
7504 
7505 		"%entry = OpLabel\n"
7506 		"%val0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
7507 		"OpBranch %loop\n"
7508 
7509 		";adds and subtracts 1.0 to %val in alternate iterations\n"
7510 		"%loop = OpLabel\n"
7511 		"%count = OpPhi %i32 %c_i32_4 %entry %count__ %loop\n"
7512 		"%delta = OpPhi %f32 %c_f32_1 %entry %minus_delta %loop\n"
7513 		"%val1 = OpPhi %f32 %val0 %entry %val %loop\n"
7514 		"%val = OpFAdd %f32 %val1 %delta\n"
7515 		"%minus_delta = OpFSub %f32 %c_f32_0 %delta\n"
7516 		"%count__ = OpISub %i32 %count %c_i32_1\n"
7517 		"%again = OpSGreaterThan %bool %count__ %c_i32_0\n"
7518 		"OpLoopMerge %exit %loop None\n"
7519 		"OpBranchConditional %again %loop %exit\n"
7520 
7521 		"%exit = OpLabel\n"
7522 		"%result = OpVectorInsertDynamic %v4f32 %param1 %val %c_i32_0\n"
7523 		"OpReturnValue %result\n"
7524 
7525 		"OpFunctionEnd\n"
7526 		;
7527 	createTestsForAllStages("single_block", defaultColors, defaultColors, fragments, testGroup.get());
7528 
7529 	// Body comprised of multiple basic blocks.
7530 	const StringTemplate multiBlock(
7531 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
7532 		"%param1 = OpFunctionParameter %v4f32\n"
7533 
7534 		"%entry = OpLabel\n"
7535 		"%val0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
7536 		"OpBranch %loop\n"
7537 
7538 		";adds and subtracts 1.0 to %val in alternate iterations\n"
7539 		"%loop = OpLabel\n"
7540 		"%count = OpPhi %i32 %c_i32_4 %entry %count__ %gather\n"
7541 		"%delta = OpPhi %f32 %c_f32_1 %entry %delta_next %gather\n"
7542 		"%val1 = OpPhi %f32 %val0 %entry %val %gather\n"
7543 		// There are several possibilities for the Continue Target below.  Each
7544 		// will be specialized into a separate test case.
7545 		"OpLoopMerge %exit ${continue_target} None\n"
7546 		"OpBranch %if\n"
7547 
7548 		"%if = OpLabel\n"
7549 		";delta_next = (delta > 0) ? -1 : 1;\n"
7550 		"%gt0 = OpFOrdGreaterThan %bool %delta %c_f32_0\n"
7551 		"OpSelectionMerge %gather DontFlatten\n"
7552 		"OpBranchConditional %gt0 %even %odd ;tells us if %count is even or odd\n"
7553 
7554 		"%odd = OpLabel\n"
7555 		"OpBranch %gather\n"
7556 
7557 		"%even = OpLabel\n"
7558 		"OpBranch %gather\n"
7559 
7560 		"%gather = OpLabel\n"
7561 		"%delta_next = OpPhi %f32 %c_f32_n1 %even %c_f32_1 %odd\n"
7562 		"%val = OpFAdd %f32 %val1 %delta\n"
7563 		"%count__ = OpISub %i32 %count %c_i32_1\n"
7564 		"%again = OpSGreaterThan %bool %count__ %c_i32_0\n"
7565 		"OpBranchConditional %again %loop %exit\n"
7566 
7567 		"%exit = OpLabel\n"
7568 		"%result = OpVectorInsertDynamic %v4f32 %param1 %val %c_i32_0\n"
7569 		"OpReturnValue %result\n"
7570 
7571 		"OpFunctionEnd\n");
7572 
7573 	map<string, string> continue_target;
7574 
7575 	// The Continue Target is the loop block itself.
7576 	continue_target["continue_target"] = "%loop";
7577 	fragments["testfun"] = multiBlock.specialize(continue_target);
7578 	createTestsForAllStages("multi_block_continue_construct", defaultColors, defaultColors, fragments, testGroup.get());
7579 
7580 	// The Continue Target is at the end of the loop.
7581 	continue_target["continue_target"] = "%gather";
7582 	fragments["testfun"] = multiBlock.specialize(continue_target);
7583 	createTestsForAllStages("multi_block_loop_construct", defaultColors, defaultColors, fragments, testGroup.get());
7584 
7585 	// A loop with continue statement.
7586 	fragments["testfun"] =
7587 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
7588 		"%param1 = OpFunctionParameter %v4f32\n"
7589 
7590 		"%entry = OpLabel\n"
7591 		"%val0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
7592 		"OpBranch %loop\n"
7593 
7594 		";adds 4, 3, and 1 to %val0 (skips 2)\n"
7595 		"%loop = OpLabel\n"
7596 		"%count = OpPhi %i32 %c_i32_4 %entry %count__ %continue\n"
7597 		"%val1 = OpPhi %f32 %val0 %entry %val %continue\n"
7598 		"OpLoopMerge %exit %continue None\n"
7599 		"OpBranch %if\n"
7600 
7601 		"%if = OpLabel\n"
7602 		";skip if %count==2\n"
7603 		"%eq2 = OpIEqual %bool %count %c_i32_2\n"
7604 		"OpSelectionMerge %continue DontFlatten\n"
7605 		"OpBranchConditional %eq2 %continue %body\n"
7606 
7607 		"%body = OpLabel\n"
7608 		"%fcount = OpConvertSToF %f32 %count\n"
7609 		"%val2 = OpFAdd %f32 %val1 %fcount\n"
7610 		"OpBranch %continue\n"
7611 
7612 		"%continue = OpLabel\n"
7613 		"%val = OpPhi %f32 %val2 %body %val1 %if\n"
7614 		"%count__ = OpISub %i32 %count %c_i32_1\n"
7615 		"%again = OpSGreaterThan %bool %count__ %c_i32_0\n"
7616 		"OpBranchConditional %again %loop %exit\n"
7617 
7618 		"%exit = OpLabel\n"
7619 		"%same = OpFSub %f32 %val %c_f32_8\n"
7620 		"%result = OpVectorInsertDynamic %v4f32 %param1 %same %c_i32_0\n"
7621 		"OpReturnValue %result\n"
7622 		"OpFunctionEnd\n";
7623 	createTestsForAllStages("continue", defaultColors, defaultColors, fragments, testGroup.get());
7624 
7625 	// A loop with break.
7626 	fragments["testfun"] =
7627 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
7628 		"%param1 = OpFunctionParameter %v4f32\n"
7629 
7630 		"%entry = OpLabel\n"
7631 		";param1 components are between 0 and 1, so dot product is 4 or less\n"
7632 		"%dot = OpDot %f32 %param1 %param1\n"
7633 		"%div = OpFDiv %f32 %dot %c_f32_5\n"
7634 		"%zero = OpConvertFToU %u32 %div\n"
7635 		"%two = OpIAdd %i32 %zero %c_i32_2\n"
7636 		"%val0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
7637 		"OpBranch %loop\n"
7638 
7639 		";adds 4 and 3 to %val0 (exits early)\n"
7640 		"%loop = OpLabel\n"
7641 		"%count = OpPhi %i32 %c_i32_4 %entry %count__ %continue\n"
7642 		"%val1 = OpPhi %f32 %val0 %entry %val2 %continue\n"
7643 		"OpLoopMerge %exit %continue None\n"
7644 		"OpBranch %if\n"
7645 
7646 		"%if = OpLabel\n"
7647 		";end loop if %count==%two\n"
7648 		"%above2 = OpSGreaterThan %bool %count %two\n"
7649 		"OpSelectionMerge %continue DontFlatten\n"
7650 		"OpBranchConditional %above2 %body %exit\n"
7651 
7652 		"%body = OpLabel\n"
7653 		"%fcount = OpConvertSToF %f32 %count\n"
7654 		"%val2 = OpFAdd %f32 %val1 %fcount\n"
7655 		"OpBranch %continue\n"
7656 
7657 		"%continue = OpLabel\n"
7658 		"%count__ = OpISub %i32 %count %c_i32_1\n"
7659 		"%again = OpSGreaterThan %bool %count__ %c_i32_0\n"
7660 		"OpBranchConditional %again %loop %exit\n"
7661 
7662 		"%exit = OpLabel\n"
7663 		"%val_post = OpPhi %f32 %val2 %continue %val1 %if\n"
7664 		"%same = OpFSub %f32 %val_post %c_f32_7\n"
7665 		"%result = OpVectorInsertDynamic %v4f32 %param1 %same %c_i32_0\n"
7666 		"OpReturnValue %result\n"
7667 		"OpFunctionEnd\n";
7668 	createTestsForAllStages("break", defaultColors, defaultColors, fragments, testGroup.get());
7669 
7670 	// A loop with return.
7671 	fragments["testfun"] =
7672 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
7673 		"%param1 = OpFunctionParameter %v4f32\n"
7674 
7675 		"%entry = OpLabel\n"
7676 		";param1 components are between 0 and 1, so dot product is 4 or less\n"
7677 		"%dot = OpDot %f32 %param1 %param1\n"
7678 		"%div = OpFDiv %f32 %dot %c_f32_5\n"
7679 		"%zero = OpConvertFToU %u32 %div\n"
7680 		"%two = OpIAdd %i32 %zero %c_i32_2\n"
7681 		"%val0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
7682 		"OpBranch %loop\n"
7683 
7684 		";returns early without modifying %param1\n"
7685 		"%loop = OpLabel\n"
7686 		"%count = OpPhi %i32 %c_i32_4 %entry %count__ %continue\n"
7687 		"%val1 = OpPhi %f32 %val0 %entry %val2 %continue\n"
7688 		"OpLoopMerge %exit %continue None\n"
7689 		"OpBranch %if\n"
7690 
7691 		"%if = OpLabel\n"
7692 		";return if %count==%two\n"
7693 		"%above2 = OpSGreaterThan %bool %count %two\n"
7694 		"OpSelectionMerge %continue DontFlatten\n"
7695 		"OpBranchConditional %above2 %body %early_exit\n"
7696 
7697 		"%early_exit = OpLabel\n"
7698 		"OpReturnValue %param1\n"
7699 
7700 		"%body = OpLabel\n"
7701 		"%fcount = OpConvertSToF %f32 %count\n"
7702 		"%val2 = OpFAdd %f32 %val1 %fcount\n"
7703 		"OpBranch %continue\n"
7704 
7705 		"%continue = OpLabel\n"
7706 		"%count__ = OpISub %i32 %count %c_i32_1\n"
7707 		"%again = OpSGreaterThan %bool %count__ %c_i32_0\n"
7708 		"OpBranchConditional %again %loop %exit\n"
7709 
7710 		"%exit = OpLabel\n"
7711 		";should never get here, so return an incorrect result\n"
7712 		"%result = OpVectorInsertDynamic %v4f32 %param1 %val2 %c_i32_0\n"
7713 		"OpReturnValue %result\n"
7714 		"OpFunctionEnd\n";
7715 	createTestsForAllStages("return", defaultColors, defaultColors, fragments, testGroup.get());
7716 
7717 	return testGroup.release();
7718 }
7719 
7720 // Adds a new test to group using custom fragments for the tessellation-control
7721 // stage and passthrough fragments for all other stages.  Uses default colors
7722 // for input and expected output.
addTessCtrlTest(tcu::TestCaseGroup * group,const char * name,const map<string,string> & fragments)7723 void addTessCtrlTest(tcu::TestCaseGroup* group, const char* name, const map<string, string>& fragments)
7724 {
7725 	RGBA defaultColors[4];
7726 	getDefaultColors(defaultColors);
7727 	const ShaderElement pipelineStages[] =
7728 	{
7729 		ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT),
7730 		ShaderElement("tessc", "main", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT),
7731 		ShaderElement("tesse", "main", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT),
7732 		ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
7733 	};
7734 
7735 	addFunctionCaseWithPrograms<InstanceContext>(group, name, "", addShaderCodeCustomTessControl,
7736 												 runAndVerifyDefaultPipeline, createInstanceContext(
7737 													 pipelineStages, defaultColors, defaultColors, fragments, StageToSpecConstantMap()));
7738 }
7739 
7740 // A collection of tests putting OpControlBarrier in places GLSL forbids but SPIR-V allows.
createBarrierTests(tcu::TestContext & testCtx)7741 tcu::TestCaseGroup* createBarrierTests(tcu::TestContext& testCtx)
7742 {
7743 	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "barrier", "OpControlBarrier"));
7744 	map<string, string> fragments;
7745 
7746 	// A barrier inside a function body.
7747 	fragments["pre_main"] =
7748 		"%Workgroup = OpConstant %i32 2\n"
7749 		"%SequentiallyConsistent = OpConstant %i32 0x10\n";
7750 	fragments["testfun"] =
7751 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
7752 		"%param1 = OpFunctionParameter %v4f32\n"
7753 		"%label_testfun = OpLabel\n"
7754 		"OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
7755 		"OpReturnValue %param1\n"
7756 		"OpFunctionEnd\n";
7757 	addTessCtrlTest(testGroup.get(), "in_function", fragments);
7758 
7759 	// Common setup code for the following tests.
7760 	fragments["pre_main"] =
7761 		"%Workgroup = OpConstant %i32 2\n"
7762 		"%SequentiallyConsistent = OpConstant %i32 0x10\n"
7763 		"%c_f32_5 = OpConstant %f32 5.\n";
7764 	const string setupPercentZero =	 // Begins %test_code function with code that sets %zero to 0u but cannot be optimized away.
7765 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
7766 		"%param1 = OpFunctionParameter %v4f32\n"
7767 		"%entry = OpLabel\n"
7768 		";param1 components are between 0 and 1, so dot product is 4 or less\n"
7769 		"%dot = OpDot %f32 %param1 %param1\n"
7770 		"%div = OpFDiv %f32 %dot %c_f32_5\n"
7771 		"%zero = OpConvertFToU %u32 %div\n";
7772 
7773 	// Barriers inside OpSwitch branches.
7774 	fragments["testfun"] =
7775 		setupPercentZero +
7776 		"OpSelectionMerge %switch_exit None\n"
7777 		"OpSwitch %zero %switch_default 0 %case0 1 %case1 ;should always go to %case0\n"
7778 
7779 		"%case1 = OpLabel\n"
7780 		";This barrier should never be executed, but its presence makes test failure more likely when there's a bug.\n"
7781 		"OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
7782 		"%wrong_branch_alert1 = OpVectorInsertDynamic %v4f32 %param1 %c_f32_0_5 %c_i32_0\n"
7783 		"OpBranch %switch_exit\n"
7784 
7785 		"%switch_default = OpLabel\n"
7786 		"%wrong_branch_alert2 = OpVectorInsertDynamic %v4f32 %param1 %c_f32_0_5 %c_i32_0\n"
7787 		";This barrier should never be executed, but its presence makes test failure more likely when there's a bug.\n"
7788 		"OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
7789 		"OpBranch %switch_exit\n"
7790 
7791 		"%case0 = OpLabel\n"
7792 		"OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
7793 		"OpBranch %switch_exit\n"
7794 
7795 		"%switch_exit = OpLabel\n"
7796 		"%ret = OpPhi %v4f32 %param1 %case0 %wrong_branch_alert1 %case1 %wrong_branch_alert2 %switch_default\n"
7797 		"OpReturnValue %ret\n"
7798 		"OpFunctionEnd\n";
7799 	addTessCtrlTest(testGroup.get(), "in_switch", fragments);
7800 
7801 	// Barriers inside if-then-else.
7802 	fragments["testfun"] =
7803 		setupPercentZero +
7804 		"%eq0 = OpIEqual %bool %zero %c_u32_0\n"
7805 		"OpSelectionMerge %exit DontFlatten\n"
7806 		"OpBranchConditional %eq0 %then %else\n"
7807 
7808 		"%else = OpLabel\n"
7809 		";This barrier should never be executed, but its presence makes test failure more likely when there's a bug.\n"
7810 		"OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
7811 		"%wrong_branch_alert = OpVectorInsertDynamic %v4f32 %param1 %c_f32_0_5 %c_i32_0\n"
7812 		"OpBranch %exit\n"
7813 
7814 		"%then = OpLabel\n"
7815 		"OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
7816 		"OpBranch %exit\n"
7817 
7818 		"%exit = OpLabel\n"
7819 		"%ret = OpPhi %v4f32 %param1 %then %wrong_branch_alert %else\n"
7820 		"OpReturnValue %ret\n"
7821 		"OpFunctionEnd\n";
7822 	addTessCtrlTest(testGroup.get(), "in_if", fragments);
7823 
7824 	// A barrier after control-flow reconvergence, tempting the compiler to attempt something like this:
7825 	// http://lists.llvm.org/pipermail/llvm-dev/2009-October/026317.html.
7826 	fragments["testfun"] =
7827 		setupPercentZero +
7828 		"%thread_id = OpLoad %i32 %BP_gl_InvocationID\n"
7829 		"%thread0 = OpIEqual %bool %thread_id %c_i32_0\n"
7830 		"OpSelectionMerge %exit DontFlatten\n"
7831 		"OpBranchConditional %thread0 %then %else\n"
7832 
7833 		"%else = OpLabel\n"
7834 		"%val0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
7835 		"OpBranch %exit\n"
7836 
7837 		"%then = OpLabel\n"
7838 		"%val1 = OpVectorExtractDynamic %f32 %param1 %zero\n"
7839 		"OpBranch %exit\n"
7840 
7841 		"%exit = OpLabel\n"
7842 		"%val = OpPhi %f32 %val0 %else %val1 %then\n"
7843 		"OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
7844 		"%ret = OpVectorInsertDynamic %v4f32 %param1 %val %zero\n"
7845 		"OpReturnValue %ret\n"
7846 		"OpFunctionEnd\n";
7847 	addTessCtrlTest(testGroup.get(), "after_divergent_if", fragments);
7848 
7849 	// A barrier inside a loop.
7850 	fragments["pre_main"] =
7851 		"%Workgroup = OpConstant %i32 2\n"
7852 		"%SequentiallyConsistent = OpConstant %i32 0x10\n"
7853 		"%c_f32_10 = OpConstant %f32 10.\n";
7854 	fragments["testfun"] =
7855 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
7856 		"%param1 = OpFunctionParameter %v4f32\n"
7857 		"%entry = OpLabel\n"
7858 		"%val0 = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
7859 		"OpBranch %loop\n"
7860 
7861 		";adds 4, 3, 2, and 1 to %val0\n"
7862 		"%loop = OpLabel\n"
7863 		"%count = OpPhi %i32 %c_i32_4 %entry %count__ %loop\n"
7864 		"%val1 = OpPhi %f32 %val0 %entry %val %loop\n"
7865 		"OpControlBarrier %Workgroup %Workgroup %SequentiallyConsistent\n"
7866 		"%fcount = OpConvertSToF %f32 %count\n"
7867 		"%val = OpFAdd %f32 %val1 %fcount\n"
7868 		"%count__ = OpISub %i32 %count %c_i32_1\n"
7869 		"%again = OpSGreaterThan %bool %count__ %c_i32_0\n"
7870 		"OpLoopMerge %exit %loop None\n"
7871 		"OpBranchConditional %again %loop %exit\n"
7872 
7873 		"%exit = OpLabel\n"
7874 		"%same = OpFSub %f32 %val %c_f32_10\n"
7875 		"%ret = OpVectorInsertDynamic %v4f32 %param1 %same %c_i32_0\n"
7876 		"OpReturnValue %ret\n"
7877 		"OpFunctionEnd\n";
7878 	addTessCtrlTest(testGroup.get(), "in_loop", fragments);
7879 
7880 	return testGroup.release();
7881 }
7882 
7883 // Test for the OpFRem instruction.
createFRemTests(tcu::TestContext & testCtx)7884 tcu::TestCaseGroup* createFRemTests(tcu::TestContext& testCtx)
7885 {
7886 	de::MovePtr<tcu::TestCaseGroup>		testGroup(new tcu::TestCaseGroup(testCtx, "frem", "OpFRem"));
7887 	map<string, string>					fragments;
7888 	RGBA								inputColors[4];
7889 	RGBA								outputColors[4];
7890 
7891 	fragments["pre_main"]				 =
7892 		"%c_f32_3 = OpConstant %f32 3.0\n"
7893 		"%c_f32_n3 = OpConstant %f32 -3.0\n"
7894 		"%c_f32_4 = OpConstant %f32 4.0\n"
7895 		"%c_f32_p75 = OpConstant %f32 0.75\n"
7896 		"%c_v4f32_p75_p75_p75_p75 = OpConstantComposite %v4f32 %c_f32_p75 %c_f32_p75 %c_f32_p75 %c_f32_p75 \n"
7897 		"%c_v4f32_4_4_4_4 = OpConstantComposite %v4f32 %c_f32_4 %c_f32_4 %c_f32_4 %c_f32_4\n"
7898 		"%c_v4f32_3_n3_3_n3 = OpConstantComposite %v4f32 %c_f32_3 %c_f32_n3 %c_f32_3 %c_f32_n3\n";
7899 
7900 	// The test does the following.
7901 	// vec4 result = (param1 * 8.0) - 4.0;
7902 	// return (frem(result.x,3) + 0.75, frem(result.y, -3) + 0.75, 0, 1)
7903 	fragments["testfun"]				 =
7904 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
7905 		"%param1 = OpFunctionParameter %v4f32\n"
7906 		"%label_testfun = OpLabel\n"
7907 		"%v_times_8 = OpVectorTimesScalar %v4f32 %param1 %c_f32_8\n"
7908 		"%minus_4 = OpFSub %v4f32 %v_times_8 %c_v4f32_4_4_4_4\n"
7909 		"%frem = OpFRem %v4f32 %minus_4 %c_v4f32_3_n3_3_n3\n"
7910 		"%added = OpFAdd %v4f32 %frem %c_v4f32_p75_p75_p75_p75\n"
7911 		"%xyz_1 = OpVectorInsertDynamic %v4f32 %added %c_f32_1 %c_i32_3\n"
7912 		"%xy_0_1 = OpVectorInsertDynamic %v4f32 %xyz_1 %c_f32_0 %c_i32_2\n"
7913 		"OpReturnValue %xy_0_1\n"
7914 		"OpFunctionEnd\n";
7915 
7916 
7917 	inputColors[0]		= RGBA(16,	16,		0, 255);
7918 	inputColors[1]		= RGBA(232, 232,	0, 255);
7919 	inputColors[2]		= RGBA(232, 16,		0, 255);
7920 	inputColors[3]		= RGBA(16,	232,	0, 255);
7921 
7922 	outputColors[0]		= RGBA(64,	64,		0, 255);
7923 	outputColors[1]		= RGBA(255, 255,	0, 255);
7924 	outputColors[2]		= RGBA(255, 64,		0, 255);
7925 	outputColors[3]		= RGBA(64,	255,	0, 255);
7926 
7927 	createTestsForAllStages("frem", inputColors, outputColors, fragments, testGroup.get());
7928 	return testGroup.release();
7929 }
7930 
7931 enum IntegerType
7932 {
7933 	INTEGER_TYPE_SIGNED_16,
7934 	INTEGER_TYPE_SIGNED_32,
7935 	INTEGER_TYPE_SIGNED_64,
7936 
7937 	INTEGER_TYPE_UNSIGNED_16,
7938 	INTEGER_TYPE_UNSIGNED_32,
7939 	INTEGER_TYPE_UNSIGNED_64,
7940 };
7941 
getBitWidthStr(IntegerType type)7942 const string getBitWidthStr (IntegerType type)
7943 {
7944 	switch (type)
7945 	{
7946 		case INTEGER_TYPE_SIGNED_16:
7947 		case INTEGER_TYPE_UNSIGNED_16:	return "16";
7948 
7949 		case INTEGER_TYPE_SIGNED_32:
7950 		case INTEGER_TYPE_UNSIGNED_32:	return "32";
7951 
7952 		case INTEGER_TYPE_SIGNED_64:
7953 		case INTEGER_TYPE_UNSIGNED_64:	return "64";
7954 
7955 		default:						DE_ASSERT(false);
7956 										return "";
7957 	}
7958 }
7959 
getByteWidthStr(IntegerType type)7960 const string getByteWidthStr (IntegerType type)
7961 {
7962 	switch (type)
7963 	{
7964 		case INTEGER_TYPE_SIGNED_16:
7965 		case INTEGER_TYPE_UNSIGNED_16:	return "2";
7966 
7967 		case INTEGER_TYPE_SIGNED_32:
7968 		case INTEGER_TYPE_UNSIGNED_32:	return "4";
7969 
7970 		case INTEGER_TYPE_SIGNED_64:
7971 		case INTEGER_TYPE_UNSIGNED_64:	return "8";
7972 
7973 		default:						DE_ASSERT(false);
7974 										return "";
7975 	}
7976 }
7977 
isSigned(IntegerType type)7978 bool isSigned (IntegerType type)
7979 {
7980 	return (type <= INTEGER_TYPE_SIGNED_64);
7981 }
7982 
getTypeName(IntegerType type)7983 const string getTypeName (IntegerType type)
7984 {
7985 	string prefix = isSigned(type) ? "" : "u";
7986 	return prefix + "int" + getBitWidthStr(type);
7987 }
7988 
getTestName(IntegerType from,IntegerType to)7989 const string getTestName (IntegerType from, IntegerType to)
7990 {
7991 	return getTypeName(from) + "_to_" + getTypeName(to);
7992 }
7993 
getAsmTypeDeclaration(IntegerType type)7994 const string getAsmTypeDeclaration (IntegerType type)
7995 {
7996 	string sign = isSigned(type) ? " 1" : " 0";
7997 	return "OpTypeInt " + getBitWidthStr(type) + sign;
7998 }
7999 
8000 template<typename T>
getSpecializedBuffer(deInt64 number)8001 BufferSp getSpecializedBuffer (deInt64 number)
8002 {
8003 	return BufferSp(new Buffer<T>(vector<T>(1, (T)number)));
8004 }
8005 
getBuffer(IntegerType type,deInt64 number)8006 BufferSp getBuffer (IntegerType type, deInt64 number)
8007 {
8008 	switch (type)
8009 	{
8010 		case INTEGER_TYPE_SIGNED_16:	return getSpecializedBuffer<deInt16>(number);
8011 		case INTEGER_TYPE_SIGNED_32:	return getSpecializedBuffer<deInt32>(number);
8012 		case INTEGER_TYPE_SIGNED_64:	return getSpecializedBuffer<deInt64>(number);
8013 
8014 		case INTEGER_TYPE_UNSIGNED_16:	return getSpecializedBuffer<deUint16>(number);
8015 		case INTEGER_TYPE_UNSIGNED_32:	return getSpecializedBuffer<deUint32>(number);
8016 		case INTEGER_TYPE_UNSIGNED_64:	return getSpecializedBuffer<deUint64>(number);
8017 
8018 		default:						DE_ASSERT(false);
8019 										return BufferSp(new Buffer<deInt32>(vector<deInt32>(1, 0)));
8020 	}
8021 }
8022 
usesInt16(IntegerType from,IntegerType to)8023 bool usesInt16 (IntegerType from, IntegerType to)
8024 {
8025 	return (from == INTEGER_TYPE_SIGNED_16 || from == INTEGER_TYPE_UNSIGNED_16
8026 			|| to == INTEGER_TYPE_SIGNED_16 || to == INTEGER_TYPE_UNSIGNED_16);
8027 }
8028 
usesInt64(IntegerType from,IntegerType to)8029 bool usesInt64 (IntegerType from, IntegerType to)
8030 {
8031 	return (from == INTEGER_TYPE_SIGNED_64 || from == INTEGER_TYPE_UNSIGNED_64
8032 			|| to == INTEGER_TYPE_SIGNED_64 || to == INTEGER_TYPE_UNSIGNED_64);
8033 }
8034 
getUsedFeatures(IntegerType from,IntegerType to)8035 ConvertTestFeatures getUsedFeatures (IntegerType from, IntegerType to)
8036 {
8037 	if (usesInt16(from, to))
8038 	{
8039 		if (usesInt64(from, to))
8040 		{
8041 			return CONVERT_TEST_USES_INT16_INT64;
8042 		}
8043 		else
8044 		{
8045 			return CONVERT_TEST_USES_INT16;
8046 		}
8047 	}
8048 	else
8049 	{
8050 		return CONVERT_TEST_USES_INT64;
8051 	}
8052 }
8053 
8054 struct ConvertCase
8055 {
ConvertCasevkt::SpirVAssembly::ConvertCase8056 	ConvertCase (IntegerType from, IntegerType to, deInt64 number)
8057 	: m_fromType		(from)
8058 	, m_toType			(to)
8059 	, m_features		(getUsedFeatures(from, to))
8060 	, m_name			(getTestName(from, to))
8061 	, m_inputBuffer		(getBuffer(from, number))
8062 	, m_outputBuffer	(getBuffer(to, number))
8063 	{
8064 		m_asmTypes["inputType"]		= getAsmTypeDeclaration(from);
8065 		m_asmTypes["outputType"]	= getAsmTypeDeclaration(to);
8066 
8067 		if (m_features == CONVERT_TEST_USES_INT16)
8068 		{
8069 			m_asmTypes["int_capabilities"] = "OpCapability Int16\n";
8070 		}
8071 		else if (m_features == CONVERT_TEST_USES_INT64)
8072 		{
8073 			m_asmTypes["int_capabilities"] = "OpCapability Int64\n";
8074 		}
8075 		else if (m_features == CONVERT_TEST_USES_INT16_INT64)
8076 		{
8077 			m_asmTypes["int_capabilities"] = string("OpCapability Int16\n") +
8078 													"OpCapability Int64\n";
8079 		}
8080 		else
8081 		{
8082 			DE_ASSERT(false);
8083 		}
8084 	}
8085 
8086 	IntegerType				m_fromType;
8087 	IntegerType				m_toType;
8088 	ConvertTestFeatures		m_features;
8089 	string					m_name;
8090 	map<string, string>		m_asmTypes;
8091 	BufferSp				m_inputBuffer;
8092 	BufferSp				m_outputBuffer;
8093 };
8094 
getConvertCaseShaderStr(const string & instruction,const ConvertCase & convertCase)8095 const string getConvertCaseShaderStr (const string& instruction, const ConvertCase& convertCase)
8096 {
8097 	map<string, string> params = convertCase.m_asmTypes;
8098 
8099 	params["instruction"] = instruction;
8100 
8101 	params["inDecorator"] = getByteWidthStr(convertCase.m_fromType);
8102 	params["outDecorator"] = getByteWidthStr(convertCase.m_toType);
8103 
8104 	const StringTemplate shader (
8105 		"OpCapability Shader\n"
8106 		"${int_capabilities}"
8107 		"OpMemoryModel Logical GLSL450\n"
8108 		"OpEntryPoint GLCompute %main \"main\" %id\n"
8109 		"OpExecutionMode %main LocalSize 1 1 1\n"
8110 		"OpSource GLSL 430\n"
8111 		"OpName %main           \"main\"\n"
8112 		"OpName %id             \"gl_GlobalInvocationID\"\n"
8113 		// Decorators
8114 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
8115 		"OpDecorate %indata DescriptorSet 0\n"
8116 		"OpDecorate %indata Binding 0\n"
8117 		"OpDecorate %outdata DescriptorSet 0\n"
8118 		"OpDecorate %outdata Binding 1\n"
8119 		"OpDecorate %in_arr ArrayStride ${inDecorator}\n"
8120 		"OpDecorate %out_arr ArrayStride ${outDecorator}\n"
8121 		"OpDecorate %in_buf BufferBlock\n"
8122 		"OpDecorate %out_buf BufferBlock\n"
8123 		"OpMemberDecorate %in_buf 0 Offset 0\n"
8124 		"OpMemberDecorate %out_buf 0 Offset 0\n"
8125 		// Base types
8126 		"%void       = OpTypeVoid\n"
8127 		"%voidf      = OpTypeFunction %void\n"
8128 		"%u32        = OpTypeInt 32 0\n"
8129 		"%i32        = OpTypeInt 32 1\n"
8130 		"%uvec3      = OpTypeVector %u32 3\n"
8131 		"%uvec3ptr   = OpTypePointer Input %uvec3\n"
8132 		// Custom types
8133 		"%in_type    = ${inputType}\n"
8134 		"%out_type   = ${outputType}\n"
8135 		// Derived types
8136 		"%in_ptr     = OpTypePointer Uniform %in_type\n"
8137 		"%out_ptr    = OpTypePointer Uniform %out_type\n"
8138 		"%in_arr     = OpTypeRuntimeArray %in_type\n"
8139 		"%out_arr    = OpTypeRuntimeArray %out_type\n"
8140 		"%in_buf     = OpTypeStruct %in_arr\n"
8141 		"%out_buf    = OpTypeStruct %out_arr\n"
8142 		"%in_bufptr  = OpTypePointer Uniform %in_buf\n"
8143 		"%out_bufptr = OpTypePointer Uniform %out_buf\n"
8144 		"%indata     = OpVariable %in_bufptr Uniform\n"
8145 		"%outdata    = OpVariable %out_bufptr Uniform\n"
8146 		"%inputptr   = OpTypePointer Input %in_type\n"
8147 		"%id         = OpVariable %uvec3ptr Input\n"
8148 		// Constants
8149 		"%zero       = OpConstant %i32 0\n"
8150 		// Main function
8151 		"%main       = OpFunction %void None %voidf\n"
8152 		"%label      = OpLabel\n"
8153 		"%idval      = OpLoad %uvec3 %id\n"
8154 		"%x          = OpCompositeExtract %u32 %idval 0\n"
8155 		"%inloc      = OpAccessChain %in_ptr %indata %zero %x\n"
8156 		"%outloc     = OpAccessChain %out_ptr %outdata %zero %x\n"
8157 		"%inval      = OpLoad %in_type %inloc\n"
8158 		"%conv       = ${instruction} %out_type %inval\n"
8159 		"              OpStore %outloc %conv\n"
8160 		"              OpReturn\n"
8161 		"              OpFunctionEnd\n"
8162 	);
8163 
8164 	return shader.specialize(params);
8165 }
8166 
createSConvertCases(vector<ConvertCase> & testCases)8167 void createSConvertCases (vector<ConvertCase>& testCases)
8168 {
8169 	// Convert int to int
8170 	testCases.push_back(ConvertCase(INTEGER_TYPE_SIGNED_16,	INTEGER_TYPE_SIGNED_32,		14669));
8171 	testCases.push_back(ConvertCase(INTEGER_TYPE_SIGNED_16,	INTEGER_TYPE_SIGNED_64,		3341));
8172 
8173 	testCases.push_back(ConvertCase(INTEGER_TYPE_SIGNED_32,	INTEGER_TYPE_SIGNED_64,		973610259));
8174 
8175 	// Convert int to unsigned int
8176 	testCases.push_back(ConvertCase(INTEGER_TYPE_SIGNED_16,	INTEGER_TYPE_UNSIGNED_32,	9288));
8177 	testCases.push_back(ConvertCase(INTEGER_TYPE_SIGNED_16,	INTEGER_TYPE_UNSIGNED_64,	15460));
8178 
8179 	testCases.push_back(ConvertCase(INTEGER_TYPE_SIGNED_32,	INTEGER_TYPE_UNSIGNED_64,	346213461));
8180 }
8181 
8182 //  Test for the OpSConvert instruction.
createSConvertTests(tcu::TestContext & testCtx)8183 tcu::TestCaseGroup* createSConvertTests (tcu::TestContext& testCtx)
8184 {
8185 	const string instruction				("OpSConvert");
8186 	de::MovePtr<tcu::TestCaseGroup>	group	(new tcu::TestCaseGroup(testCtx, "sconvert", "OpSConvert"));
8187 	vector<ConvertCase>				testCases;
8188 	createSConvertCases(testCases);
8189 
8190 	for (vector<ConvertCase>::const_iterator test = testCases.begin(); test != testCases.end(); ++test)
8191 	{
8192 		ComputeShaderSpec	spec;
8193 
8194 		spec.assembly = getConvertCaseShaderStr(instruction, *test);
8195 		spec.inputs.push_back(test->m_inputBuffer);
8196 		spec.outputs.push_back(test->m_outputBuffer);
8197 		spec.numWorkGroups = IVec3(1, 1, 1);
8198 
8199 		group->addChild(new ConvertTestCase(testCtx, test->m_name.c_str(), "Convert integers with OpSConvert.", spec, test->m_features));
8200 	}
8201 
8202 	return group.release();
8203 }
8204 
createUConvertCases(vector<ConvertCase> & testCases)8205 void createUConvertCases (vector<ConvertCase>& testCases)
8206 {
8207 	// Convert unsigned int to unsigned int
8208 	testCases.push_back(ConvertCase(INTEGER_TYPE_UNSIGNED_16,	INTEGER_TYPE_UNSIGNED_32,	60653));
8209 	testCases.push_back(ConvertCase(INTEGER_TYPE_UNSIGNED_16,	INTEGER_TYPE_UNSIGNED_64,	17991));
8210 
8211 	testCases.push_back(ConvertCase(INTEGER_TYPE_UNSIGNED_32,	INTEGER_TYPE_UNSIGNED_64,	904256275));
8212 
8213 	// Convert unsigned int to int
8214 	testCases.push_back(ConvertCase(INTEGER_TYPE_UNSIGNED_16,	INTEGER_TYPE_SIGNED_32,		38002));
8215 	testCases.push_back(ConvertCase(INTEGER_TYPE_UNSIGNED_16,	INTEGER_TYPE_SIGNED_64,		64921));
8216 
8217 	testCases.push_back(ConvertCase(INTEGER_TYPE_UNSIGNED_32,	INTEGER_TYPE_SIGNED_64,		4294956295ll));
8218 }
8219 
8220 //  Test for the OpUConvert instruction.
createUConvertTests(tcu::TestContext & testCtx)8221 tcu::TestCaseGroup* createUConvertTests (tcu::TestContext& testCtx)
8222 {
8223 	const string instruction				("OpUConvert");
8224 	de::MovePtr<tcu::TestCaseGroup>	group	(new tcu::TestCaseGroup(testCtx, "uconvert", "OpUConvert"));
8225 	vector<ConvertCase>				testCases;
8226 	createUConvertCases(testCases);
8227 
8228 	for (vector<ConvertCase>::const_iterator test = testCases.begin(); test != testCases.end(); ++test)
8229 	{
8230 		ComputeShaderSpec	spec;
8231 
8232 		spec.assembly = getConvertCaseShaderStr(instruction, *test);
8233 		spec.inputs.push_back(test->m_inputBuffer);
8234 		spec.outputs.push_back(test->m_outputBuffer);
8235 		spec.numWorkGroups = IVec3(1, 1, 1);
8236 
8237 		group->addChild(new ConvertTestCase(testCtx, test->m_name.c_str(), "Convert integers with OpUConvert.", spec, test->m_features));
8238 	}
8239 	return group.release();
8240 }
8241 
8242 enum NumberType
8243 {
8244 	TYPE_INT,
8245 	TYPE_UINT,
8246 	TYPE_FLOAT,
8247 	TYPE_END,
8248 };
8249 
getNumberTypeName(const NumberType type)8250 const string getNumberTypeName (const NumberType type)
8251 {
8252 	if (type == TYPE_INT)
8253 	{
8254 		return "int";
8255 	}
8256 	else if (type == TYPE_UINT)
8257 	{
8258 		return "uint";
8259 	}
8260 	else if (type == TYPE_FLOAT)
8261 	{
8262 		return "float";
8263 	}
8264 	else
8265 	{
8266 		DE_ASSERT(false);
8267 		return "";
8268 	}
8269 }
8270 
getInt(de::Random & rnd)8271 deInt32 getInt(de::Random& rnd)
8272 {
8273 	return rnd.getInt(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
8274 }
8275 
8276 template <typename T>
numberToString(T number)8277 const string numberToString (T number)
8278 {
8279 	std::stringstream ss;
8280 	ss << number;
8281 	return ss.str();
8282 }
8283 
repeatString(const string & str,int times)8284 const string repeatString (const string& str, int times)
8285 {
8286 	string filler;
8287 	for (int i = 0; i < times; ++i)
8288 	{
8289 		filler += str;
8290 	}
8291 	return filler;
8292 }
8293 
getRandomConstantString(const NumberType type,de::Random & rnd)8294 const string getRandomConstantString (const NumberType type, de::Random& rnd)
8295 {
8296 	if (type == TYPE_INT)
8297 	{
8298 		return numberToString<deInt32>(getInt(rnd));
8299 	}
8300 	else if (type == TYPE_UINT)
8301 	{
8302 		return numberToString<deUint32>(rnd.getUint32());
8303 	}
8304 	else if (type == TYPE_FLOAT)
8305 	{
8306 		return numberToString<float>(rnd.getFloat());
8307 	}
8308 	else
8309 	{
8310 		DE_ASSERT(false);
8311 		return "";
8312 	}
8313 }
8314 
createVectorCompositeCases(vector<map<string,string>> & testCases,de::Random & rnd,const NumberType type)8315 void createVectorCompositeCases (vector<map<string, string> >& testCases, de::Random& rnd, const NumberType type)
8316 {
8317 	map<string, string> params;
8318 
8319 	// Vec2 to Vec4
8320 	for (int width = 2; width <= 4; ++width)
8321 	{
8322 		string randomConst = numberToString(getInt(rnd));
8323 		string widthStr = numberToString(width);
8324 		int index = rnd.getInt(0, width-1);
8325 
8326 		params["type"]					= "vec";
8327 		params["name"]					= params["type"] + "_" + widthStr;
8328 		params["compositeType"]			= "%composite = OpTypeVector %custom " + widthStr +"\n";
8329 		params["filler"]				= string("%filler    = OpConstant %custom ") + getRandomConstantString(type, rnd) + "\n";
8330 		params["compositeConstruct"]	= "%instance  = OpCompositeConstruct %composite" + repeatString(" %filler", width) + "\n";
8331 		params["indexes"]				= numberToString(index);
8332 		testCases.push_back(params);
8333 	}
8334 }
8335 
createArrayCompositeCases(vector<map<string,string>> & testCases,de::Random & rnd,const NumberType type)8336 void createArrayCompositeCases (vector<map<string, string> >& testCases, de::Random& rnd, const NumberType type)
8337 {
8338 	const int limit = 10;
8339 	map<string, string> params;
8340 
8341 	for (int width = 2; width <= limit; ++width)
8342 	{
8343 		string randomConst = numberToString(getInt(rnd));
8344 		string widthStr = numberToString(width);
8345 		int index = rnd.getInt(0, width-1);
8346 
8347 		params["type"]					= "array";
8348 		params["name"]					= params["type"] + "_" + widthStr;
8349 		params["compositeType"]			= string("%arraywidth = OpConstant %u32 " + widthStr + "\n")
8350 											+	 "%composite = OpTypeArray %custom %arraywidth\n";
8351 
8352 		params["filler"]				= string("%filler    = OpConstant %custom ") + getRandomConstantString(type, rnd) + "\n";
8353 		params["compositeConstruct"]	= "%instance  = OpCompositeConstruct %composite" + repeatString(" %filler", width) + "\n";
8354 		params["indexes"]				= numberToString(index);
8355 		testCases.push_back(params);
8356 	}
8357 }
8358 
createStructCompositeCases(vector<map<string,string>> & testCases,de::Random & rnd,const NumberType type)8359 void createStructCompositeCases (vector<map<string, string> >& testCases, de::Random& rnd, const NumberType type)
8360 {
8361 	const int limit = 10;
8362 	map<string, string> params;
8363 
8364 	for (int width = 2; width <= limit; ++width)
8365 	{
8366 		string randomConst = numberToString(getInt(rnd));
8367 		int index = rnd.getInt(0, width-1);
8368 
8369 		params["type"]					= "struct";
8370 		params["name"]					= params["type"] + "_" + numberToString(width);
8371 		params["compositeType"]			= "%composite = OpTypeStruct" + repeatString(" %custom", width) + "\n";
8372 		params["filler"]				= string("%filler    = OpConstant %custom ") + getRandomConstantString(type, rnd) + "\n";
8373 		params["compositeConstruct"]	= "%instance  = OpCompositeConstruct %composite" + repeatString(" %filler", width) + "\n";
8374 		params["indexes"]				= numberToString(index);
8375 		testCases.push_back(params);
8376 	}
8377 }
8378 
createMatrixCompositeCases(vector<map<string,string>> & testCases,de::Random & rnd,const NumberType type)8379 void createMatrixCompositeCases (vector<map<string, string> >& testCases, de::Random& rnd, const NumberType type)
8380 {
8381 	map<string, string> params;
8382 
8383 	// Vec2 to Vec4
8384 	for (int width = 2; width <= 4; ++width)
8385 	{
8386 		string widthStr = numberToString(width);
8387 
8388 		for (int column = 2 ; column <= 4; ++column)
8389 		{
8390 			int index_0 = rnd.getInt(0, column-1);
8391 			int index_1 = rnd.getInt(0, width-1);
8392 			string columnStr = numberToString(column);
8393 
8394 			params["type"]					= "matrix";
8395 			params["name"]					= params["type"] + "_" + widthStr + "x" + columnStr;
8396 			params["compositeType"]			= string("%vectype   = OpTypeVector %custom " + widthStr + "\n")
8397 												+	 "%composite = OpTypeMatrix %vectype " + columnStr + "\n";
8398 
8399 			params["filler"]				= string("%filler    = OpConstant %custom ") + getRandomConstantString(type, rnd) + "\n"
8400 												+	 "%fillerVec = OpConstantComposite %vectype" + repeatString(" %filler", width) + "\n";
8401 
8402 			params["compositeConstruct"]	= "%instance  = OpCompositeConstruct %composite" + repeatString(" %fillerVec", column) + "\n";
8403 			params["indexes"]				= numberToString(index_0) + " " + numberToString(index_1);
8404 			testCases.push_back(params);
8405 		}
8406 	}
8407 }
8408 
createCompositeCases(vector<map<string,string>> & testCases,de::Random & rnd,const NumberType type)8409 void createCompositeCases (vector<map<string, string> >& testCases, de::Random& rnd, const NumberType type)
8410 {
8411 	createVectorCompositeCases(testCases, rnd, type);
8412 	createArrayCompositeCases(testCases, rnd, type);
8413 	createStructCompositeCases(testCases, rnd, type);
8414 	// Matrix only supports float types
8415 	if (type == TYPE_FLOAT)
8416 	{
8417 		createMatrixCompositeCases(testCases, rnd, type);
8418 	}
8419 }
8420 
getAssemblyTypeDeclaration(const NumberType type)8421 const string getAssemblyTypeDeclaration (const NumberType type)
8422 {
8423 	switch (type)
8424 	{
8425 		case TYPE_INT:		return "OpTypeInt 32 1";
8426 		case TYPE_UINT:		return "OpTypeInt 32 0";
8427 		case TYPE_FLOAT:	return "OpTypeFloat 32";
8428 		default:			DE_ASSERT(false); return "";
8429 	}
8430 }
8431 
specializeCompositeInsertShaderTemplate(const NumberType type,const map<string,string> & params)8432 const string specializeCompositeInsertShaderTemplate (const NumberType type, const map<string, string>& params)
8433 {
8434 	map<string, string>	parameters(params);
8435 
8436 	parameters["typeDeclaration"] = getAssemblyTypeDeclaration(type);
8437 
8438 	parameters["compositeDecorator"] = (parameters["type"] == "array") ? "OpDecorate %composite ArrayStride 4\n" : "";
8439 
8440 	return StringTemplate (
8441 		"OpCapability Shader\n"
8442 		"OpCapability Matrix\n"
8443 		"OpMemoryModel Logical GLSL450\n"
8444 		"OpEntryPoint GLCompute %main \"main\" %id\n"
8445 		"OpExecutionMode %main LocalSize 1 1 1\n"
8446 
8447 		"OpSource GLSL 430\n"
8448 		"OpName %main           \"main\"\n"
8449 		"OpName %id             \"gl_GlobalInvocationID\"\n"
8450 
8451 		// Decorators
8452 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
8453 		"OpDecorate %buf BufferBlock\n"
8454 		"OpDecorate %indata DescriptorSet 0\n"
8455 		"OpDecorate %indata Binding 0\n"
8456 		"OpDecorate %outdata DescriptorSet 0\n"
8457 		"OpDecorate %outdata Binding 1\n"
8458 		"OpDecorate %customarr ArrayStride 4\n"
8459 		"${compositeDecorator}"
8460 		"OpMemberDecorate %buf 0 Offset 0\n"
8461 
8462 		// General types
8463 		"%void      = OpTypeVoid\n"
8464 		"%voidf     = OpTypeFunction %void\n"
8465 		"%u32       = OpTypeInt 32 0\n"
8466 		"%i32       = OpTypeInt 32 1\n"
8467 		"%uvec3     = OpTypeVector %u32 3\n"
8468 		"%uvec3ptr  = OpTypePointer Input %uvec3\n"
8469 
8470 		// Custom type
8471 		"%custom    = ${typeDeclaration}\n"
8472 		"${compositeType}"
8473 
8474 		// Constants
8475 		"${filler}"
8476 
8477 		// Inherited from custom
8478 		"%customptr = OpTypePointer Uniform %custom\n"
8479 		"%customarr = OpTypeRuntimeArray %custom\n"
8480 		"%buf       = OpTypeStruct %customarr\n"
8481 		"%bufptr    = OpTypePointer Uniform %buf\n"
8482 
8483 		"%indata    = OpVariable %bufptr Uniform\n"
8484 		"%outdata   = OpVariable %bufptr Uniform\n"
8485 
8486 		"%id        = OpVariable %uvec3ptr Input\n"
8487 		"%zero      = OpConstant %i32 0\n"
8488 
8489 		"%main      = OpFunction %void None %voidf\n"
8490 		"%label     = OpLabel\n"
8491 		"%idval     = OpLoad %uvec3 %id\n"
8492 		"%x         = OpCompositeExtract %u32 %idval 0\n"
8493 
8494 		"%inloc     = OpAccessChain %customptr %indata %zero %x\n"
8495 		"%outloc    = OpAccessChain %customptr %outdata %zero %x\n"
8496 		// Read the input value
8497 		"%inval     = OpLoad %custom %inloc\n"
8498 		// Create the composite and fill it
8499 		"${compositeConstruct}"
8500 		// Insert the input value to a place
8501 		"%instance2 = OpCompositeInsert %composite %inval %instance ${indexes}\n"
8502 		// Read back the value from the position
8503 		"%out_val   = OpCompositeExtract %custom %instance2 ${indexes}\n"
8504 		// Store it in the output position
8505 		"             OpStore %outloc %out_val\n"
8506 		"             OpReturn\n"
8507 		"             OpFunctionEnd\n"
8508 	).specialize(parameters);
8509 }
8510 
8511 template<typename T>
createCompositeBuffer(T number)8512 BufferSp createCompositeBuffer(T number)
8513 {
8514 	return BufferSp(new Buffer<T>(vector<T>(1, number)));
8515 }
8516 
createOpCompositeInsertGroup(tcu::TestContext & testCtx)8517 tcu::TestCaseGroup* createOpCompositeInsertGroup (tcu::TestContext& testCtx)
8518 {
8519 	de::MovePtr<tcu::TestCaseGroup>	group	(new tcu::TestCaseGroup(testCtx, "opcompositeinsert", "Test the OpCompositeInsert instruction"));
8520 	de::Random						rnd		(deStringHash(group->getName()));
8521 
8522 	for (int type = TYPE_INT; type != TYPE_END; ++type)
8523 	{
8524 		NumberType						numberType		= NumberType(type);
8525 		const string					typeName		= getNumberTypeName(numberType);
8526 		const string					description		= "Test the OpCompositeInsert instruction with " + typeName + "s";
8527 		de::MovePtr<tcu::TestCaseGroup>	subGroup		(new tcu::TestCaseGroup(testCtx, typeName.c_str(), description.c_str()));
8528 		vector<map<string, string> >	testCases;
8529 
8530 		createCompositeCases(testCases, rnd, numberType);
8531 
8532 		for (vector<map<string, string> >::const_iterator test = testCases.begin(); test != testCases.end(); ++test)
8533 		{
8534 			ComputeShaderSpec	spec;
8535 
8536 			spec.assembly = specializeCompositeInsertShaderTemplate(numberType, *test);
8537 
8538 			switch (numberType)
8539 			{
8540 				case TYPE_INT:
8541 				{
8542 					deInt32 number = getInt(rnd);
8543 					spec.inputs.push_back(createCompositeBuffer<deInt32>(number));
8544 					spec.outputs.push_back(createCompositeBuffer<deInt32>(number));
8545 					break;
8546 				}
8547 				case TYPE_UINT:
8548 				{
8549 					deUint32 number = rnd.getUint32();
8550 					spec.inputs.push_back(createCompositeBuffer<deUint32>(number));
8551 					spec.outputs.push_back(createCompositeBuffer<deUint32>(number));
8552 					break;
8553 				}
8554 				case TYPE_FLOAT:
8555 				{
8556 					float number = rnd.getFloat();
8557 					spec.inputs.push_back(createCompositeBuffer<float>(number));
8558 					spec.outputs.push_back(createCompositeBuffer<float>(number));
8559 					break;
8560 				}
8561 				default:
8562 					DE_ASSERT(false);
8563 			}
8564 
8565 			spec.numWorkGroups = IVec3(1, 1, 1);
8566 			subGroup->addChild(new SpvAsmComputeShaderCase(testCtx, test->at("name").c_str(), "OpCompositeInsert test", spec));
8567 		}
8568 		group->addChild(subGroup.release());
8569 	}
8570 	return group.release();
8571 }
8572 
8573 struct AssemblyStructInfo
8574 {
AssemblyStructInfovkt::SpirVAssembly::AssemblyStructInfo8575 	AssemblyStructInfo (const deUint32 comp, const deUint32 idx)
8576 	: components	(comp)
8577 	, index			(idx)
8578 	{}
8579 
8580 	deUint32 components;
8581 	deUint32 index;
8582 };
8583 
specializeInBoundsShaderTemplate(const NumberType type,const AssemblyStructInfo & structInfo,const map<string,string> & params)8584 const string specializeInBoundsShaderTemplate (const NumberType type, const AssemblyStructInfo& structInfo, const map<string, string>& params)
8585 {
8586 	// Create the full index string
8587 	string				fullIndex	= numberToString(structInfo.index) + " " + params.at("indexes");
8588 	// Convert it to list of indexes
8589 	vector<string>		indexes		= de::splitString(fullIndex, ' ');
8590 
8591 	map<string, string>	parameters	(params);
8592 	parameters["typeDeclaration"]	= getAssemblyTypeDeclaration(type);
8593 	parameters["structType"]		= repeatString(" %composite", structInfo.components);
8594 	parameters["structConstruct"]	= repeatString(" %instance", structInfo.components);
8595 	parameters["insertIndexes"]		= fullIndex;
8596 
8597 	// In matrix cases the last two index is the CompositeExtract indexes
8598 	const deUint32 extractIndexes = (parameters["type"] == "matrix") ? 2 : 1;
8599 
8600 	// Construct the extractIndex
8601 	for (vector<string>::const_iterator index = indexes.end() - extractIndexes; index != indexes.end(); ++index)
8602 	{
8603 		parameters["extractIndexes"] += " " + *index;
8604 	}
8605 
8606 	// Remove the last 1 or 2 element depends on matrix case or not
8607 	indexes.erase(indexes.end() - extractIndexes, indexes.end());
8608 
8609 	deUint32 id = 0;
8610 	// Generate AccessChain index expressions (except for the last one, because we use ptr to the composite)
8611 	for (vector<string>::const_iterator index = indexes.begin(); index != indexes.end(); ++index)
8612 	{
8613 		string indexId = "%index_" + numberToString(id++);
8614 		parameters["accessChainConstDeclaration"] += indexId + "   = OpConstant %u32 " + *index + "\n";
8615 		parameters["accessChainIndexes"] += " " + indexId;
8616 	}
8617 
8618 	parameters["compositeDecorator"] = (parameters["type"] == "array") ? "OpDecorate %composite ArrayStride 4\n" : "";
8619 
8620 	return StringTemplate (
8621 		"OpCapability Shader\n"
8622 		"OpCapability Matrix\n"
8623 		"OpMemoryModel Logical GLSL450\n"
8624 		"OpEntryPoint GLCompute %main \"main\" %id\n"
8625 		"OpExecutionMode %main LocalSize 1 1 1\n"
8626 
8627 		"OpSource GLSL 430\n"
8628 		"OpName %main           \"main\"\n"
8629 		"OpName %id             \"gl_GlobalInvocationID\"\n"
8630 		// Decorators
8631 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
8632 		"OpDecorate %buf BufferBlock\n"
8633 		"OpDecorate %indata DescriptorSet 0\n"
8634 		"OpDecorate %indata Binding 0\n"
8635 		"OpDecorate %outdata DescriptorSet 0\n"
8636 		"OpDecorate %outdata Binding 1\n"
8637 		"OpDecorate %customarr ArrayStride 4\n"
8638 		"${compositeDecorator}"
8639 		"OpMemberDecorate %buf 0 Offset 0\n"
8640 		// General types
8641 		"%void      = OpTypeVoid\n"
8642 		"%voidf     = OpTypeFunction %void\n"
8643 		"%u32       = OpTypeInt 32 0\n"
8644 		"%uvec3     = OpTypeVector %u32 3\n"
8645 		"%uvec3ptr  = OpTypePointer Input %uvec3\n"
8646 		// Custom type
8647 		"%custom    = ${typeDeclaration}\n"
8648 		// Custom types
8649 		"${compositeType}"
8650 		// Inherited from composite
8651 		"%composite_p = OpTypePointer Function %composite\n"
8652 		"%struct_t  = OpTypeStruct${structType}\n"
8653 		"%struct_p  = OpTypePointer Function %struct_t\n"
8654 		// Constants
8655 		"${filler}"
8656 		"${accessChainConstDeclaration}"
8657 		// Inherited from custom
8658 		"%customptr = OpTypePointer Uniform %custom\n"
8659 		"%customarr = OpTypeRuntimeArray %custom\n"
8660 		"%buf       = OpTypeStruct %customarr\n"
8661 		"%bufptr    = OpTypePointer Uniform %buf\n"
8662 		"%indata    = OpVariable %bufptr Uniform\n"
8663 		"%outdata   = OpVariable %bufptr Uniform\n"
8664 
8665 		"%id        = OpVariable %uvec3ptr Input\n"
8666 		"%zero      = OpConstant %u32 0\n"
8667 		"%main      = OpFunction %void None %voidf\n"
8668 		"%label     = OpLabel\n"
8669 		"%struct_v  = OpVariable %struct_p Function\n"
8670 		"%idval     = OpLoad %uvec3 %id\n"
8671 		"%x         = OpCompositeExtract %u32 %idval 0\n"
8672 		// Create the input/output type
8673 		"%inloc     = OpInBoundsAccessChain %customptr %indata %zero %x\n"
8674 		"%outloc    = OpInBoundsAccessChain %customptr %outdata %zero %x\n"
8675 		// Read the input value
8676 		"%inval     = OpLoad %custom %inloc\n"
8677 		// Create the composite and fill it
8678 		"${compositeConstruct}"
8679 		// Create the struct and fill it with the composite
8680 		"%struct    = OpCompositeConstruct %struct_t${structConstruct}\n"
8681 		// Insert the value
8682 		"%comp_obj  = OpCompositeInsert %struct_t %inval %struct ${insertIndexes}\n"
8683 		// Store the object
8684 		"             OpStore %struct_v %comp_obj\n"
8685 		// Get deepest possible composite pointer
8686 		"%inner_ptr = OpInBoundsAccessChain %composite_p %struct_v${accessChainIndexes}\n"
8687 		"%read_obj  = OpLoad %composite %inner_ptr\n"
8688 		// Read back the stored value
8689 		"%read_val  = OpCompositeExtract %custom %read_obj${extractIndexes}\n"
8690 		"             OpStore %outloc %read_val\n"
8691 		"             OpReturn\n"
8692 		"             OpFunctionEnd\n").specialize(parameters);
8693 }
8694 
createOpInBoundsAccessChainGroup(tcu::TestContext & testCtx)8695 tcu::TestCaseGroup* createOpInBoundsAccessChainGroup (tcu::TestContext& testCtx)
8696 {
8697 	de::MovePtr<tcu::TestCaseGroup>	group			(new tcu::TestCaseGroup(testCtx, "opinboundsaccesschain", "Test the OpInBoundsAccessChain instruction"));
8698 	de::Random						rnd				(deStringHash(group->getName()));
8699 
8700 	for (int type = TYPE_INT; type != TYPE_END; ++type)
8701 	{
8702 		NumberType						numberType	= NumberType(type);
8703 		const string					typeName	= getNumberTypeName(numberType);
8704 		const string					description	= "Test the OpInBoundsAccessChain instruction with " + typeName + "s";
8705 		de::MovePtr<tcu::TestCaseGroup>	subGroup	(new tcu::TestCaseGroup(testCtx, typeName.c_str(), description.c_str()));
8706 
8707 		vector<map<string, string> >	testCases;
8708 		createCompositeCases(testCases, rnd, numberType);
8709 
8710 		for (vector<map<string, string> >::const_iterator test = testCases.begin(); test != testCases.end(); ++test)
8711 		{
8712 			ComputeShaderSpec	spec;
8713 
8714 			// Number of components inside of a struct
8715 			deUint32 structComponents = rnd.getInt(2, 8);
8716 			// Component index value
8717 			deUint32 structIndex = rnd.getInt(0, structComponents - 1);
8718 			AssemblyStructInfo structInfo(structComponents, structIndex);
8719 
8720 			spec.assembly = specializeInBoundsShaderTemplate(numberType, structInfo, *test);
8721 
8722 			switch (numberType)
8723 			{
8724 				case TYPE_INT:
8725 				{
8726 					deInt32 number = getInt(rnd);
8727 					spec.inputs.push_back(createCompositeBuffer<deInt32>(number));
8728 					spec.outputs.push_back(createCompositeBuffer<deInt32>(number));
8729 					break;
8730 				}
8731 				case TYPE_UINT:
8732 				{
8733 					deUint32 number = rnd.getUint32();
8734 					spec.inputs.push_back(createCompositeBuffer<deUint32>(number));
8735 					spec.outputs.push_back(createCompositeBuffer<deUint32>(number));
8736 					break;
8737 				}
8738 				case TYPE_FLOAT:
8739 				{
8740 					float number = rnd.getFloat();
8741 					spec.inputs.push_back(createCompositeBuffer<float>(number));
8742 					spec.outputs.push_back(createCompositeBuffer<float>(number));
8743 					break;
8744 				}
8745 				default:
8746 					DE_ASSERT(false);
8747 			}
8748 			spec.numWorkGroups = IVec3(1, 1, 1);
8749 			subGroup->addChild(new SpvAsmComputeShaderCase(testCtx, test->at("name").c_str(), "OpInBoundsAccessChain test", spec));
8750 		}
8751 		group->addChild(subGroup.release());
8752 	}
8753 	return group.release();
8754 }
8755 
8756 // If the params missing, uninitialized case
8757 const string specializeDefaultOutputShaderTemplate (const NumberType type, const map<string, string>& params = map<string, string>())
8758 {
8759 	map<string, string> parameters(params);
8760 
8761 	parameters["typeDeclaration"] = getAssemblyTypeDeclaration(type);
8762 
8763 	// Declare the const value, and use it in the initializer
8764 	if (params.find("constValue") != params.end())
8765 	{
8766 		parameters["constDeclaration"]		= "%const      = OpConstant %in_type " + params.at("constValue") + "\n";
8767 		parameters["variableInitializer"]	= "%const";
8768 	}
8769 	// Uninitialized case
8770 	else
8771 	{
8772 		parameters["constDeclaration"]		= "";
8773 		parameters["variableInitializer"]	= "";
8774 	}
8775 
8776 	return StringTemplate(
8777 		"OpCapability Shader\n"
8778 		"OpMemoryModel Logical GLSL450\n"
8779 		"OpEntryPoint GLCompute %main \"main\" %id\n"
8780 		"OpExecutionMode %main LocalSize 1 1 1\n"
8781 		"OpSource GLSL 430\n"
8782 		"OpName %main           \"main\"\n"
8783 		"OpName %id             \"gl_GlobalInvocationID\"\n"
8784 		// Decorators
8785 		"OpDecorate %id BuiltIn GlobalInvocationId\n"
8786 		"OpDecorate %indata DescriptorSet 0\n"
8787 		"OpDecorate %indata Binding 0\n"
8788 		"OpDecorate %outdata DescriptorSet 0\n"
8789 		"OpDecorate %outdata Binding 1\n"
8790 		"OpDecorate %in_arr ArrayStride 4\n"
8791 		"OpDecorate %in_buf BufferBlock\n"
8792 		"OpMemberDecorate %in_buf 0 Offset 0\n"
8793 		// Base types
8794 		"%void       = OpTypeVoid\n"
8795 		"%voidf      = OpTypeFunction %void\n"
8796 		"%u32        = OpTypeInt 32 0\n"
8797 		"%i32        = OpTypeInt 32 1\n"
8798 		"%uvec3      = OpTypeVector %u32 3\n"
8799 		"%uvec3ptr   = OpTypePointer Input %uvec3\n"
8800 		// Custom types
8801 		"%in_type    = ${typeDeclaration}\n"
8802 		// "%const      = OpConstant %in_type ${constValue}\n"
8803 		"${constDeclaration}\n"
8804 		// Derived types
8805 		"%in_ptr     = OpTypePointer Uniform %in_type\n"
8806 		"%in_arr     = OpTypeRuntimeArray %in_type\n"
8807 		"%in_buf     = OpTypeStruct %in_arr\n"
8808 		"%in_bufptr  = OpTypePointer Uniform %in_buf\n"
8809 		"%indata     = OpVariable %in_bufptr Uniform\n"
8810 		"%outdata    = OpVariable %in_bufptr Uniform\n"
8811 		"%id         = OpVariable %uvec3ptr Input\n"
8812 		"%var_ptr    = OpTypePointer Function %in_type\n"
8813 		// Constants
8814 		"%zero       = OpConstant %i32 0\n"
8815 		// Main function
8816 		"%main       = OpFunction %void None %voidf\n"
8817 		"%label      = OpLabel\n"
8818 		"%out_var    = OpVariable %var_ptr Function ${variableInitializer}\n"
8819 		"%idval      = OpLoad %uvec3 %id\n"
8820 		"%x          = OpCompositeExtract %u32 %idval 0\n"
8821 		"%inloc      = OpAccessChain %in_ptr %indata %zero %x\n"
8822 		"%outloc     = OpAccessChain %in_ptr %outdata %zero %x\n"
8823 
8824 		"%outval     = OpLoad %in_type %out_var\n"
8825 		"              OpStore %outloc %outval\n"
8826 		"              OpReturn\n"
8827 		"              OpFunctionEnd\n"
8828 	).specialize(parameters);
8829 }
8830 
compareFloats(const std::vector<BufferSp> &,const vector<AllocationSp> & outputAllocs,const std::vector<BufferSp> & expectedOutputs,TestLog & log)8831 bool compareFloats (const std::vector<BufferSp>&, const vector<AllocationSp>& outputAllocs, const std::vector<BufferSp>& expectedOutputs, TestLog& log)
8832 {
8833 	DE_ASSERT(outputAllocs.size() != 0);
8834 	DE_ASSERT(outputAllocs.size() == expectedOutputs.size());
8835 
8836 	// Use custom epsilon because of the float->string conversion
8837 	const float	epsilon	= 0.00001f;
8838 
8839 	for (size_t outputNdx = 0; outputNdx < outputAllocs.size(); ++outputNdx)
8840 	{
8841 		float expected;
8842 		memcpy(&expected, expectedOutputs[outputNdx]->data(), expectedOutputs[outputNdx]->getNumBytes());
8843 
8844 		float actual;
8845 		memcpy(&actual, outputAllocs[outputNdx]->getHostPtr(), expectedOutputs[outputNdx]->getNumBytes());
8846 
8847 		// Test with epsilon
8848 		if (fabs(expected - actual) > epsilon)
8849 		{
8850 			log << TestLog::Message << "Error: The actual and expected values not matching."
8851 				<< " Expected: " << expected << " Actual: " << actual << " Epsilon: " << epsilon << TestLog::EndMessage;
8852 			return false;
8853 		}
8854 	}
8855 	return true;
8856 }
8857 
8858 // Checks if the driver crash with uninitialized cases
passthruVerify(const std::vector<BufferSp> &,const vector<AllocationSp> & outputAllocs,const std::vector<BufferSp> & expectedOutputs,TestLog &)8859 bool passthruVerify (const std::vector<BufferSp>&, const vector<AllocationSp>& outputAllocs, const std::vector<BufferSp>& expectedOutputs, TestLog&)
8860 {
8861 	DE_ASSERT(outputAllocs.size() != 0);
8862 	DE_ASSERT(outputAllocs.size() == expectedOutputs.size());
8863 
8864 	// Copy and discard the result.
8865 	for (size_t outputNdx = 0; outputNdx < outputAllocs.size(); ++outputNdx)
8866 	{
8867 		size_t width = expectedOutputs[outputNdx]->getNumBytes();
8868 
8869 		vector<char> data(width);
8870 		memcpy(&data[0], outputAllocs[outputNdx]->getHostPtr(), width);
8871 	}
8872 	return true;
8873 }
8874 
createShaderDefaultOutputGroup(tcu::TestContext & testCtx)8875 tcu::TestCaseGroup* createShaderDefaultOutputGroup (tcu::TestContext& testCtx)
8876 {
8877 	de::MovePtr<tcu::TestCaseGroup>	group	(new tcu::TestCaseGroup(testCtx, "shader_default_output", "Test shader default output."));
8878 	de::Random						rnd		(deStringHash(group->getName()));
8879 
8880 	for (int type = TYPE_INT; type != TYPE_END; ++type)
8881 	{
8882 		NumberType						numberType	= NumberType(type);
8883 		const string					typeName	= getNumberTypeName(numberType);
8884 		const string					description	= "Test the OpVariable initializer with " + typeName + ".";
8885 		de::MovePtr<tcu::TestCaseGroup>	subGroup	(new tcu::TestCaseGroup(testCtx, typeName.c_str(), description.c_str()));
8886 
8887 		// 2 similar subcases (initialized and uninitialized)
8888 		for (int subCase = 0; subCase < 2; ++subCase)
8889 		{
8890 			ComputeShaderSpec spec;
8891 			spec.numWorkGroups = IVec3(1, 1, 1);
8892 
8893 			map<string, string>				params;
8894 
8895 			switch (numberType)
8896 			{
8897 				case TYPE_INT:
8898 				{
8899 					deInt32 number = getInt(rnd);
8900 					spec.inputs.push_back(createCompositeBuffer<deInt32>(number));
8901 					spec.outputs.push_back(createCompositeBuffer<deInt32>(number));
8902 					params["constValue"] = numberToString(number);
8903 					break;
8904 				}
8905 				case TYPE_UINT:
8906 				{
8907 					deUint32 number = rnd.getUint32();
8908 					spec.inputs.push_back(createCompositeBuffer<deUint32>(number));
8909 					spec.outputs.push_back(createCompositeBuffer<deUint32>(number));
8910 					params["constValue"] = numberToString(number);
8911 					break;
8912 				}
8913 				case TYPE_FLOAT:
8914 				{
8915 					float number = rnd.getFloat();
8916 					spec.inputs.push_back(createCompositeBuffer<float>(number));
8917 					spec.outputs.push_back(createCompositeBuffer<float>(number));
8918 					spec.verifyIO = &compareFloats;
8919 					params["constValue"] = numberToString(number);
8920 					break;
8921 				}
8922 				default:
8923 					DE_ASSERT(false);
8924 			}
8925 
8926 			// Initialized subcase
8927 			if (!subCase)
8928 			{
8929 				spec.assembly = specializeDefaultOutputShaderTemplate(numberType, params);
8930 				subGroup->addChild(new SpvAsmComputeShaderCase(testCtx, "initialized", "OpVariable initializer tests.", spec));
8931 			}
8932 			// Uninitialized subcase
8933 			else
8934 			{
8935 				spec.assembly = specializeDefaultOutputShaderTemplate(numberType);
8936 				spec.verifyIO = &passthruVerify;
8937 				subGroup->addChild(new SpvAsmComputeShaderCase(testCtx, "uninitialized", "OpVariable initializer tests.", spec));
8938 			}
8939 		}
8940 		group->addChild(subGroup.release());
8941 	}
8942 	return group.release();
8943 }
8944 
createInstructionTests(tcu::TestContext & testCtx)8945 tcu::TestCaseGroup* createInstructionTests (tcu::TestContext& testCtx)
8946 {
8947 	de::MovePtr<tcu::TestCaseGroup> instructionTests	(new tcu::TestCaseGroup(testCtx, "instruction", "Instructions with special opcodes/operands"));
8948 	de::MovePtr<tcu::TestCaseGroup> computeTests		(new tcu::TestCaseGroup(testCtx, "compute", "Compute Instructions with special opcodes/operands"));
8949 	de::MovePtr<tcu::TestCaseGroup> graphicsTests		(new tcu::TestCaseGroup(testCtx, "graphics", "Graphics Instructions with special opcodes/operands"));
8950 
8951 	computeTests->addChild(createOpNopGroup(testCtx));
8952 	computeTests->addChild(createOpFUnordGroup(testCtx));
8953 	computeTests->addChild(createOpAtomicGroup(testCtx));
8954 	computeTests->addChild(createOpLineGroup(testCtx));
8955 	computeTests->addChild(createOpNoLineGroup(testCtx));
8956 	computeTests->addChild(createOpConstantNullGroup(testCtx));
8957 	computeTests->addChild(createOpConstantCompositeGroup(testCtx));
8958 	computeTests->addChild(createOpConstantUsageGroup(testCtx));
8959 	computeTests->addChild(createSpecConstantGroup(testCtx));
8960 	computeTests->addChild(createOpSourceGroup(testCtx));
8961 	computeTests->addChild(createOpSourceExtensionGroup(testCtx));
8962 	computeTests->addChild(createDecorationGroupGroup(testCtx));
8963 	computeTests->addChild(createOpPhiGroup(testCtx));
8964 	computeTests->addChild(createLoopControlGroup(testCtx));
8965 	computeTests->addChild(createFunctionControlGroup(testCtx));
8966 	computeTests->addChild(createSelectionControlGroup(testCtx));
8967 	computeTests->addChild(createBlockOrderGroup(testCtx));
8968 	computeTests->addChild(createMultipleShaderGroup(testCtx));
8969 	computeTests->addChild(createMemoryAccessGroup(testCtx));
8970 	computeTests->addChild(createOpCopyMemoryGroup(testCtx));
8971 	computeTests->addChild(createOpCopyObjectGroup(testCtx));
8972 	computeTests->addChild(createNoContractionGroup(testCtx));
8973 	computeTests->addChild(createOpUndefGroup(testCtx));
8974 	computeTests->addChild(createOpUnreachableGroup(testCtx));
8975 	computeTests ->addChild(createOpQuantizeToF16Group(testCtx));
8976 	computeTests ->addChild(createOpFRemGroup(testCtx));
8977 	computeTests->addChild(createSConvertTests(testCtx));
8978 	computeTests->addChild(createUConvertTests(testCtx));
8979 	computeTests->addChild(createOpCompositeInsertGroup(testCtx));
8980 	computeTests->addChild(createOpInBoundsAccessChainGroup(testCtx));
8981 	computeTests->addChild(createShaderDefaultOutputGroup(testCtx));
8982 
8983 	RGBA defaultColors[4];
8984 	getDefaultColors(defaultColors);
8985 
8986 	de::MovePtr<tcu::TestCaseGroup> opnopTests (new tcu::TestCaseGroup(testCtx, "opnop", "Test OpNop"));
8987 	map<string, string> opNopFragments;
8988 	opNopFragments["testfun"] =
8989 		"%test_code = OpFunction %v4f32 None %v4f32_function\n"
8990 		"%param1 = OpFunctionParameter %v4f32\n"
8991 		"%label_testfun = OpLabel\n"
8992 		"OpNop\n"
8993 		"OpNop\n"
8994 		"OpNop\n"
8995 		"OpNop\n"
8996 		"OpNop\n"
8997 		"OpNop\n"
8998 		"OpNop\n"
8999 		"OpNop\n"
9000 		"%a = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
9001 		"%b = OpFAdd %f32 %a %a\n"
9002 		"OpNop\n"
9003 		"%c = OpFSub %f32 %b %a\n"
9004 		"%ret = OpVectorInsertDynamic %v4f32 %param1 %c %c_i32_0\n"
9005 		"OpNop\n"
9006 		"OpNop\n"
9007 		"OpReturnValue %ret\n"
9008 		"OpFunctionEnd\n"
9009 		;
9010 	createTestsForAllStages("opnop", defaultColors, defaultColors, opNopFragments, opnopTests.get());
9011 
9012 
9013 	graphicsTests->addChild(opnopTests.release());
9014 	graphicsTests->addChild(createOpSourceTests(testCtx));
9015 	graphicsTests->addChild(createOpSourceContinuedTests(testCtx));
9016 	graphicsTests->addChild(createOpLineTests(testCtx));
9017 	graphicsTests->addChild(createOpNoLineTests(testCtx));
9018 	graphicsTests->addChild(createOpConstantNullTests(testCtx));
9019 	graphicsTests->addChild(createOpConstantCompositeTests(testCtx));
9020 	graphicsTests->addChild(createMemoryAccessTests(testCtx));
9021 	graphicsTests->addChild(createOpUndefTests(testCtx));
9022 	graphicsTests->addChild(createSelectionBlockOrderTests(testCtx));
9023 	graphicsTests->addChild(createModuleTests(testCtx));
9024 	graphicsTests->addChild(createSwitchBlockOrderTests(testCtx));
9025 	graphicsTests->addChild(createOpPhiTests(testCtx));
9026 	graphicsTests->addChild(createNoContractionTests(testCtx));
9027 	graphicsTests->addChild(createOpQuantizeTests(testCtx));
9028 	graphicsTests->addChild(createLoopTests(testCtx));
9029 	graphicsTests->addChild(createSpecConstantTests(testCtx));
9030 	graphicsTests->addChild(createSpecConstantOpQuantizeToF16Group(testCtx));
9031 	graphicsTests->addChild(createBarrierTests(testCtx));
9032 	graphicsTests->addChild(createDecorationGroupTests(testCtx));
9033 	graphicsTests->addChild(createFRemTests(testCtx));
9034 
9035 	instructionTests->addChild(computeTests.release());
9036 	instructionTests->addChild(graphicsTests.release());
9037 
9038 	return instructionTests.release();
9039 }
9040 
9041 } // SpirVAssembly
9042 } // vkt
9043