• 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 "vktSubgroupsShapeTests.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_CLUSTERED = 0,
42 	OPTYPE_QUAD,
43 	OPTYPE_LAST
44 };
45 
46 struct CaseDefinition
47 {
48 	OpType				opType;
49 	VkShaderStageFlags	shaderStage;
50 	de::SharedPtr<bool>	geometryPointSizeSupported;
51 	deBool				requiredSubgroupSize;
52 };
53 
checkVertexPipelineStages(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)54 static bool checkVertexPipelineStages (const void*			internalData,
55 									   vector<const void*>	datas,
56 									   deUint32				width,
57 									   deUint32)
58 {
59 	DE_UNREF(internalData);
60 
61 	return subgroups::check(datas, width, 1);
62 }
63 
checkComputeOrMesh(const void * internalData,vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)64 static bool checkComputeOrMesh (const void*			internalData,
65 								vector<const void*>	datas,
66 								const deUint32		numWorkgroups[3],
67 								const deUint32		localSize[3],
68 								deUint32)
69 {
70 	DE_UNREF(internalData);
71 
72 	return subgroups::checkComputeOrMesh(datas, numWorkgroups, localSize, 1);
73 }
74 
getOpTypeName(const OpType opType)75 string getOpTypeName (const OpType opType)
76 {
77 	switch (opType)
78 	{
79 		case OPTYPE_CLUSTERED:	return "clustered";
80 		case OPTYPE_QUAD:		return "quad";
81 		default:				TCU_THROW(InternalError, "Unsupported op type");
82 	}
83 }
84 
getExtHeader(const CaseDefinition & caseDef)85 string getExtHeader (const CaseDefinition& caseDef)
86 {
87 	const string	testExtensions	= (OPTYPE_CLUSTERED == caseDef.opType)
88 									? "#extension GL_KHR_shader_subgroup_clustered: enable\n"
89 									: "#extension GL_KHR_shader_subgroup_quad: enable\n";
90 	const string	extensions		= testExtensions
91 									+ "#extension GL_KHR_shader_subgroup_ballot: enable\n";
92 
93 	return extensions;
94 }
95 
getBodySource(const CaseDefinition & caseDef)96 string getBodySource (const CaseDefinition& caseDef)
97 {
98 	ostringstream	bdy;
99 
100 	bdy << "  uint tempResult = 0x1;\n"
101 		<< "  uvec4 mask = subgroupBallot(true);\n";
102 
103 	if (OPTYPE_CLUSTERED == caseDef.opType)
104 	{
105 		for (deUint32 i = 1; i <= subgroups::maxSupportedSubgroupSize(); i *= 2)
106 		{
107 			bdy << "  if (gl_SubgroupSize >= " << i << ")\n"
108 				<< "  {\n"
109 				<< "    uvec4 contribution = uvec4(0);\n"
110 				<< "    const uint modID = gl_SubgroupInvocationID % 32;\n"
111 				<< "    switch (gl_SubgroupInvocationID / 32)\n"
112 				<< "    {\n"
113 				<< "    case 0: contribution.x = 1 << modID; break;\n"
114 				<< "    case 1: contribution.y = 1 << modID; break;\n"
115 				<< "    case 2: contribution.z = 1 << modID; break;\n"
116 				<< "    case 3: contribution.w = 1 << modID; break;\n"
117 				<< "    }\n"
118 				<< "    uvec4 result = subgroupClusteredOr(contribution, " << i << ");\n"
119 				<< "    uint rootID = gl_SubgroupInvocationID & ~(" << i - 1 << ");\n"
120 				<< "    for (uint i = 0; i < " << i << "; i++)\n"
121 				<< "    {\n"
122 				<< "      uint nextID = rootID + i;\n"
123 				<< "      if (subgroupBallotBitExtract(mask, nextID) ^^ subgroupBallotBitExtract(result, nextID))\n"
124 				<< "      {\n"
125 				<< "        tempResult = 0;\n"
126 				<< "      }\n"
127 				<< "    }\n"
128 				<< "  }\n";
129 		}
130 	}
131 	else
132 	{
133 		bdy << "  uint cluster[4] =\n"
134 			<< "  {\n"
135 			<< "    subgroupQuadBroadcast(gl_SubgroupInvocationID, 0),\n"
136 			<< "    subgroupQuadBroadcast(gl_SubgroupInvocationID, 1),\n"
137 			<< "    subgroupQuadBroadcast(gl_SubgroupInvocationID, 2),\n"
138 			<< "    subgroupQuadBroadcast(gl_SubgroupInvocationID, 3)\n"
139 			<< "  };\n"
140 			<< "  uint rootID = gl_SubgroupInvocationID & ~0x3;\n"
141 			<< "  for (uint i = 0; i < 4; i++)\n"
142 			<< "  {\n"
143 			<< "    uint nextID = rootID + i;\n"
144 			<< "    if (subgroupBallotBitExtract(mask, nextID) && (cluster[i] != nextID))\n"
145 			<< "    {\n"
146 			<< "      tempResult = mask.x;\n"
147 			<< "    }\n"
148 			<< "  }\n";
149 	}
150 
151 	bdy << "  tempRes = tempResult;\n";
152 
153 	return bdy.str();
154 }
155 
getFramebufferPerStageHeadDeclarations(const CaseDefinition & caseDef)156 vector<string> getFramebufferPerStageHeadDeclarations (const CaseDefinition& caseDef)
157 {
158 	vector<string>	result;
159 
160 	DE_UNREF(caseDef);
161 
162 	result.push_back("layout(location = 0) out float result;\n");
163 	result.push_back("layout(location = 0) out float out_color;\n");
164 	result.push_back("layout(location = 0) out float out_color[];\n");
165 	result.push_back("layout(location = 0) out float out_color;\n");
166 
167 	return result;
168 }
169 
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)170 void initFrameBufferPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
171 {
172 	const ShaderBuildOptions	buildOptions		(programCollection.usedVulkanVersion, SPIRV_VERSION_1_3, 0u);
173 	const string				extHeader			= getExtHeader(caseDef);
174 	const string				testSrc				= getBodySource(caseDef);
175 	const vector<string>		headDeclarations	= getFramebufferPerStageHeadDeclarations(caseDef);
176 	const bool					pointSizeSupported	= *caseDef.geometryPointSizeSupported;
177 
178 	subgroups::initStdFrameBufferPrograms(programCollection, buildOptions, caseDef.shaderStage, VK_FORMAT_R32_UINT, pointSizeSupported, extHeader, testSrc, "", headDeclarations);
179 }
180 
getPerStageHeadDeclarations(const CaseDefinition & caseDef)181 vector<string> getPerStageHeadDeclarations (const CaseDefinition& caseDef)
182 {
183 	const deUint32	stageCount	= subgroups::getStagesCount(caseDef.shaderStage);
184 	const bool		fragment	= (caseDef.shaderStage & VK_SHADER_STAGE_FRAGMENT_BIT) != 0;
185 	vector<string>	result		(stageCount, string());
186 
187 	if (fragment)
188 		result.reserve(result.size() + 1);
189 
190 	for (size_t i = 0; i < result.size(); ++i)
191 	{
192 		result[i] =
193 			"layout(set = 0, binding = " + de::toString(i) + ", std430) buffer Buffer1\n"
194 			"{\n"
195 			"  uint result[];\n"
196 			"};\n";
197 	}
198 
199 	if (fragment)
200 	{
201 		const string	fragPart	=
202 			"layout(location = 0) out uint result;\n";
203 
204 		result.push_back(fragPart);
205 	}
206 
207 	return result;
208 }
209 
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)210 void initPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
211 {
212 #ifndef CTS_USES_VULKANSC
213 	const bool					spirv14required		= (isAllRayTracingStages(caseDef.shaderStage) || isAllMeshShadingStages(caseDef.shaderStage));
214 #else
215 	const bool					spirv14required		= false;
216 #endif // CTS_USES_VULKANSC
217 	const SpirvVersion			spirvVersion		= spirv14required ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3;
218 	const ShaderBuildOptions	buildOptions		(programCollection.usedVulkanVersion, spirvVersion, 0u, spirv14required);
219 	const string				extHeader			= getExtHeader(caseDef);
220 	const string				testSrc				= getBodySource(caseDef);
221 	const vector<string>		headDeclarations	= getPerStageHeadDeclarations(caseDef);
222 	const bool					pointSizeSupport	= *caseDef.geometryPointSizeSupported;
223 
224 	subgroups::initStdPrograms(programCollection, buildOptions, caseDef.shaderStage, VK_FORMAT_R32_UINT, pointSizeSupport, extHeader, testSrc, "", headDeclarations);
225 }
226 
supportedCheck(Context & context,CaseDefinition caseDef)227 void supportedCheck (Context& context, CaseDefinition caseDef)
228 {
229 	if (!subgroups::isSubgroupSupported(context))
230 		TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
231 
232 	if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_BALLOT_BIT))
233 	{
234 		TCU_THROW(NotSupportedError, "Device does not support subgroup ballot operations");
235 	}
236 
237 	if (OPTYPE_CLUSTERED == caseDef.opType)
238 	{
239 		if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_CLUSTERED_BIT))
240 		{
241 			TCU_THROW(NotSupportedError, "Subgroup shape tests require that clustered operations are supported!");
242 		}
243 	}
244 
245 	if (OPTYPE_QUAD == caseDef.opType)
246 	{
247 		if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_QUAD_BIT))
248 		{
249 			TCU_THROW(NotSupportedError, "Subgroup shape tests require that quad operations are supported!");
250 		}
251 	}
252 
253 	if (caseDef.requiredSubgroupSize)
254 	{
255 		context.requireDeviceFunctionality("VK_EXT_subgroup_size_control");
256 
257 #ifndef CTS_USES_VULKANSC
258 		const VkPhysicalDeviceSubgroupSizeControlFeatures&		subgroupSizeControlFeatures		= context.getSubgroupSizeControlFeatures();
259 		const VkPhysicalDeviceSubgroupSizeControlProperties&	subgroupSizeControlProperties	= context.getSubgroupSizeControlProperties();
260 #else
261 		const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT&	subgroupSizeControlFeatures		= context.getSubgroupSizeControlFeaturesEXT();
262 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
263 #endif // CTS_USES_VULKANSC
264 
265 		if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
266 			TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes nor required subgroup size");
267 
268 		if (subgroupSizeControlFeatures.computeFullSubgroups == DE_FALSE)
269 			TCU_THROW(NotSupportedError, "Device does not support full subgroups in compute shaders");
270 
271 		if ((subgroupSizeControlProperties.requiredSubgroupSizeStages & caseDef.shaderStage) != caseDef.shaderStage)
272 			TCU_THROW(NotSupportedError, "Required subgroup size is not supported for shader stage");
273 	}
274 
275 	*caseDef.geometryPointSizeSupported = subgroups::isTessellationAndGeometryPointSizeSupported(context);
276 
277 #ifndef CTS_USES_VULKANSC
278 	if (isAllRayTracingStages(caseDef.shaderStage))
279 	{
280 		context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
281 	}
282 	else if (isAllMeshShadingStages(caseDef.shaderStage))
283 	{
284 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
285 		context.requireDeviceFunctionality("VK_EXT_mesh_shader");
286 
287 		if ((caseDef.shaderStage & VK_SHADER_STAGE_TASK_BIT_EXT) != 0u)
288 		{
289 			const auto& features = context.getMeshShaderFeaturesEXT();
290 			if (!features.taskShader)
291 				TCU_THROW(NotSupportedError, "Task shaders not supported");
292 		}
293 	}
294 #endif // CTS_USES_VULKANSC
295 
296 	subgroups::supportedCheckShader(context, caseDef.shaderStage);
297 }
298 
noSSBOtest(Context & context,const CaseDefinition caseDef)299 TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
300 {
301 	switch (caseDef.shaderStage)
302 	{
303 		case VK_SHADER_STAGE_VERTEX_BIT:					return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages);
304 		case VK_SHADER_STAGE_GEOMETRY_BIT:					return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages);
305 		case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:		return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
306 		case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:	return subgroups::makeTessellationEvaluationFrameBufferTest(context,  VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
307 		default:											TCU_THROW(InternalError, "Unhandled shader stage");
308 	}
309 }
310 
test(Context & context,const CaseDefinition caseDef)311 TestStatus test (Context& context, const CaseDefinition caseDef)
312 {
313 	const bool isCompute	= isAllComputeStages(caseDef.shaderStage);
314 #ifndef CTS_USES_VULKANSC
315 	const bool isMesh		= isAllMeshShadingStages(caseDef.shaderStage);
316 #else
317 	const bool isMesh		= false;
318 #endif // CTS_USES_VULKANSC
319 	DE_ASSERT(!(isCompute && isMesh));
320 
321 	if (isCompute || isMesh)
322 	{
323 #ifndef CTS_USES_VULKANSC
324 		const VkPhysicalDeviceSubgroupSizeControlProperties&	subgroupSizeControlProperties	= context.getSubgroupSizeControlProperties();
325 #else
326 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
327 #endif // CTS_USES_VULKANSC
328 		TestLog&												log								= context.getTestContext().getLog();
329 
330 		if (caseDef.requiredSubgroupSize == DE_FALSE)
331 		{
332 			if (isCompute)
333 				return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkComputeOrMesh);
334 			else
335 				return subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkComputeOrMesh);
336 		}
337 
338 		log << TestLog::Message << "Testing required subgroup size range [" <<  subgroupSizeControlProperties.minSubgroupSize << ", "
339 			<< subgroupSizeControlProperties.maxSubgroupSize << "]" << TestLog::EndMessage;
340 
341 		// According to the spec, requiredSubgroupSize must be a power-of-two integer.
342 		for (deUint32 size = subgroupSizeControlProperties.minSubgroupSize; size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
343 		{
344 			TestStatus result (QP_TEST_RESULT_INTERNAL_ERROR, "Internal Error");
345 
346 			if (isCompute)
347 				result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkComputeOrMesh, size);
348 			else
349 				result = subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkComputeOrMesh, size);
350 
351 			if (result.getCode() != QP_TEST_RESULT_PASS)
352 			{
353 				log << TestLog::Message << "subgroupSize " << size << " failed" << TestLog::EndMessage;
354 				return result;
355 			}
356 		}
357 
358 		return TestStatus::pass("OK");
359 	}
360 	else if (isAllGraphicsStages(caseDef.shaderStage))
361 	{
362 		const VkShaderStageFlags	stages	= subgroups::getPossibleGraphicsSubgroupStages(context, caseDef.shaderStage);
363 
364 		return subgroups::allStages(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages, stages);
365 	}
366 #ifndef CTS_USES_VULKANSC
367 	else if (isAllRayTracingStages(caseDef.shaderStage))
368 	{
369 		const VkShaderStageFlags	stages	= subgroups::getPossibleRayTracingSubgroupStages(context, caseDef.shaderStage);
370 
371 		return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages, stages);
372 	}
373 #endif // CTS_USES_VULKANSC
374 	else
375 		TCU_THROW(InternalError, "Unknown stage or invalid stage set");
376 }
377 }
378 
379 namespace vkt
380 {
381 namespace subgroups
382 {
createSubgroupsShapeTests(TestContext & testCtx)383 TestCaseGroup* createSubgroupsShapeTests (TestContext& testCtx)
384 {
385 	de::MovePtr<TestCaseGroup>	group				(new TestCaseGroup(testCtx, "shape", "Subgroup shape category tests"));
386 	de::MovePtr<TestCaseGroup>	graphicGroup		(new TestCaseGroup(testCtx, "graphics", "Subgroup shape category tests: graphics"));
387 	de::MovePtr<TestCaseGroup>	computeGroup		(new TestCaseGroup(testCtx, "compute", "Subgroup shape category tests: compute"));
388 	de::MovePtr<TestCaseGroup>	framebufferGroup	(new TestCaseGroup(testCtx, "framebuffer", "Subgroup shape category tests: framebuffer"));
389 #ifndef CTS_USES_VULKANSC
390 	de::MovePtr<TestCaseGroup>	raytracingGroup		(new TestCaseGroup(testCtx, "ray_tracing", "Subgroup shape category tests: ray tracing"));
391 	de::MovePtr<TestCaseGroup>	meshGroup			(new TestCaseGroup(testCtx, "mesh", "Subgroup shape category tests: mesh shading"));
392 #endif // CTS_USES_VULKANSC
393 	const VkShaderStageFlags	fbStages[]			=
394 	{
395 		VK_SHADER_STAGE_VERTEX_BIT,
396 		VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
397 		VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
398 		VK_SHADER_STAGE_GEOMETRY_BIT,
399 	};
400 #ifndef CTS_USES_VULKANSC
401 	const VkShaderStageFlags	meshStages[]		=
402 	{
403 		VK_SHADER_STAGE_MESH_BIT_EXT,
404 		VK_SHADER_STAGE_TASK_BIT_EXT,
405 	};
406 #endif // CTS_USES_VULKANSC
407 	const deBool				boolValues[]		=
408 	{
409 		DE_FALSE,
410 		DE_TRUE
411 	};
412 
413 	for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
414 	{
415 		const OpType	opType	= static_cast<OpType>(opTypeIndex);
416 		const string	op		= de::toLower(getOpTypeName(opType));
417 
418 		for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
419 		{
420 			const deBool			requiredSubgroupSize	= boolValues[groupSizeNdx];
421 			const string			testName				= op + (requiredSubgroupSize ? "_requiredsubgroupsize" : "");
422 			const CaseDefinition	caseDef					=
423 			{
424 				opType,							//  OpType				opType;
425 				VK_SHADER_STAGE_COMPUTE_BIT,	//  VkShaderStageFlags	shaderStage;
426 				de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
427 				requiredSubgroupSize			//  deBool				requiredSubgroupSize;
428 			};
429 
430 			addFunctionCaseWithPrograms(computeGroup.get(), testName, "", supportedCheck, initPrograms, test, caseDef);
431 		}
432 
433 #ifndef CTS_USES_VULKANSC
434 		for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
435 		{
436 			for (const auto& stage : meshStages)
437 			{
438 				const deBool			requiredSubgroupSize	= boolValues[groupSizeNdx];
439 				const string			testName				= op + (requiredSubgroupSize ? "_requiredsubgroupsize" : "") + "_" + getShaderStageName(stage);
440 				const CaseDefinition	caseDef					=
441 				{
442 					opType,							//  OpType				opType;
443 					stage,							//  VkShaderStageFlags	shaderStage;
444 					de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
445 					requiredSubgroupSize			//  deBool				requiredSubgroupSize;
446 				};
447 
448 				addFunctionCaseWithPrograms(meshGroup.get(), testName, "", supportedCheck, initPrograms, test, caseDef);
449 			}
450 		}
451 #endif // CTS_USES_VULKANSC
452 
453 		{
454 			const CaseDefinition	caseDef		=
455 			{
456 				opType,							//  OpType				opType;
457 				VK_SHADER_STAGE_ALL_GRAPHICS,	//  VkShaderStageFlags	shaderStage;
458 				de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
459 				DE_FALSE						//  deBool				requiredSubgroupSize;
460 			};
461 
462 			addFunctionCaseWithPrograms(graphicGroup.get(), op, "", supportedCheck, initPrograms, test, caseDef);
463 		}
464 
465 #ifndef CTS_USES_VULKANSC
466 		{
467 			const CaseDefinition	caseDef		=
468 			{
469 				opType,							//  OpType				opType;
470 				SHADER_STAGE_ALL_RAY_TRACING,	//  VkShaderStageFlags	shaderStage;
471 				de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
472 				DE_FALSE						//  deBool				requiredSubgroupSize;
473 			};
474 
475 			addFunctionCaseWithPrograms(raytracingGroup.get(), op, "", supportedCheck, initPrograms, test, caseDef);
476 		}
477 #endif // CTS_USES_VULKANSC
478 
479 		for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(fbStages); ++stageIndex)
480 		{
481 			const CaseDefinition	caseDef		=
482 			{
483 				opType,							//  OpType				opType;
484 				fbStages[stageIndex],			//  VkShaderStageFlags	shaderStage;
485 				de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
486 				DE_FALSE						//  deBool				requiredSubgroupSize;
487 			};
488 			const string			testName	= op + "_" + getShaderStageName(caseDef.shaderStage);
489 
490 			addFunctionCaseWithPrograms(framebufferGroup.get(), testName, "", supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
491 		}
492 	}
493 
494 	group->addChild(graphicGroup.release());
495 	group->addChild(computeGroup.release());
496 	group->addChild(framebufferGroup.release());
497 #ifndef CTS_USES_VULKANSC
498 	group->addChild(raytracingGroup.release());
499 	group->addChild(meshGroup.release());
500 #endif // CTS_USES_VULKANSC
501 
502 	return group.release();
503 }
504 
505 } // subgroups
506 } // vkt
507