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