• 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 "vktSubgroupsShuffleTests.hpp"
27 #include "vktSubgroupsTestsUtils.hpp"
28 
29 #include <string>
30 #include <vector>
31 
32 using namespace tcu;
33 using namespace std;
34 using namespace vk;
35 using namespace vkt;
36 
37 namespace
38 {
39 enum OpType
40 {
41 	OPTYPE_SHUFFLE = 0,
42 	OPTYPE_SHUFFLE_XOR,
43 	OPTYPE_SHUFFLE_UP,
44 	OPTYPE_SHUFFLE_DOWN,
45 	OPTYPE_LAST
46 };
47 
48 struct CaseDefinition
49 {
50 	OpType				opType;
51 	VkShaderStageFlags	shaderStage;
52 	VkFormat			format;
53 	de::SharedPtr<bool>	geometryPointSizeSupported;
54 	deBool				requiredSubgroupSize;
55 };
56 
checkVertexPipelineStages(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)57 static bool checkVertexPipelineStages (const void*			internalData,
58 									   vector<const void*>	datas,
59 									   deUint32				width,
60 									   deUint32)
61 {
62 	DE_UNREF(internalData);
63 
64 	return subgroups::check(datas, width, 1);
65 }
66 
checkCompute(const void * internalData,vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)67 static bool checkCompute (const void*			internalData,
68 						  vector<const void*>	datas,
69 						  const deUint32		numWorkgroups[3],
70 						  const deUint32		localSize[3],
71 						  deUint32)
72 {
73 	DE_UNREF(internalData);
74 
75 	return subgroups::checkCompute(datas, numWorkgroups, localSize, 1);
76 }
77 
getOpTypeName(OpType opType)78 string getOpTypeName (OpType opType)
79 {
80 	switch (opType)
81 	{
82 		case OPTYPE_SHUFFLE:		return "subgroupShuffle";
83 		case OPTYPE_SHUFFLE_XOR:	return "subgroupShuffleXor";
84 		case OPTYPE_SHUFFLE_UP:		return "subgroupShuffleUp";
85 		case OPTYPE_SHUFFLE_DOWN:	return "subgroupShuffleDown";
86 		default:					TCU_THROW(InternalError, "Unsupported op type");
87 	}
88 }
89 
getExtHeader(const CaseDefinition & caseDef)90 string getExtHeader (const CaseDefinition& caseDef)
91 {
92 	const string	eSource		= (OPTYPE_SHUFFLE == caseDef.opType || OPTYPE_SHUFFLE_XOR == caseDef.opType)
93 								? "#extension GL_KHR_shader_subgroup_shuffle: enable\n"
94 								: "#extension GL_KHR_shader_subgroup_shuffle_relative: enable\n";
95 
96 	return	eSource
97 			+ "#extension GL_KHR_shader_subgroup_ballot: enable\n"
98 			+ subgroups::getAdditionalExtensionForFormat(caseDef.format);
99 }
100 
getPerStageHeadDeclarations(const CaseDefinition & caseDef)101 vector<string> getPerStageHeadDeclarations (const CaseDefinition& caseDef)
102 {
103 	const string	formatName	= subgroups::getFormatNameForGLSL(caseDef.format);
104 	const deUint32	stageCount	= subgroups::getStagesCount(caseDef.shaderStage);
105 	const bool		fragment	= (caseDef.shaderStage & VK_SHADER_STAGE_FRAGMENT_BIT) != 0;
106 	const size_t	resultSize	= stageCount + (fragment ? 1 : 0);
107 	vector<string>	result		(resultSize, string());
108 
109 	for (deUint32 i = 0; i < result.size(); ++i)
110 	{
111 		const deUint32	binding0	= i;
112 		const deUint32	binding1	= stageCount;
113 		const deUint32	binding2	= stageCount + 1;
114 		const string	buffer1		= (i == stageCount)
115 									? "layout(location = 0) out uint result;\n"
116 									: "layout(set = 0, binding = " + de::toString(binding0) + ", std430) buffer Buffer1\n"
117 									  "{\n"
118 									  "  uint result[];\n"
119 									  "};\n";
120 
121 		result[i] =
122 			buffer1 +
123 			"layout(set = 0, binding = " + de::toString(binding1) + ", std430) readonly buffer Buffer2\n"
124 			"{\n"
125 			"  " + formatName + " data1[];\n"
126 			"};\n"
127 			"layout(set = 0, binding = " + de::toString(binding2) + ", std430) readonly buffer Buffer3\n"
128 			"{\n"
129 			"  uint data2[];\n"
130 			"};\n";
131 	}
132 
133 	return result;
134 }
135 
getFramebufferPerStageHeadDeclarations(const CaseDefinition & caseDef)136 vector<string> getFramebufferPerStageHeadDeclarations (const CaseDefinition& caseDef)
137 {
138 	const string	formatName	= subgroups::getFormatNameForGLSL(caseDef.format);
139 	const deUint32	stageCount	= subgroups::getStagesCount(caseDef.shaderStage);
140 	vector<string>	result		(stageCount, string());
141 	const string	buffer2
142 	{
143 		"layout(set = 0, binding = 0) uniform Buffer1\n"
144 		"{\n"
145 		"  " + formatName + " data1[" + de::toString(subgroups::maxSupportedSubgroupSize()) + "];\n"
146 		"};\n"
147 		"layout(set = 0, binding = 1) uniform Buffer2\n"
148 		"{\n"
149 		"  uint data2[" + de::toString(subgroups::maxSupportedSubgroupSize()) + "];\n"
150 		"};\n"
151 	};
152 
153 	for (size_t i = 0; i < result.size(); ++i)
154 	{
155 		switch (i)
156 		{
157 			case 0: result[i] = "layout(location = 0) out float result;\n" + buffer2;		break;
158 			case 1: result[i] = "layout(location = 0) out float out_color;\n" + buffer2;	break;
159 			case 2: result[i] = "layout(location = 0) out float out_color[];\n" + buffer2;	break;
160 			case 3: result[i] = "layout(location = 0) out float out_color;\n" + buffer2;	break;
161 			default: TCU_THROW(InternalError, "Unknown stage");
162 		}
163 	}
164 
165 	return result;
166 }
167 
getTestSource(const CaseDefinition & caseDef)168 const string getTestSource (const CaseDefinition& caseDef)
169 {
170 	const string	id			= caseDef.opType == OPTYPE_SHUFFLE		? "id_in"
171 								: caseDef.opType == OPTYPE_SHUFFLE_XOR	? "gl_SubgroupInvocationID ^ id_in"
172 								: caseDef.opType == OPTYPE_SHUFFLE_UP	? "gl_SubgroupInvocationID - id_in"
173 								: caseDef.opType == OPTYPE_SHUFFLE_DOWN	? "gl_SubgroupInvocationID + id_in"
174 								: "";
175 	const string	testSource	=
176 		"  uint temp_res;\n"
177 		"  uvec4 mask = subgroupBallot(true);\n"
178 		"  uint id_in = data2[gl_SubgroupInvocationID] & (gl_SubgroupSize - 1);\n"
179 		"  " + subgroups::getFormatNameForGLSL(caseDef.format) + " op = "
180 		+ getOpTypeName(caseDef.opType) + "(data1[gl_SubgroupInvocationID], id_in);\n"
181 		"  uint id = " + id + ";\n"
182 		"  if ((id < gl_SubgroupSize) && subgroupBallotBitExtract(mask, id))\n"
183 		"  {\n"
184 		"    temp_res = (op == data1[id]) ? 1 : 0;\n"
185 		"  }\n"
186 		"  else\n"
187 		"  {\n"
188 		"    temp_res = 1; // Invocation we read from was inactive, so we can't verify results!\n"
189 		"  }\n"
190 		"  tempRes = temp_res;\n";
191 
192 	return testSource;
193 }
194 
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)195 void initFrameBufferPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
196 {
197 	const ShaderBuildOptions	buildOptions		(programCollection.usedVulkanVersion, SPIRV_VERSION_1_3, 0u);
198 	const string				extHeader			= getExtHeader(caseDef);
199 	const string				testSrc				= getTestSource(caseDef);
200 	const vector<string>		headDeclarations	= getFramebufferPerStageHeadDeclarations(caseDef);
201 	const bool					pointSizeSupported	= *caseDef.geometryPointSizeSupported;
202 
203 	subgroups::initStdFrameBufferPrograms(programCollection, buildOptions, caseDef.shaderStage, VK_FORMAT_R32_UINT, pointSizeSupported, extHeader, testSrc, "", headDeclarations);
204 }
205 
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)206 void initPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
207 {
208 	const SpirvVersion			spirvVersion		= isAllRayTracingStages(caseDef.shaderStage) ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3;
209 	const ShaderBuildOptions	buildOptions		(programCollection.usedVulkanVersion, spirvVersion, 0u);
210 	const string				extHeader			= getExtHeader(caseDef);
211 	const string				testSrc				= getTestSource(caseDef);
212 	const vector<string>		headDeclarations	= getPerStageHeadDeclarations(caseDef);
213 	const bool					pointSizeSupported	= *caseDef.geometryPointSizeSupported;
214 
215 	subgroups::initStdPrograms(programCollection, buildOptions, caseDef.shaderStage, VK_FORMAT_R32_UINT, pointSizeSupported, extHeader, testSrc, "", headDeclarations);
216 }
217 
supportedCheck(Context & context,CaseDefinition caseDef)218 void supportedCheck (Context& context, CaseDefinition caseDef)
219 {
220 	if (!subgroups::isSubgroupSupported(context))
221 		TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
222 
223 	switch (caseDef.opType)
224 	{
225 		case OPTYPE_SHUFFLE:
226 		case OPTYPE_SHUFFLE_XOR:
227 			if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_SHUFFLE_BIT))
228 			{
229 				TCU_THROW(NotSupportedError, "Device does not support subgroup shuffle operations");
230 			}
231 			break;
232 		default:
233 			if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT))
234 			{
235 				TCU_THROW(NotSupportedError, "Device does not support subgroup shuffle relative operations");
236 			}
237 			break;
238 	}
239 
240 	if (!subgroups::isFormatSupportedForDevice(context, caseDef.format))
241 		TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
242 
243 	if (caseDef.requiredSubgroupSize)
244 	{
245 		context.requireDeviceFunctionality("VK_EXT_subgroup_size_control");
246 
247 		const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT&	subgroupSizeControlFeatures		= context.getSubgroupSizeControlFeaturesEXT();
248 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
249 
250 		if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
251 			TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes nor required subgroup size");
252 
253 		if (subgroupSizeControlFeatures.computeFullSubgroups == DE_FALSE)
254 			TCU_THROW(NotSupportedError, "Device does not support full subgroups in compute shaders");
255 
256 		if ((subgroupSizeControlProperties.requiredSubgroupSizeStages & caseDef.shaderStage) != caseDef.shaderStage)
257 			TCU_THROW(NotSupportedError, "Required subgroup size is not supported for shader stage");
258 	}
259 
260 	*caseDef.geometryPointSizeSupported = subgroups::isTessellationAndGeometryPointSizeSupported(context);
261 
262 	if (isAllRayTracingStages(caseDef.shaderStage))
263 	{
264 		context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
265 	}
266 
267 	subgroups::supportedCheckShader(context, caseDef.shaderStage);
268 }
269 
noSSBOtest(Context & context,const CaseDefinition caseDef)270 TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
271 {
272 	const subgroups::SSBOData	inputData[2]
273 	{
274 		{
275 			subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
276 			subgroups::SSBOData::LayoutStd140,		//  InputDataLayoutType			layout;
277 			caseDef.format,							//  vk::VkFormat				format;
278 			subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
279 		},
280 		{
281 			subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
282 			subgroups::SSBOData::LayoutStd140,		//  InputDataLayoutType			layout;
283 			VK_FORMAT_R32_UINT,						//  vk::VkFormat				format;
284 			subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
285 		}
286 	};
287 
288 	switch (caseDef.shaderStage)
289 	{
290 		case VK_SHADER_STAGE_VERTEX_BIT:					return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages);
291 		case VK_SHADER_STAGE_GEOMETRY_BIT:					return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages);
292 		case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:		return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
293 		case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:	return subgroups::makeTessellationEvaluationFrameBufferTest(context,  VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
294 		default:											TCU_THROW(InternalError, "Unhandled shader stage");
295 	}
296 }
297 
test(Context & context,const CaseDefinition caseDef)298 TestStatus test (Context& context, const CaseDefinition caseDef)
299 {
300 	if (isAllComputeStages(caseDef.shaderStage))
301 	{
302 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
303 		TestLog&												log								= context.getTestContext().getLog();
304 		const subgroups::SSBOData								inputData[2]
305 		{
306 			{
307 				subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
308 				subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
309 				caseDef.format,							//  vk::VkFormat				format;
310 				subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
311 			},
312 			{
313 				subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
314 				subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
315 				VK_FORMAT_R32_UINT,						//  vk::VkFormat				format;
316 				subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
317 			},
318 		};
319 
320 		if (caseDef.requiredSubgroupSize == DE_FALSE)
321 			return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, inputData, 2, 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, 2, 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[2]
344 		{
345 			{
346 				subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
347 				subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
348 				caseDef.format,							//  vk::VkFormat				format;
349 				subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
350 				false,									//  bool						isImage;
351 				4u,										//  deUint32					binding;
352 				stages,									//  vk::VkShaderStageFlags		stages;
353 			},
354 			{
355 				subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
356 				subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
357 				VK_FORMAT_R32_UINT,						//  vk::VkFormat				format;
358 				subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
359 				false,									//  bool						isImage;
360 				5u,										//  deUint32					binding;
361 				stages,									//  vk::VkShaderStageFlags		stages;
362 			},
363 		};
364 
365 		return subgroups::allStages(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages, stages);
366 	}
367 	else if (isAllRayTracingStages(caseDef.shaderStage))
368 	{
369 		const VkShaderStageFlags	stages			= subgroups::getPossibleRayTracingSubgroupStages(context, caseDef.shaderStage);
370 		const subgroups::SSBOData	inputData[2]
371 		{
372 			{
373 				subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
374 				subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
375 				caseDef.format,							//  vk::VkFormat				format;
376 				subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
377 				false,									//  bool						isImage;
378 				6u,										//  deUint32					binding;
379 				stages,									//  vk::VkShaderStageFlags		stages;
380 			},
381 			{
382 				subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
383 				subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
384 				VK_FORMAT_R32_UINT,						//  vk::VkFormat				format;
385 				subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
386 				false,									//  bool						isImage;
387 				7u,										//  deUint32					binding;
388 				stages,									//  vk::VkShaderStageFlags		stages;
389 			},
390 		};
391 
392 		return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages, stages);
393 	}
394 	else
395 		TCU_THROW(InternalError, "Unknown stage or invalid stage set");
396 }
397 }
398 
399 namespace vkt
400 {
401 namespace subgroups
402 {
createSubgroupsShuffleTests(TestContext & testCtx)403 TestCaseGroup* createSubgroupsShuffleTests (TestContext& testCtx)
404 {
405 	de::MovePtr<TestCaseGroup>	group				(new TestCaseGroup(testCtx, "shuffle", "Subgroup shuffle category tests"));
406 	de::MovePtr<TestCaseGroup>	graphicGroup		(new TestCaseGroup(testCtx, "graphics", "Subgroup shuffle category tests: graphics"));
407 	de::MovePtr<TestCaseGroup>	computeGroup		(new TestCaseGroup(testCtx, "compute", "Subgroup shuffle category tests: compute"));
408 	de::MovePtr<TestCaseGroup>	framebufferGroup	(new TestCaseGroup(testCtx, "framebuffer", "Subgroup shuffle category tests: framebuffer"));
409 	de::MovePtr<TestCaseGroup>	raytracingGroup		(new TestCaseGroup(testCtx, "ray_tracing", "Subgroup shuffle category tests: ray tracing"));
410 	const VkShaderStageFlags	stages[]			=
411 	{
412 		VK_SHADER_STAGE_VERTEX_BIT,
413 		VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
414 		VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
415 		VK_SHADER_STAGE_GEOMETRY_BIT,
416 	};
417 	const deBool				boolValues[]		=
418 	{
419 		DE_FALSE,
420 		DE_TRUE
421 	};
422 
423 	{
424 		const vector<VkFormat>	formats	= subgroups::getAllFormats();
425 
426 		for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
427 		{
428 			const VkFormat	format		= formats[formatIndex];
429 			const string	formatName	= subgroups::getFormatNameForGLSL(format);
430 
431 			for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
432 			{
433 				const OpType	opType	= static_cast<OpType>(opTypeIndex);
434 				const string	name	= de::toLower(getOpTypeName(opType)) + "_" + formatName;
435 
436 				{
437 					const CaseDefinition	caseDef		=
438 					{
439 						opType,							//  OpType				opType;
440 						VK_SHADER_STAGE_ALL_GRAPHICS,	//  VkShaderStageFlags	shaderStage;
441 						format,							//  VkFormat			format;
442 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
443 						DE_FALSE						//  deBool				requiredSubgroupSize;
444 					};
445 
446 					addFunctionCaseWithPrograms(graphicGroup.get(), name, "", supportedCheck, initPrograms, test, caseDef);
447 				}
448 
449 				for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
450 				{
451 					const deBool			requiredSubgroupSize	= boolValues[groupSizeNdx];
452 					const string			testName				= name + (requiredSubgroupSize ? "_requiredsubgroupsize" : "");
453 					const CaseDefinition	caseDef					=
454 					{
455 						opType,							//  OpType				opType;
456 						VK_SHADER_STAGE_COMPUTE_BIT,	//  VkShaderStageFlags	shaderStage;
457 						format,							//  VkFormat			format;
458 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
459 						requiredSubgroupSize,			//  deBool				requiredSubgroupSize;
460 					};
461 
462 					addFunctionCaseWithPrograms(computeGroup.get(), testName, "", supportedCheck, initPrograms, test, caseDef);
463 				}
464 
465 				for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
466 				{
467 					const CaseDefinition	caseDef		=
468 					{
469 						opType,							//  OpType				opType;
470 						stages[stageIndex],				//  VkShaderStageFlags	shaderStage;
471 						format,							//  VkFormat			format;
472 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
473 						DE_FALSE						//  deBool				requiredSubgroupSize;
474 					};
475 					const string			testName	= name + "_" + getShaderStageName(caseDef.shaderStage);
476 
477 					addFunctionCaseWithPrograms(framebufferGroup.get(), testName, "", supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
478 				}
479 			}
480 		}
481 	}
482 
483 	{
484 		const vector<VkFormat>	formats	= subgroups::getAllRayTracingFormats();
485 
486 		for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
487 		{
488 			const VkFormat	format		= formats[formatIndex];
489 			const string	formatName	= subgroups::getFormatNameForGLSL(format);
490 
491 			for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
492 			{
493 				const OpType			opType	= static_cast<OpType>(opTypeIndex);
494 				const string			name	= de::toLower(getOpTypeName(opType)) + "_" + formatName;
495 				const CaseDefinition	caseDef	=
496 				{
497 					opType,							//  OpType				opType;
498 					SHADER_STAGE_ALL_RAY_TRACING,	//  VkShaderStageFlags	shaderStage;
499 					format,							//  VkFormat			format;
500 					de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
501 					DE_FALSE						//  deBool				requiredSubgroupSize;
502 				};
503 
504 				addFunctionCaseWithPrograms(raytracingGroup.get(), name, "", supportedCheck, initPrograms, test, caseDef);
505 			}
506 		}
507 	}
508 
509 	group->addChild(graphicGroup.release());
510 	group->addChild(computeGroup.release());
511 	group->addChild(framebufferGroup.release());
512 	group->addChild(raytracingGroup.release());
513 
514 	return group.release();
515 }
516 
517 } // subgroups
518 } // vkt
519