• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  * Copyright (c) 2019 Google Inc.
7  * Copyright (c) 2017 Codeplay Software Ltd.
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */ /*!
22  * \file
23  * \brief Subgroups Tests
24  */ /*--------------------------------------------------------------------*/
25 
26 #include "vktSubgroupsBasicTests.hpp"
27 #include "vktSubgroupsTestsUtils.hpp"
28 
29 #include "tcuStringTemplate.hpp"
30 
31 #include <string>
32 #include <vector>
33 
34 using namespace tcu;
35 using namespace std;
36 using namespace vk;
37 using namespace vkt;
38 
39 namespace
40 {
41 enum OpType
42 {
43 	OPTYPE_ELECT = 0,
44 	OPTYPE_SUBGROUP_BARRIER,
45 	OPTYPE_SUBGROUP_MEMORY_BARRIER,
46 	OPTYPE_SUBGROUP_MEMORY_BARRIER_BUFFER,
47 	OPTYPE_SUBGROUP_MEMORY_BARRIER_SHARED,
48 	OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE,
49 	OPTYPE_LAST
50 };
51 
52 struct CaseDefinition
53 {
54 	OpType				opType;
55 	VkShaderStageFlags	shaderStage;
56 	de::SharedPtr<bool>	geometryPointSizeSupported;
57 	deBool				requiredSubgroupSize;
58 };
59 
60 static const deUint32		ELECTED_VALUE		= 42u;
61 static const deUint32		UNELECTED_VALUE		= 13u;
62 static const VkDeviceSize	SHADER_BUFFER_SIZE	= 4096ull; // min(maxUniformBufferRange, maxImageDimension1D)
63 
_checkFragmentSubgroupBarriersNoSSBO(vector<const void * > datas,deUint32 width,deUint32 height,bool withImage)64 static bool _checkFragmentSubgroupBarriersNoSSBO (vector<const void*>	datas,
65 												  deUint32				width,
66 												  deUint32				height,
67 												  bool					withImage)
68 {
69 	const float* const	resultData	= reinterpret_cast<const float*>(datas[0]);
70 
71 	for (deUint32 x = 0u; x < width; ++x)
72 	{
73 		for (deUint32 y = 0u; y < height; ++y)
74 		{
75 			const deUint32 ndx = (x * height + y) * 4u;
76 
77 			if (!withImage && 0.0f == resultData[ndx])
78 			{
79 				return false;
80 			}
81 			else if (1.0f == resultData[ndx +2])
82 			{
83 				if(resultData[ndx] != resultData[ndx +1])
84 				{
85 					return false;
86 				}
87 			}
88 			else if (resultData[ndx] != resultData[ndx +3])
89 			{
90 				return false;
91 			}
92 		}
93 	}
94 
95 	return true;
96 }
97 
checkFragmentSubgroupBarriersNoSSBO(const void * internalData,vector<const void * > datas,deUint32 width,deUint32 height,deUint32)98 static bool checkFragmentSubgroupBarriersNoSSBO (const void				*internalData,
99 												 vector<const void*>	datas,
100 												 deUint32				width,
101 												 deUint32				height,
102 												 deUint32)
103 {
104 	DE_UNREF(internalData);
105 
106 	return _checkFragmentSubgroupBarriersNoSSBO(datas, width, height, false);
107 }
108 
checkFragmentSubgroupBarriersWithImageNoSSBO(const void * internalData,vector<const void * > datas,deUint32 width,deUint32 height,deUint32)109 static bool checkFragmentSubgroupBarriersWithImageNoSSBO (const void*			internalData,
110 														  vector<const void*>	datas,
111 														  deUint32				width,
112 														  deUint32				height,
113 														  deUint32)
114 {
115 	DE_UNREF(internalData);
116 
117 	return _checkFragmentSubgroupBarriersNoSSBO(datas, width, height, true);
118 }
119 
checkVertexPipelineStagesSubgroupElectNoSSBO(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)120 static bool checkVertexPipelineStagesSubgroupElectNoSSBO (const void*			internalData,
121 														  vector<const void*>	datas,
122 														  deUint32				width,
123 														  deUint32)
124 {
125 	DE_UNREF(internalData);
126 
127 	const float* const	resultData			= reinterpret_cast<const float*>(datas[0]);
128 	float				poisonValuesFound	= 0.0f;
129 	float				numSubgroupsUsed	= 0.0f;
130 
131 	for (deUint32 x = 0; x < width; ++x)
132 	{
133 		deUint32 val = static_cast<deUint32>(resultData[x * 2]);
134 		numSubgroupsUsed += resultData[x * 2 + 1];
135 
136 		switch (val)
137 		{
138 			default:
139 				// some garbage value was found!
140 				return false;
141 			case UNELECTED_VALUE:
142 				break;
143 			case ELECTED_VALUE:
144 				poisonValuesFound += 1.0f;
145 				break;
146 		}
147 	}
148 
149 	return numSubgroupsUsed == poisonValuesFound;
150 }
151 
checkVertexPipelineStagesSubgroupElect(const void * internalData,vector<const void * > datas,deUint32 width,deUint32,bool multipleCallsPossible)152 static bool checkVertexPipelineStagesSubgroupElect (const void*				internalData,
153 													vector<const void*>		datas,
154 													deUint32				width,
155 													deUint32,
156 													bool					multipleCallsPossible)
157 {
158 	DE_UNREF(internalData);
159 
160 	const deUint32* const	resultData			= reinterpret_cast<const deUint32*>(datas[0]);
161 	deUint32				poisonValuesFound	= 0;
162 
163 	for (deUint32 x = 0; x < width; ++x)
164 	{
165 		deUint32 val = resultData[x];
166 
167 		switch (val)
168 		{
169 			default:
170 				// some garbage value was found!
171 				return false;
172 			case UNELECTED_VALUE:
173 				break;
174 			case ELECTED_VALUE:
175 				poisonValuesFound++;
176 				break;
177 		}
178 	}
179 
180 	// we used an atomicly incremented counter to note how many subgroups we used for the vertex shader
181 	const deUint32	numSubgroupsUsed	= *reinterpret_cast<const deUint32*>(datas[1]);
182 
183 	return (multipleCallsPossible ? (numSubgroupsUsed >= poisonValuesFound) : (numSubgroupsUsed == poisonValuesFound));
184 }
185 
checkVertexPipelineStagesSubgroupBarriers(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)186 static bool checkVertexPipelineStagesSubgroupBarriers (const void*				internalData,
187 													   vector<const void*>		datas,
188 													   deUint32					width,
189 													   deUint32)
190 {
191 	DE_UNREF(internalData);
192 
193 	const deUint32* const resultData = reinterpret_cast<const deUint32*>(datas[0]);
194 
195 	// We used this SSBO to generate our unique value!
196 	const deUint32 ref = *reinterpret_cast<const deUint32*>(datas[3]);
197 
198 	for (deUint32 x = 0; x < width; ++x)
199 	{
200 		deUint32 val = resultData[x];
201 
202 		if (val != ref)
203 			return false;
204 	}
205 
206 	return true;
207 }
208 
_checkVertexPipelineStagesSubgroupBarriersNoSSBO(vector<const void * > datas,deUint32 width,bool withImage)209 static bool _checkVertexPipelineStagesSubgroupBarriersNoSSBO (vector<const void*>	datas,
210 															  deUint32				width,
211 															  bool					withImage)
212 {
213 	const float* const	resultData	= reinterpret_cast<const float*>(datas[0]);
214 
215 	for (deUint32 x = 0u; x < width; ++x)
216 	{
217 		const deUint32 ndx = x*4u;
218 		if (!withImage && 0.0f == resultData[ndx])
219 		{
220 			return false;
221 		}
222 		else if (1.0f == resultData[ndx +2])
223 		{
224 			if(resultData[ndx] != resultData[ndx +1])
225 				return false;
226 		}
227 		else if (resultData[ndx] != resultData[ndx +3])
228 		{
229 			return false;
230 		}
231 	}
232 
233 	return true;
234 }
235 
checkVertexPipelineStagesSubgroupBarriersNoSSBO(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)236 static bool checkVertexPipelineStagesSubgroupBarriersNoSSBO (const void*			internalData,
237 															 vector<const void*>	datas,
238 															 deUint32				width,
239 															 deUint32)
240 {
241 	DE_UNREF(internalData);
242 
243 	return _checkVertexPipelineStagesSubgroupBarriersNoSSBO(datas, width, false);
244 }
245 
checkVertexPipelineStagesSubgroupBarriersWithImageNoSSBO(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)246 static bool checkVertexPipelineStagesSubgroupBarriersWithImageNoSSBO (const void*			internalData,
247 																	  vector<const void*>	datas,
248 																	  deUint32				width,
249 																	  deUint32)
250 {
251 	DE_UNREF(internalData);
252 
253 	return _checkVertexPipelineStagesSubgroupBarriersNoSSBO(datas, width, true);
254 }
255 
_checkTessellationEvaluationSubgroupBarriersNoSSBO(vector<const void * > datas,deUint32 width,deUint32,bool withImage)256 static bool _checkTessellationEvaluationSubgroupBarriersNoSSBO (vector<const void*>	datas,
257 																deUint32			width,
258 																deUint32,
259 																bool				withImage)
260 {
261 	const float* const	resultData	= reinterpret_cast<const float*>(datas[0]);
262 
263 	for (deUint32 x = 0u; x < width; ++x)
264 	{
265 		const deUint32 ndx = x*4u;
266 
267 		if (!withImage && 0.0f == resultData[ndx])
268 		{
269 			return false;
270 		}
271 		else if (0.0f == resultData[ndx +2] && resultData[ndx] != resultData[ndx +3])
272 		{
273 			return false;
274 		}
275 	}
276 
277 	return true;
278 }
279 
checkTessellationEvaluationSubgroupBarriersWithImageNoSSBO(const void * internalData,vector<const void * > datas,deUint32 width,deUint32 height)280 static bool checkTessellationEvaluationSubgroupBarriersWithImageNoSSBO (const void*			internalData,
281 																		vector<const void*>	datas,
282 																		deUint32			width,
283 																		deUint32			height)
284 {
285 	DE_UNREF(internalData);
286 
287 	return _checkTessellationEvaluationSubgroupBarriersNoSSBO(datas, width, height, true);
288 }
289 
checkTessellationEvaluationSubgroupBarriersNoSSBO(const void * internalData,vector<const void * > datas,deUint32 width,deUint32 height)290 static bool checkTessellationEvaluationSubgroupBarriersNoSSBO (const void*				internalData,
291 															   vector<const void*>		datas,
292 															   deUint32					width,
293 															   deUint32					height)
294 {
295 	DE_UNREF(internalData);
296 
297 	return _checkTessellationEvaluationSubgroupBarriersNoSSBO (datas, width, height, false);
298 }
299 
checkComputeOrMeshSubgroupElect(const void * internalData,vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)300 static bool checkComputeOrMeshSubgroupElect (const void*			internalData,
301 											 vector<const void*>	datas,
302 											 const deUint32			numWorkgroups[3],
303 											 const deUint32			localSize[3],
304 											 deUint32)
305 {
306 	DE_UNREF(internalData);
307 
308 	return subgroups::checkComputeOrMesh(datas, numWorkgroups, localSize, 1);
309 }
310 
checkComputeOrMeshSubgroupBarriers(const void * internalData,vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)311 static bool checkComputeOrMeshSubgroupBarriers (const void*			internalData,
312 												vector<const void*>	datas,
313 												const deUint32		numWorkgroups[3],
314 												const deUint32		localSize[3],
315 												deUint32)
316 {
317 	DE_UNREF(internalData);
318 
319 	// We used this SSBO to generate our unique value!
320 	const deUint32 ref = *reinterpret_cast<const deUint32*>(datas[2]);
321 
322 	return subgroups::checkComputeOrMesh(datas, numWorkgroups, localSize, ref);
323 }
324 
getOpTypeName(OpType opType)325 string getOpTypeName (OpType opType)
326 {
327 	switch (opType)
328 	{
329 		case OPTYPE_ELECT:							return "subgroupElect";
330 		case OPTYPE_SUBGROUP_BARRIER:				return "subgroupBarrier";
331 		case OPTYPE_SUBGROUP_MEMORY_BARRIER:		return "subgroupMemoryBarrier";
332 		case OPTYPE_SUBGROUP_MEMORY_BARRIER_BUFFER:	return "subgroupMemoryBarrierBuffer";
333 		case OPTYPE_SUBGROUP_MEMORY_BARRIER_SHARED:	return "subgroupMemoryBarrierShared";
334 		case OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE:	return "subgroupMemoryBarrierImage";
335 		default:									TCU_THROW(InternalError, "Unsupported op type");
336 	}
337 }
338 
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)339 void initFrameBufferPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
340 {
341 	const ShaderBuildOptions	buildOptions	(programCollection.usedVulkanVersion, SPIRV_VERSION_1_3, 0u);
342 	const SpirVAsmBuildOptions	buildOptionsSpr	(programCollection.usedVulkanVersion, SPIRV_VERSION_1_3);
343 
344 	if (VK_SHADER_STAGE_FRAGMENT_BIT != caseDef.shaderStage)
345 	{
346 		/*
347 			"layout(location = 0) in vec4 in_color;\n"
348 			"layout(location = 0) out vec4 out_color;\n"
349 			"void main()\n"
350 			{\n"
351 			"	out_color = in_color;\n"
352 			"}\n";
353 		*/
354 		const string fragment =
355 			"; SPIR-V\n"
356 			"; Version: 1.3\n"
357 			"; Generator: Khronos Glslang Reference Front End; 2\n"
358 			"; Bound: 13\n"
359 			"; Schema: 0\n"
360 			"OpCapability Shader\n"
361 			"%1 = OpExtInstImport \"GLSL.std.450\"\n"
362 			"OpMemoryModel Logical GLSL450\n"
363 			"OpEntryPoint Fragment %4 \"main\" %9 %11\n"
364 			"OpExecutionMode %4 OriginUpperLeft\n"
365 			"OpDecorate %9 Location 0\n"
366 			"OpDecorate %11 Location 0\n"
367 			"%2 = OpTypeVoid\n"
368 			"%3 = OpTypeFunction %2\n"
369 			"%6 = OpTypeFloat 32\n"
370 			"%7 = OpTypeVector %6 4\n"
371 			"%8 = OpTypePointer Output %7\n"
372 			"%9 = OpVariable %8 Output\n"
373 			"%10 = OpTypePointer Input %7\n"
374 			"%11 = OpVariable %10 Input\n"
375 			"%4 = OpFunction %2 None %3\n"
376 			"%5 = OpLabel\n"
377 			"%12 = OpLoad %7 %11\n"
378 			"OpStore %9 %12\n"
379 			"OpReturn\n"
380 			"OpFunctionEnd\n";
381 
382 		programCollection.spirvAsmSources.add("fragment") << fragment;
383 	}
384 	if (VK_SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
385 	{
386 		/*
387 			"#version 450\n"
388 			"void main (void)\n"
389 			"{\n"
390 			"  vec2 uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);\n"
391 			"  gl_Position = vec4(uv * 2.0f + -1.0f, 0.0f, 1.0f);\n"
392 			"  gl_PointSize = 1.0f;\n"
393 			"}\n";
394 		*/
395 		const string vertex =
396 			"; SPIR-V\n"
397 			"; Version: 1.3\n"
398 			"; Generator: Khronos Glslang Reference Front End; 2\n"
399 			"; Bound: 44\n"
400 			"; Schema: 0\n"
401 			"OpCapability Shader\n"
402 			"%1 = OpExtInstImport \"GLSL.std.450\"\n"
403 			"OpMemoryModel Logical GLSL450\n"
404 			"OpEntryPoint Vertex %4 \"main\" %12 %29\n"
405 			"OpDecorate %12 BuiltIn VertexIndex\n"
406 			"OpMemberDecorate %27 0 BuiltIn Position\n"
407 			"OpMemberDecorate %27 1 BuiltIn PointSize\n"
408 			"OpMemberDecorate %27 2 BuiltIn ClipDistance\n"
409 			"OpMemberDecorate %27 3 BuiltIn CullDistance\n"
410 			"OpDecorate %27 Block\n"
411 			"%2 = OpTypeVoid\n"
412 			"%3 = OpTypeFunction %2\n"
413 			"%6 = OpTypeFloat 32\n"
414 			"%7 = OpTypeVector %6 2\n"
415 			"%8 = OpTypePointer Function %7\n"
416 			"%10 = OpTypeInt 32 1\n"
417 			"%11 = OpTypePointer Input %10\n"
418 			"%12 = OpVariable %11 Input\n"
419 			"%14 = OpConstant %10 1\n"
420 			"%16 = OpConstant %10 2\n"
421 			"%23 = OpTypeVector %6 4\n"
422 			"%24 = OpTypeInt 32 0\n"
423 			"%25 = OpConstant %24 1\n"
424 			"%26 = OpTypeArray %6 %25\n"
425 			"%27 = OpTypeStruct %23 %6 %26 %26\n"
426 			"%28 = OpTypePointer Output %27\n"
427 			"%29 = OpVariable %28 Output\n"
428 			"%30 = OpConstant %10 0\n"
429 			"%32 = OpConstant %6 2\n"
430 			"%34 = OpConstant %6 -1\n"
431 			"%37 = OpConstant %6 0\n"
432 			"%38 = OpConstant %6 1\n"
433 			"%42 = OpTypePointer Output %23\n"
434 			"%44 = OpTypePointer Output %6\n"
435 			"%4 = OpFunction %2 None %3\n"
436 			"%5 = OpLabel\n"
437 			"%9 = OpVariable %8 Function\n"
438 			"%13 = OpLoad %10 %12\n"
439 			"%15 = OpShiftLeftLogical %10 %13 %14\n"
440 			"%17 = OpBitwiseAnd %10 %15 %16\n"
441 			"%18 = OpConvertSToF %6 %17\n"
442 			"%19 = OpLoad %10 %12\n"
443 			"%20 = OpBitwiseAnd %10 %19 %16\n"
444 			"%21 = OpConvertSToF %6 %20\n"
445 			"%22 = OpCompositeConstruct %7 %18 %21\n"
446 			"OpStore %9 %22\n"
447 			"%31 = OpLoad %7 %9\n"
448 			"%33 = OpVectorTimesScalar %7 %31 %32\n"
449 			"%35 = OpCompositeConstruct %7 %34 %34\n"
450 			"%36 = OpFAdd %7 %33 %35\n"
451 			"%39 = OpCompositeExtract %6 %36 0\n"
452 			"%40 = OpCompositeExtract %6 %36 1\n"
453 			"%41 = OpCompositeConstruct %23 %39 %40 %37 %38\n"
454 			"%43 = OpAccessChain %42 %29 %30\n"
455 			"OpStore %43 %41\n"
456 			"%45 = OpAccessChain %44 %29 %14\n"
457 			"OpStore %45 %38\n"
458 			"OpReturn\n"
459 			"OpFunctionEnd\n";
460 
461 		programCollection.spirvAsmSources.add("vert") << vertex;
462 	}
463 	else if (VK_SHADER_STAGE_VERTEX_BIT != caseDef.shaderStage)
464 	{
465 		subgroups::setVertexShaderFrameBuffer(programCollection);
466 	}
467 
468 	if (OPTYPE_ELECT == caseDef.opType)
469 	{
470 		ostringstream electedValue ;
471 		ostringstream unelectedValue;
472 
473 		electedValue << ELECTED_VALUE;
474 		unelectedValue << UNELECTED_VALUE;
475 
476 		if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
477 		{
478 			/*
479 				"#extension GL_KHR_shader_subgroup_basic: enable\n"
480 				"layout(location = 0) out vec4 out_color;\n"
481 				"layout(location = 0) in highp vec4 in_position;\n"
482 				"\n"
483 				"void main (void)\n"
484 				"{\n"
485 				"  if (subgroupElect())\n"
486 				"  {\n"
487 				"    out_color.r = " << ELECTED_VALUE << ";\n"
488 				"    out_color.g = 1.0f;\n"
489 				"  }\n"
490 				"  else\n"
491 				"  {\n"
492 				"    out_color.r = " << UNELECTED_VALUE << ";\n"
493 				"    out_color.g = 0.0f;\n"
494 				"  }\n"
495 				"  gl_Position = in_position;\n"
496 				"  gl_PointSize = 1.0f;\n"
497 				"}\n";
498 			*/
499 			const string vertex =
500 				"; SPIR-V\n"
501 				"; Version: 1.3\n"
502 				"; Generator: Khronos Glslang Reference Front End; 2\n"
503 				"; Bound: 38\n"
504 				"; Schema: 0\n"
505 				"OpCapability Shader\n"
506 				"OpCapability GroupNonUniform\n"
507 				"%1 = OpExtInstImport \"GLSL.std.450\"\n"
508 				"OpMemoryModel Logical GLSL450\n"
509 				"OpEntryPoint Vertex %4 \"main\" %15 %31 %35\n"
510 				"OpDecorate %15 Location 0\n"
511 				"OpMemberDecorate %29 0 BuiltIn Position\n"
512 				"OpMemberDecorate %29 1 BuiltIn PointSize\n"
513 				"OpMemberDecorate %29 2 BuiltIn ClipDistance\n"
514 				"OpMemberDecorate %29 3 BuiltIn CullDistance\n"
515 				"OpDecorate %29 Block\n"
516 				"OpDecorate %35 Location 0\n"
517 				"%2 = OpTypeVoid\n"
518 				"%3 = OpTypeFunction %2\n"
519 				"%6 = OpTypeBool\n"
520 				"%7 = OpTypeInt 32 0\n"
521 				"%8 = OpConstant %7 3\n"
522 				"%12 = OpTypeFloat 32\n"
523 				"%13 = OpTypeVector %12 4\n"
524 				"%14 = OpTypePointer Output %13\n"
525 				"%15 = OpVariable %14 Output\n"
526 				"%16 = OpConstant %12 " + electedValue.str() + "\n"
527 				"%17 = OpConstant %7 0\n"
528 				"%18 = OpTypePointer Output %12\n"
529 				"%20 = OpConstant %12 1\n"
530 				"%21 = OpConstant %7 1\n"
531 				"%24 = OpConstant %12 " + unelectedValue.str() + "\n"
532 				"%26 = OpConstant %12 0\n"
533 				"%28 = OpTypeArray %12 %21\n"
534 				"%29 = OpTypeStruct %13 %12 %28 %28\n"
535 				"%30 = OpTypePointer Output %29\n"
536 				"%31 = OpVariable %30 Output\n"
537 				"%32 = OpTypeInt 32 1\n"
538 				"%33 = OpConstant %32 0\n"
539 				"%34 = OpTypePointer Input %13\n"
540 				"%35 = OpVariable %34 Input\n"
541 				"%38 = OpConstant %32 1\n"
542 				"%4 = OpFunction %2 None %3\n"
543 				"%5 = OpLabel\n"
544 				"%9 = OpGroupNonUniformElect %6 %8\n"
545 				"OpSelectionMerge %11 None\n"
546 				"OpBranchConditional %9 %10 %23\n"
547 				"%10 = OpLabel\n"
548 				"%19 = OpAccessChain %18 %15 %17\n"
549 				"OpStore %19 %16\n"
550 				"%22 = OpAccessChain %18 %15 %21\n"
551 				"OpStore %22 %20\n"
552 				"OpBranch %11\n"
553 				"%23 = OpLabel\n"
554 				"%25 = OpAccessChain %18 %15 %17\n"
555 				"OpStore %25 %24\n"
556 				"%27 = OpAccessChain %18 %15 %21\n"
557 				"OpStore %27 %26\n"
558 				"OpBranch %11\n"
559 				"%11 = OpLabel\n"
560 				"%36 = OpLoad %13 %35\n"
561 				"%37 = OpAccessChain %14 %31 %33\n"
562 				"OpStore %37 %36\n"
563 				"%39 = OpAccessChain %18 %31 %38\n"
564 				"OpStore %39 %20\n"
565 				"OpReturn\n"
566 				"OpFunctionEnd\n";
567 
568 			programCollection.spirvAsmSources.add("vert") << vertex << buildOptionsSpr;
569 		}
570 		else if (VK_SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
571 		{
572 			/*
573 				"#version 450\n"
574 				"#extension GL_KHR_shader_subgroup_basic: enable\n"
575 				"layout(points) in;\n"
576 				"layout(points, max_vertices = 1) out;\n"
577 				"layout(location = 0) out vec4 out_color;\n"
578 				"void main (void)\n"
579 				"{\n"
580 				"  if (subgroupElect())\n"
581 				"  {\n"
582 				"    out_color.r = " << ELECTED_VALUE << ";\n"
583 				"    out_color.g = 1.0f;\n"
584 				"  }\n"
585 				"  else\n"
586 				"  {\n"
587 				"    out_color.r = " << UNELECTED_VALUE << ";\n"
588 				"    out_color.g = 0.0f;\n"
589 				"  }\n"
590 				"  gl_Position = gl_in[0].gl_Position;\n"
591 				"  gl_PointSize = gl_in[0].gl_PointSize;\n"
592 				"  EmitVertex();\n"
593 				"  EndPrimitive();\n"
594 				"}\n";
595 			*/
596 			ostringstream geometry;
597 
598 			geometry
599 				<< "; SPIR-V\n"
600 				<< "; Version: 1.3\n"
601 				<< "; Generator: Khronos Glslang Reference Front End; 2\n"
602 				<< "; Bound: 42\n"
603 				<< "; Schema: 0\n"
604 				<< "OpCapability Geometry\n"
605 				<< (*caseDef.geometryPointSizeSupported ?
606 					"OpCapability GeometryPointSize\n" : "")
607 				<< "OpCapability GroupNonUniform\n"
608 				<< "%1 = OpExtInstImport \"GLSL.std.450\"\n"
609 				<< "OpMemoryModel Logical GLSL450\n"
610 				<< "OpEntryPoint Geometry %4 \"main\" %15 %31 %37\n"
611 				<< "OpExecutionMode %4 InputPoints\n"
612 				<< "OpExecutionMode %4 Invocations 1\n"
613 				<< "OpExecutionMode %4 OutputPoints\n"
614 				<< "OpExecutionMode %4 OutputVertices 1\n"
615 				<< "OpDecorate %15 Location 0\n"
616 				<< "OpMemberDecorate %29 0 BuiltIn Position\n"
617 				<< "OpMemberDecorate %29 1 BuiltIn PointSize\n"
618 				<< "OpMemberDecorate %29 2 BuiltIn ClipDistance\n"
619 				<< "OpMemberDecorate %29 3 BuiltIn CullDistance\n"
620 				<< "OpDecorate %29 Block\n"
621 				<< "OpMemberDecorate %34 0 BuiltIn Position\n"
622 				<< "OpMemberDecorate %34 1 BuiltIn PointSize\n"
623 				<< "OpMemberDecorate %34 2 BuiltIn ClipDistance\n"
624 				<< "OpMemberDecorate %34 3 BuiltIn CullDistance\n"
625 				<< "OpDecorate %34 Block\n"
626 				<< "%2 = OpTypeVoid\n"
627 				<< "%3 = OpTypeFunction %2\n"
628 				<< "%6 = OpTypeBool\n"
629 				<< "%7 = OpTypeInt 32 0\n"
630 				<< "%8 = OpConstant %7 3\n"
631 				<< "%12 = OpTypeFloat 32\n"
632 				<< "%13 = OpTypeVector %12 4\n"
633 				<< "%14 = OpTypePointer Output %13\n"
634 				<< "%15 = OpVariable %14 Output\n"
635 				<< "%16 = OpConstant %12 " << electedValue.str() << "\n"
636 				<< "%17 = OpConstant %7 0\n"
637 				<< "%18 = OpTypePointer Output %12\n"
638 				<< "%20 = OpConstant %12 1\n"
639 				<< "%21 = OpConstant %7 1\n"
640 				<< "%24 = OpConstant %12 " << unelectedValue.str() << "\n"
641 				<< "%26 = OpConstant %12 0\n"
642 				<< "%28 = OpTypeArray %12 %21\n"
643 				<< "%29 = OpTypeStruct %13 %12 %28 %28\n"
644 				<< "%30 = OpTypePointer Output %29\n"
645 				<< "%31 = OpVariable %30 Output\n"
646 				<< "%32 = OpTypeInt 32 1\n"
647 				<< "%33 = OpConstant %32 0\n"
648 				<< "%34 = OpTypeStruct %13 %12 %28 %28\n"
649 				<< "%35 = OpTypeArray %34 %21\n"
650 				<< "%36 = OpTypePointer Input %35\n"
651 				<< "%37 = OpVariable %36 Input\n"
652 				<< "%38 = OpTypePointer Input %13\n"
653 				<< (*caseDef.geometryPointSizeSupported ?
654 					"%42 = OpConstant %32 1\n"
655 					"%43 = OpTypePointer Input %12\n"
656 					"%44 = OpTypePointer Output %12\n" : "")
657 				<< "%4 = OpFunction %2 None %3\n"
658 				<< "%5 = OpLabel\n"
659 				<< "%9 = OpGroupNonUniformElect %6 %8\n"
660 				<< "OpSelectionMerge %11 None\n"
661 				<< "OpBranchConditional %9 %10 %23\n"
662 				<< "%10 = OpLabel\n"
663 				<< "%19 = OpAccessChain %18 %15 %17\n"
664 				<< "OpStore %19 %16\n"
665 				<< "%22 = OpAccessChain %18 %15 %21\n"
666 				<< "OpStore %22 %20\n"
667 				<< "OpBranch %11\n"
668 				<< "%23 = OpLabel\n"
669 				<< "%25 = OpAccessChain %18 %15 %17\n"
670 				<< "OpStore %25 %24\n"
671 				<< "%27 = OpAccessChain %18 %15 %21\n"
672 				<< "OpStore %27 %26\n"
673 				<< "OpBranch %11\n"
674 				<< "%11 = OpLabel\n"
675 				<< "%39 = OpAccessChain %38 %37 %33 %33\n"
676 				<< "%40 = OpLoad %13 %39\n"
677 				<< "%41 = OpAccessChain %14 %31 %33\n"
678 				<< "OpStore %41 %40\n"
679 				<< (*caseDef.geometryPointSizeSupported ?
680 					"%45 = OpAccessChain %43 %37 %33 %42\n"
681 					"%46 = OpLoad %12 %45\n"
682 					"%47 = OpAccessChain %44 %31 %42\n"
683 					"OpStore %47 %46\n" : "" )
684 				<< "OpEmitVertex\n"
685 				<< "OpEndPrimitive\n"
686 				<< "OpReturn\n"
687 				<< "OpFunctionEnd\n";
688 
689 			programCollection.spirvAsmSources.add("geometry") << geometry.str() << buildOptionsSpr;
690 		}
691 		else if (VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT == caseDef.shaderStage)
692 		{
693 			/*
694 				<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
695 				<< "#extension GL_EXT_tessellation_shader : require\n"
696 				<< "layout(vertices = 2) out;\n"
697 				<< "void main (void)\n"
698 				<< "{\n"
699 				<< "  if (gl_InvocationID == 0)\n"
700 				<< "  {\n"
701 				<< "    gl_TessLevelOuter[0] = 1.0f;\n"
702 				<< "    gl_TessLevelOuter[1] = 1.0f;\n"
703 				<< "  }\n"
704 				<< "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
705 				<< "}\n";
706 			*/
707 			const string controlSource =
708 				"; SPIR-V\n"
709 				"; Version: 1.3\n"
710 				"; Generator: Khronos Glslang Reference Front End; 2\n"
711 				"; Bound: 46\n"
712 				"; Schema: 0\n"
713 				"OpCapability Tessellation\n"
714 				"%1 = OpExtInstImport \"GLSL.std.450\"\n"
715 				"OpMemoryModel Logical GLSL450\n"
716 				"OpEntryPoint TessellationControl %4 \"main\" %8 %20 %33 %39\n"
717 				"OpExecutionMode %4 OutputVertices 2\n"
718 				"OpDecorate %8 BuiltIn InvocationId\n"
719 				"OpDecorate %20 Patch\n"
720 				"OpDecorate %20 BuiltIn TessLevelOuter\n"
721 				"OpMemberDecorate %29 0 BuiltIn Position\n"
722 				"OpMemberDecorate %29 1 BuiltIn PointSize\n"
723 				"OpMemberDecorate %29 2 BuiltIn ClipDistance\n"
724 				"OpMemberDecorate %29 3 BuiltIn CullDistance\n"
725 				"OpDecorate %29 Block\n"
726 				"OpMemberDecorate %35 0 BuiltIn Position\n"
727 				"OpMemberDecorate %35 1 BuiltIn PointSize\n"
728 				"OpMemberDecorate %35 2 BuiltIn ClipDistance\n"
729 				"OpMemberDecorate %35 3 BuiltIn CullDistance\n"
730 				"OpDecorate %35 Block\n"
731 				"%2 = OpTypeVoid\n"
732 				"%3 = OpTypeFunction %2\n"
733 				"%6 = OpTypeInt 32 1\n"
734 				"%7 = OpTypePointer Input %6\n"
735 				"%8 = OpVariable %7 Input\n"
736 				"%10 = OpConstant %6 0\n"
737 				"%11 = OpTypeBool\n"
738 				"%15 = OpTypeFloat 32\n"
739 				"%16 = OpTypeInt 32 0\n"
740 				"%17 = OpConstant %16 4\n"
741 				"%18 = OpTypeArray %15 %17\n"
742 				"%19 = OpTypePointer Output %18\n"
743 				"%20 = OpVariable %19 Output\n"
744 				"%21 = OpConstant %15 1\n"
745 				"%22 = OpTypePointer Output %15\n"
746 				"%24 = OpConstant %6 1\n"
747 				"%26 = OpTypeVector %15 4\n"
748 				"%27 = OpConstant %16 1\n"
749 				"%28 = OpTypeArray %15 %27\n"
750 				"%29 = OpTypeStruct %26 %15 %28 %28\n"
751 				"%30 = OpConstant %16 2\n"
752 				"%31 = OpTypeArray %29 %30\n"
753 				"%32 = OpTypePointer Output %31\n"
754 				"%33 = OpVariable %32 Output\n"
755 				"%35 = OpTypeStruct %26 %15 %28 %28\n"
756 				"%36 = OpConstant %16 32\n"
757 				"%37 = OpTypeArray %35 %36\n"
758 				"%38 = OpTypePointer Input %37\n"
759 				"%39 = OpVariable %38 Input\n"
760 				"%41 = OpTypePointer Input %26\n"
761 				"%44 = OpTypePointer Output %26\n"
762 				"%4 = OpFunction %2 None %3\n"
763 				"%5 = OpLabel\n"
764 				"%9 = OpLoad %6 %8\n"
765 				"%12 = OpIEqual %11 %9 %10\n"
766 				"OpSelectionMerge %14 None\n"
767 				"OpBranchConditional %12 %13 %14\n"
768 				"%13 = OpLabel\n"
769 				"%23 = OpAccessChain %22 %20 %10\n"
770 				"OpStore %23 %21\n"
771 				"%25 = OpAccessChain %22 %20 %24\n"
772 				"OpStore %25 %21\n"
773 				"OpBranch %14\n"
774 				"%14 = OpLabel\n"
775 				"%34 = OpLoad %6 %8\n"
776 				"%40 = OpLoad %6 %8\n"
777 				"%42 = OpAccessChain %41 %39 %40 %10\n"
778 				"%43 = OpLoad %26 %42\n"
779 				"%45 = OpAccessChain %44 %33 %34 %10\n"
780 				"OpStore %45 %43\n"
781 				"OpReturn\n"
782 				"OpFunctionEnd\n";
783 
784 			programCollection.spirvAsmSources.add("tesc") << controlSource << buildOptionsSpr;
785 
786 			/*
787 				"#extension GL_KHR_shader_subgroup_basic: enable\n"
788 				"#extension GL_EXT_tessellation_shader : require\n"
789 				"layout(isolines, equal_spacing, ccw ) in;\n"
790 				"layout(location = 0) out vec4 out_color;\n"
791 				"\n"
792 				"void main (void)\n"
793 				"{\n"
794 				"  if (subgroupElect())\n"
795 				"  {\n"
796 				"    out_color.r = " << 2 * ELECTED_VALUE - UNELECTED_VALUE << ";\n"
797 				"    out_color.g = 2.0f;\n"
798 				"  }\n"
799 				"  else\n"
800 				"  {\n"
801 				"    out_color.r = " << UNELECTED_VALUE << ";\n"
802 				"    out_color.g = 0.0f;\n"
803 				"  }\n"
804 				"  gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
805 				"}\n";
806 			*/
807 
808 			const string evaluationSource =
809 				"; SPIR-V\n"
810 				"; Version: 1.3\n"
811 				"; Generator: Khronos Glslang Reference Front End; 2\n"
812 				"; Bound: 54\n"
813 				"; Schema: 0\n"
814 				"OpCapability Tessellation\n"
815 				"OpCapability GroupNonUniform\n"
816 				"%1 = OpExtInstImport \"GLSL.std.450\"\n"
817 				"OpMemoryModel Logical GLSL450\n"
818 				"OpEntryPoint TessellationEvaluation %4 \"main\" %15 %31 %38 %47\n"
819 				"OpExecutionMode %4 Isolines\n"
820 				"OpExecutionMode %4 SpacingEqual\n"
821 				"OpExecutionMode %4 VertexOrderCcw\n"
822 				"OpDecorate %15 Location 0\n"
823 				"OpMemberDecorate %29 0 BuiltIn Position\n"
824 				"OpMemberDecorate %29 1 BuiltIn PointSize\n"
825 				"OpMemberDecorate %29 2 BuiltIn ClipDistance\n"
826 				"OpMemberDecorate %29 3 BuiltIn CullDistance\n"
827 				"OpDecorate %29 Block\n"
828 				"OpMemberDecorate %34 0 BuiltIn Position\n"
829 				"OpMemberDecorate %34 1 BuiltIn PointSize\n"
830 				"OpMemberDecorate %34 2 BuiltIn ClipDistance\n"
831 				"OpMemberDecorate %34 3 BuiltIn CullDistance\n"
832 				"OpDecorate %34 Block\n"
833 				"OpDecorate %47 BuiltIn TessCoord\n"
834 				"%2 = OpTypeVoid\n"
835 				"%3 = OpTypeFunction %2\n"
836 				"%6 = OpTypeBool\n"
837 				"%7 = OpTypeInt 32 0\n"
838 				"%8 = OpConstant %7 3\n"
839 				"%12 = OpTypeFloat 32\n"
840 				"%13 = OpTypeVector %12 4\n"
841 				"%14 = OpTypePointer Output %13\n"
842 				"%15 = OpVariable %14 Output\n"
843 				"%16 = OpConstant %12 71\n"//electedValue
844 				"%17 = OpConstant %7 0\n"
845 				"%18 = OpTypePointer Output %12\n"
846 				"%20 = OpConstant %12 2\n"
847 				"%21 = OpConstant %7 1\n"
848 				"%24 = OpConstant %12 " + unelectedValue.str() + "\n"
849 				"%26 = OpConstant %12 0\n"
850 				"%28 = OpTypeArray %12 %21\n"
851 				"%29 = OpTypeStruct %13 %12 %28 %28\n"
852 				"%30 = OpTypePointer Output %29\n"
853 				"%31 = OpVariable %30 Output\n"
854 				"%32 = OpTypeInt 32 1\n"
855 				"%33 = OpConstant %32 0\n"
856 				"%34 = OpTypeStruct %13 %12 %28 %28\n"
857 				"%35 = OpConstant %7 32\n"
858 				"%36 = OpTypeArray %34 %35\n"
859 				"%37 = OpTypePointer Input %36\n"
860 				"%38 = OpVariable %37 Input\n"
861 				"%39 = OpTypePointer Input %13\n"
862 				"%42 = OpConstant %32 1\n"
863 				"%45 = OpTypeVector %12 3\n"
864 				"%46 = OpTypePointer Input %45\n"
865 				"%47 = OpVariable %46 Input\n"
866 				"%48 = OpTypePointer Input %12\n"
867 				"%4 = OpFunction %2 None %3\n"
868 				"%5 = OpLabel\n"
869 				"%9 = OpGroupNonUniformElect %6 %8\n"
870 				"OpSelectionMerge %11 None\n"
871 				"OpBranchConditional %9 %10 %23\n"
872 				"%10 = OpLabel\n"
873 				"%19 = OpAccessChain %18 %15 %17\n"
874 				"OpStore %19 %16\n"
875 				"%22 = OpAccessChain %18 %15 %21\n"
876 				"OpStore %22 %20\n"
877 				"OpBranch %11\n"
878 				"%23 = OpLabel\n"
879 				"%25 = OpAccessChain %18 %15 %17\n"
880 				"OpStore %25 %24\n"
881 				"%27 = OpAccessChain %18 %15 %21\n"
882 				"OpStore %27 %26\n"
883 				"OpBranch %11\n"
884 				"%11 = OpLabel\n"
885 				"%40 = OpAccessChain %39 %38 %33 %33\n"
886 				"%41 = OpLoad %13 %40\n"
887 				"%43 = OpAccessChain %39 %38 %42 %33\n"
888 				"%44 = OpLoad %13 %43\n"
889 				"%49 = OpAccessChain %48 %47 %17\n"
890 				"%50 = OpLoad %12 %49\n"
891 				"%51 = OpCompositeConstruct %13 %50 %50 %50 %50\n"
892 				"%52 = OpExtInst %13 %1 FMix %41 %44 %51\n"
893 				"%53 = OpAccessChain %14 %31 %33\n"
894 				"OpStore %53 %52\n"
895 				"OpReturn\n"
896 				"OpFunctionEnd\n";
897 
898 			programCollection.spirvAsmSources.add("tese") << evaluationSource << buildOptionsSpr;
899 		}
900 		else if (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage)
901 		{
902 			/*
903 				"#extension GL_KHR_shader_subgroup_basic: enable\n"
904 				"#extension GL_EXT_tessellation_shader : require\n"
905 				"layout(vertices = 2) out;\n"
906 				"layout(location = 0) out vec4 out_color[];\n"
907 				"void main (void)\n"
908 				"{\n"
909 				"  if (gl_InvocationID == 0)\n"
910 				"  {\n"
911 				"    gl_TessLevelOuter[0] = 1.0f;\n"
912 				"    gl_TessLevelOuter[1] = 1.0f;\n"
913 				"  }\n"
914 				"  if (subgroupElect())\n"
915 				"  {\n"
916 				"    out_color[gl_InvocationID].r = " << ELECTED_VALUE << ";\n"
917 				"    out_color[gl_InvocationID].g = 1.0f;\n"
918 				"  }\n"
919 				"  else\n"
920 				"  {\n"
921 				"    out_color[gl_InvocationID].r = " << UNELECTED_VALUE << ";\n"
922 				"    out_color[gl_InvocationID].g = 0.0f;\n"
923 				"  }\n"
924 				"  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
925 				"}\n";
926 			*/
927 			const string  controlSource =
928 				"; SPIR-V\n"
929 				"; Version: 1.3\n"
930 				"; Generator: Khronos Glslang Reference Front End; 2\n"
931 				"; Bound: 66\n"
932 				"; Schema: 0\n"
933 				"OpCapability Tessellation\n"
934 				"OpCapability GroupNonUniform\n"
935 				"%1 = OpExtInstImport \"GLSL.std.450\"\n"
936 				"OpMemoryModel Logical GLSL450\n"
937 				"OpEntryPoint TessellationControl %4 \"main\" %8 %20 %34 %53 %59\n"
938 				"OpExecutionMode %4 OutputVertices 2\n"
939 				"OpDecorate %8 BuiltIn InvocationId\n"
940 				"OpDecorate %20 Patch\n"
941 				"OpDecorate %20 BuiltIn TessLevelOuter\n"
942 				"OpDecorate %34 Location 0\n"
943 				"OpMemberDecorate %50 0 BuiltIn Position\n"
944 				"OpMemberDecorate %50 1 BuiltIn PointSize\n"
945 				"OpMemberDecorate %50 2 BuiltIn ClipDistance\n"
946 				"OpMemberDecorate %50 3 BuiltIn CullDistance\n"
947 				"OpDecorate %50 Block\n"
948 				"OpMemberDecorate %55 0 BuiltIn Position\n"
949 				"OpMemberDecorate %55 1 BuiltIn PointSize\n"
950 				"OpMemberDecorate %55 2 BuiltIn ClipDistance\n"
951 				"OpMemberDecorate %55 3 BuiltIn CullDistance\n"
952 				"OpDecorate %55 Block\n"
953 				"%2 = OpTypeVoid\n"
954 				"%3 = OpTypeFunction %2\n"
955 				"%6 = OpTypeInt 32 1\n"
956 				"%7 = OpTypePointer Input %6\n"
957 				"%8 = OpVariable %7 Input\n"
958 				"%10 = OpConstant %6 0\n"
959 				"%11 = OpTypeBool\n"
960 				"%15 = OpTypeFloat 32\n"
961 				"%16 = OpTypeInt 32 0\n"
962 				"%17 = OpConstant %16 4\n"
963 				"%18 = OpTypeArray %15 %17\n"
964 				"%19 = OpTypePointer Output %18\n"
965 				"%20 = OpVariable %19 Output\n"
966 				"%21 = OpConstant %15 1\n"
967 				"%22 = OpTypePointer Output %15\n"
968 				"%24 = OpConstant %6 1\n"
969 				"%26 = OpConstant %16 3\n"
970 				"%30 = OpTypeVector %15 4\n"
971 				"%31 = OpConstant %16 2\n"
972 				"%32 = OpTypeArray %30 %31\n"
973 				"%33 = OpTypePointer Output %32\n"
974 				"%34 = OpVariable %33 Output\n"
975 				"%36 = OpConstant %15 " + electedValue.str() + "\n"
976 				"%37 = OpConstant %16 0\n"
977 				"%40 = OpConstant %16 1\n"
978 				"%44 = OpConstant %15 " + unelectedValue.str() + "\n"
979 				"%47 = OpConstant %15 0\n"
980 				"%49 = OpTypeArray %15 %40\n"
981 				"%50 = OpTypeStruct %30 %15 %49 %49\n"
982 				"%51 = OpTypeArray %50 %31\n"
983 				"%52 = OpTypePointer Output %51\n"
984 				"%53 = OpVariable %52 Output\n"
985 				"%55 = OpTypeStruct %30 %15 %49 %49\n"
986 				"%56 = OpConstant %16 32\n"
987 				"%57 = OpTypeArray %55 %56\n"
988 				"%58 = OpTypePointer Input %57\n"
989 				"%59 = OpVariable %58 Input\n"
990 				"%61 = OpTypePointer Input %30\n"
991 				"%64 = OpTypePointer Output %30\n"
992 				"%4 = OpFunction %2 None %3\n"
993 				"%5 = OpLabel\n"
994 				"%9 = OpLoad %6 %8\n"
995 				"%12 = OpIEqual %11 %9 %10\n"
996 				"OpSelectionMerge %14 None\n"
997 				"OpBranchConditional %12 %13 %14\n"
998 				"%13 = OpLabel\n"
999 				"%23 = OpAccessChain %22 %20 %10\n"
1000 				"OpStore %23 %21\n"
1001 				"%25 = OpAccessChain %22 %20 %24\n"
1002 				"OpStore %25 %21\n"
1003 				"OpBranch %14\n"
1004 				"%14 = OpLabel\n"
1005 				"%27 = OpGroupNonUniformElect %11 %26\n"
1006 				"OpSelectionMerge %29 None\n"
1007 				"OpBranchConditional %27 %28 %42\n"
1008 				"%28 = OpLabel\n"
1009 				"%35 = OpLoad %6 %8\n"
1010 				"%38 = OpAccessChain %22 %34 %35 %37\n"
1011 				"OpStore %38 %36\n"
1012 				"%39 = OpLoad %6 %8\n"
1013 				"%41 = OpAccessChain %22 %34 %39 %40\n"
1014 				"OpStore %41 %21\n"
1015 				"OpBranch %29\n"
1016 				"%42 = OpLabel\n"
1017 				"%43 = OpLoad %6 %8\n"
1018 				"%45 = OpAccessChain %22 %34 %43 %37\n"
1019 				"OpStore %45 %44\n"
1020 				"%46 = OpLoad %6 %8\n"
1021 				"%48 = OpAccessChain %22 %34 %46 %40\n"
1022 				"OpStore %48 %47\n"
1023 				"OpBranch %29\n"
1024 				"%29 = OpLabel\n"
1025 				"%54 = OpLoad %6 %8\n"
1026 				"%60 = OpLoad %6 %8\n"
1027 				"%62 = OpAccessChain %61 %59 %60 %10\n"
1028 				"%63 = OpLoad %30 %62\n"
1029 				"%65 = OpAccessChain %64 %53 %54 %10\n"
1030 				"OpStore %65 %63\n"
1031 				"OpReturn\n"
1032 				"OpFunctionEnd\n";
1033 
1034 			programCollection.spirvAsmSources.add("tesc") << controlSource << buildOptionsSpr;
1035 
1036 			/*
1037 				"#extension GL_KHR_shader_subgroup_ballot: enable\n"
1038 				"#extension GL_EXT_tessellation_shader : require\n"
1039 				"layout(isolines, equal_spacing, ccw ) in;\n"
1040 				"layout(location = 0) in vec4 in_color[];\n"
1041 				"layout(location = 0) out vec4 out_color;\n"
1042 				"\n"
1043 				"void main (void)\n"
1044 				"{\n"
1045 				"  gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
1046 				"  out_color = in_color[0];\n"
1047 				"}\n";
1048 			*/
1049 
1050 			const string evaluationSource =
1051 				"; SPIR-V\n"
1052 				"; Version: 1.3\n"
1053 				"; Generator: Khronos Glslang Reference Front End; 2\n"
1054 				"; Bound: 44\n"
1055 				"; Schema: 0\n"
1056 				"OpCapability Tessellation\n"
1057 				"%1 = OpExtInstImport \"GLSL.std.450\"\n"
1058 				"OpMemoryModel Logical GLSL450\n"
1059 				"OpEntryPoint TessellationEvaluation %4 \"main\" %13 %20 %29 %38 %41\n"
1060 				"OpExecutionMode %4 Isolines\n"
1061 				"OpExecutionMode %4 SpacingEqual\n"
1062 				"OpExecutionMode %4 VertexOrderCcw\n"
1063 				"OpMemberDecorate %11 0 BuiltIn Position\n"
1064 				"OpMemberDecorate %11 1 BuiltIn PointSize\n"
1065 				"OpMemberDecorate %11 2 BuiltIn ClipDistance\n"
1066 				"OpMemberDecorate %11 3 BuiltIn CullDistance\n"
1067 				"OpDecorate %11 Block\n"
1068 				"OpMemberDecorate %16 0 BuiltIn Position\n"
1069 				"OpMemberDecorate %16 1 BuiltIn PointSize\n"
1070 				"OpMemberDecorate %16 2 BuiltIn ClipDistance\n"
1071 				"OpMemberDecorate %16 3 BuiltIn CullDistance\n"
1072 				"OpDecorate %16 Block\n"
1073 				"OpDecorate %29 BuiltIn TessCoord\n"
1074 				"OpDecorate %38 Location 0\n"
1075 				"OpDecorate %41 Location 0\n"
1076 				"%2 = OpTypeVoid\n"
1077 				"%3 = OpTypeFunction %2\n"
1078 				"%6 = OpTypeFloat 32\n"
1079 				"%7 = OpTypeVector %6 4\n"
1080 				"%8 = OpTypeInt 32 0\n"
1081 				"%9 = OpConstant %8 1\n"
1082 				"%10 = OpTypeArray %6 %9\n"
1083 				"%11 = OpTypeStruct %7 %6 %10 %10\n"
1084 				"%12 = OpTypePointer Output %11\n"
1085 				"%13 = OpVariable %12 Output\n"
1086 				"%14 = OpTypeInt 32 1\n"
1087 				"%15 = OpConstant %14 0\n"
1088 				"%16 = OpTypeStruct %7 %6 %10 %10\n"
1089 				"%17 = OpConstant %8 32\n"
1090 				"%18 = OpTypeArray %16 %17\n"
1091 				"%19 = OpTypePointer Input %18\n"
1092 				"%20 = OpVariable %19 Input\n"
1093 				"%21 = OpTypePointer Input %7\n"
1094 				"%24 = OpConstant %14 1\n"
1095 				"%27 = OpTypeVector %6 3\n"
1096 				"%28 = OpTypePointer Input %27\n"
1097 				"%29 = OpVariable %28 Input\n"
1098 				"%30 = OpConstant %8 0\n"
1099 				"%31 = OpTypePointer Input %6\n"
1100 				"%36 = OpTypePointer Output %7\n"
1101 				"%38 = OpVariable %36 Output\n"
1102 				"%39 = OpTypeArray %7 %17\n"
1103 				"%40 = OpTypePointer Input %39\n"
1104 				"%41 = OpVariable %40 Input\n"
1105 				"%4 = OpFunction %2 None %3\n"
1106 				"%5 = OpLabel\n"
1107 				"%22 = OpAccessChain %21 %20 %15 %15\n"
1108 				"%23 = OpLoad %7 %22\n"
1109 				"%25 = OpAccessChain %21 %20 %24 %15\n"
1110 				"%26 = OpLoad %7 %25\n"
1111 				"%32 = OpAccessChain %31 %29 %30\n"
1112 				"%33 = OpLoad %6 %32\n"
1113 				"%34 = OpCompositeConstruct %7 %33 %33 %33 %33\n"
1114 				"%35 = OpExtInst %7 %1 FMix %23 %26 %34\n"
1115 				"%37 = OpAccessChain %36 %13 %15\n"
1116 				"OpStore %37 %35\n"
1117 				"%42 = OpAccessChain %21 %41 %15\n"
1118 				"%43 = OpLoad %7 %42\n"
1119 				"OpStore %38 %43\n"
1120 				"OpReturn\n"
1121 				"OpFunctionEnd\n";
1122 
1123 			programCollection.spirvAsmSources.add("tese") << evaluationSource << buildOptionsSpr;
1124 		}
1125 		else
1126 			TCU_THROW(InternalError, "Unsupported shader stage");
1127 	}
1128 	else
1129 	{
1130 		const string	color = (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage) ? "out_color[gl_InvocationID].b = 1.0f;\n" : "out_color.b = 1.0f;\n";
1131 		ostringstream	bdy;
1132 
1133 		switch (caseDef.opType)
1134 		{
1135 			case OPTYPE_SUBGROUP_BARRIER:
1136 			case OPTYPE_SUBGROUP_MEMORY_BARRIER:
1137 			case OPTYPE_SUBGROUP_MEMORY_BARRIER_BUFFER:
1138 			{
1139 				bdy << " tempResult2 = tempBuffer[id];\n"
1140 					<< "  if (subgroupElect())\n"
1141 					<< "  {\n"
1142 					<< "    tempResult = value;\n"
1143 					<< "    " << color
1144 					<< "  }\n"
1145 					 << "  else\n"
1146 					<< "  {\n"
1147 					<< "    tempResult = tempBuffer[id];\n"
1148 					<< "  }\n"
1149 					<< "  " << getOpTypeName(caseDef.opType) << "();\n";
1150 				break;
1151 			}
1152 
1153 			case OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE:
1154 				bdy <<"tempResult2 = imageLoad(tempImage, ivec2(id, 0)).x;\n"
1155 					<< "  if (subgroupElect())\n"
1156 					<< "  {\n"
1157 					<< "    tempResult = value;\n"
1158 					<< "     " << color
1159 					<< "  }\n"
1160 					<< "  else\n"
1161 					<< "  {\n"
1162 					<< "    tempResult = imageLoad(tempImage, ivec2(id, 0)).x;\n"
1163 					<< "  }\n"
1164 					<< "  subgroupMemoryBarrierImage();\n";
1165 				break;
1166 
1167 			default:
1168 				TCU_THROW(InternalError, "Unhandled op type");
1169 		}
1170 
1171 		if (VK_SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
1172 		{
1173 			ostringstream	fragment;
1174 
1175 			fragment	<< glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
1176 				<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
1177 				<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
1178 				<< "layout(location = 0) out vec4 out_color;\n"
1179 				<< "\n"
1180 				<< "layout(set = 0, binding = 0) uniform Buffer1\n"
1181 				<< "{\n"
1182 				<< "  uint tempBuffer["<<SHADER_BUFFER_SIZE/4ull<<"];\n"
1183 				<< "};\n"
1184 				<< "\n"
1185 				<< "layout(set = 0, binding = 1) uniform Buffer2\n"
1186 				<< "{\n"
1187 				<< "  uint value;\n"
1188 				<< "};\n"
1189 				<< (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? "layout(set = 0, binding = 2, r32ui) readonly uniform highp uimage2D tempImage;\n" : "\n")
1190 				<< "void main (void)\n"
1191 				<< "{\n"
1192 				<< "  if (gl_HelperInvocation) return;\n"
1193 				<< "  uint id = 0;\n"
1194 				<< "  if (subgroupElect())\n"
1195 				<< "  {\n"
1196 				<< "    id = uint(gl_FragCoord.x);\n"
1197 				<< "  }\n"
1198 				<< "  id = subgroupBroadcastFirst(id);\n"
1199 				<< "  uint localId = id;\n"
1200 				<< "  uint tempResult = 0u;\n"
1201 				<< "  uint tempResult2 = 0u;\n"
1202 				<< "  out_color.b = 0.0f;\n"
1203 				<< bdy.str()
1204 				<< "  out_color.r = float(tempResult);\n"
1205 				<< "  out_color.g = float(value);\n"
1206 				<< "  out_color.a = float(tempResult2);\n"
1207 				<< "}\n";
1208 
1209 			programCollection.glslSources.add("fragment") << glu::FragmentSource(fragment.str()) << buildOptions;
1210 		}
1211 		else if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
1212 		{
1213 			ostringstream	vertex;
1214 
1215 			vertex	<< glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
1216 				<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
1217 				<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
1218 				<<"\n"
1219 				<< "layout(location = 0) out vec4 out_color;\n"
1220 				<< "layout(location = 0) in highp vec4 in_position;\n"
1221 				<< "\n"
1222 				<< "layout(set = 0, binding = 0) uniform Buffer1\n"
1223 				<< "{\n"
1224 				<< "  uint tempBuffer["<<SHADER_BUFFER_SIZE/4ull<<"];\n"
1225 				<< "};\n"
1226 				<< "\n"
1227 				<< "layout(set = 0, binding = 1) uniform Buffer2\n"
1228 				<< "{\n"
1229 				<< "  uint value;\n"
1230 				<< "};\n"
1231 				<< (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? "layout(set = 0, binding = 2, r32ui) readonly uniform highp uimage2D tempImage;\n" : "\n")
1232 				<< "void main (void)\n"
1233 				<< "{\n"
1234 				<< "  uint id = 0;\n"
1235 				<< "  if (subgroupElect())\n"
1236 				<< "  {\n"
1237 				<< "    id = gl_VertexIndex;\n"
1238 				<< "  }\n"
1239 				<< "  id = subgroupBroadcastFirst(id);\n"
1240 				<< "  uint tempResult = 0u;\n"
1241 				<< "  uint tempResult2 = 0u;\n"
1242 				<< "  out_color.b = 0.0f;\n"
1243 				<< bdy.str()
1244 				<< "  out_color.r = float(tempResult);\n"
1245 				<< "  out_color.g = float(value);\n"
1246 				<< "  out_color.a = float(tempResult2);\n"
1247 				<< "  gl_Position = in_position;\n"
1248 				<< "  gl_PointSize = 1.0f;\n"
1249 				<< "}\n";
1250 
1251 			programCollection.glslSources.add("vert") << glu::VertexSource(vertex.str()) << buildOptions;
1252 		}
1253 		else if (VK_SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
1254 		{
1255 			ostringstream geometry;
1256 
1257 			geometry << "#version 450\n"
1258 					<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
1259 					<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
1260 					<< "layout(points) in;\n"
1261 					<< "layout(points, max_vertices = 1) out;\n"
1262 					<< "layout(location = 0) out vec4 out_color;\n"
1263 					<< "layout(set = 0, binding = 0) uniform Buffer1\n"
1264 					<< "{\n"
1265 					<< "  uint tempBuffer["<<SHADER_BUFFER_SIZE/4ull<<"];\n"
1266 					<< "};\n"
1267 					<< "\n"
1268 					<< "layout(set = 0, binding = 1) uniform Buffer2\n"
1269 					<< "{\n"
1270 					<< "  uint value;\n"
1271 					<< "};\n"
1272 					<< (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? "layout(set = 0, binding = 2, r32ui) readonly uniform highp uimage2D tempImage;\n" : "\n")
1273 					<< "void main (void)\n"
1274 					<< "{\n"
1275 					<< "  uint id = 0;\n"
1276 					<< "  if (subgroupElect())\n"
1277 					<< "  {\n"
1278 					<< "    id = gl_InvocationID;\n"
1279 					<< "  }\n"
1280 					<< "  id = subgroupBroadcastFirst(id);\n"
1281 					<< "  uint tempResult = 0u;\n"
1282 					<< "  uint tempResult2 = 0u;\n"
1283 					<< "  out_color.b = 0.0f;\n"
1284 					<< bdy.str()
1285 					<< "  out_color.r = float(tempResult);\n"
1286 					<< "  out_color.g = float(value);\n"
1287 					<< "  out_color.a = float(tempResult2);\n"
1288 					<< "  gl_Position = gl_in[0].gl_Position;\n"
1289 					<< (*caseDef.geometryPointSizeSupported ? "  gl_PointSize = gl_in[0].gl_PointSize;\n" : "" )
1290 					<< "  EmitVertex();\n"
1291 					<< "  EndPrimitive();\n"
1292 					<< "}\n";
1293 
1294 			programCollection.glslSources.add("geometry") << glu::GeometrySource(geometry.str()) << buildOptions;
1295 		}
1296 		else if (VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT == caseDef.shaderStage)
1297 		{
1298 			ostringstream controlSource;
1299 			ostringstream evaluationSource;
1300 
1301 			controlSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
1302 				<< "#extension GL_EXT_tessellation_shader : require\n"
1303 				<< "layout(vertices = 2) out;\n"
1304 				<< "void main (void)\n"
1305 				<< "{\n"
1306 				<< "  if (gl_InvocationID == 0)\n"
1307 				<<"  {\n"
1308 				<< "    gl_TessLevelOuter[0] = 1.0f;\n"
1309 				<< "    gl_TessLevelOuter[1] = 1.0f;\n"
1310 				<< "  }\n"
1311 				<< "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
1312 				<< (*caseDef.geometryPointSizeSupported ? "  gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n" : "" )
1313 				<< "}\n";
1314 
1315 			evaluationSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
1316 				<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
1317 				<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
1318 				<< "#extension GL_EXT_tessellation_shader : require\n"
1319 				<< "layout(isolines, equal_spacing, ccw ) in;\n"
1320 				<< "layout(location = 0) out vec4 out_color;\n"
1321 				<< "layout(set = 0, binding = 0) uniform Buffer1\n"
1322 				<< "{\n"
1323 				<< "  uint tempBuffer["<<SHADER_BUFFER_SIZE/4ull<<"];\n"
1324 				<< "};\n"
1325 				<< "\n"
1326 				<< "layout(set = 0, binding = 1) uniform Buffer2\n"
1327 				<< "{\n"
1328 				<< "  uint value;\n"
1329 				<< "};\n"
1330 				<< (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? "layout(set = 0, binding = 2, r32ui) readonly uniform highp uimage2D tempImage;\n" : "\n")
1331 				<< "void main (void)\n"
1332 				<< "{\n"
1333 				<< "  uint id = 0;\n"
1334 				<< "  if (subgroupElect())\n"
1335 				<< "  {\n"
1336 				<< "    id = gl_PrimitiveID;\n"
1337 				<< "  }\n"
1338 				<< "  id = subgroupBroadcastFirst(id);\n"
1339 				<< "  uint tempResult = 0u;\n"
1340 				<< "  uint tempResult2 = 0u;\n"
1341 				<< "  out_color.b = 0.0f;\n"
1342 				<< bdy.str()
1343 				<< "  out_color.r = float(tempResult);\n"
1344 				<< "  out_color.g = float(value);\n"
1345 				<< "  out_color.a = float(tempResult2);\n"
1346 				<< "  gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
1347 				<< (*caseDef.geometryPointSizeSupported ? "  gl_PointSize = gl_in[0].gl_PointSize;\n" : "" )
1348 				<< "}\n";
1349 
1350 			programCollection.glslSources.add("tesc") << glu::TessellationControlSource(controlSource.str()) << buildOptions;
1351 			programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(evaluationSource.str()) << buildOptions;
1352 		}
1353 		else if (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage)
1354 		{
1355 			ostringstream controlSource;
1356 			ostringstream evaluationSource;
1357 
1358 			controlSource  << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
1359 				<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
1360 				<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
1361 				<< "#extension GL_EXT_tessellation_shader : require\n"
1362 				<< "layout(vertices = 2) out;\n"
1363 				<< "layout(location = 0) out vec4 out_color[];\n"
1364 				<< "layout(set = 0, binding = 0) uniform Buffer1\n"
1365 				<< "{\n"
1366 				<< "  uint tempBuffer["<<SHADER_BUFFER_SIZE/4ull<<"];\n"
1367 				<< "};\n"
1368 				<< "\n"
1369 				<< "layout(set = 0, binding = 1) uniform Buffer2\n"
1370 				<< "{\n"
1371 				<< "  uint value;\n"
1372 				<< "};\n"
1373 				<< (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? "layout(set = 0, binding = 2, r32ui) readonly uniform highp uimage2D tempImage;\n" : "\n")
1374 				<< "void main (void)\n"
1375 				<< "{\n"
1376 				<< "  uint id = 0;\n"
1377 				<< "  if (gl_InvocationID == 0)\n"
1378 				<<"  {\n"
1379 				<< "    gl_TessLevelOuter[0] = 1.0f;\n"
1380 				<< "    gl_TessLevelOuter[1] = 1.0f;\n"
1381 				<< "  }\n"
1382 				<< "  if (subgroupElect())\n"
1383 				<< "  {\n"
1384 				<< "    id = gl_InvocationID;\n"
1385 				<< "  }\n"
1386 				<< "  id = subgroupBroadcastFirst(id);\n"
1387 				<< "  uint tempResult = 0u;\n"
1388 				<< "  uint tempResult2 = 0u;\n"
1389 				<< "  out_color[gl_InvocationID].b = 0.0f;\n"
1390 				<< bdy.str()
1391 				<< "  out_color[gl_InvocationID].r = float(tempResult);\n"
1392 				<< "  out_color[gl_InvocationID].g = float(value);\n"
1393 				<< "  out_color[gl_InvocationID].a = float(tempResult2);\n"
1394 				<< "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
1395 				<< (*caseDef.geometryPointSizeSupported ? "  gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n" : "" )
1396 				<< "}\n";
1397 
1398 			evaluationSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
1399 				<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
1400 				<< "#extension GL_EXT_tessellation_shader : require\n"
1401 				<< "layout(isolines, equal_spacing, ccw ) in;\n"
1402 				<< "layout(location = 0) in vec4 in_color[];\n"
1403 				<< "layout(location = 0) out vec4 out_color;\n"
1404 				<< "\n"
1405 				<< "void main (void)\n"
1406 				<< "{\n"
1407 				<< "  gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
1408 				<< (*caseDef.geometryPointSizeSupported ? "  gl_PointSize = gl_in[0].gl_PointSize;\n" : "" )
1409 				<< "  out_color = in_color[0];\n"
1410 				<< "}\n";
1411 
1412 			programCollection.glslSources.add("tesc") << glu::TessellationControlSource(controlSource.str()) << buildOptions;
1413 			programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(evaluationSource.str()) << buildOptions;
1414 		}
1415 		else
1416 			TCU_THROW(InternalError, "Unsupported shader stage");
1417 	}
1418 }
1419 
getPerStageHeadDeclarations(const CaseDefinition & caseDef)1420 vector<string> getPerStageHeadDeclarations (const CaseDefinition& caseDef)
1421 {
1422 	const deUint32	stageCount	= subgroups::getStagesCount(caseDef.shaderStage);
1423 	const bool		fragment	= (caseDef.shaderStage & VK_SHADER_STAGE_FRAGMENT_BIT) != 0;
1424 	vector<string>	result		(stageCount, string());
1425 
1426 	if (fragment)
1427 		result.resize(result.size() + 1);
1428 
1429 	if (caseDef.opType == OPTYPE_ELECT)
1430 	{
1431 		for (size_t i = 0; i < result.size(); ++i)
1432 		{
1433 			const bool		frag		= (i == stageCount);
1434 			const size_t	binding1	= i;
1435 			const size_t	binding2	= stageCount + i;
1436 
1437 			if (frag)
1438 			{
1439 				result[i] += "layout(location = 0) out uint result;\n";
1440 			}
1441 			else
1442 			{
1443 				result[i] +=
1444 					"layout(set = 0, binding = " + de::toString(binding1) + ", std430) buffer Buffer1\n"
1445 					"{\n"
1446 					"  uint result[];\n"
1447 					"};\n";
1448 			}
1449 
1450 			result[i] +=
1451 				"layout(set = 0, binding = " + de::toString(binding2) + ", std430) buffer Buffer2\n"
1452 				"{\n"
1453 				"  uint numSubgroupsExecuted;\n"
1454 				"};\n";
1455 		}
1456 	}
1457 	else
1458 	{
1459 		for (size_t i = 0; i < result.size(); ++i)
1460 		{
1461 			const bool		frag		= (i == stageCount);
1462 			const size_t	binding1	= i;
1463 			const size_t	binding2	= stageCount + 4 * i;
1464 			const size_t	binding3	= stageCount + 4 * i + 1;
1465 			const size_t	binding4	= stageCount + 4 * i + 2;
1466 			const size_t	binding5	= stageCount + 4 * i + 3;
1467 
1468 			if (frag)
1469 			{
1470 				result[i] = "layout(location = 0) out uint result;\n";
1471 			}
1472 			else
1473 			{
1474 				result[i] +=
1475 					"layout(set = 0, binding = " + de::toString(binding1) + ", std430) buffer Buffer1\n"
1476 					"{\n"
1477 					"  uint result[];\n"
1478 					"};\n";
1479 			}
1480 
1481 			result[i] +=
1482 				"layout(set = 0, binding = " + de::toString(binding2) + ", std430) buffer Buffer2\n"
1483 				"{\n"
1484 				"  uint tempBuffer[];\n"
1485 				"};\n"
1486 				"layout(set = 0, binding = " + de::toString(binding3) + ", std430) buffer Buffer3\n"
1487 				"{\n"
1488 				"  uint subgroupID;\n"
1489 				"};\n"
1490 				"layout(set = 0, binding = " + de::toString(binding4) + ", std430) buffer Buffer4\n"
1491 				"{\n"
1492 				"  uint value;\n"
1493 				"};\n"
1494 				"layout(set = 0, binding = " + de::toString(binding5) + ", r32ui) uniform uimage2D tempImage;\n";
1495 		}
1496 	}
1497 
1498 	return result;
1499 }
1500 
getTestString(const CaseDefinition & caseDef)1501 string getTestString (const CaseDefinition& caseDef)
1502 {
1503 	stringstream	body;
1504 
1505 #ifndef CTS_USES_VULKANSC
1506 	if (caseDef.opType != OPTYPE_ELECT && (isAllGraphicsStages(caseDef.shaderStage) || isAllRayTracingStages(caseDef.shaderStage)))
1507 #else
1508 	if (caseDef.opType != OPTYPE_ELECT && (isAllGraphicsStages(caseDef.shaderStage)))
1509 #endif // CTS_USES_VULKANSC
1510 	{
1511 		body << "  uint id = 0;\n"
1512 				"  if (subgroupElect())\n"
1513 				"  {\n"
1514 				"    id = atomicAdd(subgroupID, 1);\n"
1515 				"  }\n"
1516 				"  id = subgroupBroadcastFirst(id);\n"
1517 				"  uint localId = id;\n"
1518 				"  uint tempResult = 0;\n";
1519 	}
1520 
1521 	switch (caseDef.opType)
1522 	{
1523 		case OPTYPE_ELECT:
1524 			if (isAllComputeStages(caseDef.shaderStage))
1525 			{
1526 				body << "  uint value = " << UNELECTED_VALUE << ";\n"
1527 						"  if (subgroupElect())\n"
1528 						"  {\n"
1529 						"    value = " << ELECTED_VALUE << ";\n"
1530 						"  }\n"
1531 						"  uvec4 bits = bitCount(sharedMemoryBallot(value == " << ELECTED_VALUE << "));\n"
1532 						"  tempRes = bits.x + bits.y + bits.z + bits.w;\n";
1533 			}
1534 			else
1535 			{
1536 				body << "  if (subgroupElect())\n"
1537 						"  {\n"
1538 						"    tempRes = " << ELECTED_VALUE << ";\n"
1539 						"    atomicAdd(numSubgroupsExecuted, 1);\n"
1540 						"  }\n"
1541 						"  else\n"
1542 						"  {\n"
1543 						"    tempRes = " << UNELECTED_VALUE << ";\n"
1544 						"  }\n";
1545 			}
1546 			break;
1547 
1548 		case OPTYPE_SUBGROUP_BARRIER:
1549 		case OPTYPE_SUBGROUP_MEMORY_BARRIER:
1550 		case OPTYPE_SUBGROUP_MEMORY_BARRIER_BUFFER:
1551 			body << "  if (subgroupElect())\n"
1552 					"  {\n"
1553 					"    tempBuffer[id] = value;\n"
1554 					"  }\n"
1555 					"  " << getOpTypeName(caseDef.opType) << "();\n"
1556 					"  tempResult = tempBuffer[id];\n";
1557 			break;
1558 
1559 		case OPTYPE_SUBGROUP_MEMORY_BARRIER_SHARED:
1560 			body <<  "  if (subgroupElect())\n"
1561 					"  {\n"
1562 					"    tempShared[localId] = value;\n"
1563 					"  }\n"
1564 					"  subgroupMemoryBarrierShared();\n"
1565 					"  tempResult = tempShared[localId];\n";
1566 			break;
1567 
1568 		case OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE:
1569 			body << "  if (subgroupElect())\n"
1570 					"  {\n"
1571 					"    imageStore(tempImage, ivec2(id, 0), ivec4(value));\n"
1572 					"  }\n"
1573 					"  subgroupMemoryBarrierImage();\n"
1574 					"  tempResult = imageLoad(tempImage, ivec2(id, 0)).x;\n";
1575 			break;
1576 
1577 		default:
1578 			TCU_THROW(InternalError, "Unhandled op type!");
1579 	}
1580 
1581 #ifndef CTS_USES_VULKANSC
1582 	if (caseDef.opType != OPTYPE_ELECT && (isAllGraphicsStages(caseDef.shaderStage) || isAllRayTracingStages(caseDef.shaderStage)))
1583 #else
1584 	if (caseDef.opType != OPTYPE_ELECT && (isAllGraphicsStages(caseDef.shaderStage)))
1585 #endif // CTS_USES_VULKANSC
1586 	{
1587 		body << "  tempRes = tempResult;\n";
1588 	}
1589 
1590 	return body.str();
1591 }
1592 
getExtHeader(const CaseDefinition & caseDef)1593 string getExtHeader (const CaseDefinition& caseDef)
1594 {
1595 	const string	extensions	= (caseDef.opType == OPTYPE_ELECT)
1596 								? "#extension GL_KHR_shader_subgroup_basic: enable\n"
1597 								: "#extension GL_KHR_shader_subgroup_basic: enable\n"
1598 								  "#extension GL_KHR_shader_subgroup_ballot: enable\n";
1599 	return extensions;
1600 }
1601 
initComputeOrMeshPrograms(SourceCollections & programCollection,CaseDefinition & caseDef,const string & extensions,const string & testSrc,const ShaderBuildOptions & buildOptions)1602 void initComputeOrMeshPrograms (SourceCollections&			programCollection,
1603 								CaseDefinition&				caseDef,
1604 								const string&				extensions,
1605 								const string&				testSrc,
1606 								const ShaderBuildOptions&	buildOptions)
1607 {
1608 	std::ostringstream electTemplateStream;
1609 	electTemplateStream
1610 		<< "#version 450\n"
1611 		<< extensions
1612 		<< "${EXTENSIONS:opt}"
1613 		<< "layout (local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in;\n"
1614 		<< "${LAYOUTS:opt}"
1615 		<< "layout (set = 0, binding = 0, std430) buffer Buffer1\n"
1616 		<< "{\n"
1617 		<< "  uint result[];\n"
1618 		<< "};\n"
1619 		<< "\n"
1620 		<< subgroups::getSharedMemoryBallotHelper()
1621 		<< "void main (void)\n"
1622 		<< "{\n"
1623 		<< "  uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
1624 		<< "  highp uint offset = globalSize.x * ((globalSize.y * gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + gl_GlobalInvocationID.x;\n"
1625 		<< "  uint value = " << UNELECTED_VALUE << ";\n"
1626 		<< "  if (subgroupElect())\n"
1627 		<< "  {\n"
1628 		<< "    value = " << ELECTED_VALUE << ";\n"
1629 		<< "  }\n"
1630 		<< "  uvec4 bits = bitCount(sharedMemoryBallot(value == " << ELECTED_VALUE << "));\n"
1631 		<< "  result[offset] = bits.x + bits.y + bits.z + bits.w;\n"
1632 		<< "${BODY:opt}"
1633 		<< "}\n";
1634 		;
1635 	const tcu::StringTemplate electTemplate(electTemplateStream.str());
1636 
1637 	std::ostringstream nonElectTemplateStream;
1638 	nonElectTemplateStream
1639 		<< "#version 450\n"
1640 		<< "#extension GL_KHR_shader_subgroup_basic: enable\n"
1641 		<< "${EXTENSIONS:opt}"
1642 		<< "layout (local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in;\n"
1643 		<< "${LAYOUTS:opt}"
1644 		<< "layout (set = 0, binding = 0, std430) buffer Buffer1\n"
1645 		<< "{\n"
1646 		<< "  uint result[];\n"
1647 		<< "};\n"
1648 		<< "layout (set = 0, binding = 1, std430) buffer Buffer2\n"
1649 		<< "{\n"
1650 		<< "  uint tempBuffer[];\n"
1651 		<< "};\n"
1652 		<< "layout (set = 0, binding = 2, std430) buffer Buffer3\n"
1653 		<< "{\n"
1654 		<< "  uint value;\n"
1655 		<< "};\n"
1656 		<< "layout (set = 0, binding = 3, r32ui) uniform uimage2D tempImage;\n"
1657 		<< "shared uint tempShared[gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z];\n"
1658 		<< "\n"
1659 		<< "void main (void)\n"
1660 		<< "{\n"
1661 		<< "  uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
1662 		<< "  highp uint offset = globalSize.x * ((globalSize.y * gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + gl_GlobalInvocationID.x;\n"
1663 		<< "  uint localId = gl_SubgroupID;\n"
1664 		<< "  uint id = globalSize.x * ((globalSize.y * gl_WorkGroupID.z) + gl_WorkGroupID.y) + gl_WorkGroupID.x + localId;\n"
1665 		<< "  uint tempResult = 0;\n"
1666 		<< testSrc
1667 		<< "  result[offset] = tempResult;\n"
1668 		<< "${BODY:opt}"
1669 		<< "}\n";
1670 		;
1671 	const tcu::StringTemplate nonElectTemplate(nonElectTemplateStream.str());
1672 
1673 	if (isAllComputeStages(caseDef.shaderStage))
1674 	{
1675 		const std::map<std::string, std::string> emptyMap;
1676 
1677 		if (OPTYPE_ELECT == caseDef.opType)
1678 		{
1679 			const auto programSource = electTemplate.specialize(emptyMap);
1680 			programCollection.glslSources.add("comp") << glu::ComputeSource(programSource) << buildOptions;
1681 		}
1682 		else
1683 		{
1684 			const auto programSource = nonElectTemplate.specialize(emptyMap);
1685 			programCollection.glslSources.add("comp") << glu::ComputeSource(programSource) << buildOptions;
1686 		}
1687 	}
1688 #ifndef CTS_USES_VULKANSC
1689 	else if (isAllMeshShadingStages(caseDef.shaderStage))
1690 	{
1691 		const bool			testMesh = ((caseDef.shaderStage & VK_SHADER_STAGE_MESH_BIT_EXT) != 0u);
1692 		const bool			testTask = ((caseDef.shaderStage & VK_SHADER_STAGE_TASK_BIT_EXT) != 0u);
1693 		const tcu::UVec3	emitSize = (testMesh ? tcu::UVec3(1u, 1u, 1u) : tcu::UVec3(0u, 0u, 0u));
1694 
1695 		const std::map<std::string, std::string> meshMap
1696 		{
1697 			std::make_pair("EXTENSIONS",	"#extension GL_EXT_mesh_shader : enable\n"),
1698 			std::make_pair("LAYOUTS",		"layout (points) out;\nlayout (max_vertices=1, max_primitives=1) out;\n"),
1699 			std::make_pair("BODY",			"  SetMeshOutputsEXT(0u, 0u);\n")
1700 		};
1701 
1702 		const std::map<std::string, std::string> taskMap
1703 		{
1704 			std::make_pair("EXTENSIONS",	"#extension GL_EXT_mesh_shader : enable\n"),
1705 			std::make_pair("BODY",			"  EmitMeshTasksEXT(" + std::to_string(emitSize.x()) + ", " + std::to_string(emitSize.y()) + ", " + std::to_string(emitSize.z()) + ");\n")
1706 		};
1707 
1708 		if (testMesh)
1709 		{
1710 			if (OPTYPE_ELECT == caseDef.opType)
1711 			{
1712 				const auto programSource = electTemplate.specialize(meshMap);
1713 				programCollection.glslSources.add("mesh") << glu::MeshSource(programSource) << buildOptions;
1714 			}
1715 			else
1716 			{
1717 				const auto programSource = nonElectTemplate.specialize(meshMap);
1718 				programCollection.glslSources.add("mesh") << glu::MeshSource(programSource) << buildOptions;
1719 			}
1720 		}
1721 		else
1722 		{
1723 			const std::string meshShaderNoSubgroups =
1724 				"#version 450\n"
1725 				"#extension GL_EXT_mesh_shader : enable\n"
1726 				"\n"
1727 				"layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
1728 				"layout (points) out;\n"
1729 				"layout (max_vertices = 1, max_primitives = 1) out;\n"
1730 				"\n"
1731 				"void main (void)\n"
1732 				"{\n"
1733 				"  SetMeshOutputsEXT(0u, 0u);\n"
1734 				"}\n"
1735 				;
1736 			programCollection.glslSources.add("mesh") << glu::MeshSource(meshShaderNoSubgroups) << buildOptions;
1737 		}
1738 
1739 		if (testTask)
1740 		{
1741 			if (OPTYPE_ELECT == caseDef.opType)
1742 			{
1743 				const auto programSource = electTemplate.specialize(taskMap);
1744 				programCollection.glslSources.add("task") << glu::TaskSource(programSource) << buildOptions;
1745 			}
1746 			else
1747 			{
1748 				const auto programSource = nonElectTemplate.specialize(taskMap);
1749 				programCollection.glslSources.add("task") << glu::TaskSource(programSource) << buildOptions;
1750 			}
1751 		}
1752 	}
1753 #endif // CTS_USES_VULKANSC
1754 	else
1755 	{
1756 		DE_ASSERT(false);
1757 	}
1758 }
1759 
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)1760 void initPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
1761 {
1762 #ifndef CTS_USES_VULKANSC
1763 	const bool					spirv14required		= (isAllRayTracingStages(caseDef.shaderStage) || isAllMeshShadingStages(caseDef.shaderStage));
1764 #else
1765 	const bool					spirv14required		= false;
1766 #endif // CTS_USES_VULKANSC
1767 	const SpirvVersion			spirvVersion		= (spirv14required ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3);
1768 	const ShaderBuildOptions	buildOptions		(programCollection.usedVulkanVersion, spirvVersion, 0u, spirv14required);
1769 	const string				extHeader			= getExtHeader(caseDef);
1770 	const string				testSrc				= getTestString(caseDef);
1771 	const vector<string>		headDeclarations	= getPerStageHeadDeclarations(caseDef);
1772 	const bool					pointSizeSupport	= *caseDef.geometryPointSizeSupported;
1773 	const bool					isComp				= isAllComputeStages(caseDef.shaderStage);
1774 #ifndef CTS_USES_VULKANSC
1775 	const bool					isMesh				= isAllMeshShadingStages(caseDef.shaderStage);
1776 #else
1777 	const bool					isMesh				= false;
1778 #endif // CTS_USES_VULKANSC
1779 
1780 	if (isComp || isMesh)
1781 		initComputeOrMeshPrograms(programCollection, caseDef, extHeader, testSrc, buildOptions);
1782 	else
1783 		subgroups::initStdPrograms(programCollection, buildOptions, caseDef.shaderStage, VK_FORMAT_R32_UINT, pointSizeSupport, extHeader, testSrc, "", headDeclarations, true);
1784 }
1785 
supportedCheck(Context & context,CaseDefinition caseDef)1786 void supportedCheck (Context& context, CaseDefinition caseDef)
1787 {
1788 	if (!subgroups::isSubgroupSupported(context))
1789 		TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
1790 
1791 	if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_BASIC_BIT))
1792 		TCU_FAIL("supportedOperations will have the VK_SUBGROUP_FEATURE_BASIC_BIT bit set if any of the physical device's queues support VK_QUEUE_GRAPHICS_BIT or VK_QUEUE_COMPUTE_BIT.");
1793 
1794 	if (caseDef.requiredSubgroupSize)
1795 	{
1796 		context.requireDeviceFunctionality("VK_EXT_subgroup_size_control");
1797 
1798 #ifndef CTS_USES_VULKANSC
1799 		const VkPhysicalDeviceSubgroupSizeControlFeatures&		subgroupSizeControlFeatures		= context.getSubgroupSizeControlFeatures();
1800 		const VkPhysicalDeviceSubgroupSizeControlProperties&	subgroupSizeControlProperties	= context.getSubgroupSizeControlProperties();
1801 #else
1802 		const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT&		subgroupSizeControlFeatures	= context.getSubgroupSizeControlFeaturesEXT();
1803 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
1804 #endif // CTS_USES_VULKANSC
1805 
1806 		if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
1807 			TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes nor required subgroup size");
1808 
1809 		if (subgroupSizeControlFeatures.computeFullSubgroups == DE_FALSE)
1810 			TCU_THROW(NotSupportedError, "Device does not support full subgroups in compute shaders");
1811 
1812 		if ((subgroupSizeControlProperties.requiredSubgroupSizeStages & caseDef.shaderStage) != caseDef.shaderStage)
1813 			TCU_THROW(NotSupportedError, "Required subgroup size is not supported for shader stage");
1814 	}
1815 
1816 	*caseDef.geometryPointSizeSupported = subgroups::isTessellationAndGeometryPointSizeSupported(context);
1817 
1818 	subgroups::supportedCheckShader(context, caseDef.shaderStage);
1819 
1820 	if (OPTYPE_ELECT != caseDef.opType && VK_SHADER_STAGE_COMPUTE_BIT != caseDef.shaderStage)
1821 	{
1822 		if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_BALLOT_BIT))
1823 		{
1824 			TCU_THROW(NotSupportedError, "Subgroup basic operation non-compute stage test required that ballot operations are supported!");
1825 		}
1826 	}
1827 
1828 #ifndef CTS_USES_VULKANSC
1829 	if (isAllRayTracingStages(caseDef.shaderStage))
1830 	{
1831 		context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
1832 	}
1833 	else if (isAllMeshShadingStages(caseDef.shaderStage))
1834 	{
1835 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
1836 		context.requireDeviceFunctionality("VK_EXT_mesh_shader");
1837 
1838 		if ((caseDef.shaderStage & VK_SHADER_STAGE_TASK_BIT_EXT) != 0u)
1839 		{
1840 			const auto& features = context.getMeshShaderFeaturesEXT();
1841 			if (!features.taskShader)
1842 				TCU_THROW(NotSupportedError, "Task shaders not supported");
1843 		}
1844 	}
1845 #endif // CTS_USES_VULKANSC
1846 }
1847 
noSSBOtest(Context & context,const CaseDefinition caseDef)1848 TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
1849 {
1850 	const deUint32				inputDatasCount	= OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? 3u : 2u;
1851 	vector<subgroups::SSBOData>	inputDatas		(inputDatasCount);
1852 
1853 	inputDatas[0].format = VK_FORMAT_R32_UINT;
1854 	inputDatas[0].layout = subgroups::SSBOData::LayoutStd140;
1855 	inputDatas[0].numElements = SHADER_BUFFER_SIZE/4ull;
1856 	inputDatas[0].initializeType = subgroups::SSBOData::InitializeNonZero;
1857 	inputDatas[0].bindingType = subgroups::SSBOData::BindingUBO;
1858 
1859 	inputDatas[1].format = VK_FORMAT_R32_UINT;
1860 	inputDatas[1].layout = subgroups::SSBOData::LayoutStd140;
1861 	inputDatas[1].numElements = 1ull;
1862 	inputDatas[1].initializeType = subgroups::SSBOData::InitializeNonZero;
1863 	inputDatas[1].bindingType = subgroups::SSBOData::BindingUBO;
1864 
1865 	if(OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType )
1866 	{
1867 		inputDatas[2].format = VK_FORMAT_R32_UINT;
1868 		inputDatas[2].layout = subgroups::SSBOData::LayoutPacked;
1869 		inputDatas[2].numElements = SHADER_BUFFER_SIZE;
1870 		inputDatas[2].initializeType = subgroups::SSBOData::InitializeNone;
1871 		inputDatas[2].bindingType = subgroups::SSBOData::BindingImage;
1872 	}
1873 
1874 	if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
1875 	{
1876 		if (OPTYPE_ELECT == caseDef.opType)
1877 			return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32G32_SFLOAT, DE_NULL, 0u, DE_NULL, checkVertexPipelineStagesSubgroupElectNoSSBO);
1878 		else
1879 			return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32G32B32A32_SFLOAT, &inputDatas[0], inputDatasCount, DE_NULL,
1880 				(OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType) ?
1881 					checkVertexPipelineStagesSubgroupBarriersWithImageNoSSBO :
1882 					checkVertexPipelineStagesSubgroupBarriersNoSSBO
1883 			);
1884 	}
1885 	else if (VK_SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
1886 	{
1887 		return subgroups::makeFragmentFrameBufferTest(context, VK_FORMAT_R32G32B32A32_SFLOAT, &inputDatas[0], inputDatasCount, DE_NULL,
1888 			(OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType) ?
1889 				checkFragmentSubgroupBarriersWithImageNoSSBO :
1890 				checkFragmentSubgroupBarriersNoSSBO
1891 		);
1892 	}
1893 	else if (VK_SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
1894 	{
1895 		if (OPTYPE_ELECT == caseDef.opType)
1896 			return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32G32_SFLOAT, DE_NULL, 0u, DE_NULL, checkVertexPipelineStagesSubgroupElectNoSSBO);
1897 		else
1898 			return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32G32B32A32_SFLOAT, &inputDatas[0], inputDatasCount, DE_NULL,
1899 				(OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType) ?
1900 					checkVertexPipelineStagesSubgroupBarriersWithImageNoSSBO :
1901 					checkVertexPipelineStagesSubgroupBarriersNoSSBO
1902 			);
1903 	}
1904 
1905 	if (OPTYPE_ELECT == caseDef.opType)
1906 		return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32G32_SFLOAT, DE_NULL, 0u, DE_NULL, checkVertexPipelineStagesSubgroupElectNoSSBO, caseDef.shaderStage);
1907 
1908 	return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32G32B32A32_SFLOAT, &inputDatas[0], inputDatasCount, DE_NULL,
1909 		(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage) ?
1910 			((OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType) ?
1911 				checkVertexPipelineStagesSubgroupBarriersWithImageNoSSBO :
1912 				checkVertexPipelineStagesSubgroupBarriersNoSSBO) :
1913 			((OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType) ?
1914 				checkTessellationEvaluationSubgroupBarriersWithImageNoSSBO :
1915 				checkTessellationEvaluationSubgroupBarriersNoSSBO),
1916 		caseDef.shaderStage);
1917 }
1918 
test(Context & context,const CaseDefinition caseDef)1919 TestStatus test (Context& context, const CaseDefinition caseDef)
1920 {
1921 	const bool isCompute	= isAllComputeStages(caseDef.shaderStage);
1922 #ifndef CTS_USES_VULKANSC
1923 	const bool isMesh		= isAllMeshShadingStages(caseDef.shaderStage);
1924 #else
1925 	const bool isMesh		= false;
1926 #endif // CTS_USES_VULKANSC
1927 	DE_ASSERT(!(isCompute && isMesh));
1928 
1929 	if (isCompute || isMesh)
1930 	{
1931 #ifndef CTS_USES_VULKANSC
1932 		const VkPhysicalDeviceSubgroupSizeControlProperties&	subgroupSizeControlProperties	= context.getSubgroupSizeControlProperties();
1933 #else
1934 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
1935 #endif // CTS_USES_VULKANSC
1936 		TestLog&												log								= context.getTestContext().getLog();
1937 
1938 		if (OPTYPE_ELECT == caseDef.opType)
1939 		{
1940 			if (caseDef.requiredSubgroupSize == DE_FALSE)
1941 			{
1942 				if (isCompute)
1943 					return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkComputeOrMeshSubgroupElect);
1944 				else
1945 					return subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, nullptr, 0, nullptr, checkComputeOrMeshSubgroupElect);
1946 			}
1947 
1948 			log << TestLog::Message << "Testing required subgroup size range [" <<  subgroupSizeControlProperties.minSubgroupSize << ", "
1949 				<< subgroupSizeControlProperties.maxSubgroupSize << "]" << TestLog::EndMessage;
1950 
1951 			// According to the spec, requiredSubgroupSize must be a power-of-two integer.
1952 			for (deUint32 size = subgroupSizeControlProperties.minSubgroupSize; size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
1953 			{
1954 				TestStatus result (QP_TEST_RESULT_INTERNAL_ERROR, "Internal Error");
1955 
1956 				if (isCompute)
1957 					result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0u, DE_NULL, checkComputeOrMeshSubgroupElect, size);
1958 				else
1959 					result = subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, nullptr, 0u, nullptr, checkComputeOrMeshSubgroupElect, size);
1960 
1961 				if (result.getCode() != QP_TEST_RESULT_PASS)
1962 				{
1963 					log << TestLog::Message << "subgroupSize " << size << " failed" << TestLog::EndMessage;
1964 					return result;
1965 				}
1966 			}
1967 
1968 			return TestStatus::pass("OK");
1969 		}
1970 		else
1971 		{
1972 			const deUint32				inputDatasCount					= 3;
1973 			const subgroups::SSBOData	inputDatas[inputDatasCount]		=
1974 			{
1975 				{
1976 					subgroups::SSBOData::InitializeNone,	//  InputDataInitializeType		initializeType;
1977 					subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
1978 					VK_FORMAT_R32_UINT,						//  vk::VkFormat				format;
1979 					SHADER_BUFFER_SIZE,						//  vk::VkDeviceSize			numElements;
1980 				},
1981 				{
1982 					subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
1983 					subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
1984 					VK_FORMAT_R32_UINT,						//  vk::VkFormat				format;
1985 					1,										//  vk::VkDeviceSize			numElements;
1986 				},
1987 				{
1988 					subgroups::SSBOData::InitializeNone,	//  InputDataInitializeType		initializeType;
1989 					subgroups::SSBOData::LayoutPacked,		//  InputDataLayoutType			layout;
1990 					VK_FORMAT_R32_UINT,						//  vk::VkFormat				format;
1991 					SHADER_BUFFER_SIZE,						//  vk::VkDeviceSize			numElements;
1992 					subgroups::SSBOData::BindingImage,		//  bool						isImage;
1993 				},
1994 			};
1995 
1996 			if (caseDef.requiredSubgroupSize == DE_FALSE)
1997 			{
1998 				if (isCompute)
1999 					return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, inputDatas, inputDatasCount, DE_NULL, checkComputeOrMeshSubgroupBarriers);
2000 				else
2001 					return subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, inputDatas, inputDatasCount, nullptr, checkComputeOrMeshSubgroupBarriers);
2002 			}
2003 
2004 			log << TestLog::Message << "Testing required subgroup size range [" <<  subgroupSizeControlProperties.minSubgroupSize << ", "
2005 				<< subgroupSizeControlProperties.maxSubgroupSize << "]" << TestLog::EndMessage;
2006 
2007 			// According to the spec, requiredSubgroupSize must be a power-of-two integer.
2008 			for (deUint32 size = subgroupSizeControlProperties.minSubgroupSize; size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
2009 			{
2010 				TestStatus result (QP_TEST_RESULT_INTERNAL_ERROR, "Internal Error");
2011 
2012 				if (isCompute)
2013 					result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, inputDatas, inputDatasCount, DE_NULL, checkComputeOrMeshSubgroupBarriers, size);
2014 				else
2015 					result = subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, inputDatas, inputDatasCount, nullptr, checkComputeOrMeshSubgroupBarriers, size);
2016 
2017 				if (result.getCode() != QP_TEST_RESULT_PASS)
2018 				{
2019 					log << TestLog::Message << "subgroupSize " << size << " failed" << TestLog::EndMessage;
2020 					return result;
2021 				}
2022 			}
2023 
2024 			return TestStatus::pass("OK");
2025 		}
2026 	}
2027 	else if (isAllGraphicsStages(caseDef.shaderStage))
2028 	{
2029 		if (!subgroups::isFragmentSSBOSupportedForDevice(context))
2030 		{
2031 			TCU_THROW(NotSupportedError, "Subgroup basic operation require that the fragment stage be able to write to SSBOs!");
2032 		}
2033 
2034 		const VkShaderStageFlags	stages	= subgroups::getPossibleGraphicsSubgroupStages(context, caseDef.shaderStage);
2035 		const VkShaderStageFlags	stagesBits[] =
2036 		{
2037 			VK_SHADER_STAGE_VERTEX_BIT,
2038 			VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
2039 			VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
2040 			VK_SHADER_STAGE_GEOMETRY_BIT,
2041 			VK_SHADER_STAGE_FRAGMENT_BIT,
2042 		};
2043 
2044 		if (OPTYPE_ELECT == caseDef.opType)
2045 		{
2046 			const deUint32		inputCount				= DE_LENGTH_OF_ARRAY(stagesBits);
2047 			subgroups::SSBOData	inputData[inputCount];
2048 
2049 			for (deUint32 ndx = 0; ndx < DE_LENGTH_OF_ARRAY(stagesBits); ++ndx)
2050 			{
2051 				inputData[ndx]	=
2052 				{
2053 					subgroups::SSBOData::InitializeZero,	//  InputDataInitializeType		initializeType;
2054 					subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
2055 					VK_FORMAT_R32_UINT,						//  vk::VkFormat				format;
2056 					1,										//  vk::VkDeviceSize			numElements;
2057 					subgroups::SSBOData::BindingSSBO,		//  bool						isImage;
2058 					4 + ndx,								//  deUint32					binding;
2059 					stagesBits[ndx],						//  vk::VkShaderStageFlags		stages;
2060 				};
2061 			}
2062 
2063 			return subgroups::allStages(context, VK_FORMAT_R32_UINT, inputData, inputCount, DE_NULL, checkVertexPipelineStagesSubgroupElect, stages);
2064 		}
2065 		else
2066 		{
2067 			const deUint32		inputDatasCount					= DE_LENGTH_OF_ARRAY(stagesBits) * 4u;
2068 			subgroups::SSBOData	inputDatas[inputDatasCount];
2069 
2070 			for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(stagesBits); ++ndx)
2071 			{
2072 				const deUint32 index = ndx*4;
2073 
2074 				inputDatas[index].format				= VK_FORMAT_R32_UINT;
2075 				inputDatas[index].layout				= subgroups::SSBOData::LayoutStd430;
2076 				inputDatas[index].numElements			= SHADER_BUFFER_SIZE;
2077 				inputDatas[index].initializeType		= subgroups::SSBOData::InitializeNonZero;
2078 				inputDatas[index].binding				= index + 4u;
2079 				inputDatas[index].stages				= stagesBits[ndx];
2080 
2081 				inputDatas[index + 1].format			= VK_FORMAT_R32_UINT;
2082 				inputDatas[index + 1].layout			= subgroups::SSBOData::LayoutStd430;
2083 				inputDatas[index + 1].numElements		= 1;
2084 				inputDatas[index + 1].initializeType	= subgroups::SSBOData::InitializeZero;
2085 				inputDatas[index + 1].binding			= index + 5u;
2086 				inputDatas[index + 1].stages			= stagesBits[ndx];
2087 
2088 				inputDatas[index + 2].format			= VK_FORMAT_R32_UINT;
2089 				inputDatas[index + 2].layout			= subgroups::SSBOData::LayoutStd430;
2090 				inputDatas[index + 2].numElements		= 1;
2091 				inputDatas[index + 2].initializeType	= subgroups::SSBOData::InitializeNonZero;
2092 				inputDatas[index + 2].binding			= index + 6u;
2093 				inputDatas[index + 2].stages			= stagesBits[ndx];
2094 
2095 				inputDatas[index + 3].format			= VK_FORMAT_R32_UINT;
2096 				inputDatas[index + 3].layout			= subgroups::SSBOData::LayoutStd430;
2097 				inputDatas[index + 3].numElements		= SHADER_BUFFER_SIZE;
2098 				inputDatas[index + 3].initializeType	= subgroups::SSBOData::InitializeNone;
2099 				inputDatas[index + 3].bindingType		= subgroups::SSBOData::BindingImage;
2100 				inputDatas[index + 3].binding			= index + 7u;
2101 				inputDatas[index + 3].stages			= stagesBits[ndx];
2102 			}
2103 
2104 			return subgroups::allStages(context, VK_FORMAT_R32_UINT, inputDatas, inputDatasCount, DE_NULL, checkVertexPipelineStagesSubgroupBarriers, stages);
2105 		}
2106 	}
2107 #ifndef CTS_USES_VULKANSC
2108 	else if (isAllRayTracingStages(caseDef.shaderStage))
2109 	{
2110 		const VkShaderStageFlags	stages			= subgroups::getPossibleRayTracingSubgroupStages(context, caseDef.shaderStage);
2111 		const VkShaderStageFlags	stagesBits[]	=
2112 		{
2113 			VK_SHADER_STAGE_RAYGEN_BIT_KHR,
2114 			VK_SHADER_STAGE_ANY_HIT_BIT_KHR,
2115 			VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
2116 			VK_SHADER_STAGE_MISS_BIT_KHR,
2117 			VK_SHADER_STAGE_INTERSECTION_BIT_KHR,
2118 			VK_SHADER_STAGE_CALLABLE_BIT_KHR,
2119 		};
2120 		const deUint32				stagesCount		= DE_LENGTH_OF_ARRAY(stagesBits);
2121 
2122 		if (OPTYPE_ELECT == caseDef.opType)
2123 		{
2124 			const deUint32		inputDataCount				= stagesCount;
2125 			subgroups::SSBOData	inputData[inputDataCount];
2126 
2127 			for (deUint32 ndx = 0; ndx < inputDataCount; ++ndx)
2128 			{
2129 				inputData[ndx].format			= VK_FORMAT_R32_UINT;
2130 				inputData[ndx].layout			= subgroups::SSBOData::LayoutStd430;
2131 				inputData[ndx].numElements		= 1;
2132 				inputData[ndx].initializeType	= subgroups::SSBOData::InitializeZero;
2133 				inputData[ndx].binding			= stagesCount + ndx;
2134 				inputData[ndx].stages			= stagesBits[ndx];
2135 			}
2136 
2137 			return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, inputData, inputDataCount, DE_NULL, checkVertexPipelineStagesSubgroupElect, stages);
2138 		}
2139 		else
2140 		{
2141 			const deUint32		datasPerStage				= 4u;
2142 			const deUint32		inputDatasCount				= datasPerStage * stagesCount;
2143 			subgroups::SSBOData	inputDatas[inputDatasCount];
2144 
2145 			for (deUint32 ndx = 0; ndx < stagesCount; ++ndx)
2146 			{
2147 				const deUint32 index = datasPerStage * ndx;
2148 
2149 				for (deUint32 perStageNdx = 0; perStageNdx < datasPerStage; ++perStageNdx)
2150 				{
2151 					inputDatas[index + perStageNdx].format		= VK_FORMAT_R32_UINT;
2152 					inputDatas[index + perStageNdx].layout		= subgroups::SSBOData::LayoutStd430;
2153 					inputDatas[index + perStageNdx].stages		= stagesBits[ndx];
2154 					inputDatas[index + perStageNdx].bindingType	= subgroups::SSBOData::BindingSSBO;
2155 				}
2156 
2157 				inputDatas[index + 0].numElements		= SHADER_BUFFER_SIZE;
2158 				inputDatas[index + 0].initializeType	= subgroups::SSBOData::InitializeNonZero;
2159 				inputDatas[index + 0].binding			= index + stagesCount;
2160 
2161 				inputDatas[index + 1].numElements		= 1;
2162 				inputDatas[index + 1].initializeType	= subgroups::SSBOData::InitializeZero;
2163 				inputDatas[index + 1].binding			= index + stagesCount + 1u;
2164 
2165 				inputDatas[index + 2].numElements		= 1;
2166 				inputDatas[index + 2].initializeType	= subgroups::SSBOData::InitializeNonZero;
2167 				inputDatas[index + 2].binding			= index + stagesCount + 2u;
2168 
2169 				inputDatas[index + 3].numElements		= SHADER_BUFFER_SIZE;
2170 				inputDatas[index + 3].initializeType	= subgroups::SSBOData::InitializeNone;
2171 				inputDatas[index + 3].bindingType		= subgroups::SSBOData::BindingImage;
2172 				inputDatas[index + 3].binding			= index + stagesCount + 3u;
2173 			}
2174 
2175 			return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, inputDatas, inputDatasCount, DE_NULL, checkVertexPipelineStagesSubgroupBarriers, stages);
2176 		}
2177 	}
2178 #endif // CTS_USES_VULKANSC
2179 	else
2180 		TCU_THROW(InternalError, "Unknown stage or invalid stage set");
2181 }
2182 }
2183 
2184 namespace vkt
2185 {
2186 namespace subgroups
2187 {
createSubgroupsBasicTests(TestContext & testCtx)2188 TestCaseGroup* createSubgroupsBasicTests (TestContext& testCtx)
2189 {
2190 	de::MovePtr<TestCaseGroup>	group				(new TestCaseGroup(testCtx, "basic", "Subgroup basic category tests"));
2191 	de::MovePtr<TestCaseGroup>	graphicGroup		(new TestCaseGroup(testCtx, "graphics", "Subgroup basic category tests: graphics"));
2192 	de::MovePtr<TestCaseGroup>	computeGroup		(new TestCaseGroup(testCtx, "compute", "Subgroup basic category tests: compute"));
2193 	de::MovePtr<TestCaseGroup>	meshGroup			(new TestCaseGroup(testCtx, "mesh", "Subgroup basic category tests: mesh shading"));
2194 	de::MovePtr<TestCaseGroup>	framebufferGroup	(new TestCaseGroup(testCtx, "framebuffer", "Subgroup basic category tests: framebuffer"));
2195 	de::MovePtr<TestCaseGroup>	raytracingGroup		(new TestCaseGroup(testCtx, "ray_tracing", "Subgroup basic category tests: ray tracing"));
2196 	const VkShaderStageFlags	fbStages[]			=
2197 	{
2198 		VK_SHADER_STAGE_FRAGMENT_BIT,
2199 		VK_SHADER_STAGE_VERTEX_BIT,
2200 		VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
2201 		VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
2202 		VK_SHADER_STAGE_GEOMETRY_BIT,
2203 	};
2204 #ifndef CTS_USES_VULKANSC
2205 	const VkShaderStageFlags	meshStages[]		=
2206 	{
2207 		VK_SHADER_STAGE_MESH_BIT_EXT,
2208 		VK_SHADER_STAGE_TASK_BIT_EXT,
2209 	};
2210 #endif // CTS_USES_VULKANSC
2211 	const deBool				boolValues[]		=
2212 	{
2213 		DE_FALSE,
2214 		DE_TRUE
2215 	};
2216 
2217 	for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
2218 	{
2219 		const OpType	opType	= static_cast<OpType>(opTypeIndex);
2220 		const string	op		= de::toLower(getOpTypeName(opType));
2221 
2222 		for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
2223 		{
2224 			const deBool			requiredSubgroupSize	= boolValues[groupSizeNdx];
2225 			const string			testNameSuffix			= requiredSubgroupSize ? "_requiredsubgroupsize" : "";
2226 			const CaseDefinition	caseDef					=
2227 			{
2228 				opType,							//  OpType				opType;
2229 				VK_SHADER_STAGE_COMPUTE_BIT,	//  VkShaderStageFlags	shaderStage;
2230 				de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
2231 				requiredSubgroupSize			//  deBool				requiredSubgroupSize;
2232 			};
2233 			const string			testName				= op + testNameSuffix;
2234 
2235 			addFunctionCaseWithPrograms(computeGroup.get(), testName, "", supportedCheck, initPrograms, test, caseDef);
2236 		}
2237 
2238 #ifndef CTS_USES_VULKANSC
2239 		for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
2240 		{
2241 			for (const auto& stage : meshStages)
2242 			{
2243 				const deBool			requiredSubgroupSize	= boolValues[groupSizeNdx];
2244 				const string			testNameSuffix			= requiredSubgroupSize ? "_requiredsubgroupsize" : "";
2245 				const CaseDefinition	caseDef					=
2246 				{
2247 					opType,							//  OpType				opType;
2248 					stage,							//  VkShaderStageFlags	shaderStage;
2249 					de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
2250 					requiredSubgroupSize			//  deBool				requiredSubgroupSize;
2251 				};
2252 				const string			testName				= op + testNameSuffix + "_" + getShaderStageName(stage);
2253 
2254 				addFunctionCaseWithPrograms(meshGroup.get(), testName, "", supportedCheck, initPrograms, test, caseDef);
2255 			}
2256 		}
2257 #endif // CTS_USES_VULKANSC
2258 
2259 		if (OPTYPE_SUBGROUP_MEMORY_BARRIER_SHARED == opType)
2260 		{
2261 			// Shared isn't available in non compute shaders.
2262 			continue;
2263 		}
2264 
2265 		{
2266 			const CaseDefinition caseDef =
2267 			{
2268 				opType,							//  OpType				opType;
2269 				VK_SHADER_STAGE_ALL_GRAPHICS,	//  VkShaderStageFlags	shaderStage;
2270 				de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
2271 				DE_FALSE						//  deBool				requiredSubgroupSize;
2272 			};
2273 
2274 			addFunctionCaseWithPrograms(graphicGroup.get(), op, "", supportedCheck, initPrograms, test, caseDef);
2275 		}
2276 
2277 #ifndef CTS_USES_VULKANSC
2278 		{
2279 			const CaseDefinition caseDef =
2280 			{
2281 				opType,							//  OpType				opType;
2282 				SHADER_STAGE_ALL_RAY_TRACING,	//  VkShaderStageFlags	shaderStage;
2283 				de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
2284 				DE_FALSE						//  deBool				requiredSubgroupSize;
2285 			};
2286 
2287 			addFunctionCaseWithPrograms(raytracingGroup.get(), op, "", supportedCheck, initPrograms, test, caseDef);
2288 		}
2289 #endif // CTS_USES_VULKANSC
2290 
2291 		for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(fbStages); ++stageIndex)
2292 		{
2293 			if (OPTYPE_ELECT == opType && fbStages[stageIndex] == VK_SHADER_STAGE_FRAGMENT_BIT)
2294 				continue;		// This is not tested. I don't know why.
2295 
2296 			const CaseDefinition	caseDef		=
2297 			{
2298 				opType,							//  OpType				opType;
2299 				fbStages[stageIndex],			//  VkShaderStageFlags	shaderStage;
2300 				de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
2301 				DE_FALSE						//  deBool				requiredSubgroupSize;
2302 			};
2303 			const string			testName	= op + "_" + getShaderStageName(caseDef.shaderStage);
2304 
2305 			addFunctionCaseWithPrograms(framebufferGroup.get(), testName, "", supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
2306 		}
2307 	}
2308 
2309 	group->addChild(graphicGroup.release());
2310 	group->addChild(computeGroup.release());
2311 	group->addChild(framebufferGroup.release());
2312 	group->addChild(raytracingGroup.release());
2313 	group->addChild(meshGroup.release());
2314 
2315 	return group.release();
2316 }
2317 
2318 } // subgroups
2319 } // vkt
2320