1 /*------------------------------------------------------------------------
2  * OpenGL Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017-2019 The Khronos Group Inc.
6  * Copyright (c) 2017 Codeplay Software Ltd.
7  * Copyright (c) 2019 NVIDIA Corporation.
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 "glcSubgroupsBallotBroadcastTests.hpp"
27 #include "glcSubgroupsTestsUtils.hpp"
28 
29 #include <string>
30 #include <vector>
31 
32 using namespace tcu;
33 using namespace std;
34 
35 namespace glc
36 {
37 namespace subgroups
38 {
39 namespace
40 {
41 enum OpType
42 {
43     OPTYPE_BROADCAST = 0,
44     OPTYPE_BROADCAST_FIRST,
45     OPTYPE_LAST
46 };
47 
checkVertexPipelineStages(std::vector<const void * > datas,uint32_t width,uint32_t)48 static bool checkVertexPipelineStages(std::vector<const void *> datas, uint32_t width, uint32_t)
49 {
50     return glc::subgroups::check(datas, width, 3);
51 }
52 
checkComputeStages(std::vector<const void * > datas,const uint32_t numWorkgroups[3],const uint32_t localSize[3],uint32_t)53 static bool checkComputeStages(std::vector<const void *> datas, const uint32_t numWorkgroups[3],
54                                const uint32_t localSize[3], uint32_t)
55 {
56     return glc::subgroups::checkCompute(datas, numWorkgroups, localSize, 3);
57 }
58 
getOpTypeName(int opType)59 std::string getOpTypeName(int opType)
60 {
61     switch (opType)
62     {
63     default:
64         DE_FATAL("Unsupported op type");
65         return "";
66     case OPTYPE_BROADCAST:
67         return "subgroupBroadcast";
68     case OPTYPE_BROADCAST_FIRST:
69         return "subgroupBroadcastFirst";
70     }
71 }
72 
73 struct CaseDefinition
74 {
75     int opType;
76     ShaderStageFlags shaderStage;
77     Format format;
78 };
79 
getBodySource(CaseDefinition caseDef)80 std::string getBodySource(CaseDefinition caseDef)
81 {
82     std::ostringstream bdy;
83 
84     bdy << "  uvec4 mask = subgroupBallot(true);\n";
85     bdy << "  uint tempResult = 0u;\n";
86 
87     if (OPTYPE_BROADCAST == caseDef.opType)
88     {
89         bdy << "  tempResult = 0x3u;\n";
90         for (int i = 0; i < (int)subgroups::maxSupportedSubgroupSize(); i++)
91         {
92             bdy << "  {\n"
93                 << "    const uint id = " << i << "u;\n"
94                 << "    " << subgroups::getFormatNameForGLSL(caseDef.format)
95                 << " op = subgroupBroadcast(data1[gl_SubgroupInvocationID], id);\n"
96                 << "    if ((id < gl_SubgroupSize) && subgroupBallotBitExtract(mask, id))\n"
97                 << "    {\n"
98                 << "      if (op != data1[id])\n"
99                 << "      {\n"
100                 << "        tempResult = 0u;\n"
101                 << "      }\n"
102                 << "    }\n"
103                 << "  }\n";
104         }
105     }
106     else
107     {
108         bdy << "  uint firstActive = 0u;\n"
109             << "  for (uint i = 0u; i < gl_SubgroupSize; i++)\n"
110             << "  {\n"
111             << "    if (subgroupBallotBitExtract(mask, i))\n"
112             << "    {\n"
113             << "      firstActive = i;\n"
114             << "      break;\n"
115             << "    }\n"
116             << "  }\n"
117             << "  tempResult |= (subgroupBroadcastFirst(data1[gl_SubgroupInvocationID]) == data1[firstActive]) ? 0x1u "
118                ": 0u;\n"
119             << "  // make the firstActive invocation inactive now\n"
120             << "  if (firstActive == gl_SubgroupInvocationID)\n"
121             << "  {\n"
122             << "    for (uint i = 0u; i < gl_SubgroupSize; i++)\n"
123             << "    {\n"
124             << "      if (subgroupBallotBitExtract(mask, i))\n"
125             << "      {\n"
126             << "        firstActive = i;\n"
127             << "        break;\n"
128             << "      }\n"
129             << "    }\n"
130             << "    tempResult |= (subgroupBroadcastFirst(data1[gl_SubgroupInvocationID]) == data1[firstActive]) ? "
131                "0x2u : 0u;\n"
132             << "  }\n"
133             << "  else\n"
134             << "  {\n"
135             << "    // the firstActive invocation didn't partake in the second result so set it to true\n"
136             << "    tempResult |= 0x2u;\n"
137             << "  }\n";
138     }
139     return bdy.str();
140 }
141 
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)142 void initFrameBufferPrograms(SourceCollections &programCollection, CaseDefinition caseDef)
143 {
144     subgroups::setFragmentShaderFrameBuffer(programCollection);
145 
146     if (SHADER_STAGE_VERTEX_BIT != caseDef.shaderStage)
147         subgroups::setVertexShaderFrameBuffer(programCollection);
148 
149     std::string bdyStr = getBodySource(caseDef);
150 
151     if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
152     {
153         std::ostringstream vertex;
154         vertex << "${VERSION_DECL}\n"
155                << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
156                << "layout(location = 0) in highp vec4 in_position;\n"
157                << "layout(location = 0) out float out_color;\n"
158                << "layout(binding = 0, std140) uniform Buffer0\n"
159                << "{\n"
160                << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data1["
161                << subgroups::maxSupportedSubgroupSize() << "];\n"
162                << "};\n"
163                << "\n"
164                << "void main (void)\n"
165                << "{\n"
166                << bdyStr << "  out_color = float(tempResult);\n"
167                << "  gl_Position = in_position;\n"
168                << "  gl_PointSize = 1.0f;\n"
169                << "}\n";
170         programCollection.add("vert") << glu::VertexSource(vertex.str());
171     }
172     else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
173     {
174         std::ostringstream geometry;
175 
176         geometry << "${VERSION_DECL}\n"
177                  << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
178                  << "layout(points) in;\n"
179                  << "layout(points, max_vertices = 1) out;\n"
180                  << "layout(location = 0) out float out_color;\n"
181                  << "layout(binding = 0, std140) uniform Buffer0\n"
182                  << "{\n"
183                  << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data1["
184                  << subgroups::maxSupportedSubgroupSize() << "];\n"
185                  << "};\n"
186                  << "\n"
187                  << "void main (void)\n"
188                  << "{\n"
189                  << bdyStr << "  out_color = float(tempResult);\n"
190                  << "  gl_Position = gl_in[0].gl_Position;\n"
191                  << "  EmitVertex();\n"
192                  << "  EndPrimitive();\n"
193                  << "}\n";
194 
195         programCollection.add("geometry") << glu::GeometrySource(geometry.str());
196     }
197     else if (SHADER_STAGE_TESS_CONTROL_BIT == caseDef.shaderStage)
198     {
199         std::ostringstream controlSource;
200 
201         controlSource << "${VERSION_DECL}\n"
202                       << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
203                       << "layout(vertices = 2) out;\n"
204                       << "layout(location = 0) out float out_color[];\n"
205                       << "layout(binding = 0, std140) uniform Buffer0\n"
206                       << "{\n"
207                       << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data1["
208                       << subgroups::maxSupportedSubgroupSize() << "];\n"
209                       << "};\n"
210                       << "\n"
211                       << "void main (void)\n"
212                       << "{\n"
213                       << "  if (gl_InvocationID == 0)\n"
214                       << "  {\n"
215                       << "    gl_TessLevelOuter[0] = 1.0f;\n"
216                       << "    gl_TessLevelOuter[1] = 1.0f;\n"
217                       << "  }\n"
218                       << bdyStr << "  out_color[gl_InvocationID ] = float(tempResult);\n"
219                       << "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
220                       << "}\n";
221 
222         programCollection.add("tesc") << glu::TessellationControlSource(controlSource.str());
223         subgroups::setTesEvalShaderFrameBuffer(programCollection);
224     }
225     else if (SHADER_STAGE_TESS_EVALUATION_BIT == caseDef.shaderStage)
226     {
227         std::ostringstream evaluationSource;
228         evaluationSource << "${VERSION_DECL}\n"
229                          << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
230                          << "layout(isolines, equal_spacing, ccw ) in;\n"
231                          << "layout(location = 0) out float out_color;\n"
232                          << "layout(binding = 0, std140) uniform Buffer0\n"
233                          << "{\n"
234                          << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data1["
235                          << subgroups::maxSupportedSubgroupSize() << "];\n"
236                          << "};\n"
237                          << "\n"
238                          << "void main (void)\n"
239                          << "{\n"
240                          << bdyStr << "  out_color  = float(tempResult);\n"
241                          << "  gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
242                          << "}\n";
243 
244         subgroups::setTesCtrlShaderFrameBuffer(programCollection);
245         programCollection.add("tese") << glu::TessellationEvaluationSource(evaluationSource.str());
246     }
247     else
248     {
249         DE_FATAL("Unsupported shader stage");
250     }
251 }
252 
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)253 void initPrograms(SourceCollections &programCollection, CaseDefinition caseDef)
254 {
255     std::string bdyStr = getBodySource(caseDef);
256 
257     if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
258     {
259         std::ostringstream src;
260 
261         src << "${VERSION_DECL}\n"
262             << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
263             << "layout (${LOCAL_SIZE_X}, ${LOCAL_SIZE_Y}, ${LOCAL_SIZE_Z}) in;\n"
264             << "layout(binding = 0, std430) buffer Buffer0\n"
265             << "{\n"
266             << "  uint result[];\n"
267             << "};\n"
268             << "layout(binding = 1, std430) buffer Buffer1\n"
269             << "{\n"
270             << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data1[];\n"
271             << "};\n"
272             << "\n"
273             << "void main (void)\n"
274             << "{\n"
275             << "  uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
276             << "  highp uint offset = globalSize.x * ((globalSize.y * "
277                "gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + "
278                "gl_GlobalInvocationID.x;\n"
279             << bdyStr << "  result[offset] = tempResult;\n"
280             << "}\n";
281 
282         programCollection.add("comp") << glu::ComputeSource(src.str());
283     }
284     else
285     {
286         const string vertex =
287             "${VERSION_DECL}\n"
288             "#extension GL_KHR_shader_subgroup_ballot: enable\n"
289             "layout(binding = 0, std430) buffer Buffer0\n"
290             "{\n"
291             "  uint result[];\n"
292             "} b0;\n"
293             "layout(binding = 4, std430) readonly buffer Buffer4\n"
294             "{\n"
295             "  " +
296             subgroups::getFormatNameForGLSL(caseDef.format) +
297             " data1[];\n"
298             "};\n"
299             "\n"
300             "void main (void)\n"
301             "{\n" +
302             bdyStr +
303             "  b0.result[gl_VertexID] = tempResult;\n"
304             "  float pixelSize = 2.0f/1024.0f;\n"
305             "  float pixelPosition = pixelSize/2.0f - 1.0f;\n"
306             "  gl_Position = vec4(float(gl_VertexID) * pixelSize + pixelPosition, 0.0f, 0.0f, 1.0f);\n"
307             "  gl_PointSize = 1.0f;\n"
308             "}\n";
309 
310         const string tesc = "${VERSION_DECL}\n"
311                             "#extension GL_KHR_shader_subgroup_ballot: enable\n"
312                             "layout(vertices=1) out;\n"
313                             "layout(binding = 1, std430) buffer Buffer1\n"
314                             "{\n"
315                             "  uint result[];\n"
316                             "} b1;\n"
317                             "layout(binding = 4, std430) readonly buffer Buffer4\n"
318                             "{\n"
319                             "  " +
320                             subgroups::getFormatNameForGLSL(caseDef.format) +
321                             " data1[];\n"
322                             "};\n"
323                             "\n"
324                             "void main (void)\n"
325                             "{\n" +
326                             bdyStr +
327                             "  b1.result[gl_PrimitiveID] = tempResult;\n"
328                             "  if (gl_InvocationID == 0)\n"
329                             "  {\n"
330                             "    gl_TessLevelOuter[0] = 1.0f;\n"
331                             "    gl_TessLevelOuter[1] = 1.0f;\n"
332                             "  }\n"
333                             "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
334                             "}\n";
335 
336         const string tese = "${VERSION_DECL}\n"
337                             "#extension GL_KHR_shader_subgroup_ballot: enable\n"
338                             "layout(isolines) in;\n"
339                             "layout(binding = 2, std430) buffer Buffer2\n"
340                             "{\n"
341                             "  uint result[];\n"
342                             "} b2;\n"
343                             "layout(binding = 4, std430) readonly buffer Buffer4\n"
344                             "{\n"
345                             "  " +
346                             subgroups::getFormatNameForGLSL(caseDef.format) +
347                             " data1[];\n"
348                             "};\n"
349                             "\n"
350                             "void main (void)\n"
351                             "{\n" +
352                             bdyStr +
353                             "  b2.result[gl_PrimitiveID * 2 + int(gl_TessCoord.x + 0.5)] = tempResult;\n"
354                             "  float pixelSize = 2.0f/1024.0f;\n"
355                             "  gl_Position = gl_in[0].gl_Position + gl_TessCoord.x * pixelSize / 2.0f;\n"
356                             "}\n";
357 
358         const string geometry =
359             //version string added by addGeometryShadersFromTemplate
360             "#extension GL_KHR_shader_subgroup_ballot: enable\n"
361             "layout(${TOPOLOGY}) in;\n"
362             "layout(points, max_vertices = 1) out;\n"
363             "layout(binding = 3, std430) buffer Buffer3\n"
364             "{\n"
365             "  uint result[];\n"
366             "} b3;\n"
367             "layout(binding = 4, std430) readonly buffer Buffer4\n"
368             "{\n"
369             "  " +
370             subgroups::getFormatNameForGLSL(caseDef.format) +
371             " data1[];\n"
372             "};\n"
373             "\n"
374             "void main (void)\n"
375             "{\n" +
376             bdyStr +
377             "  b3.result[gl_PrimitiveIDIn] = tempResult;\n"
378             "  gl_Position = gl_in[0].gl_Position;\n"
379             "  EmitVertex();\n"
380             "  EndPrimitive();\n"
381             "}\n";
382 
383         const string fragment = "${VERSION_DECL}\n"
384                                 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
385                                 "precision highp int;\n"
386                                 "precision highp float;\n"
387                                 "layout(location = 0) out uint result;\n"
388                                 "layout(binding = 4, std430) readonly buffer Buffer4\n"
389                                 "{\n"
390                                 "  " +
391                                 subgroups::getFormatNameForGLSL(caseDef.format) +
392                                 " data1[];\n"
393                                 "};\n"
394                                 "void main (void)\n"
395                                 "{\n" +
396                                 bdyStr +
397                                 "  result = tempResult;\n"
398                                 "}\n";
399 
400         subgroups::addNoSubgroupShader(programCollection);
401 
402         programCollection.add("vert") << glu::VertexSource(vertex);
403         programCollection.add("tesc") << glu::TessellationControlSource(tesc);
404         programCollection.add("tese") << glu::TessellationEvaluationSource(tese);
405         subgroups::addGeometryShadersFromTemplate(geometry, programCollection);
406         programCollection.add("fragment") << glu::FragmentSource(fragment);
407     }
408 }
409 
supportedCheck(Context & context,CaseDefinition caseDef)410 void supportedCheck(Context &context, CaseDefinition caseDef)
411 {
412     if (!subgroups::isSubgroupSupported(context))
413         TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
414 
415     if (!subgroups::isSubgroupFeatureSupportedForDevice(context, SUBGROUP_FEATURE_BALLOT_BIT))
416     {
417         TCU_THROW(NotSupportedError, "Device does not support subgroup ballot operations");
418     }
419 
420     if (subgroups::isDoubleFormat(caseDef.format) && !subgroups::isDoubleSupportedForDevice(context))
421     {
422         TCU_THROW(NotSupportedError, "Device does not support subgroup double operations");
423     }
424 }
425 
noSSBOtest(Context & context,const CaseDefinition caseDef)426 tcu::TestStatus noSSBOtest(Context &context, const CaseDefinition caseDef)
427 {
428     if (!subgroups::areSubgroupOperationsSupportedForStage(context, caseDef.shaderStage))
429     {
430         if (subgroups::areSubgroupOperationsRequiredForStage(caseDef.shaderStage))
431         {
432             return tcu::TestStatus::fail("Shader stage " + subgroups::getShaderStageName(caseDef.shaderStage) +
433                                          " is required to support subgroup operations!");
434         }
435         else
436         {
437             TCU_THROW(NotSupportedError, "Device does not support subgroup operations for this stage");
438         }
439     }
440 
441     subgroups::SSBOData inputData[1];
442     inputData[0].format         = caseDef.format;
443     inputData[0].layout         = subgroups::SSBOData::LayoutStd140;
444     inputData[0].numElements    = subgroups::maxSupportedSubgroupSize();
445     inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero;
446 
447     if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
448         return subgroups::makeVertexFrameBufferTest(context, FORMAT_R32_UINT, inputData, 1, checkVertexPipelineStages);
449     else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
450         return subgroups::makeGeometryFrameBufferTest(context, FORMAT_R32_UINT, inputData, 1,
451                                                       checkVertexPipelineStages);
452     else if (SHADER_STAGE_TESS_CONTROL_BIT == caseDef.shaderStage)
453         return subgroups::makeTessellationEvaluationFrameBufferTest(
454             context, FORMAT_R32_UINT, inputData, 1, checkVertexPipelineStages, SHADER_STAGE_TESS_CONTROL_BIT);
455     else if (SHADER_STAGE_TESS_EVALUATION_BIT == caseDef.shaderStage)
456         return subgroups::makeTessellationEvaluationFrameBufferTest(
457             context, FORMAT_R32_UINT, inputData, 1, checkVertexPipelineStages, SHADER_STAGE_TESS_EVALUATION_BIT);
458     else
459         TCU_THROW(InternalError, "Unhandled shader stage");
460 }
461 
test(Context & context,const CaseDefinition caseDef)462 tcu::TestStatus test(Context &context, const CaseDefinition caseDef)
463 {
464     if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
465     {
466         if (!subgroups::areSubgroupOperationsSupportedForStage(context, caseDef.shaderStage))
467         {
468             if (subgroups::areSubgroupOperationsRequiredForStage(caseDef.shaderStage))
469             {
470                 return tcu::TestStatus::fail("Shader stage " + subgroups::getShaderStageName(caseDef.shaderStage) +
471                                              " is required to support subgroup operations!");
472             }
473             else
474             {
475                 TCU_THROW(NotSupportedError, "Device does not support subgroup operations for this stage");
476             }
477         }
478         subgroups::SSBOData inputData[1];
479         inputData[0].format         = caseDef.format;
480         inputData[0].layout         = subgroups::SSBOData::LayoutStd430;
481         inputData[0].numElements    = subgroups::maxSupportedSubgroupSize();
482         inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero;
483         inputData[0].binding        = 1u;
484 
485         return subgroups::makeComputeTest(context, FORMAT_R32_UINT, inputData, 1, checkComputeStages);
486     }
487     else
488     {
489         int supportedStages = context.getDeqpContext().getContextInfo().getInt(GL_SUBGROUP_SUPPORTED_STAGES_KHR);
490 
491         ShaderStageFlags stages = (ShaderStageFlags)(caseDef.shaderStage & supportedStages);
492 
493         if (SHADER_STAGE_FRAGMENT_BIT != stages && !subgroups::isVertexSSBOSupportedForDevice(context))
494         {
495             if ((stages & SHADER_STAGE_FRAGMENT_BIT) == 0)
496                 TCU_THROW(NotSupportedError, "Device does not support vertex stage SSBO writes");
497             else
498                 stages = SHADER_STAGE_FRAGMENT_BIT;
499         }
500 
501         if ((ShaderStageFlags)0u == stages)
502             TCU_THROW(NotSupportedError, "Subgroup operations are not supported for any graphic shader");
503 
504         subgroups::SSBOData inputData;
505         inputData.format         = caseDef.format;
506         inputData.layout         = subgroups::SSBOData::LayoutStd430;
507         inputData.numElements    = subgroups::maxSupportedSubgroupSize();
508         inputData.initializeType = subgroups::SSBOData::InitializeNonZero;
509         inputData.binding        = 4u;
510         inputData.stages         = stages;
511 
512         return subgroups::allStages(context, FORMAT_R32_UINT, &inputData, 1, checkVertexPipelineStages, stages);
513     }
514 }
515 } // namespace
516 
createSubgroupsBallotBroadcastTests(deqp::Context & testCtx)517 deqp::TestCaseGroup *createSubgroupsBallotBroadcastTests(deqp::Context &testCtx)
518 {
519     de::MovePtr<deqp::TestCaseGroup> graphicGroup(
520         new deqp::TestCaseGroup(testCtx, "graphics", "Subgroup ballot broadcast category tests: graphics"));
521     de::MovePtr<deqp::TestCaseGroup> computeGroup(
522         new deqp::TestCaseGroup(testCtx, "compute", "Subgroup ballot broadcast category tests: compute"));
523     de::MovePtr<deqp::TestCaseGroup> framebufferGroup(
524         new deqp::TestCaseGroup(testCtx, "framebuffer", "Subgroup ballot broadcast category tests: framebuffer"));
525 
526     const ShaderStageFlags stages[] = {
527         SHADER_STAGE_VERTEX_BIT,
528         SHADER_STAGE_TESS_EVALUATION_BIT,
529         SHADER_STAGE_TESS_CONTROL_BIT,
530         SHADER_STAGE_GEOMETRY_BIT,
531     };
532 
533     const Format formats[] = {
534         FORMAT_R32_SINT,   FORMAT_R32G32_SINT,   FORMAT_R32G32B32_SINT,   FORMAT_R32G32B32A32_SINT,
535         FORMAT_R32_UINT,   FORMAT_R32G32_UINT,   FORMAT_R32G32B32_UINT,   FORMAT_R32G32B32A32_UINT,
536         FORMAT_R32_SFLOAT, FORMAT_R32G32_SFLOAT, FORMAT_R32G32B32_SFLOAT, FORMAT_R32G32B32A32_SFLOAT,
537         FORMAT_R64_SFLOAT, FORMAT_R64G64_SFLOAT, FORMAT_R64G64B64_SFLOAT, FORMAT_R64G64B64A64_SFLOAT,
538         FORMAT_R32_BOOL,   FORMAT_R32G32_BOOL,   FORMAT_R32G32B32_BOOL,   FORMAT_R32G32B32A32_BOOL,
539     };
540 
541     for (int formatIndex = 0; formatIndex < DE_LENGTH_OF_ARRAY(formats); ++formatIndex)
542     {
543         const Format format = formats[formatIndex];
544 
545         for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
546         {
547             const std::string op   = de::toLower(getOpTypeName(opTypeIndex));
548             const std::string name = op + "_" + subgroups::getFormatNameForGLSL(format);
549 
550             {
551                 CaseDefinition caseDef = {opTypeIndex, SHADER_STAGE_COMPUTE_BIT, format};
552                 SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(
553                     computeGroup.get(), name, "", supportedCheck, initPrograms, test, caseDef);
554             }
555 
556             {
557                 const CaseDefinition caseDef = {opTypeIndex, SHADER_STAGE_ALL_GRAPHICS, format};
558                 SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(
559                     graphicGroup.get(), name, "", supportedCheck, initPrograms, test, caseDef);
560             }
561 
562             for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
563             {
564                 const CaseDefinition caseDef = {opTypeIndex, stages[stageIndex], format};
565                 SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(
566                     framebufferGroup.get(), name + getShaderStageName(caseDef.shaderStage), "", supportedCheck,
567                     initFrameBufferPrograms, noSSBOtest, caseDef);
568             }
569         }
570     }
571 
572     de::MovePtr<deqp::TestCaseGroup> group(
573         new deqp::TestCaseGroup(testCtx, "ballot_broadcast", "Subgroup ballot broadcast category tests"));
574 
575     group->addChild(graphicGroup.release());
576     group->addChild(computeGroup.release());
577     group->addChild(framebufferGroup.release());
578     return group.release();
579 }
580 
581 } // namespace subgroups
582 } // namespace glc
583