1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2017 The Khronos Group Inc.
6 * Copyright (c) 2017 Codeplay Software Ltd.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 * \brief Subgroups Tests
23 */ /*--------------------------------------------------------------------*/
25 #include "vktSubgroupsBallotOtherTests.hpp"
26 #include "vktSubgroupsTestsUtils.hpp"
40 OPTYPE_INVERSE_BALLOT = 0,
41 OPTYPE_BALLOT_BIT_EXTRACT,
42 OPTYPE_BALLOT_BIT_COUNT,
43 OPTYPE_BALLOT_INCLUSIVE_BIT_COUNT,
44 OPTYPE_BALLOT_EXCLUSIVE_BIT_COUNT,
45 OPTYPE_BALLOT_FIND_LSB,
46 OPTYPE_BALLOT_FIND_MSB,
50 static bool checkVertexPipelineStages(std::vector<const void*> datas,
51 deUint32 width, deUint32)
53 return vkt::subgroups::check(datas, width, 0xf);
56 static bool checkCompute(std::vector<const void*> datas,
57 const deUint32 numWorkgroups[3], const deUint32 localSize[3],
60 return vkt::subgroups::checkCompute(datas, numWorkgroups, localSize, 0xf);
63 std::string getOpTypeName(int opType)
68 DE_FATAL("Unsupported op type");
70 case OPTYPE_INVERSE_BALLOT:
71 return "subgroupInverseBallot";
72 case OPTYPE_BALLOT_BIT_EXTRACT:
73 return "subgroupBallotBitExtract";
74 case OPTYPE_BALLOT_BIT_COUNT:
75 return "subgroupBallotBitCount";
76 case OPTYPE_BALLOT_INCLUSIVE_BIT_COUNT:
77 return "subgroupBallotInclusiveBitCount";
78 case OPTYPE_BALLOT_EXCLUSIVE_BIT_COUNT:
79 return "subgroupBallotExclusiveBitCount";
80 case OPTYPE_BALLOT_FIND_LSB:
81 return "subgroupBallotFindLSB";
82 case OPTYPE_BALLOT_FIND_MSB:
83 return "subgroupBallotFindMSB";
90 VkShaderStageFlags shaderStage;
93 std::string getBodySource(CaseDefinition caseDef)
95 std::ostringstream bdy;
97 bdy << " uvec4 allOnes = uvec4(0xFFFFFFFF);\n"
98 << " uvec4 allZeros = uvec4(0);\n"
99 << " uint tempResult = 0;\n"
100 << "#define MAKE_HIGH_BALLOT_RESULT(i) uvec4("
101 << "i >= 32 ? 0 : (0xFFFFFFFF << i), "
102 << "i >= 64 ? 0 : (0xFFFFFFFF << ((i < 32) ? 0 : (i - 32))), "
103 << "i >= 96 ? 0 : (0xFFFFFFFF << ((i < 64) ? 0 : (i - 64))), "
104 << " 0xFFFFFFFF << ((i < 96) ? 0 : (i - 96)))\n"
105 << "#define MAKE_SINGLE_BIT_BALLOT_RESULT(i) uvec4("
106 << "i >= 32 ? 0 : 0x1 << i, "
107 << "i < 32 || i >= 64 ? 0 : 0x1 << (i - 32), "
108 << "i < 64 || i >= 96 ? 0 : 0x1 << (i - 64), "
109 << "i < 96 ? 0 : 0x1 << (i - 96))\n";
111 switch (caseDef.opType)
114 DE_FATAL("Unknown op type!");
116 case OPTYPE_INVERSE_BALLOT:
117 bdy << " tempResult |= subgroupInverseBallot(allOnes) ? 0x1 : 0;\n"
118 << " tempResult |= subgroupInverseBallot(allZeros) ? 0 : 0x2;\n"
119 << " tempResult |= subgroupInverseBallot(subgroupBallot(true)) ? 0x4 : 0;\n"
120 << " tempResult |= 0x8;\n";
122 case OPTYPE_BALLOT_BIT_EXTRACT:
123 bdy << " tempResult |= subgroupBallotBitExtract(allOnes, gl_SubgroupInvocationID) ? 0x1 : 0;\n"
124 << " tempResult |= subgroupBallotBitExtract(allZeros, gl_SubgroupInvocationID) ? 0 : 0x2;\n"
125 << " tempResult |= subgroupBallotBitExtract(subgroupBallot(true), gl_SubgroupInvocationID) ? 0x4 : 0;\n"
126 << " tempResult |= 0x8;\n"
127 << " for (uint i = 0; i < gl_SubgroupSize; i++)\n"
129 << " if (!subgroupBallotBitExtract(allOnes, gl_SubgroupInvocationID))\n"
131 << " tempResult &= ~0x8;\n"
135 case OPTYPE_BALLOT_BIT_COUNT:
136 bdy << " tempResult |= gl_SubgroupSize == subgroupBallotBitCount(allOnes) ? 0x1 : 0;\n"
137 << " tempResult |= 0 == subgroupBallotBitCount(allZeros) ? 0x2 : 0;\n"
138 << " tempResult |= 0 < subgroupBallotBitCount(subgroupBallot(true)) ? 0x4 : 0;\n"
139 << " tempResult |= 0 == subgroupBallotBitCount(MAKE_HIGH_BALLOT_RESULT(gl_SubgroupSize)) ? 0x8 : 0;\n";
141 case OPTYPE_BALLOT_INCLUSIVE_BIT_COUNT:
142 bdy << " uint inclusiveOffset = gl_SubgroupInvocationID + 1;\n"
143 << " tempResult |= inclusiveOffset == subgroupBallotInclusiveBitCount(allOnes) ? 0x1 : 0;\n"
144 << " tempResult |= 0 == subgroupBallotInclusiveBitCount(allZeros) ? 0x2 : 0;\n"
145 << " tempResult |= 0 < subgroupBallotInclusiveBitCount(subgroupBallot(true)) ? 0x4 : 0;\n"
146 << " tempResult |= 0x8;\n"
147 << " uvec4 inclusiveUndef = MAKE_HIGH_BALLOT_RESULT(inclusiveOffset);\n"
148 << " bool undefTerritory = false;\n"
149 << " for (uint i = 0; i <= 128; i++)\n"
151 << " uvec4 iUndef = MAKE_HIGH_BALLOT_RESULT(i);\n"
152 << " if (iUndef == inclusiveUndef)"
154 << " undefTerritory = true;\n"
156 << " uint inclusiveBitCount = subgroupBallotInclusiveBitCount(iUndef);\n"
157 << " if (undefTerritory && (0 != inclusiveBitCount))\n"
159 << " tempResult &= ~0x8;\n"
161 << " else if (!undefTerritory && (0 == inclusiveBitCount))\n"
163 << " tempResult &= ~0x8;\n"
167 case OPTYPE_BALLOT_EXCLUSIVE_BIT_COUNT:
168 bdy << " uint exclusiveOffset = gl_SubgroupInvocationID;\n"
169 << " tempResult |= exclusiveOffset == subgroupBallotExclusiveBitCount(allOnes) ? 0x1 : 0;\n"
170 << " tempResult |= 0 == subgroupBallotExclusiveBitCount(allZeros) ? 0x2 : 0;\n"
171 << " tempResult |= 0x4;\n"
172 << " tempResult |= 0x8;\n"
173 << " uvec4 exclusiveUndef = MAKE_HIGH_BALLOT_RESULT(exclusiveOffset);\n"
174 << " bool undefTerritory = false;\n"
175 << " for (uint i = 0; i <= 128; i++)\n"
177 << " uvec4 iUndef = MAKE_HIGH_BALLOT_RESULT(i);\n"
178 << " if (iUndef == exclusiveUndef)"
180 << " undefTerritory = true;\n"
182 << " uint exclusiveBitCount = subgroupBallotExclusiveBitCount(iUndef);\n"
183 << " if (undefTerritory && (0 != exclusiveBitCount))\n"
185 << " tempResult &= ~0x4;\n"
187 << " else if (!undefTerritory && (0 == exclusiveBitCount))\n"
189 << " tempResult &= ~0x8;\n"
193 case OPTYPE_BALLOT_FIND_LSB:
194 bdy << " tempResult |= 0 == subgroupBallotFindLSB(allOnes) ? 0x1 : 0;\n"
195 << " if (subgroupElect())\n"
197 << " tempResult |= 0x2;\n"
201 << " tempResult |= 0 < subgroupBallotFindLSB(subgroupBallot(true)) ? 0x2 : 0;\n"
203 << " tempResult |= gl_SubgroupSize > subgroupBallotFindLSB(subgroupBallot(true)) ? 0x4 : 0;\n"
204 << " tempResult |= 0x8;\n"
205 << " for (uint i = 0; i < gl_SubgroupSize; i++)\n"
207 << " if (i != subgroupBallotFindLSB(MAKE_HIGH_BALLOT_RESULT(i)))\n"
209 << " tempResult &= ~0x8;\n"
213 case OPTYPE_BALLOT_FIND_MSB:
214 bdy << " tempResult |= (gl_SubgroupSize - 1) == subgroupBallotFindMSB(allOnes) ? 0x1 : 0;\n"
215 << " if (subgroupElect())\n"
217 << " tempResult |= 0x2;\n"
221 << " tempResult |= 0 < subgroupBallotFindMSB(subgroupBallot(true)) ? 0x2 : 0;\n"
223 << " tempResult |= gl_SubgroupSize > subgroupBallotFindMSB(subgroupBallot(true)) ? 0x4 : 0;\n"
224 << " tempResult |= 0x8;\n"
225 << " for (uint i = 0; i < gl_SubgroupSize; i++)\n"
227 << " if (i != subgroupBallotFindMSB(MAKE_SINGLE_BIT_BALLOT_RESULT(i)))\n"
229 << " tempResult &= ~0x8;\n"
237 void initFrameBufferPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
239 const vk::ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
241 subgroups::setFragmentShaderFrameBuffer(programCollection);
243 if (VK_SHADER_STAGE_VERTEX_BIT != caseDef.shaderStage)
244 subgroups::setVertexShaderFrameBuffer(programCollection);
246 std::string bdyStr = getBodySource(caseDef);
248 if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
250 std::ostringstream vertex;
251 vertex << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
252 << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
253 << "layout(location = 0) in highp vec4 in_position;\n"
254 << "layout(location = 0) out float out_color;\n"
256 << "void main (void)\n"
259 << " out_color = float(tempResult);\n"
260 << " gl_Position = in_position;\n"
261 << " gl_PointSize = 1.0f;\n"
263 programCollection.glslSources.add("vert")
264 << glu::VertexSource(vertex.str()) << buildOptions;
266 else if (VK_SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
268 std::ostringstream geometry;
270 geometry << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
271 << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
272 << "layout(points) in;\n"
273 << "layout(points, max_vertices = 1) out;\n"
274 << "layout(location = 0) out float out_color;\n"
275 << "void main (void)\n"
278 << " out_color = float(tempResult);\n"
279 << " gl_Position = gl_in[0].gl_Position;\n"
280 << " EmitVertex();\n"
281 << " EndPrimitive();\n"
284 programCollection.glslSources.add("geometry")
285 << glu::GeometrySource(geometry.str()) << buildOptions;
287 else if (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage)
289 std::ostringstream controlSource;
291 controlSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
292 << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
293 << "layout(vertices = 2) out;\n"
294 << "layout(location = 0) out float out_color[];\n"
296 << "void main (void)\n"
298 << " if (gl_InvocationID == 0)\n"
300 << " gl_TessLevelOuter[0] = 1.0f;\n"
301 << " gl_TessLevelOuter[1] = 1.0f;\n"
304 << " out_color[gl_InvocationID ] = float(tempResult);\n"
305 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
308 programCollection.glslSources.add("tesc")
309 << glu::TessellationControlSource(controlSource.str()) << buildOptions;
310 subgroups::setTesEvalShaderFrameBuffer(programCollection);
312 else if (VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT == caseDef.shaderStage)
314 std::ostringstream evaluationSource;
315 evaluationSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
316 << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
317 << "layout(isolines, equal_spacing, ccw ) in;\n"
318 << "layout(location = 0) out float out_color;\n"
319 << "void main (void)\n"
322 << " out_color = float(tempResult);\n"
323 << " gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
326 subgroups::setTesCtrlShaderFrameBuffer(programCollection);
327 programCollection.glslSources.add("tese")
328 << glu::TessellationEvaluationSource(evaluationSource.str()) << buildOptions;
332 DE_FATAL("Unsupported shader stage");
336 void initPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
338 std::string bdyStr = getBodySource(caseDef);
340 if (VK_SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
342 std::ostringstream src;
344 src << "#version 450\n"
345 << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
346 << "layout (local_size_x_id = 0, local_size_y_id = 1, "
347 "local_size_z_id = 2) in;\n"
348 << "layout(set = 0, binding = 0, std430) buffer Buffer1\n"
350 << " uint result[];\n"
353 << "void main (void)\n"
355 << " uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
356 << " highp uint offset = globalSize.x * ((globalSize.y * "
357 "gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + "
358 "gl_GlobalInvocationID.x;\n"
360 << " result[offset] = tempResult;\n"
363 programCollection.glslSources.add("comp")
364 << glu::ComputeSource(src.str()) << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
368 const string vertex =
370 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
371 "layout(set = 0, binding = 0, std430) buffer Buffer1\n"
379 " result[gl_VertexIndex] = tempResult;\n"
380 " float pixelSize = 2.0f/1024.0f;\n"
381 " float pixelPosition = pixelSize/2.0f - 1.0f;\n"
382 " gl_Position = vec4(float(gl_VertexIndex) * pixelSize + pixelPosition, 0.0f, 0.0f, 1.0f);\n"
383 " gl_PointSize = 1.0f;\n"
388 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
389 "layout(vertices=1) out;\n"
390 "layout(set = 0, binding = 1, std430) buffer Buffer1\n"
398 " result[gl_PrimitiveID] = tempResult;\n"
399 " if (gl_InvocationID == 0)\n"
401 " gl_TessLevelOuter[0] = 1.0f;\n"
402 " gl_TessLevelOuter[1] = 1.0f;\n"
404 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
409 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
410 "layout(isolines) in;\n"
411 "layout(set = 0, binding = 2, std430) buffer Buffer1\n"
419 " result[gl_PrimitiveID * 2 + uint(gl_TessCoord.x + 0.5)] = tempResult;\n"
420 " float pixelSize = 2.0f/1024.0f;\n"
421 " gl_Position = gl_in[0].gl_Position + gl_TessCoord.x * pixelSize / 2.0f;\n"
424 const string geometry =
426 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
427 "layout(${TOPOLOGY}) in;\n"
428 "layout(points, max_vertices = 1) out;\n"
429 "layout(set = 0, binding = 3, std430) buffer Buffer1\n"
437 " result[gl_PrimitiveIDIn] = tempResult;\n"
438 " gl_Position = gl_in[0].gl_Position;\n"
443 const string fragment =
445 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
446 "layout(location = 0) out uint result;\n"
450 " result = tempResult;\n"
453 subgroups::addNoSubgroupShader(programCollection);
455 programCollection.glslSources.add("vert")
456 << glu::VertexSource(vertex) << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
457 programCollection.glslSources.add("tesc")
458 << glu::TessellationControlSource(tesc) << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
459 programCollection.glslSources.add("tese")
460 << glu::TessellationEvaluationSource(tese) << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
461 subgroups::addGeometryShadersFromTemplate(geometry, vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u),
462 programCollection.glslSources);
463 programCollection.glslSources.add("fragment")
464 << glu::FragmentSource(fragment)<< vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_3, 0u);
468 void supportedCheck (Context& context, CaseDefinition caseDef)
471 if (!subgroups::isSubgroupSupported(context))
472 TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
474 if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_BALLOT_BIT))
476 TCU_THROW(NotSupportedError, "Device does not support subgroup ballot operations");
480 tcu::TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
482 if (!subgroups::areSubgroupOperationsSupportedForStage(
483 context, caseDef.shaderStage))
485 if (subgroups::areSubgroupOperationsRequiredForStage(caseDef.shaderStage))
487 return tcu::TestStatus::fail(
489 subgroups::getShaderStageName(caseDef.shaderStage) +
490 " is required to support subgroup operations!");
494 TCU_THROW(NotSupportedError, "Device does not support subgroup operations for this stage");
498 if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
499 return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages);
500 else if (VK_SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
501 return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages);
502 else if ((VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) & caseDef.shaderStage)
503 return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages);
505 TCU_THROW(InternalError, "Unhandled shader stage");
508 tcu::TestStatus test (Context& context, const CaseDefinition caseDef)
510 if (VK_SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
512 if (!subgroups::areSubgroupOperationsSupportedForStage(context, caseDef.shaderStage))
514 return tcu::TestStatus::fail(
516 subgroups::getShaderStageName(caseDef.shaderStage) +
517 " is required to support subgroup operations!");
519 return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, checkCompute);
523 VkPhysicalDeviceSubgroupProperties subgroupProperties;
524 subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
525 subgroupProperties.pNext = DE_NULL;
527 VkPhysicalDeviceProperties2 properties;
528 properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
529 properties.pNext = &subgroupProperties;
531 context.getInstanceInterface().getPhysicalDeviceProperties2(context.getPhysicalDevice(), &properties);
533 VkShaderStageFlagBits stages = (VkShaderStageFlagBits)(caseDef.shaderStage & subgroupProperties.supportedStages);
535 if ( VK_SHADER_STAGE_FRAGMENT_BIT != stages && !subgroups::isVertexSSBOSupportedForDevice(context))
537 if ( (stages & VK_SHADER_STAGE_FRAGMENT_BIT) == 0)
538 TCU_THROW(NotSupportedError, "Device does not support vertex stage SSBO writes");
540 stages = VK_SHADER_STAGE_FRAGMENT_BIT;
543 if ((VkShaderStageFlagBits)0u == stages)
544 TCU_THROW(NotSupportedError, "Subgroup operations are not supported for any graphic shader");
546 return subgroups::allStages(context, VK_FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages, stages);
548 return tcu::TestStatus::pass("OK");
556 tcu::TestCaseGroup* createSubgroupsBallotOtherTests(tcu::TestContext& testCtx)
558 de::MovePtr<tcu::TestCaseGroup> graphicGroup(new tcu::TestCaseGroup(
559 testCtx, "graphics", "Subgroup ballot other category tests: graphics"));
560 de::MovePtr<tcu::TestCaseGroup> computeGroup(new tcu::TestCaseGroup(
561 testCtx, "compute", "Subgroup ballot other category tests: compute"));
562 de::MovePtr<tcu::TestCaseGroup> framebufferGroup(new tcu::TestCaseGroup(
563 testCtx, "framebuffer", "Subgroup ballot other category tests: framebuffer"));
565 const VkShaderStageFlags stages[] =
567 VK_SHADER_STAGE_VERTEX_BIT,
568 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
569 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
570 VK_SHADER_STAGE_GEOMETRY_BIT,
573 for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
575 const string op = de::toLower(getOpTypeName(opTypeIndex));
577 const CaseDefinition caseDef = {opTypeIndex, VK_SHADER_STAGE_COMPUTE_BIT};
578 addFunctionCaseWithPrograms(computeGroup.get(), op, "", supportedCheck, initPrograms, test, caseDef);
582 const CaseDefinition caseDef = {opTypeIndex, VK_SHADER_STAGE_ALL_GRAPHICS};
583 addFunctionCaseWithPrograms(graphicGroup.get(), op, "", supportedCheck, initPrograms, test, caseDef);
586 for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
588 const CaseDefinition caseDef = {opTypeIndex, stages[stageIndex]};
589 addFunctionCaseWithPrograms(framebufferGroup.get(), op + "_" + getShaderStageName(caseDef.shaderStage), "", supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
593 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(
594 testCtx, "ballot_other", "Subgroup ballot other category tests"));
596 group->addChild(graphicGroup.release());
597 group->addChild(computeGroup.release());
598 group->addChild(framebufferGroup.release());
600 return group.release();