• 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 "vktSubgroupsArithmeticTests.hpp"
27 #include "vktSubgroupsScanHelpers.hpp"
28 #include "vktSubgroupsTestsUtils.hpp"
29 
30 #include <string>
31 #include <vector>
32 
33 using namespace tcu;
34 using namespace std;
35 using namespace vk;
36 using namespace vkt;
37 
38 namespace
39 {
40 enum OpType
41 {
42 	OPTYPE_ADD = 0,
43 	OPTYPE_MUL,
44 	OPTYPE_MIN,
45 	OPTYPE_MAX,
46 	OPTYPE_AND,
47 	OPTYPE_OR,
48 	OPTYPE_XOR,
49 	OPTYPE_INCLUSIVE_ADD,
50 	OPTYPE_INCLUSIVE_MUL,
51 	OPTYPE_INCLUSIVE_MIN,
52 	OPTYPE_INCLUSIVE_MAX,
53 	OPTYPE_INCLUSIVE_AND,
54 	OPTYPE_INCLUSIVE_OR,
55 	OPTYPE_INCLUSIVE_XOR,
56 	OPTYPE_EXCLUSIVE_ADD,
57 	OPTYPE_EXCLUSIVE_MUL,
58 	OPTYPE_EXCLUSIVE_MIN,
59 	OPTYPE_EXCLUSIVE_MAX,
60 	OPTYPE_EXCLUSIVE_AND,
61 	OPTYPE_EXCLUSIVE_OR,
62 	OPTYPE_EXCLUSIVE_XOR,
63 	OPTYPE_LAST
64 };
65 
66 struct CaseDefinition
67 {
68 	Operator			op;
69 	ScanType			scanType;
70 	VkShaderStageFlags	shaderStage;
71 	VkFormat			format;
72 	de::SharedPtr<bool>	geometryPointSizeSupported;
73 	deBool				requiredSubgroupSize;
74 };
75 
getOperator(OpType opType)76 static Operator getOperator (OpType opType)
77 {
78 	switch (opType)
79 	{
80 		case OPTYPE_ADD:
81 		case OPTYPE_INCLUSIVE_ADD:
82 		case OPTYPE_EXCLUSIVE_ADD:
83 			return OPERATOR_ADD;
84 		case OPTYPE_MUL:
85 		case OPTYPE_INCLUSIVE_MUL:
86 		case OPTYPE_EXCLUSIVE_MUL:
87 			return OPERATOR_MUL;
88 		case OPTYPE_MIN:
89 		case OPTYPE_INCLUSIVE_MIN:
90 		case OPTYPE_EXCLUSIVE_MIN:
91 			return OPERATOR_MIN;
92 		case OPTYPE_MAX:
93 		case OPTYPE_INCLUSIVE_MAX:
94 		case OPTYPE_EXCLUSIVE_MAX:
95 			return OPERATOR_MAX;
96 		case OPTYPE_AND:
97 		case OPTYPE_INCLUSIVE_AND:
98 		case OPTYPE_EXCLUSIVE_AND:
99 			return OPERATOR_AND;
100 		case OPTYPE_OR:
101 		case OPTYPE_INCLUSIVE_OR:
102 		case OPTYPE_EXCLUSIVE_OR:
103 			return OPERATOR_OR;
104 		case OPTYPE_XOR:
105 		case OPTYPE_INCLUSIVE_XOR:
106 		case OPTYPE_EXCLUSIVE_XOR:
107 			return OPERATOR_XOR;
108 		default:
109 			DE_FATAL("Unsupported op type");
110 			return OPERATOR_ADD;
111 	}
112 }
113 
getScanType(OpType opType)114 static ScanType getScanType(OpType opType)
115 {
116 	switch (opType)
117 	{
118 		case OPTYPE_ADD:
119 		case OPTYPE_MUL:
120 		case OPTYPE_MIN:
121 		case OPTYPE_MAX:
122 		case OPTYPE_AND:
123 		case OPTYPE_OR:
124 		case OPTYPE_XOR:
125 			return SCAN_REDUCE;
126 		case OPTYPE_INCLUSIVE_ADD:
127 		case OPTYPE_INCLUSIVE_MUL:
128 		case OPTYPE_INCLUSIVE_MIN:
129 		case OPTYPE_INCLUSIVE_MAX:
130 		case OPTYPE_INCLUSIVE_AND:
131 		case OPTYPE_INCLUSIVE_OR:
132 		case OPTYPE_INCLUSIVE_XOR:
133 			return SCAN_INCLUSIVE;
134 		case OPTYPE_EXCLUSIVE_ADD:
135 		case OPTYPE_EXCLUSIVE_MUL:
136 		case OPTYPE_EXCLUSIVE_MIN:
137 		case OPTYPE_EXCLUSIVE_MAX:
138 		case OPTYPE_EXCLUSIVE_AND:
139 		case OPTYPE_EXCLUSIVE_OR:
140 		case OPTYPE_EXCLUSIVE_XOR:
141 			return SCAN_EXCLUSIVE;
142 		default:
143 			DE_FATAL("Unsupported op type");
144 			return SCAN_REDUCE;
145 	}
146 }
147 
checkVertexPipelineStages(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)148 static bool checkVertexPipelineStages (const void*			internalData,
149 									   vector<const void*>	datas,
150 									   deUint32				width,
151 									   deUint32)
152 {
153 	DE_UNREF(internalData);
154 
155 	return subgroups::check(datas, width, 0x3);
156 }
157 
checkComputeOrMesh(const void * internalData,vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)158 static bool checkComputeOrMesh (const void*			internalData,
159 								vector<const void*>	datas,
160 								const deUint32		numWorkgroups[3],
161 								const deUint32		localSize[3],
162 								deUint32)
163 {
164 	DE_UNREF(internalData);
165 
166 	return subgroups::checkComputeOrMesh(datas, numWorkgroups, localSize, 0x3);
167 }
168 
getOpTypeName(Operator op,ScanType scanType)169 string getOpTypeName (Operator op, ScanType scanType)
170 {
171 	return getScanOpName("subgroup", "", op, scanType);
172 }
173 
getExtHeader(const CaseDefinition & caseDef)174 string getExtHeader (const CaseDefinition& caseDef)
175 {
176 	return	"#extension GL_KHR_shader_subgroup_arithmetic: enable\n"
177 			"#extension GL_KHR_shader_subgroup_ballot: enable\n" +
178 			subgroups::getAdditionalExtensionForFormat(caseDef.format);
179 }
180 
getIndexVars(const CaseDefinition & caseDef)181 string getIndexVars (const CaseDefinition& caseDef)
182 {
183 	switch (caseDef.scanType)
184 	{
185 		case SCAN_REDUCE:		return "  uint start = 0, end = gl_SubgroupSize;\n";
186 		case SCAN_INCLUSIVE:	return "  uint start = 0, end = gl_SubgroupInvocationID + 1;\n";
187 		case SCAN_EXCLUSIVE:	return "  uint start = 0, end = gl_SubgroupInvocationID;\n";
188 		default:				TCU_THROW(InternalError, "Unreachable");
189 	}
190 }
191 
getTestSrc(const CaseDefinition & caseDef)192 string getTestSrc (const CaseDefinition& caseDef)
193 {
194 	const string indexVars = getIndexVars(caseDef);
195 
196 	return	"  uvec4 mask = subgroupBallot(true);\n"
197 			+ indexVars +
198 			"  " + subgroups::getFormatNameForGLSL(caseDef.format) + " ref = "
199 			+ getIdentity(caseDef.op, caseDef.format) + ";\n"
200 			"  tempRes = 0;\n"
201 			"  for (uint index = start; index < end; index++)\n"
202 			"  {\n"
203 			"    if (subgroupBallotBitExtract(mask, index))\n"
204 			"    {\n"
205 			"      ref = " + getOpOperation(caseDef.op, caseDef.format, "ref", "data[index]") + ";\n"
206 			"    }\n"
207 			"  }\n"
208 			"  tempRes = " + getCompare(caseDef.op, caseDef.format, "ref", getOpTypeName(caseDef.op, caseDef.scanType) + "(data[gl_SubgroupInvocationID])") + " ? 0x1 : 0;\n"
209 			"  if (1 == (gl_SubgroupInvocationID % 2))\n"
210 			"  {\n"
211 			"    mask = subgroupBallot(true);\n"
212 			"    ref = " + getIdentity(caseDef.op, caseDef.format) + ";\n"
213 			"    for (uint index = start; index < end; index++)\n"
214 			"    {\n"
215 			"      if (subgroupBallotBitExtract(mask, index))\n"
216 			"      {\n"
217 			"        ref = " + getOpOperation(caseDef.op, caseDef.format, "ref", "data[index]") + ";\n"
218 			"      }\n"
219 			"    }\n"
220 			"    tempRes |= " + getCompare(caseDef.op, caseDef.format, "ref", getOpTypeName(caseDef.op, caseDef.scanType) + "(data[gl_SubgroupInvocationID])") + " ? 0x2 : 0;\n"
221 			"  }\n"
222 			"  else\n"
223 			"  {\n"
224 			"    tempRes |= 0x2;\n"
225 			"  }\n";
226 }
227 
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)228 void initFrameBufferPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
229 {
230 	const ShaderBuildOptions	buildOptions	(programCollection.usedVulkanVersion, SPIRV_VERSION_1_3, 0u);
231 	const string				extHeader		= getExtHeader(caseDef);
232 	const string				testSrc			= getTestSrc(caseDef);
233 
234 	subgroups::initStdFrameBufferPrograms(programCollection, buildOptions, caseDef.shaderStage, caseDef.format, *caseDef.geometryPointSizeSupported, extHeader, testSrc, "");
235 }
236 
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)237 void initPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
238 {
239 #ifndef CTS_USES_VULKANSC
240 	const bool					spirv14required	= (isAllRayTracingStages(caseDef.shaderStage) || isAllMeshShadingStages(caseDef.shaderStage));
241 #else
242 	const bool					spirv14required	= false;
243 #endif // CTS_USES_VULKANSC
244 	const SpirvVersion			spirvVersion	= spirv14required ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3;
245 	const ShaderBuildOptions	buildOptions	(programCollection.usedVulkanVersion, spirvVersion, 0u, spirv14required);
246 	const string				extHeader		= getExtHeader(caseDef);
247 	const string				testSrc			= getTestSrc(caseDef);
248 
249 	subgroups::initStdPrograms(programCollection, buildOptions, caseDef.shaderStage, caseDef.format, *caseDef.geometryPointSizeSupported, extHeader, testSrc, "");
250 }
251 
supportedCheck(Context & context,CaseDefinition caseDef)252 void supportedCheck (Context& context, CaseDefinition caseDef)
253 {
254 	if (!subgroups::isSubgroupSupported(context))
255 		TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
256 
257 	if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_ARITHMETIC_BIT))
258 		TCU_THROW(NotSupportedError, "Device does not support subgroup arithmetic operations");
259 
260 	if (!subgroups::isFormatSupportedForDevice(context, caseDef.format))
261 		TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
262 
263 	if (caseDef.requiredSubgroupSize)
264 	{
265 		context.requireDeviceFunctionality("VK_EXT_subgroup_size_control");
266 
267 #ifndef CTS_USES_VULKANSC
268 		const VkPhysicalDeviceSubgroupSizeControlFeatures&		subgroupSizeControlFeatures		= context.getSubgroupSizeControlFeatures();
269 		const VkPhysicalDeviceSubgroupSizeControlProperties&	subgroupSizeControlProperties	= context.getSubgroupSizeControlProperties();
270 #else
271 		const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT&	subgroupSizeControlFeatures		= context.getSubgroupSizeControlFeaturesEXT();
272 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
273 #endif // CTS_USES_VULKANSC
274 
275 		if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
276 			TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes nor required subgroup size");
277 
278 		if (subgroupSizeControlFeatures.computeFullSubgroups == DE_FALSE)
279 			TCU_THROW(NotSupportedError, "Device does not support full subgroups in compute shaders");
280 
281 		if ((subgroupSizeControlProperties.requiredSubgroupSizeStages & caseDef.shaderStage) != caseDef.shaderStage)
282 			TCU_THROW(NotSupportedError, "Required subgroup size is not supported for shader stage");
283 	}
284 
285 	*caseDef.geometryPointSizeSupported = subgroups::isTessellationAndGeometryPointSizeSupported(context);
286 
287 #ifndef CTS_USES_VULKANSC
288 	if (isAllRayTracingStages(caseDef.shaderStage))
289 	{
290 		context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
291 	}
292 	else if (isAllMeshShadingStages(caseDef.shaderStage))
293 	{
294 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
295 		context.requireDeviceFunctionality("VK_EXT_mesh_shader");
296 
297 		if ((caseDef.shaderStage & VK_SHADER_STAGE_TASK_BIT_EXT) != 0u)
298 		{
299 			const auto& features = context.getMeshShaderFeaturesEXT();
300 			if (!features.taskShader)
301 				TCU_THROW(NotSupportedError, "Task shaders not supported");
302 		}
303 	}
304 #endif // CTS_USES_VULKANSC
305 
306 	subgroups::supportedCheckShader(context, caseDef.shaderStage);
307 }
308 
noSSBOtest(Context & context,const CaseDefinition caseDef)309 TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
310 {
311 	const subgroups::SSBOData	inputData	=
312 	{
313 		subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
314 		subgroups::SSBOData::LayoutStd140,		//  InputDataLayoutType			layout;
315 		caseDef.format,							//  vk::VkFormat				format;
316 		subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
317 		subgroups::SSBOData::BindingUBO,		//  BindingType					bindingType;
318 	};
319 
320 	switch (caseDef.shaderStage)
321 	{
322 		case VK_SHADER_STAGE_VERTEX_BIT:					return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages);
323 		case VK_SHADER_STAGE_GEOMETRY_BIT:					return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages);
324 		case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:		return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
325 		case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:	return subgroups::makeTessellationEvaluationFrameBufferTest(context,  VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
326 		default:											TCU_THROW(InternalError, "Unhandled shader stage");
327 	}
328 }
329 
test(Context & context,const CaseDefinition caseDef)330 TestStatus test (Context& context, const CaseDefinition caseDef)
331 {
332 	const bool isCompute	= isAllComputeStages(caseDef.shaderStage);
333 #ifndef CTS_USES_VULKANSC
334 	const bool isMesh		= isAllMeshShadingStages(caseDef.shaderStage);
335 #else
336 	const bool isMesh		= false;
337 #endif // CTS_USES_VULKANSC
338 	DE_ASSERT(!(isCompute && isMesh));
339 
340 	if (isCompute || isMesh)
341 	{
342 #ifndef CTS_USES_VULKANSC
343 		const VkPhysicalDeviceSubgroupSizeControlProperties&	subgroupSizeControlProperties	= context.getSubgroupSizeControlProperties();
344 #else
345 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
346 #endif // CTS_USES_VULKANSC
347 		TestLog&												log								= context.getTestContext().getLog();
348 		const subgroups::SSBOData								inputData						=
349 		{
350 			subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
351 			subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
352 			caseDef.format,							//  vk::VkFormat				format;
353 			subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
354 		};
355 
356 		if (caseDef.requiredSubgroupSize == DE_FALSE)
357 		{
358 			if (isMesh)
359 				return subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkComputeOrMesh);
360 			else
361 				return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkComputeOrMesh);
362 		}
363 
364 		log << TestLog::Message << "Testing required subgroup size range [" <<  subgroupSizeControlProperties.minSubgroupSize << ", "
365 			<< subgroupSizeControlProperties.maxSubgroupSize << "]" << TestLog::EndMessage;
366 
367 		// According to the spec, requiredSubgroupSize must be a power-of-two integer.
368 		for (deUint32 size = subgroupSizeControlProperties.minSubgroupSize; size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
369 		{
370 			TestStatus result (QP_TEST_RESULT_INTERNAL_ERROR, "Internal Error");
371 
372 			if (isCompute)
373 				result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkComputeOrMesh, size);
374 			else
375 				result = subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkComputeOrMesh, size);
376 
377 			if (result.getCode() != QP_TEST_RESULT_PASS)
378 			{
379 				log << TestLog::Message << "subgroupSize " << size << " failed" << TestLog::EndMessage;
380 				return result;
381 			}
382 		}
383 
384 		return TestStatus::pass("OK");
385 	}
386 	else if (isAllGraphicsStages(caseDef.shaderStage))
387 	{
388 		const VkShaderStageFlags	stages		= subgroups::getPossibleGraphicsSubgroupStages(context, caseDef.shaderStage);
389 		const subgroups::SSBOData	inputData	=
390 		{
391 			subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
392 			subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
393 			caseDef.format,							//  vk::VkFormat				format;
394 			subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
395 			subgroups::SSBOData::BindingSSBO,		//  bool						isImage;
396 			4u,										//  deUint32					binding;
397 			stages,									//  vk::VkShaderStageFlags		stages;
398 		};
399 
400 		return subgroups::allStages(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, stages);
401 	}
402 #ifndef CTS_USES_VULKANSC
403 	else if (isAllRayTracingStages(caseDef.shaderStage))
404 	{
405 		const VkShaderStageFlags	stages		= subgroups::getPossibleRayTracingSubgroupStages(context, caseDef.shaderStage);
406 		const subgroups::SSBOData	inputData	=
407 		{
408 			subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
409 			subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
410 			caseDef.format,							//  vk::VkFormat				format;
411 			subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
412 			subgroups::SSBOData::BindingSSBO,		//  bool						isImage;
413 			6u,										//  deUint32					binding;
414 			stages,									//  vk::VkShaderStageFlags		stages;
415 		};
416 
417 		return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, stages);
418 	}
419 #endif // CTS_USES_VULKANSC
420 	else
421 		TCU_THROW(InternalError, "Unknown stage or invalid stage set");
422 }
423 }
424 
425 namespace vkt
426 {
427 namespace subgroups
428 {
createSubgroupsArithmeticTests(TestContext & testCtx)429 TestCaseGroup* createSubgroupsArithmeticTests (TestContext& testCtx)
430 {
431 	de::MovePtr<TestCaseGroup>	group				(new TestCaseGroup(testCtx, "arithmetic", "Subgroup arithmetic category tests"));
432 
433 	de::MovePtr<TestCaseGroup>	graphicGroup		(new TestCaseGroup(testCtx, "graphics", "Subgroup arithmetic category tests: graphics"));
434 	de::MovePtr<TestCaseGroup>	computeGroup		(new TestCaseGroup(testCtx, "compute", "Subgroup arithmetic category tests: compute"));
435 	de::MovePtr<TestCaseGroup>	framebufferGroup	(new TestCaseGroup(testCtx, "framebuffer", "Subgroup arithmetic category tests: framebuffer"));
436 #ifndef CTS_USES_VULKANSC
437 	de::MovePtr<TestCaseGroup>	raytracingGroup		(new TestCaseGroup(testCtx, "ray_tracing", "Subgroup arithmetic category tests: ray tracing"));
438 	de::MovePtr<TestCaseGroup>	meshGroup			(new TestCaseGroup(testCtx, "mesh", "Subgroup arithmetic category tests: mesh"));
439 #endif // CTS_USES_VULKANSC
440 
441 	const VkShaderStageFlags	fbStages[]			=
442 	{
443 		VK_SHADER_STAGE_VERTEX_BIT,
444 		VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
445 		VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
446 		VK_SHADER_STAGE_GEOMETRY_BIT,
447 	};
448 #ifndef CTS_USES_VULKANSC
449 	const VkShaderStageFlags	meshStages[]		=
450 	{
451 		VK_SHADER_STAGE_MESH_BIT_EXT,
452 		VK_SHADER_STAGE_TASK_BIT_EXT,
453 	};
454 #endif // CTS_USES_VULKANSC
455 	const deBool				boolValues[]		=
456 	{
457 		DE_FALSE,
458 		DE_TRUE
459 	};
460 
461 	{
462 		const vector<VkFormat>		formats		= subgroups::getAllFormats();
463 
464 		for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
465 		{
466 			const VkFormat	format		= formats[formatIndex];
467 			const string	formatName	= subgroups::getFormatNameForGLSL(format);
468 			const bool		isBool		= subgroups::isFormatBool(format);
469 			const bool		isFloat		= subgroups::isFormatFloat(format);
470 
471 			for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
472 			{
473 				const OpType	opType		= static_cast<OpType>(opTypeIndex);
474 				const Operator	op			= getOperator(opType);
475 				const ScanType	st			= getScanType(opType);
476 				const bool		isBitwiseOp	= (op == OPERATOR_AND || op == OPERATOR_OR || op == OPERATOR_XOR);
477 
478 				// Skip float with bitwise category.
479 				if (isFloat && isBitwiseOp)
480 					continue;
481 
482 				// Skip bool when its not the bitwise category.
483 				if (isBool && !isBitwiseOp)
484 					continue;
485 
486 				const string	name	= de::toLower(getOpTypeName(op, st)) + "_" + formatName;
487 
488 				for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
489 				{
490 					const deBool			requiredSubgroupSize	= boolValues[groupSizeNdx];
491 					const string			testName				= name + (requiredSubgroupSize ? "_requiredsubgroupsize" : "");
492 					const CaseDefinition	caseDef					=
493 					{
494 						op,								//  Operator			op;
495 						st,								//  ScanType			scanType;
496 						VK_SHADER_STAGE_COMPUTE_BIT,	//  VkShaderStageFlags	shaderStage;
497 						format,							//  VkFormat			format;
498 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
499 						requiredSubgroupSize			//  deBool				requiredSubgroupSize;
500 					};
501 
502 					addFunctionCaseWithPrograms(computeGroup.get(), testName, "", supportedCheck, initPrograms, test, caseDef);
503 				}
504 
505 #ifndef CTS_USES_VULKANSC
506 				for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
507 				{
508 					for (const auto& meshStage : meshStages)
509 					{
510 						const deBool			requiredSubgroupSize	= boolValues[groupSizeNdx];
511 						const string			testName				= name + "_" + getShaderStageName(meshStage) + (requiredSubgroupSize ? "_requiredsubgroupsize" : "");
512 						const CaseDefinition	caseDef					=
513 						{
514 							op,								//  Operator			op;
515 							st,								//  ScanType			scanType;
516 							meshStage,						//  VkShaderStageFlags	shaderStage;
517 							format,							//  VkFormat			format;
518 							de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
519 							requiredSubgroupSize			//  deBool				requiredSubgroupSize;
520 						};
521 
522 						addFunctionCaseWithPrograms(meshGroup.get(), testName, "", supportedCheck, initPrograms, test, caseDef);
523 					}
524 				}
525 #endif // CTS_USES_VULKANSC
526 
527 				{
528 					const CaseDefinition	caseDef	=
529 					{
530 						op,								//  Operator			op;
531 						st,								//  ScanType			scanType;
532 						VK_SHADER_STAGE_ALL_GRAPHICS,	//  VkShaderStageFlags	shaderStage;
533 						format,							//  VkFormat			format;
534 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
535 						DE_FALSE						//  deBool				requiredSubgroupSize;
536 					};
537 
538 					addFunctionCaseWithPrograms(graphicGroup.get(), name, "", supportedCheck, initPrograms, test, caseDef);
539 				}
540 
541 				for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(fbStages); ++stageIndex)
542 				{
543 					const CaseDefinition	caseDef		=
544 					{
545 						op,								//  Operator			op;
546 						st,								//  ScanType			scanType;
547 						fbStages[stageIndex],			//  VkShaderStageFlags	shaderStage;
548 						format,							//  VkFormat			format;
549 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
550 						DE_FALSE						//  deBool				requiredSubgroupSize;
551 					};
552 					const string			testName	= name + "_" + getShaderStageName(caseDef.shaderStage);
553 
554 					addFunctionCaseWithPrograms(framebufferGroup.get(), testName, "", supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
555 				}
556 			}
557 		}
558 	}
559 
560 #ifndef CTS_USES_VULKANSC
561 	{
562 		const vector<VkFormat>		formats		= subgroups::getAllRayTracingFormats();
563 
564 		for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
565 		{
566 			const VkFormat	format		= formats[formatIndex];
567 			const string	formatName	= subgroups::getFormatNameForGLSL(format);
568 			const bool		isBool		= subgroups::isFormatBool(format);
569 			const bool		isFloat		= subgroups::isFormatFloat(format);
570 
571 			for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
572 			{
573 				const OpType	opType		= static_cast<OpType>(opTypeIndex);
574 				const Operator	op			= getOperator(opType);
575 				const ScanType	st			= getScanType(opType);
576 				const bool		isBitwiseOp	= (op == OPERATOR_AND || op == OPERATOR_OR || op == OPERATOR_XOR);
577 
578 				// Skip float with bitwise category.
579 				if (isFloat && isBitwiseOp)
580 					continue;
581 
582 				// Skip bool when its not the bitwise category.
583 				if (isBool && !isBitwiseOp)
584 					continue;
585 
586 				{
587 					const CaseDefinition	caseDef	=
588 					{
589 						op,								//  Operator			op;
590 						st,								//  ScanType			scanType;
591 						SHADER_STAGE_ALL_RAY_TRACING,	//  VkShaderStageFlags	shaderStage;
592 						format,							//  VkFormat			format;
593 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
594 						DE_FALSE						//  deBool				requiredSubgroupSize;
595 					};
596 					const string			name	= de::toLower(getOpTypeName(op, st)) + "_" + formatName;
597 
598 					addFunctionCaseWithPrograms(raytracingGroup.get(), name, "", supportedCheck, initPrograms, test, caseDef);
599 				}
600 			}
601 		}
602 	}
603 #endif // CTS_USES_VULKANSC
604 
605 	group->addChild(graphicGroup.release());
606 	group->addChild(computeGroup.release());
607 	group->addChild(framebufferGroup.release());
608 #ifndef CTS_USES_VULKANSC
609 	group->addChild(raytracingGroup.release());
610 	group->addChild(meshGroup.release());
611 #endif // CTS_USES_VULKANSC
612 
613 	return group.release();
614 }
615 } // subgroups
616 } // vkt
617