• 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 "vktSubgroupsBallotBroadcastTests.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_BROADCAST = 0,
42 	OPTYPE_BROADCAST_NONCONST,
43 	OPTYPE_BROADCAST_FIRST,
44 	OPTYPE_LAST
45 };
46 
47 struct CaseDefinition
48 {
49 	OpType				opType;
50 	VkShaderStageFlags	shaderStage;
51 	VkFormat			format;
52 	de::SharedPtr<bool>	geometryPointSizeSupported;
53 	deBool				extShaderSubGroupBallotTests;
54 	deBool				subgroupSizeControl;
55 	deUint32			requiredSubgroupSize;
56 };
57 
checkVertexPipelineStages(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)58 bool checkVertexPipelineStages (const void*			internalData,
59 								vector<const void*>	datas,
60 								deUint32			width,
61 								deUint32)
62 {
63 	DE_UNREF(internalData);
64 
65 	return subgroups::check(datas, width, 3);
66 }
67 
checkCompute(const void * internalData,vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)68 bool checkCompute (const void*			internalData,
69 				   vector<const void*>	datas,
70 				   const deUint32		numWorkgroups[3],
71 				   const deUint32		localSize[3],
72 				   deUint32)
73 {
74 	DE_UNREF(internalData);
75 
76 	return subgroups::checkCompute(datas, numWorkgroups, localSize, 3);
77 }
78 
getOpTypeCaseName(OpType opType)79 string getOpTypeCaseName (OpType opType)
80 {
81 	switch (opType)
82 	{
83 		case OPTYPE_BROADCAST:			return "subgroupbroadcast";
84 		case OPTYPE_BROADCAST_NONCONST:	return "subgroupbroadcast_nonconst";
85 		case OPTYPE_BROADCAST_FIRST:	return "subgroupbroadcastfirst";
86 		default:						TCU_THROW(InternalError, "Unsupported op type");
87 	}
88 }
89 
getExtHeader(const CaseDefinition & caseDef)90 string getExtHeader (const CaseDefinition& caseDef)
91 {
92 	return (caseDef.extShaderSubGroupBallotTests ?	"#extension GL_ARB_shader_ballot: enable\n"
93 													"#extension GL_KHR_shader_subgroup_basic: enable\n"
94 													"#extension GL_ARB_gpu_shader_int64: enable\n"
95 												:	"#extension GL_KHR_shader_subgroup_ballot: enable\n")
96 				+ subgroups::getAdditionalExtensionForFormat(caseDef.format);
97 }
98 
getTestSrc(const CaseDefinition & caseDef)99 string getTestSrc (const CaseDefinition &caseDef)
100 {
101 	ostringstream	bdy;
102 	string			broadcast;
103 	string			broadcastFirst;
104 	string			mask;
105 	int				max;
106 	const string	fmt					= subgroups::getFormatNameForGLSL(caseDef.format);
107 
108 	if (caseDef.extShaderSubGroupBallotTests)
109 	{
110 		broadcast		= "readInvocationARB";
111 		broadcastFirst	= "readFirstInvocationARB";
112 		mask			= "mask = ballotARB(true);\n";
113 		max				= 64;
114 
115 		bdy << "  uint64_t mask;\n"
116 			<< mask
117 			<< "  uint sgSize = gl_SubGroupSizeARB;\n"
118 			<< "  uint sgInvocation = gl_SubGroupInvocationARB;\n";
119 	}
120 	else
121 	{
122 		broadcast		= "subgroupBroadcast";
123 		broadcastFirst	= "subgroupBroadcastFirst";
124 		mask			= "mask = subgroupBallot(true);\n";
125 
126 		if (caseDef.subgroupSizeControl)
127 			max = caseDef.requiredSubgroupSize;
128 		else
129 			max = (int)subgroups::maxSupportedSubgroupSize();
130 
131 		bdy << "  uvec4 mask = subgroupBallot(true);\n"
132 			<< "  uint sgSize = gl_SubgroupSize;\n"
133 			<< "  uint sgInvocation = gl_SubgroupInvocationID;\n";
134 	}
135 
136 	if (caseDef.opType == OPTYPE_BROADCAST)
137 	{
138 		bdy	<< "  tempRes = 0x3;\n"
139 			<< "  " << fmt << " ops[" << max << "];\n"
140 			<< "  " << fmt << " d = data[sgInvocation];\n";
141 
142 		for (int i = 0; i < max; i++)
143 			bdy << "  ops[" << i << "] = " << broadcast << "(d, " << i << "u);\n";
144 
145 		bdy << "  for(int id = 0; id < sgSize; id++)\n"
146 			<< "  {\n"
147 			<< "    if (subgroupBallotBitExtract(mask, id) && ops[id] != data[id])\n"
148 			<< "    {\n"
149 			<< "      tempRes = 0;\n"
150 			<< "    }\n"
151 			<< "  };\n";
152 	}
153 	else if (caseDef.opType == OPTYPE_BROADCAST_NONCONST)
154 	{
155 		const string validate =	"    if (subgroupBallotBitExtract(mask, id) && op != data[id])\n"
156 								"        tempRes = 0;\n";
157 
158 		bdy	<< "  tempRes= 0x3;\n"
159 			<< "  for (uint id = 0; id < sgSize; id++)\n"
160 			<< "  {\n"
161 			<< "    " << fmt << " op = " << broadcast << "(data[sgInvocation], id);\n"
162 			<< validate
163 			<< "  }\n"
164 			<< "  // Test lane id that is only uniform across active lanes\n"
165 			<< "  if (sgInvocation >= sgSize / 2)\n"
166 			<< "  {\n"
167 			<< "    uint id = sgInvocation & ~((sgSize / 2) - 1);\n"
168 			<< "    " << fmt << " op = " << broadcast << "(data[sgInvocation], id);\n"
169 			<< validate
170 			<< "  }\n";
171 	}
172 	else if (caseDef.opType == OPTYPE_BROADCAST_FIRST)
173 	{
174 		bdy << "  tempRes = 0;\n"
175 			<< "  uint firstActive = 0;\n"
176 			<< "  for (uint i = 0; i < sgSize; i++)\n"
177 			<< "  {\n"
178 			<< "    if (subgroupBallotBitExtract(mask, i))\n"
179 			<< "    {\n"
180 			<< "      firstActive = i;\n"
181 			<< "      break;\n"
182 			<< "    }\n"
183 			<< "  }\n"
184 			<< "  tempRes |= (" << broadcastFirst << "(data[sgInvocation]) == data[firstActive]) ? 0x1 : 0;\n"
185 			<< "  // make the firstActive invocation inactive now\n"
186 			<< "  if (firstActive != sgInvocation)\n"
187 			<< "  {\n"
188 			<< mask
189 			<< "    for (uint i = 0; i < sgSize; i++)\n"
190 			<< "    {\n"
191 			<< "      if (subgroupBallotBitExtract(mask, i))\n"
192 			<< "      {\n"
193 			<< "        firstActive = i;\n"
194 			<< "        break;\n"
195 			<< "      }\n"
196 			<< "    }\n"
197 			<< "    tempRes |= (" << broadcastFirst << "(data[sgInvocation]) == data[firstActive]) ? 0x2 : 0;\n"
198 			<< "  }\n"
199 			<< "  else\n"
200 			<< "  {\n"
201 			<< "    // the firstActive invocation didn't partake in the second result so set it to true\n"
202 			<< "    tempRes |= 0x2;\n"
203 			<< "  }\n";
204 	}
205 	else
206 		TCU_THROW(InternalError, "Unknown operation type");
207 
208 	return bdy.str();
209 }
210 
getHelperFunctionARB(const CaseDefinition & caseDef)211 string getHelperFunctionARB (const CaseDefinition &caseDef)
212 {
213 	ostringstream bdy;
214 
215 	if (caseDef.extShaderSubGroupBallotTests == DE_FALSE)
216 		return "";
217 
218 	bdy << "bool subgroupBallotBitExtract(uint64_t value, uint index)\n";
219 	bdy << "{\n";
220 	bdy << "    if (index > 63)\n";
221 	bdy << "        return false;\n";
222 	bdy << "    uint64_t mask = 1ul << index;\n";
223 	bdy << "    if (bool((value & mask)) == true)\n";
224 	bdy << "        return true;\n";
225 	bdy << "    return false;\n";
226 	bdy << "}\n";
227 
228 	return bdy.str();
229 }
230 
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)231 void initFrameBufferPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
232 {
233 	const SpirvVersion			spirvVersion	= (caseDef.opType == OPTYPE_BROADCAST_NONCONST) ? SPIRV_VERSION_1_5 : SPIRV_VERSION_1_3;
234 	const ShaderBuildOptions	buildOptions	(programCollection.usedVulkanVersion, spirvVersion, 0u);
235 	const string				extHeader		= getExtHeader(caseDef);
236 	const string				testSrc			= getTestSrc(caseDef);
237 	const string				helperStr		= getHelperFunctionARB(caseDef);
238 
239 	subgroups::initStdFrameBufferPrograms(programCollection, buildOptions, caseDef.shaderStage, caseDef.format, *caseDef.geometryPointSizeSupported, extHeader, testSrc, helperStr);
240 }
241 
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)242 void initPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
243 {
244 	const bool					spirv15required	= caseDef.opType == OPTYPE_BROADCAST_NONCONST;
245 	const bool					spirv14required	= isAllRayTracingStages(caseDef.shaderStage);
246 	const SpirvVersion			spirvVersion	= spirv15required ? SPIRV_VERSION_1_5
247 												: spirv14required ? SPIRV_VERSION_1_4
248 												: SPIRV_VERSION_1_3;
249 	const ShaderBuildOptions	buildOptions	(programCollection.usedVulkanVersion, spirvVersion, 0u);
250 	const string				extHeader		= getExtHeader(caseDef);
251 	const string				testSrc			= getTestSrc(caseDef);
252 	const string				helperStr		= getHelperFunctionARB(caseDef);
253 
254 	subgroups::initStdPrograms(programCollection, buildOptions, caseDef.shaderStage, caseDef.format, *caseDef.geometryPointSizeSupported, extHeader, testSrc, helperStr);
255 }
256 
supportedCheck(Context & context,CaseDefinition caseDef)257 void supportedCheck (Context& context, CaseDefinition caseDef)
258 {
259 	if (!subgroups::isSubgroupSupported(context))
260 		TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
261 
262 	if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_BALLOT_BIT))
263 		TCU_THROW(NotSupportedError, "Device does not support subgroup ballot operations");
264 
265 	if (!subgroups::isFormatSupportedForDevice(context, caseDef.format))
266 		TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
267 
268 	if (caseDef.extShaderSubGroupBallotTests)
269 	{
270 		context.requireDeviceFunctionality("VK_EXT_shader_subgroup_ballot");
271 
272 		if (!subgroups::isInt64SupportedForDevice(context))
273 			TCU_THROW(NotSupportedError, "Device does not support int64 data types");
274 	}
275 
276 	if ((caseDef.opType == OPTYPE_BROADCAST_NONCONST) && !subgroups::isSubgroupBroadcastDynamicIdSupported(context))
277 		TCU_THROW(NotSupportedError, "Device does not support SubgroupBroadcastDynamicId");
278 
279 	if (caseDef.subgroupSizeControl)
280 	{
281 		context.requireDeviceFunctionality("VK_EXT_subgroup_size_control");
282 
283 		const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT&	subgroupSizeControlFeatures		= context.getSubgroupSizeControlFeaturesEXT();
284 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
285 
286 		if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
287 			TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes nor required subgroup size");
288 
289 		if (subgroupSizeControlFeatures.computeFullSubgroups == DE_FALSE)
290 			TCU_THROW(NotSupportedError, "Device does not support full subgroups in compute shaders");
291 
292 		if (caseDef.requiredSubgroupSize < subgroupSizeControlProperties.minSubgroupSize
293 			|| caseDef.requiredSubgroupSize > subgroupSizeControlProperties.maxSubgroupSize)
294 		{
295 			TCU_THROW(NotSupportedError, "Unsupported subgroup size");
296 		}
297 
298 		if ((subgroupSizeControlProperties.requiredSubgroupSizeStages & caseDef.shaderStage) != caseDef.shaderStage)
299 			TCU_THROW(NotSupportedError, "Required subgroup size is not supported for shader stage");
300 	}
301 
302 	*caseDef.geometryPointSizeSupported = subgroups::isTessellationAndGeometryPointSizeSupported(context);
303 
304 	if (isAllRayTracingStages(caseDef.shaderStage))
305 	{
306 		context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
307 	}
308 
309 	subgroups::supportedCheckShader(context, caseDef.shaderStage);
310 }
311 
noSSBOtest(Context & context,const CaseDefinition caseDef)312 TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
313 {
314 	const VkDeviceSize			numElements	=	caseDef.extShaderSubGroupBallotTests ? 64u : subgroups::maxSupportedSubgroupSize();
315 	const subgroups::SSBOData	inputData	=
316 	{
317 		subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
318 		subgroups::SSBOData::LayoutStd140,		//  InputDataLayoutType			layout;
319 		caseDef.format,							//  vk::VkFormat				format;
320 		numElements,							//  vk::VkDeviceSize		numElements;
321 	};
322 
323 	switch (caseDef.shaderStage)
324 	{
325 		case VK_SHADER_STAGE_VERTEX_BIT:					return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages);
326 		case VK_SHADER_STAGE_GEOMETRY_BIT:					return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages);
327 		case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:		return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
328 		case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:	return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
329 		default:											TCU_THROW(InternalError, "Unhandled shader stage");
330 	}
331 }
332 
test(Context & context,const CaseDefinition caseDef)333 TestStatus test (Context& context, const CaseDefinition caseDef)
334 {
335 	const VkDeviceSize	numElements	= caseDef.extShaderSubGroupBallotTests ? 64u : subgroups::maxSupportedSubgroupSize();
336 
337 	if (isAllComputeStages(caseDef.shaderStage))
338 	{
339 		const subgroups::SSBOData	inputData	=
340 		{
341 			subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
342 			subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
343 			caseDef.format,							//  vk::VkFormat				format;
344 			numElements,							//  vk::VkDeviceSize			numElements;
345 		};
346 
347 		if (caseDef.subgroupSizeControl)
348 			return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkCompute, caseDef.requiredSubgroupSize, VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT);
349 		else
350 			return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkCompute);
351 	}
352 	else if (isAllGraphicsStages(caseDef.shaderStage))
353 	{
354 		const VkShaderStageFlags	stages		= subgroups::getPossibleGraphicsSubgroupStages(context, caseDef.shaderStage);
355 		const subgroups::SSBOData	inputData	=
356 		{
357 			subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
358 			subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
359 			caseDef.format,							//  vk::VkFormat				format;
360 			numElements,							//  vk::VkDeviceSize			numElements;
361 			false,									//  bool						isImage;
362 			4u,										//  deUint32					binding;
363 			stages,									//  vk::VkShaderStageFlagBits	stages;
364 		};
365 
366 		return subgroups::allStages(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, stages);
367 	}
368 	else if (isAllRayTracingStages(caseDef.shaderStage))
369 	{
370 		const VkShaderStageFlags	stages		= subgroups::getPossibleRayTracingSubgroupStages(context, caseDef.shaderStage);
371 		const subgroups::SSBOData	inputData	=
372 		{
373 			subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
374 			subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
375 			caseDef.format,							//  vk::VkFormat				format;
376 			numElements,							//  vk::VkDeviceSize			numElements;
377 			false,									//  bool						isImage;
378 			6u,										//  deUint32					binding;
379 			stages,									//  vk::VkShaderStageFlagBits	stages;
380 		};
381 
382 		return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, stages);
383 	}
384 	else
385 		TCU_THROW(InternalError, "Unknown stage or invalid stage set");
386 }
387 }
388 
389 namespace vkt
390 {
391 namespace subgroups
392 {
createSubgroupsBallotBroadcastTests(TestContext & testCtx)393 TestCaseGroup* createSubgroupsBallotBroadcastTests (TestContext& testCtx)
394 {
395 	de::MovePtr<TestCaseGroup>	group				(new TestCaseGroup(testCtx, "ballot_broadcast", "Subgroup ballot broadcast category tests"));
396 	de::MovePtr<TestCaseGroup>	graphicGroup		(new TestCaseGroup(testCtx, "graphics", "Subgroup ballot broadcast category tests: graphics"));
397 	de::MovePtr<TestCaseGroup>	computeGroup		(new TestCaseGroup(testCtx, "compute", "Subgroup ballot broadcast category tests: compute"));
398 	de::MovePtr<TestCaseGroup>	framebufferGroup	(new TestCaseGroup(testCtx, "framebuffer", "Subgroup ballot broadcast category tests: framebuffer"));
399 	de::MovePtr<TestCaseGroup>	raytracingGroup		(new TestCaseGroup(testCtx, "ray_tracing", "Subgroup ballot broadcast category tests: ray tracing"));
400 
401 	de::MovePtr<TestCaseGroup>	groupARB			(new TestCaseGroup(testCtx, "ext_shader_subgroup_ballot", "VK_EXT_shader_subgroup_ballot category tests"));
402 	de::MovePtr<TestCaseGroup>	graphicGroupARB		(new TestCaseGroup(testCtx, "graphics", "Subgroup ballot broadcast category tests: graphics"));
403 	de::MovePtr<TestCaseGroup>	computeGroupARB		(new TestCaseGroup(testCtx, "compute", "Subgroup ballot broadcast category tests: compute"));
404 	de::MovePtr<TestCaseGroup>	framebufferGroupARB	(new TestCaseGroup(testCtx, "framebuffer", "Subgroup ballot broadcast category tests: framebuffer"));
405 
406 	const VkShaderStageFlags	stages[]			=
407 	{
408 		VK_SHADER_STAGE_VERTEX_BIT,
409 		VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
410 		VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
411 		VK_SHADER_STAGE_GEOMETRY_BIT,
412 	};
413 	const deBool				boolValues[]		=
414 	{
415 		DE_FALSE,
416 		DE_TRUE
417 	};
418 
419 	{
420 		const vector<VkFormat>	formats		= subgroups::getAllFormats();
421 
422 		for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
423 		{
424 			const VkFormat	format						= formats[formatIndex];
425 			// Vector, boolean and double types are not supported by functions defined in VK_EXT_shader_subgroup_ballot.
426 			const bool		formatTypeIsSupportedARB	= format == VK_FORMAT_R32_SINT || format == VK_FORMAT_R32_UINT || format == VK_FORMAT_R32_SFLOAT;
427 
428 			for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
429 			{
430 				const OpType	opType	= static_cast<OpType>(opTypeIndex);
431 				const string	name	= getOpTypeCaseName(opType) + "_" + subgroups::getFormatNameForGLSL(format);
432 
433 				for (size_t extNdx = 0; extNdx < DE_LENGTH_OF_ARRAY(boolValues); ++extNdx)
434 				{
435 					const deBool	extShaderSubGroupBallotTests	= boolValues[extNdx];
436 
437 					if (extShaderSubGroupBallotTests && !formatTypeIsSupportedARB)
438 						continue;
439 
440 					{
441 						TestCaseGroup*		testGroup	= extShaderSubGroupBallotTests ? computeGroupARB.get() : computeGroup.get();
442 						{
443 							const CaseDefinition	caseDef		=
444 							{
445 								opType,							//  OpType				opType;
446 								VK_SHADER_STAGE_COMPUTE_BIT,	//  VkShaderStageFlags	shaderStage;
447 								format,							//  VkFormat			format;
448 								de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
449 								extShaderSubGroupBallotTests,	//  deBool				extShaderSubGroupBallotTests;
450 								DE_FALSE,						//  deBool				subgroupSizeControl;
451 								0u								//  deUint32			requiredSubgroupSize;
452 							};
453 
454 							addFunctionCaseWithPrograms(testGroup, name, "", supportedCheck, initPrograms, test, caseDef);
455 						}
456 
457 						for (deUint32 subgroupSize = 1; subgroupSize <= subgroups::maxSupportedSubgroupSize(); subgroupSize *= 2)
458 						{
459 							const CaseDefinition	caseDef		=
460 							{
461 								opType,							//  OpType				opType;
462 								VK_SHADER_STAGE_COMPUTE_BIT,	//  VkShaderStageFlags	shaderStage;
463 								format,							//  VkFormat			format;
464 								de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
465 								extShaderSubGroupBallotTests,	//  deBool				extShaderSubGroupBallotTests;
466 								DE_TRUE,						//  deBool				subgroupSizeControl;
467 								subgroupSize,					//  deUint32			requiredSubgroupSize;
468 							};
469 							const string			testName	= name + "_requiredsubgroupsize" + de::toString(subgroupSize);
470 
471 							addFunctionCaseWithPrograms(testGroup, testName, "", supportedCheck, initPrograms, test, caseDef);
472 						}
473 					}
474 
475 					{
476 						TestCaseGroup*			testGroup	= extShaderSubGroupBallotTests ? graphicGroupARB.get() : graphicGroup.get();
477 						const CaseDefinition	caseDef		=
478 						{
479 							opType,							//  OpType				opType;
480 							VK_SHADER_STAGE_ALL_GRAPHICS,	//  VkShaderStageFlags	shaderStage;
481 							format,							//  VkFormat			format;
482 							de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
483 							extShaderSubGroupBallotTests,	//  deBool				extShaderSubGroupBallotTests;
484 							DE_FALSE,						//  deBool				subgroupSizeControl;
485 							0u								//  deUint32			requiredSubgroupSize;
486 						};
487 
488 						addFunctionCaseWithPrograms(testGroup, name, "", supportedCheck, initPrograms, test, caseDef);
489 					}
490 
491 					{
492 						TestCaseGroup*	testGroup	= extShaderSubGroupBallotTests ? framebufferGroupARB.get() : framebufferGroup.get();
493 
494 						for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
495 						{
496 							const CaseDefinition	caseDef		=
497 							{
498 								opType,							//  OpType				opType;
499 								stages[stageIndex],				//  VkShaderStageFlags	shaderStage;
500 								format,							//  VkFormat			format;
501 								de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
502 								extShaderSubGroupBallotTests,	//  deBool				extShaderSubGroupBallotTests;
503 								DE_FALSE,						//  deBool				subgroupSizeControl;
504 								0u								//  deUint32			requiredSubgroupSize;
505 							};
506 
507 							addFunctionCaseWithPrograms(testGroup, name + getShaderStageName(caseDef.shaderStage), "", supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
508 						}
509 					}
510 				}
511 			}
512 		}
513 	}
514 
515 	{
516 		const vector<VkFormat>	formats		= subgroups::getAllRayTracingFormats();
517 
518 		for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
519 		{
520 			const VkFormat	format		= formats[formatIndex];
521 			const string	formatName	= subgroups::getFormatNameForGLSL(format);
522 
523 			for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
524 			{
525 				const OpType			opType		= static_cast<OpType>(opTypeIndex);
526 				const string			name		= getOpTypeCaseName(opType) + "_" + formatName;
527 				const CaseDefinition	caseDef		=
528 				{
529 					opType,							//  OpType				opType;
530 					SHADER_STAGE_ALL_RAY_TRACING,	//  VkShaderStageFlags	shaderStage;
531 					format,							//  VkFormat			format;
532 					de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
533 					DE_FALSE,						//  deBool				extShaderSubGroupBallotTests;
534 					DE_FALSE,						//  deBool				subgroupSizeControl;
535 					0								//  int					requiredSubgroupSize;
536 				};
537 
538 				addFunctionCaseWithPrograms(raytracingGroup.get(), name, "", supportedCheck, initPrograms, test, caseDef);
539 			}
540 		}
541 	}
542 
543 	groupARB->addChild(graphicGroupARB.release());
544 	groupARB->addChild(computeGroupARB.release());
545 	groupARB->addChild(framebufferGroupARB.release());
546 
547 	group->addChild(graphicGroup.release());
548 	group->addChild(computeGroup.release());
549 	group->addChild(framebufferGroup.release());
550 	group->addChild(raytracingGroup.release());
551 	group->addChild(groupARB.release());
552 
553 	return group.release();
554 }
555 } // subgroups
556 } // vkt
557