• 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 
checkCompute(const void * internalData,vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)158 static bool checkCompute (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::checkCompute(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 	const bool					spirv14required	= isAllRayTracingStages(caseDef.shaderStage);
240 	const SpirvVersion			spirvVersion	= spirv14required ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3;
241 	const ShaderBuildOptions	buildOptions	(programCollection.usedVulkanVersion, spirvVersion, 0u);
242 	const string				extHeader		= getExtHeader(caseDef);
243 	const string				testSrc			= getTestSrc(caseDef);
244 
245 	subgroups::initStdPrograms(programCollection, buildOptions, caseDef.shaderStage, caseDef.format, *caseDef.geometryPointSizeSupported, extHeader, testSrc, "");
246 }
247 
supportedCheck(Context & context,CaseDefinition caseDef)248 void supportedCheck (Context& context, CaseDefinition caseDef)
249 {
250 	if (!subgroups::isSubgroupSupported(context))
251 		TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
252 
253 	if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_ARITHMETIC_BIT))
254 		TCU_THROW(NotSupportedError, "Device does not support subgroup arithmetic operations");
255 
256 	if (!subgroups::isFormatSupportedForDevice(context, caseDef.format))
257 		TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
258 
259 	if (caseDef.requiredSubgroupSize)
260 	{
261 		context.requireDeviceFunctionality("VK_EXT_subgroup_size_control");
262 
263 		const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT&	subgroupSizeControlFeatures		= context.getSubgroupSizeControlFeaturesEXT();
264 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
265 
266 		if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
267 			TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes nor required subgroup size");
268 
269 		if (subgroupSizeControlFeatures.computeFullSubgroups == DE_FALSE)
270 			TCU_THROW(NotSupportedError, "Device does not support full subgroups in compute shaders");
271 
272 		if ((subgroupSizeControlProperties.requiredSubgroupSizeStages & caseDef.shaderStage) != caseDef.shaderStage)
273 			TCU_THROW(NotSupportedError, "Required subgroup size is not supported for shader stage");
274 	}
275 
276 	*caseDef.geometryPointSizeSupported = subgroups::isTessellationAndGeometryPointSizeSupported(context);
277 
278 	if (isAllRayTracingStages(caseDef.shaderStage))
279 	{
280 		context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
281 	}
282 
283 	subgroups::supportedCheckShader(context, caseDef.shaderStage);
284 }
285 
noSSBOtest(Context & context,const CaseDefinition caseDef)286 TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
287 {
288 	const subgroups::SSBOData	inputData	=
289 	{
290 		subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
291 		subgroups::SSBOData::LayoutStd140,		//  InputDataLayoutType			layout;
292 		caseDef.format,							//  vk::VkFormat				format;
293 		subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
294 	};
295 
296 	switch (caseDef.shaderStage)
297 	{
298 		case VK_SHADER_STAGE_VERTEX_BIT:					return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages);
299 		case VK_SHADER_STAGE_GEOMETRY_BIT:					return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages);
300 		case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:		return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
301 		case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:	return subgroups::makeTessellationEvaluationFrameBufferTest(context,  VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
302 		default:											TCU_THROW(InternalError, "Unhandled shader stage");
303 	}
304 }
305 
test(Context & context,const CaseDefinition caseDef)306 TestStatus test (Context& context, const CaseDefinition caseDef)
307 {
308 	if (isAllComputeStages(caseDef.shaderStage))
309 	{
310 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
311 		TestLog&												log								= context.getTestContext().getLog();
312 		const subgroups::SSBOData								inputData						=
313 		{
314 			subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
315 			subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
316 			caseDef.format,							//  vk::VkFormat				format;
317 			subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
318 		};
319 
320 		if (caseDef.requiredSubgroupSize == DE_FALSE)
321 			return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkCompute);
322 
323 		log << TestLog::Message << "Testing required subgroup size range [" <<  subgroupSizeControlProperties.minSubgroupSize << ", "
324 			<< subgroupSizeControlProperties.maxSubgroupSize << "]" << TestLog::EndMessage;
325 
326 		// According to the spec, requiredSubgroupSize must be a power-of-two integer.
327 		for (deUint32 size = subgroupSizeControlProperties.minSubgroupSize; size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
328 		{
329 			TestStatus result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkCompute,
330 															size, VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT);
331 			if (result.getCode() != QP_TEST_RESULT_PASS)
332 			{
333 				log << TestLog::Message << "subgroupSize " << size << " failed" << TestLog::EndMessage;
334 				return result;
335 			}
336 		}
337 
338 		return TestStatus::pass("OK");
339 	}
340 	else if (isAllGraphicsStages(caseDef.shaderStage))
341 	{
342 		const VkShaderStageFlags	stages		= subgroups::getPossibleGraphicsSubgroupStages(context, caseDef.shaderStage);
343 		const subgroups::SSBOData	inputData	=
344 		{
345 			subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
346 			subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
347 			caseDef.format,							//  vk::VkFormat				format;
348 			subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
349 			false,									//  bool						isImage;
350 			4u,										//  deUint32					binding;
351 			stages,									//  vk::VkShaderStageFlags		stages;
352 		};
353 
354 		return subgroups::allStages(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, stages);
355 	}
356 	else if (isAllRayTracingStages(caseDef.shaderStage))
357 	{
358 		const VkShaderStageFlags	stages		= subgroups::getPossibleRayTracingSubgroupStages(context, caseDef.shaderStage);
359 		const subgroups::SSBOData	inputData	=
360 		{
361 			subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
362 			subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
363 			caseDef.format,							//  vk::VkFormat				format;
364 			subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
365 			false,									//  bool						isImage;
366 			6u,										//  deUint32					binding;
367 			stages,									//  vk::VkShaderStageFlags		stages;
368 		};
369 
370 		return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, stages);
371 	}
372 	else
373 		TCU_THROW(InternalError, "Unknown stage or invalid stage set");
374 }
375 }
376 
377 namespace vkt
378 {
379 namespace subgroups
380 {
createSubgroupsArithmeticTests(TestContext & testCtx)381 TestCaseGroup* createSubgroupsArithmeticTests (TestContext& testCtx)
382 {
383 	de::MovePtr<TestCaseGroup>	group				(new TestCaseGroup(testCtx, "arithmetic", "Subgroup arithmetic category tests"));
384 	de::MovePtr<TestCaseGroup>	graphicGroup		(new TestCaseGroup(testCtx, "graphics", "Subgroup arithmetic category tests: graphics"));
385 	de::MovePtr<TestCaseGroup>	computeGroup		(new TestCaseGroup(testCtx, "compute", "Subgroup arithmetic category tests: compute"));
386 	de::MovePtr<TestCaseGroup>	framebufferGroup	(new TestCaseGroup(testCtx, "framebuffer", "Subgroup arithmetic category tests: framebuffer"));
387 	de::MovePtr<TestCaseGroup>	raytracingGroup		(new TestCaseGroup(testCtx, "ray_tracing", "Subgroup arithmetic category tests: ray tracing"));
388 	const VkShaderStageFlags	stages[]			=
389 	{
390 		VK_SHADER_STAGE_VERTEX_BIT,
391 		VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
392 		VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
393 		VK_SHADER_STAGE_GEOMETRY_BIT,
394 	};
395 	const deBool				boolValues[]		=
396 	{
397 		DE_FALSE,
398 		DE_TRUE
399 	};
400 
401 	{
402 		const vector<VkFormat>		formats		= subgroups::getAllFormats();
403 
404 		for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
405 		{
406 			const VkFormat	format		= formats[formatIndex];
407 			const string	formatName	= subgroups::getFormatNameForGLSL(format);
408 			const bool		isBool		= subgroups::isFormatBool(format);
409 			const bool		isFloat		= subgroups::isFormatFloat(format);
410 
411 			for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
412 			{
413 				const OpType	opType		= static_cast<OpType>(opTypeIndex);
414 				const Operator	op			= getOperator(opType);
415 				const ScanType	st			= getScanType(opType);
416 				const bool		isBitwiseOp	= (op == OPERATOR_AND || op == OPERATOR_OR || op == OPERATOR_XOR);
417 
418 				// Skip float with bitwise category.
419 				if (isFloat && isBitwiseOp)
420 					continue;
421 
422 				// Skip bool when its not the bitwise category.
423 				if (isBool && !isBitwiseOp)
424 					continue;
425 
426 				const string	name	= de::toLower(getOpTypeName(op, st)) + "_" + formatName;
427 
428 				for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
429 				{
430 					const deBool			requiredSubgroupSize	= boolValues[groupSizeNdx];
431 					const string			testName				= name + (requiredSubgroupSize ? "_requiredsubgroupsize" : "");
432 					const CaseDefinition	caseDef					=
433 					{
434 						op,								//  Operator			op;
435 						st,								//  ScanType			scanType;
436 						VK_SHADER_STAGE_COMPUTE_BIT,	//  VkShaderStageFlags	shaderStage;
437 						format,							//  VkFormat			format;
438 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
439 						requiredSubgroupSize			//  deBool				requiredSubgroupSize;
440 					};
441 
442 					addFunctionCaseWithPrograms(computeGroup.get(), testName, "", supportedCheck, initPrograms, test, caseDef);
443 				}
444 
445 				{
446 					const CaseDefinition	caseDef	=
447 					{
448 						op,								//  Operator			op;
449 						st,								//  ScanType			scanType;
450 						VK_SHADER_STAGE_ALL_GRAPHICS,	//  VkShaderStageFlags	shaderStage;
451 						format,							//  VkFormat			format;
452 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
453 						DE_FALSE						//  deBool				requiredSubgroupSize;
454 					};
455 
456 					addFunctionCaseWithPrograms(graphicGroup.get(), name, "", supportedCheck, initPrograms, test, caseDef);
457 				}
458 
459 				for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
460 				{
461 					const CaseDefinition	caseDef		=
462 					{
463 						op,								//  Operator			op;
464 						st,								//  ScanType			scanType;
465 						stages[stageIndex],				//  VkShaderStageFlags	shaderStage;
466 						format,							//  VkFormat			format;
467 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
468 						DE_FALSE						//  deBool				requiredSubgroupSize;
469 					};
470 					const string			testName	= name + "_" + getShaderStageName(caseDef.shaderStage);
471 
472 					addFunctionCaseWithPrograms(framebufferGroup.get(), testName, "", supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
473 				}
474 			}
475 		}
476 	}
477 
478 	{
479 		const vector<VkFormat>		formats		= subgroups::getAllRayTracingFormats();
480 
481 		for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
482 		{
483 			const VkFormat	format		= formats[formatIndex];
484 			const string	formatName	= subgroups::getFormatNameForGLSL(format);
485 			const bool		isBool		= subgroups::isFormatBool(format);
486 			const bool		isFloat		= subgroups::isFormatFloat(format);
487 
488 			for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
489 			{
490 				const OpType	opType		= static_cast<OpType>(opTypeIndex);
491 				const Operator	op			= getOperator(opType);
492 				const ScanType	st			= getScanType(opType);
493 				const bool		isBitwiseOp	= (op == OPERATOR_AND || op == OPERATOR_OR || op == OPERATOR_XOR);
494 
495 				// Skip float with bitwise category.
496 				if (isFloat && isBitwiseOp)
497 					continue;
498 
499 				// Skip bool when its not the bitwise category.
500 				if (isBool && !isBitwiseOp)
501 					continue;
502 
503 				{
504 					const CaseDefinition	caseDef	=
505 					{
506 						op,								//  Operator			op;
507 						st,								//  ScanType			scanType;
508 						SHADER_STAGE_ALL_RAY_TRACING,	//  VkShaderStageFlags	shaderStage;
509 						format,							//  VkFormat			format;
510 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
511 						DE_FALSE						//  deBool				requiredSubgroupSize;
512 					};
513 					const string			name	= de::toLower(getOpTypeName(op, st)) + "_" + formatName;
514 
515 					addFunctionCaseWithPrograms(raytracingGroup.get(), name, "", supportedCheck, initPrograms, test, caseDef);
516 				}
517 			}
518 		}
519 	}
520 
521 	group->addChild(graphicGroup.release());
522 	group->addChild(computeGroup.release());
523 	group->addChild(framebufferGroup.release());
524 	group->addChild(raytracingGroup.release());
525 
526 	return group.release();
527 }
528 } // subgroups
529 } // vkt
530