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