• 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  * Copyright (c) 2018 NVIDIA Corporation
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  */ /*!
23  * \file
24  * \brief Subgroups Tests
25  */ /*--------------------------------------------------------------------*/
26 
27 #include "vktSubgroupsPartitionedTests.hpp"
28 #include "vktSubgroupsScanHelpers.hpp"
29 #include "vktSubgroupsTestsUtils.hpp"
30 
31 #include <string>
32 #include <vector>
33 
34 using namespace tcu;
35 using namespace std;
36 using namespace vk;
37 using namespace vkt;
38 
39 namespace
40 {
41 enum OpType
42 {
43 	OPTYPE_ADD = 0,
44 	OPTYPE_MUL,
45 	OPTYPE_MIN,
46 	OPTYPE_MAX,
47 	OPTYPE_AND,
48 	OPTYPE_OR,
49 	OPTYPE_XOR,
50 	OPTYPE_INCLUSIVE_ADD,
51 	OPTYPE_INCLUSIVE_MUL,
52 	OPTYPE_INCLUSIVE_MIN,
53 	OPTYPE_INCLUSIVE_MAX,
54 	OPTYPE_INCLUSIVE_AND,
55 	OPTYPE_INCLUSIVE_OR,
56 	OPTYPE_INCLUSIVE_XOR,
57 	OPTYPE_EXCLUSIVE_ADD,
58 	OPTYPE_EXCLUSIVE_MUL,
59 	OPTYPE_EXCLUSIVE_MIN,
60 	OPTYPE_EXCLUSIVE_MAX,
61 	OPTYPE_EXCLUSIVE_AND,
62 	OPTYPE_EXCLUSIVE_OR,
63 	OPTYPE_EXCLUSIVE_XOR,
64 	OPTYPE_LAST
65 };
66 
67 struct CaseDefinition
68 {
69 	Operator			op;
70 	ScanType			scanType;
71 	VkShaderStageFlags	shaderStage;
72 	VkFormat			format;
73 	de::SharedPtr<bool>	geometryPointSizeSupported;
74 	deBool				requiredSubgroupSize;
75 };
76 
getOperator(OpType opType)77 static Operator getOperator (OpType opType)
78 {
79 	switch (opType)
80 	{
81 		case OPTYPE_ADD:
82 		case OPTYPE_INCLUSIVE_ADD:
83 		case OPTYPE_EXCLUSIVE_ADD:
84 			return OPERATOR_ADD;
85 		case OPTYPE_MUL:
86 		case OPTYPE_INCLUSIVE_MUL:
87 		case OPTYPE_EXCLUSIVE_MUL:
88 			return OPERATOR_MUL;
89 		case OPTYPE_MIN:
90 		case OPTYPE_INCLUSIVE_MIN:
91 		case OPTYPE_EXCLUSIVE_MIN:
92 			return OPERATOR_MIN;
93 		case OPTYPE_MAX:
94 		case OPTYPE_INCLUSIVE_MAX:
95 		case OPTYPE_EXCLUSIVE_MAX:
96 			return OPERATOR_MAX;
97 		case OPTYPE_AND:
98 		case OPTYPE_INCLUSIVE_AND:
99 		case OPTYPE_EXCLUSIVE_AND:
100 			return OPERATOR_AND;
101 		case OPTYPE_OR:
102 		case OPTYPE_INCLUSIVE_OR:
103 		case OPTYPE_EXCLUSIVE_OR:
104 			return OPERATOR_OR;
105 		case OPTYPE_XOR:
106 		case OPTYPE_INCLUSIVE_XOR:
107 		case OPTYPE_EXCLUSIVE_XOR:
108 			return OPERATOR_XOR;
109 		default:
110 			DE_FATAL("Unsupported op type");
111 			return OPERATOR_ADD;
112 	}
113 }
114 
getScanType(OpType opType)115 static ScanType getScanType (OpType opType)
116 {
117 	switch (opType)
118 	{
119 		case OPTYPE_ADD:
120 		case OPTYPE_MUL:
121 		case OPTYPE_MIN:
122 		case OPTYPE_MAX:
123 		case OPTYPE_AND:
124 		case OPTYPE_OR:
125 		case OPTYPE_XOR:
126 			return SCAN_REDUCE;
127 		case OPTYPE_INCLUSIVE_ADD:
128 		case OPTYPE_INCLUSIVE_MUL:
129 		case OPTYPE_INCLUSIVE_MIN:
130 		case OPTYPE_INCLUSIVE_MAX:
131 		case OPTYPE_INCLUSIVE_AND:
132 		case OPTYPE_INCLUSIVE_OR:
133 		case OPTYPE_INCLUSIVE_XOR:
134 			return SCAN_INCLUSIVE;
135 		case OPTYPE_EXCLUSIVE_ADD:
136 		case OPTYPE_EXCLUSIVE_MUL:
137 		case OPTYPE_EXCLUSIVE_MIN:
138 		case OPTYPE_EXCLUSIVE_MAX:
139 		case OPTYPE_EXCLUSIVE_AND:
140 		case OPTYPE_EXCLUSIVE_OR:
141 		case OPTYPE_EXCLUSIVE_XOR:
142 			return SCAN_EXCLUSIVE;
143 		default:
144 			DE_FATAL("Unsupported op type");
145 			return SCAN_REDUCE;
146 	}
147 }
148 
checkVertexPipelineStages(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)149 static bool checkVertexPipelineStages (const void*			internalData,
150 									   vector<const void*>	datas,
151 									   deUint32				width,
152 									   deUint32)
153 {
154 	DE_UNREF(internalData);
155 
156 	return subgroups::check(datas, width, 0xFFFFFF);
157 }
158 
checkCompute(const void * internalData,vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)159 static bool checkCompute (const void*			internalData,
160 						  vector<const void*>	datas,
161 						  const deUint32		numWorkgroups[3],
162 						  const deUint32		localSize[3],
163 						  deUint32)
164 {
165 	DE_UNREF(internalData);
166 
167 	return subgroups::checkCompute(datas, numWorkgroups, localSize, 0xFFFFFF);
168 }
169 
getOpTypeName(Operator op,ScanType scanType)170 string getOpTypeName (Operator op, ScanType scanType)
171 {
172 	return getScanOpName("subgroup", "", op, scanType);
173 }
174 
getOpTypeNamePartitioned(Operator op,ScanType scanType)175 string getOpTypeNamePartitioned (Operator op, ScanType scanType)
176 {
177 	return getScanOpName("subgroupPartitioned", "NV", op, scanType);
178 }
179 
getExtHeader(const CaseDefinition & caseDef)180 string getExtHeader (const CaseDefinition& caseDef)
181 {
182 	return	"#extension GL_NV_shader_subgroup_partitioned: enable\n"
183 			"#extension GL_KHR_shader_subgroup_arithmetic: enable\n"
184 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
185 			+ subgroups::getAdditionalExtensionForFormat(caseDef.format);
186 }
187 
getTestString(const CaseDefinition & caseDef)188 string getTestString (const CaseDefinition& caseDef)
189 {
190 	Operator op = caseDef.op;
191 	ScanType st = caseDef.scanType;
192 
193 	// NOTE: tempResult can't have anything in bits 31:24 to avoid int->float
194 	// conversion overflow in framebuffer tests.
195 	string fmt = subgroups::getFormatNameForGLSL(caseDef.format);
196 	string bdy =
197 		"  uvec4 mask = subgroupBallot(true);\n"
198 		"  uint tempResult = 0;\n"
199 		"  uint id = gl_SubgroupInvocationID;\n";
200 
201 	// Test the case where the partition has a single subset with all invocations in it.
202 	// This should generate the same result as the non-partitioned function.
203 	bdy +=
204 		"  uvec4 allBallot = mask;\n"
205 		"  " + fmt + " allResult = " + getOpTypeNamePartitioned(op, st) + "(data[gl_SubgroupInvocationID], allBallot);\n"
206 		"  " + fmt + " refResult = " + getOpTypeName(op, st) + "(data[gl_SubgroupInvocationID]);\n"
207 		"  if (" + getCompare(op, caseDef.format, "allResult", "refResult") + ") {\n"
208 		"      tempResult |= 0x1;\n"
209 		"  }\n";
210 
211 	// The definition of a partition doesn't forbid bits corresponding to inactive
212 	// invocations being in the subset with active invocations. In other words, test that
213 	// bits corresponding to inactive invocations are ignored.
214 	bdy +=
215 		"  if (0 == (gl_SubgroupInvocationID % 2)) {\n"
216 		"    " + fmt + " allResult = " + getOpTypeNamePartitioned(op, st) + "(data[gl_SubgroupInvocationID], allBallot);\n"
217 		"    " + fmt + " refResult = " + getOpTypeName(op, st) + "(data[gl_SubgroupInvocationID]);\n"
218 		"    if (" + getCompare(op, caseDef.format, "allResult", "refResult") + ") {\n"
219 		"        tempResult |= 0x2;\n"
220 		"    }\n"
221 		"  } else {\n"
222 		"    tempResult |= 0x2;\n"
223 		"  }\n";
224 
225 	// Test the case where the partition has each invocation in a unique subset. For
226 	// exclusive ops, the result is identity. For reduce/inclusive, it's the original value.
227 	string expectedSelfResult = "data[gl_SubgroupInvocationID]";
228 	if (st == SCAN_EXCLUSIVE)
229 		expectedSelfResult = getIdentity(op, caseDef.format);
230 
231 	bdy +=
232 		"  uvec4 selfBallot = subgroupPartitionNV(gl_SubgroupInvocationID);\n"
233 		"  " + fmt + " selfResult = " + getOpTypeNamePartitioned(op, st) + "(data[gl_SubgroupInvocationID], selfBallot);\n"
234 		"  if (" + getCompare(op, caseDef.format, "selfResult", expectedSelfResult) + ") {\n"
235 		"      tempResult |= 0x4;\n"
236 		"  }\n";
237 
238 	// Test "random" partitions based on a hash of the invocation id.
239 	// This "hash" function produces interesting/randomish partitions.
240 	static const char *idhash = "((id%N)+(id%(N+1))-(id%2)+(id/2))%((N+1)/2)";
241 
242 	bdy +=
243 		"  for (uint N = 1; N < 16; ++N) {\n"
244 		"    " + fmt + " idhashFmt = " + fmt + "(" + idhash + ");\n"
245 		"    uvec4 partitionBallot = subgroupPartitionNV(idhashFmt) & mask;\n"
246 		"    " + fmt + " partitionedResult = " + getOpTypeNamePartitioned(op, st) + "(data[gl_SubgroupInvocationID], partitionBallot);\n"
247 		"      for (uint i = 0; i < N; ++i) {\n"
248 		"        " + fmt + " iFmt = " + fmt + "(i);\n"
249 		"        if (" + getCompare(op, caseDef.format, "idhashFmt", "iFmt") + ") {\n"
250 		"          " + fmt + " subsetResult = " + getOpTypeName(op, st) + "(data[gl_SubgroupInvocationID]);\n"
251 		"          tempResult |= " + getCompare(op, caseDef.format, "partitionedResult", "subsetResult") + " ? (0x4 << N) : 0;\n"
252 		"        }\n"
253 		"      }\n"
254 		"  }\n"
255 		// tests in flow control:
256 		"  if (1 == (gl_SubgroupInvocationID % 2)) {\n"
257 		"    for (uint N = 1; N < 7; ++N) {\n"
258 		"      " + fmt + " idhashFmt = " + fmt + "(" + idhash + ");\n"
259 		"      uvec4 partitionBallot = subgroupPartitionNV(idhashFmt) & mask;\n"
260 		"      " + fmt + " partitionedResult = " + getOpTypeNamePartitioned(op, st) + "(data[gl_SubgroupInvocationID], partitionBallot);\n"
261 		"        for (uint i = 0; i < N; ++i) {\n"
262 		"          " + fmt + " iFmt = " + fmt + "(i);\n"
263 		"          if (" + getCompare(op, caseDef.format, "idhashFmt", "iFmt") + ") {\n"
264 		"            " + fmt + " subsetResult = " + getOpTypeName(op, st) + "(data[gl_SubgroupInvocationID]);\n"
265 		"            tempResult |= " + getCompare(op, caseDef.format, "partitionedResult", "subsetResult") + " ? (0x20000 << N) : 0;\n"
266 		"          }\n"
267 		"        }\n"
268 		"    }\n"
269 		"  } else {\n"
270 		"    tempResult |= 0xFC0000;\n"
271 		"  }\n"
272 		"  tempRes = tempResult;\n"
273 		;
274 
275 	return bdy;
276 }
277 
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)278 void initFrameBufferPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
279 {
280 	const ShaderBuildOptions	buildOptions		(programCollection.usedVulkanVersion, SPIRV_VERSION_1_3, 0u);
281 	const string				extHeader			= getExtHeader(caseDef);
282 	const string				testSrc				= getTestString(caseDef);
283 	const bool					pointSizeSupport	= *caseDef.geometryPointSizeSupported;
284 
285 	subgroups::initStdFrameBufferPrograms(programCollection, buildOptions, caseDef.shaderStage, caseDef.format, pointSizeSupport, extHeader, testSrc, "");
286 }
287 
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)288 void initPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
289 {
290 	const SpirvVersion			spirvVersion		= isAllRayTracingStages(caseDef.shaderStage) ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3;
291 	const ShaderBuildOptions	buildOptions		(programCollection.usedVulkanVersion, spirvVersion, 0u);
292 	const string				extHeader			= getExtHeader(caseDef);
293 	const string				testSrc				= getTestString(caseDef);
294 	const bool					pointSizeSupport	= false;
295 
296 	subgroups::initStdPrograms(programCollection, buildOptions, caseDef.shaderStage, caseDef.format, pointSizeSupport, extHeader, testSrc, "");
297 }
298 
supportedCheck(Context & context,CaseDefinition caseDef)299 void supportedCheck (Context& context, CaseDefinition caseDef)
300 {
301 	if (!subgroups::isSubgroupSupported(context))
302 		TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
303 
304 	if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV))
305 		TCU_THROW(NotSupportedError, "Device does not support subgroup partitioned operations");
306 
307 	if (!subgroups::isFormatSupportedForDevice(context, caseDef.format))
308 		TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
309 
310 	if (caseDef.requiredSubgroupSize)
311 	{
312 		context.requireDeviceFunctionality("VK_EXT_subgroup_size_control");
313 
314 		const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT&	subgroupSizeControlFeatures		= context.getSubgroupSizeControlFeaturesEXT();
315 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
316 
317 		if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
318 			TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes nor required subgroup size");
319 
320 		if (subgroupSizeControlFeatures.computeFullSubgroups == DE_FALSE)
321 			TCU_THROW(NotSupportedError, "Device does not support full subgroups in compute shaders");
322 
323 		if ((subgroupSizeControlProperties.requiredSubgroupSizeStages & caseDef.shaderStage) != caseDef.shaderStage)
324 			TCU_THROW(NotSupportedError, "Required subgroup size is not supported for shader stage");
325 	}
326 
327 	*caseDef.geometryPointSizeSupported = subgroups::isTessellationAndGeometryPointSizeSupported(context);
328 
329 	if (isAllRayTracingStages(caseDef.shaderStage))
330 	{
331 		context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
332 	}
333 
334 	subgroups::supportedCheckShader(context, caseDef.shaderStage);
335 }
336 
noSSBOtest(Context & context,const CaseDefinition caseDef)337 TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
338 {
339 	const subgroups::SSBOData	inputData
340 	{
341 		subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
342 		subgroups::SSBOData::LayoutStd140,		//  InputDataLayoutType			layout;
343 		caseDef.format,							//  vk::VkFormat				format;
344 		subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
345 	};
346 
347 	switch (caseDef.shaderStage)
348 	{
349 		case VK_SHADER_STAGE_VERTEX_BIT:					return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages);
350 		case VK_SHADER_STAGE_GEOMETRY_BIT:					return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages);
351 		case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:		return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
352 		case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:	return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
353 		default:											TCU_THROW(InternalError, "Unhandled shader stage");
354 	}
355 }
356 
test(Context & context,const CaseDefinition caseDef)357 TestStatus test (Context& context, const CaseDefinition caseDef)
358 {
359 	if (isAllComputeStages(caseDef.shaderStage))
360 	{
361 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
362 		TestLog&												log								= context.getTestContext().getLog();
363 		const subgroups::SSBOData								inputData						=
364 		{
365 			subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
366 			subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
367 			caseDef.format,							//  vk::VkFormat				format;
368 			subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
369 		};
370 
371 		if (caseDef.requiredSubgroupSize == DE_FALSE)
372 			return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkCompute);
373 
374 		log << TestLog::Message << "Testing required subgroup size range [" <<  subgroupSizeControlProperties.minSubgroupSize << ", "
375 			<< subgroupSizeControlProperties.maxSubgroupSize << "]" << TestLog::EndMessage;
376 
377 		// According to the spec, requiredSubgroupSize must be a power-of-two integer.
378 		for (deUint32 size = subgroupSizeControlProperties.minSubgroupSize; size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
379 		{
380 			TestStatus result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkCompute,
381 																size, VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT);
382 			if (result.getCode() != QP_TEST_RESULT_PASS)
383 			{
384 				log << TestLog::Message << "subgroupSize " << size << " failed" << TestLog::EndMessage;
385 				return result;
386 			}
387 		}
388 
389 		return TestStatus::pass("OK");
390 	}
391 	else if (isAllGraphicsStages(caseDef.shaderStage))
392 	{
393 		const VkShaderStageFlags	stages		= subgroups::getPossibleGraphicsSubgroupStages(context, caseDef.shaderStage);
394 		const subgroups::SSBOData	inputData
395 		{
396 			subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
397 			subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
398 			caseDef.format,							//  vk::VkFormat				format;
399 			subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
400 			false,									//  bool						isImage;
401 			4u,										//  deUint32					binding;
402 			stages,									//  vk::VkShaderStageFlags		stages;
403 		};
404 
405 		return subgroups::allStages(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, stages);
406 	}
407 	else if (isAllRayTracingStages(caseDef.shaderStage))
408 	{
409 		const VkShaderStageFlags	stages		= subgroups::getPossibleRayTracingSubgroupStages(context, caseDef.shaderStage);
410 		const subgroups::SSBOData	inputData
411 		{
412 			subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
413 			subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
414 			caseDef.format,							//  vk::VkFormat				format;
415 			subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
416 			false,									//  bool						isImage;
417 			6u,										//  deUint32					binding;
418 			stages,									//  vk::VkShaderStageFlags		stages;
419 		};
420 
421 		return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, stages);
422 	}
423 	else
424 		TCU_THROW(InternalError, "Unknown stage or invalid stage set");
425 }
426 }
427 
428 namespace vkt
429 {
430 namespace subgroups
431 {
createSubgroupsPartitionedTests(TestContext & testCtx)432 TestCaseGroup* createSubgroupsPartitionedTests (TestContext& testCtx)
433 {
434 	de::MovePtr<TestCaseGroup>	group				(new TestCaseGroup(testCtx, "partitioned", "Subgroup partitioned category tests"));
435 	de::MovePtr<TestCaseGroup>	graphicGroup		(new TestCaseGroup(testCtx, "graphics", "Subgroup partitioned category tests: graphics"));
436 	de::MovePtr<TestCaseGroup>	computeGroup		(new TestCaseGroup(testCtx, "compute", "Subgroup partitioned category tests: compute"));
437 	de::MovePtr<TestCaseGroup>	framebufferGroup	(new TestCaseGroup(testCtx, "framebuffer", "Subgroup partitioned category tests: framebuffer"));
438 	de::MovePtr<TestCaseGroup>	raytracingGroup		(new TestCaseGroup(testCtx, "ray_tracing", "Subgroup partitioned category tests: ray tracing"));
439 	const VkShaderStageFlags	stages[]			=
440 	{
441 		VK_SHADER_STAGE_VERTEX_BIT,
442 		VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
443 		VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
444 		VK_SHADER_STAGE_GEOMETRY_BIT,
445 	};
446 	const deBool				boolValues[]		=
447 	{
448 		DE_FALSE,
449 		DE_TRUE
450 	};
451 
452 	{
453 		const vector<VkFormat>		formats		= subgroups::getAllFormats();
454 
455 		for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
456 		{
457 			const VkFormat	format		= formats[formatIndex];
458 			const string	formatName	= subgroups::getFormatNameForGLSL(format);
459 			const bool		isBool		= subgroups::isFormatBool(format);
460 			const bool		isFloat		= subgroups::isFormatFloat(format);
461 
462 			for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
463 			{
464 				const OpType	opType		= static_cast<OpType>(opTypeIndex);
465 				const Operator	op			= getOperator(opType);
466 				const ScanType	st			= getScanType(opType);
467 				const bool		isBitwiseOp	= (op == OPERATOR_AND || op == OPERATOR_OR || op == OPERATOR_XOR);
468 
469 				// Skip float with bitwise category.
470 				if (isFloat && isBitwiseOp)
471 					continue;
472 
473 				// Skip bool when its not the bitwise category.
474 				if (isBool && !isBitwiseOp)
475 					continue;
476 
477 				const string	name = de::toLower(getOpTypeName(op, st)) + "_" + formatName;
478 
479 				for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
480 				{
481 					const deBool			requiredSubgroupSize	= boolValues[groupSizeNdx];
482 					const string			testName				= name + (requiredSubgroupSize ? "_requiredsubgroupsize" : "");
483 					const CaseDefinition	caseDef					=
484 					{
485 						op,								//  Operator			op;
486 						st,								//  ScanType			scanType;
487 						VK_SHADER_STAGE_COMPUTE_BIT,	//  VkShaderStageFlags	shaderStage;
488 						format,							//  VkFormat			format;
489 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
490 						requiredSubgroupSize			//  deBool				requiredSubgroupSize;
491 					};
492 
493 					addFunctionCaseWithPrograms(computeGroup.get(), testName, "", supportedCheck, initPrograms, test, caseDef);
494 				}
495 
496 				{
497 					const CaseDefinition	caseDef		=
498 					{
499 						op,								//  Operator			op;
500 						st,								//  ScanType			scanType;
501 						VK_SHADER_STAGE_ALL_GRAPHICS,	//  VkShaderStageFlags	shaderStage;
502 						format,							//  VkFormat			format;
503 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
504 						DE_FALSE						//  deBool				requiredSubgroupSize;
505 					};
506 
507 					addFunctionCaseWithPrograms(graphicGroup.get(), name, "", supportedCheck, initPrograms, test, caseDef);
508 				}
509 
510 				for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
511 				{
512 					const CaseDefinition	caseDef		=
513 					{
514 						op,								//  Operator			op;
515 						st,								//  ScanType			scanType;
516 						stages[stageIndex],				//  VkShaderStageFlags	shaderStage;
517 						format,							//  VkFormat			format;
518 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
519 						DE_FALSE						//  deBool				requiredSubgroupSize;
520 					};
521 					const string			testName	= name + "_" + getShaderStageName(caseDef.shaderStage);
522 
523 					addFunctionCaseWithPrograms(framebufferGroup.get(), testName, "", supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
524 				}
525 			}
526 		}
527 	}
528 
529 	{
530 		const vector<VkFormat>	formats		= subgroups::getAllRayTracingFormats();
531 
532 		for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
533 		{
534 			const VkFormat	format		= formats[formatIndex];
535 			const string	formatName	= subgroups::getFormatNameForGLSL(format);
536 			const bool		isBool		= subgroups::isFormatBool(format);
537 			const bool		isFloat		= subgroups::isFormatFloat(format);
538 
539 			for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
540 			{
541 				const OpType	opType		= static_cast<OpType>(opTypeIndex);
542 				const Operator	op			= getOperator(opType);
543 				const ScanType	st			= getScanType(opType);
544 				const bool		isBitwiseOp	= (op == OPERATOR_AND || op == OPERATOR_OR || op == OPERATOR_XOR);
545 
546 				// Skip float with bitwise category.
547 				if (isFloat && isBitwiseOp)
548 					continue;
549 
550 				// Skip bool when its not the bitwise category.
551 				if (isBool && !isBitwiseOp)
552 					continue;
553 
554 				{
555 					const CaseDefinition	caseDef		=
556 					{
557 						op,								//  Operator			op;
558 						st,								//  ScanType			scanType;
559 						SHADER_STAGE_ALL_RAY_TRACING,	//  VkShaderStageFlags	shaderStage;
560 						format,							//  VkFormat			format;
561 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
562 						DE_FALSE						//  deBool				requiredSubgroupSize;
563 					};
564 					const string			name		= de::toLower(getOpTypeName(op, st)) + "_" + formatName;
565 
566 					addFunctionCaseWithPrograms(raytracingGroup.get(), name, "", supportedCheck, initPrograms, test, caseDef);
567 				}
568 			}
569 		}
570 	}
571 
572 	group->addChild(graphicGroup.release());
573 	group->addChild(computeGroup.release());
574 	group->addChild(framebufferGroup.release());
575 	group->addChild(raytracingGroup.release());
576 
577 	return group.release();
578 }
579 } // subgroups
580 } // vkt
581