xref: /aosp_15_r20/external/deqp/external/openglcts/modules/common/subgroups/glcSubgroupsBuiltinVarTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 "glcSubgroupsBuiltinVarTests.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 
checkVertexPipelineStagesSubgroupSize(std::vector<const void * > datas,uint32_t width,uint32_t subgroupSize)40 bool checkVertexPipelineStagesSubgroupSize(std::vector<const void *> datas, uint32_t width, uint32_t subgroupSize)
41 {
42     const uint32_t *data = reinterpret_cast<const uint32_t *>(datas[0]);
43     for (uint32_t x = 0; x < width; ++x)
44     {
45         uint32_t val = data[x * 4];
46 
47         if (subgroupSize != val)
48             return false;
49     }
50 
51     return true;
52 }
53 
checkVertexPipelineStagesSubgroupInvocationID(std::vector<const void * > datas,uint32_t width,uint32_t subgroupSize)54 bool checkVertexPipelineStagesSubgroupInvocationID(std::vector<const void *> datas, uint32_t width,
55                                                    uint32_t subgroupSize)
56 {
57     const uint32_t *data = reinterpret_cast<const uint32_t *>(datas[0]);
58     vector<uint32_t> subgroupInvocationHits(subgroupSize, 0);
59 
60     for (uint32_t x = 0; x < width; ++x)
61     {
62         uint32_t subgroupInvocationID = data[(x * 4) + 1];
63 
64         if (subgroupInvocationID >= subgroupSize)
65             return false;
66         subgroupInvocationHits[subgroupInvocationID]++;
67     }
68 
69     const uint32_t totalSize = width;
70 
71     uint32_t totalInvocationsRun = 0;
72     for (uint32_t i = 0; i < subgroupSize; ++i)
73     {
74         totalInvocationsRun += subgroupInvocationHits[i];
75     }
76 
77     if (totalInvocationsRun != totalSize)
78         return false;
79 
80     return true;
81 }
82 
checkComputeSubgroupSize(std::vector<const void * > datas,const uint32_t numWorkgroups[3],const uint32_t localSize[3],uint32_t subgroupSize)83 static bool checkComputeSubgroupSize(std::vector<const void *> datas, const uint32_t numWorkgroups[3],
84                                      const uint32_t localSize[3], uint32_t subgroupSize)
85 {
86     const uint32_t *data = reinterpret_cast<const uint32_t *>(datas[0]);
87 
88     for (uint32_t nX = 0; nX < numWorkgroups[0]; ++nX)
89     {
90         for (uint32_t nY = 0; nY < numWorkgroups[1]; ++nY)
91         {
92             for (uint32_t nZ = 0; nZ < numWorkgroups[2]; ++nZ)
93             {
94                 for (uint32_t lX = 0; lX < localSize[0]; ++lX)
95                 {
96                     for (uint32_t lY = 0; lY < localSize[1]; ++lY)
97                     {
98                         for (uint32_t lZ = 0; lZ < localSize[2]; ++lZ)
99                         {
100                             const uint32_t globalInvocationX = nX * localSize[0] + lX;
101                             const uint32_t globalInvocationY = nY * localSize[1] + lY;
102                             const uint32_t globalInvocationZ = nZ * localSize[2] + lZ;
103 
104                             const uint32_t globalSizeX = numWorkgroups[0] * localSize[0];
105                             const uint32_t globalSizeY = numWorkgroups[1] * localSize[1];
106 
107                             const uint32_t offset =
108                                 globalSizeX * ((globalSizeY * globalInvocationZ) + globalInvocationY) +
109                                 globalInvocationX;
110 
111                             if (subgroupSize != data[offset * 4])
112                                 return false;
113                         }
114                     }
115                 }
116             }
117         }
118     }
119 
120     return true;
121 }
122 
checkComputeSubgroupInvocationID(std::vector<const void * > datas,const uint32_t numWorkgroups[3],const uint32_t localSize[3],uint32_t subgroupSize)123 static bool checkComputeSubgroupInvocationID(std::vector<const void *> datas, const uint32_t numWorkgroups[3],
124                                              const uint32_t localSize[3], uint32_t subgroupSize)
125 {
126     const uint32_t *data = reinterpret_cast<const uint32_t *>(datas[0]);
127 
128     for (uint32_t nX = 0; nX < numWorkgroups[0]; ++nX)
129     {
130         for (uint32_t nY = 0; nY < numWorkgroups[1]; ++nY)
131         {
132             for (uint32_t nZ = 0; nZ < numWorkgroups[2]; ++nZ)
133             {
134                 const uint32_t totalLocalSize = localSize[0] * localSize[1] * localSize[2];
135                 vector<uint32_t> subgroupInvocationHits(subgroupSize, 0);
136 
137                 for (uint32_t lX = 0; lX < localSize[0]; ++lX)
138                 {
139                     for (uint32_t lY = 0; lY < localSize[1]; ++lY)
140                     {
141                         for (uint32_t lZ = 0; lZ < localSize[2]; ++lZ)
142                         {
143                             const uint32_t globalInvocationX = nX * localSize[0] + lX;
144                             const uint32_t globalInvocationY = nY * localSize[1] + lY;
145                             const uint32_t globalInvocationZ = nZ * localSize[2] + lZ;
146 
147                             const uint32_t globalSizeX = numWorkgroups[0] * localSize[0];
148                             const uint32_t globalSizeY = numWorkgroups[1] * localSize[1];
149 
150                             const uint32_t offset =
151                                 globalSizeX * ((globalSizeY * globalInvocationZ) + globalInvocationY) +
152                                 globalInvocationX;
153 
154                             uint32_t subgroupInvocationID = data[(offset * 4) + 1];
155 
156                             if (subgroupInvocationID >= subgroupSize)
157                                 return false;
158 
159                             subgroupInvocationHits[subgroupInvocationID]++;
160                         }
161                     }
162                 }
163 
164                 uint32_t totalInvocationsRun = 0;
165                 for (uint32_t i = 0; i < subgroupSize; ++i)
166                 {
167                     totalInvocationsRun += subgroupInvocationHits[i];
168                 }
169 
170                 if (totalInvocationsRun != totalLocalSize)
171                     return false;
172             }
173         }
174     }
175 
176     return true;
177 }
178 
checkComputeNumSubgroups(std::vector<const void * > datas,const uint32_t numWorkgroups[3],const uint32_t localSize[3],uint32_t)179 static bool checkComputeNumSubgroups(std::vector<const void *> datas, const uint32_t numWorkgroups[3],
180                                      const uint32_t localSize[3], uint32_t)
181 {
182     const uint32_t *data = reinterpret_cast<const uint32_t *>(datas[0]);
183 
184     for (uint32_t nX = 0; nX < numWorkgroups[0]; ++nX)
185     {
186         for (uint32_t nY = 0; nY < numWorkgroups[1]; ++nY)
187         {
188             for (uint32_t nZ = 0; nZ < numWorkgroups[2]; ++nZ)
189             {
190                 const uint32_t totalLocalSize = localSize[0] * localSize[1] * localSize[2];
191 
192                 for (uint32_t lX = 0; lX < localSize[0]; ++lX)
193                 {
194                     for (uint32_t lY = 0; lY < localSize[1]; ++lY)
195                     {
196                         for (uint32_t lZ = 0; lZ < localSize[2]; ++lZ)
197                         {
198                             const uint32_t globalInvocationX = nX * localSize[0] + lX;
199                             const uint32_t globalInvocationY = nY * localSize[1] + lY;
200                             const uint32_t globalInvocationZ = nZ * localSize[2] + lZ;
201 
202                             const uint32_t globalSizeX = numWorkgroups[0] * localSize[0];
203                             const uint32_t globalSizeY = numWorkgroups[1] * localSize[1];
204 
205                             const uint32_t offset =
206                                 globalSizeX * ((globalSizeY * globalInvocationZ) + globalInvocationY) +
207                                 globalInvocationX;
208 
209                             uint32_t numSubgroups = data[(offset * 4) + 2];
210 
211                             if (numSubgroups > totalLocalSize)
212                                 return false;
213                         }
214                     }
215                 }
216             }
217         }
218     }
219 
220     return true;
221 }
222 
checkComputeSubgroupID(std::vector<const void * > datas,const uint32_t numWorkgroups[3],const uint32_t localSize[3],uint32_t)223 static bool checkComputeSubgroupID(std::vector<const void *> datas, const uint32_t numWorkgroups[3],
224                                    const uint32_t localSize[3], uint32_t)
225 {
226     const uint32_t *data = reinterpret_cast<const uint32_t *>(datas[0]);
227 
228     for (uint32_t nX = 0; nX < numWorkgroups[0]; ++nX)
229     {
230         for (uint32_t nY = 0; nY < numWorkgroups[1]; ++nY)
231         {
232             for (uint32_t nZ = 0; nZ < numWorkgroups[2]; ++nZ)
233             {
234                 for (uint32_t lX = 0; lX < localSize[0]; ++lX)
235                 {
236                     for (uint32_t lY = 0; lY < localSize[1]; ++lY)
237                     {
238                         for (uint32_t lZ = 0; lZ < localSize[2]; ++lZ)
239                         {
240                             const uint32_t globalInvocationX = nX * localSize[0] + lX;
241                             const uint32_t globalInvocationY = nY * localSize[1] + lY;
242                             const uint32_t globalInvocationZ = nZ * localSize[2] + lZ;
243 
244                             const uint32_t globalSizeX = numWorkgroups[0] * localSize[0];
245                             const uint32_t globalSizeY = numWorkgroups[1] * localSize[1];
246 
247                             const uint32_t offset =
248                                 globalSizeX * ((globalSizeY * globalInvocationZ) + globalInvocationY) +
249                                 globalInvocationX;
250 
251                             uint32_t numSubgroups = data[(offset * 4) + 2];
252                             uint32_t subgroupID   = data[(offset * 4) + 3];
253 
254                             if (subgroupID >= numSubgroups)
255                                 return false;
256                         }
257                     }
258                 }
259             }
260         }
261     }
262 
263     return true;
264 }
265 
266 namespace
267 {
268 struct CaseDefinition
269 {
270     std::string varName;
271     ShaderStageFlags shaderStage;
272 };
273 } // namespace
274 
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)275 void initFrameBufferPrograms(SourceCollections &programCollection, CaseDefinition caseDef)
276 {
277     {
278         const string fragmentGLSL = "${VERSION_DECL}\n"
279                                     "precision highp int;\n"
280                                     "layout(location = 0) in highp vec4 in_color;\n"
281                                     "layout(location = 0) out uvec4 out_color;\n"
282                                     "void main()\n"
283                                     "{\n"
284                                     "    out_color = uvec4(in_color);\n"
285                                     "}\n";
286         programCollection.add("fragment") << glu::FragmentSource(fragmentGLSL);
287     }
288 
289     if (SHADER_STAGE_VERTEX_BIT != caseDef.shaderStage)
290         subgroups::setVertexShaderFrameBuffer(programCollection);
291 
292     if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
293     {
294         const string vertexGLSL = "${VERSION_DECL}\n"
295                                   "#extension GL_KHR_shader_subgroup_basic: enable\n"
296                                   "layout(location = 0) out vec4 out_color;\n"
297                                   "layout(location = 0) in highp vec4 in_position;\n"
298                                   "\n"
299                                   "void main (void)\n"
300                                   "{\n"
301                                   "  out_color = vec4(gl_SubgroupSize, gl_SubgroupInvocationID, 1.0f, 1.0f);\n"
302                                   "  gl_Position = in_position;\n"
303                                   "  gl_PointSize = 1.0f;\n"
304                                   "}\n";
305         programCollection.add("vert") << glu::VertexSource(vertexGLSL);
306     }
307     else if (SHADER_STAGE_TESS_EVALUATION_BIT == caseDef.shaderStage)
308     {
309         const string controlSourceGLSL = "${VERSION_DECL}\n"
310                                          "${TESS_EXTENSION}\n"
311                                          "layout(vertices = 2) out;\n"
312                                          "layout(location = 0) out vec4 out_color[];\n"
313                                          "void main (void)\n"
314                                          "{\n"
315                                          "  if (gl_InvocationID == 0)\n"
316                                          "  {\n"
317                                          "    gl_TessLevelOuter[0] = 1.0f;\n"
318                                          "    gl_TessLevelOuter[1] = 1.0f;\n"
319                                          "  }\n"
320                                          "  out_color[gl_InvocationID] = vec4(0.0f);\n"
321                                          "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
322                                          "}\n";
323         programCollection.add("tesc") << glu::TessellationControlSource(controlSourceGLSL);
324 
325         const string evaluationSourceGLSL =
326             "${VERSION_DECL}\n"
327             "#extension GL_KHR_shader_subgroup_basic: enable\n"
328             "${TESS_EXTENSION}\n"
329             "layout(isolines, equal_spacing, ccw ) in;\n"
330             "layout(location = 0) in vec4 in_color[];\n"
331             "layout(location = 0) out vec4 out_color;\n"
332             "\n"
333             "void main (void)\n"
334             "{\n"
335             "  gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
336             "  out_color = vec4(gl_SubgroupSize, gl_SubgroupInvocationID, 0.0f, 0.0f);\n"
337             "}\n";
338         programCollection.add("tese") << glu::TessellationEvaluationSource(evaluationSourceGLSL);
339     }
340     else if (SHADER_STAGE_TESS_CONTROL_BIT == caseDef.shaderStage)
341     {
342         const string controlSourceGLSL =
343             "${VERSION_DECL}\n"
344             "${TESS_EXTENSION}\n"
345             "#extension GL_KHR_shader_subgroup_basic: enable\n"
346             "layout(vertices = 2) out;\n"
347             "layout(location = 0) out vec4 out_color[];\n"
348             "void main (void)\n"
349             "{\n"
350             "  if (gl_InvocationID == 0)\n"
351             "  {\n"
352             "    gl_TessLevelOuter[0] = 1.0f;\n"
353             "    gl_TessLevelOuter[1] = 1.0f;\n"
354             "  }\n"
355             "  out_color[gl_InvocationID] = vec4(gl_SubgroupSize, gl_SubgroupInvocationID, 0, 0);\n"
356             "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
357             "}\n";
358         programCollection.add("tesc") << glu::TessellationControlSource(controlSourceGLSL);
359 
360         const string evaluationSourceGLSL =
361             "${VERSION_DECL}\n"
362             "#extension GL_KHR_shader_subgroup_basic: enable\n"
363             "${TESS_EXTENSION}\n"
364             "layout(isolines, equal_spacing, ccw ) in;\n"
365             "layout(location = 0) in vec4 in_color[];\n"
366             "layout(location = 0) out vec4 out_color;\n"
367             "\n"
368             "void main (void)\n"
369             "{\n"
370             "  gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
371             "  out_color = in_color[0];\n"
372             "}\n";
373         programCollection.add("tese") << glu::TessellationEvaluationSource(evaluationSourceGLSL);
374     }
375     else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
376     {
377         const string geometryGLSL = "${VERSION_DECL}\n"
378                                     "#extension GL_KHR_shader_subgroup_basic: enable\n"
379                                     "layout(points) in;\n"
380                                     "layout(points, max_vertices = 1) out;\n"
381                                     "layout(location = 0) out vec4 out_color;\n"
382                                     "void main (void)\n"
383                                     "{\n"
384                                     "  out_color = vec4(gl_SubgroupSize, gl_SubgroupInvocationID, 0, 0);\n"
385                                     "  gl_Position = gl_in[0].gl_Position;\n"
386                                     "  EmitVertex();\n"
387                                     "  EndPrimitive();\n"
388                                     "}\n";
389         programCollection.add("geometry") << glu::GeometrySource(geometryGLSL);
390     }
391     else
392     {
393         DE_FATAL("Unsupported shader stage");
394     }
395 }
396 
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)397 void initPrograms(SourceCollections &programCollection, CaseDefinition caseDef)
398 {
399     if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
400     {
401         std::ostringstream src;
402 
403         src << "${VERSION_DECL}\n"
404             << "#extension GL_KHR_shader_subgroup_basic: enable\n"
405             << "layout (${LOCAL_SIZE_X}, ${LOCAL_SIZE_Y}, ${LOCAL_SIZE_Z}) in;\n"
406             << "layout(binding = 0, std430) buffer Output\n"
407             << "{\n"
408             << "  uvec4 result[];\n"
409             << "};\n"
410             << "\n"
411             << "void main (void)\n"
412             << "{\n"
413             << "  uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
414             << "  highp uint offset = globalSize.x * ((globalSize.y * "
415                "gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + "
416                "gl_GlobalInvocationID.x;\n"
417             << "  result[offset] = uvec4(gl_SubgroupSize, gl_SubgroupInvocationID, gl_NumSubgroups, gl_SubgroupID);\n"
418             << "}\n";
419 
420         programCollection.add("comp") << glu::ComputeSource(src.str());
421     }
422     else
423     {
424         {
425             const string vertexGLSL =
426                 "${VERSION_DECL}\n"
427                 "#extension GL_KHR_shader_subgroup_basic: enable\n"
428                 "layout(binding = 0, std430) buffer Output0\n"
429                 "{\n"
430                 "  uvec4 result[];\n"
431                 "} b0;\n"
432                 "\n"
433                 "void main (void)\n"
434                 "{\n"
435                 "  b0.result[gl_VertexID] = uvec4(gl_SubgroupSize, gl_SubgroupInvocationID, 0, 0);\n"
436                 "  float pixelSize = 2.0f/1024.0f;\n"
437                 "  float pixelPosition = pixelSize/2.0f - 1.0f;\n"
438                 "  gl_Position = vec4(float(gl_VertexID) * pixelSize + pixelPosition, 0.0f, 0.0f, 1.0f);\n"
439                 "  gl_PointSize = 1.0f;\n"
440                 "}\n";
441             programCollection.add("vert") << glu::VertexSource(vertexGLSL);
442         }
443 
444         {
445             const string tescGLSL =
446                 "${VERSION_DECL}\n"
447                 "#extension GL_KHR_shader_subgroup_basic: enable\n"
448                 "layout(vertices=1) out;\n"
449                 "layout(binding = 1, std430) buffer Output1\n"
450                 "{\n"
451                 "  uvec4 result[];\n"
452                 "} b1;\n"
453                 "\n"
454                 "void main (void)\n"
455                 "{\n"
456                 "  b1.result[gl_PrimitiveID] = uvec4(gl_SubgroupSize, gl_SubgroupInvocationID, 0, 0);\n"
457                 "  if (gl_InvocationID == 0)\n"
458                 "  {\n"
459                 "    gl_TessLevelOuter[0] = 1.0f;\n"
460                 "    gl_TessLevelOuter[1] = 1.0f;\n"
461                 "  }\n"
462                 "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
463                 "}\n";
464             programCollection.add("tesc") << glu::TessellationControlSource(tescGLSL);
465         }
466 
467         {
468             const string teseGLSL = "${VERSION_DECL}\n"
469                                     "#extension GL_KHR_shader_subgroup_basic: enable\n"
470                                     "layout(isolines) in;\n"
471                                     "layout(binding = 2, std430) buffer Output2\n"
472                                     "{\n"
473                                     "  uvec4 result[];\n"
474                                     "} b2;\n"
475                                     "\n"
476                                     "void main (void)\n"
477                                     "{\n"
478                                     "  b2.result[gl_PrimitiveID * 2 + int(gl_TessCoord.x + 0.5)] = "
479                                     "uvec4(gl_SubgroupSize, gl_SubgroupInvocationID, 0, 0);\n"
480                                     "  float pixelSize = 2.0f/1024.0f;\n"
481                                     "  gl_Position = gl_in[0].gl_Position + gl_TessCoord.x * pixelSize / 2.0f;\n"
482                                     "}\n";
483             programCollection.add("tese") << glu::TessellationEvaluationSource(teseGLSL);
484         }
485 
486         {
487             const string geometryGLSL =
488                 // version string is added by addGeometryShadersFromTemplate
489                 "#extension GL_KHR_shader_subgroup_basic: enable\n"
490                 "layout(${TOPOLOGY}) in;\n"
491                 "layout(points, max_vertices = 1) out;\n"
492                 "layout(binding = 3, std430) buffer Output3\n"
493                 "{\n"
494                 "  uvec4 result[];\n"
495                 "} b3;\n"
496                 "\n"
497                 "void main (void)\n"
498                 "{\n"
499                 "  b3.result[gl_PrimitiveIDIn] = uvec4(gl_SubgroupSize, gl_SubgroupInvocationID, 0, 0);\n"
500                 "  gl_Position = gl_in[0].gl_Position;\n"
501                 "  EmitVertex();\n"
502                 "  EndPrimitive();\n"
503                 "}\n";
504             addGeometryShadersFromTemplate(geometryGLSL, programCollection);
505         }
506 
507         {
508             const string fragmentGLSL = "${VERSION_DECL}\n"
509                                         "#extension GL_KHR_shader_subgroup_basic: enable\n"
510                                         "precision highp int;\n"
511                                         "layout(location = 0) out uvec4 data;\n"
512                                         "void main (void)\n"
513                                         "{\n"
514                                         "  data = uvec4(gl_SubgroupSize, gl_SubgroupInvocationID, 0, 0);\n"
515                                         "}\n";
516             programCollection.add("fragment") << glu::FragmentSource(fragmentGLSL);
517         }
518 
519         subgroups::addNoSubgroupShader(programCollection);
520     }
521 }
522 
supportedCheck(Context & context,CaseDefinition caseDef)523 void supportedCheck(Context &context, CaseDefinition caseDef)
524 {
525     DE_UNREF(caseDef);
526     if (!subgroups::isSubgroupSupported(context))
527         TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
528 }
529 
noSSBOtest(Context & context,const CaseDefinition caseDef)530 tcu::TestStatus noSSBOtest(Context &context, const CaseDefinition caseDef)
531 {
532     if (!areSubgroupOperationsSupportedForStage(context, caseDef.shaderStage))
533     {
534         if (areSubgroupOperationsRequiredForStage(caseDef.shaderStage))
535         {
536             return tcu::TestStatus::fail("Shader stage " + getShaderStageName(caseDef.shaderStage) +
537                                          " is required to support subgroup operations!");
538         }
539         else
540         {
541             TCU_THROW(NotSupportedError, "Device does not support subgroup operations for this stage");
542         }
543     }
544 
545     if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
546     {
547         if ("gl_SubgroupSize" == caseDef.varName)
548         {
549             return makeVertexFrameBufferTest(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0,
550                                              checkVertexPipelineStagesSubgroupSize);
551         }
552         else if ("gl_SubgroupInvocationID" == caseDef.varName)
553         {
554             return makeVertexFrameBufferTest(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0,
555                                              checkVertexPipelineStagesSubgroupInvocationID);
556         }
557         else
558         {
559             return tcu::TestStatus::fail(caseDef.varName + " failed (unhandled error checking case " + caseDef.varName +
560                                          ")!");
561         }
562     }
563     else if ((SHADER_STAGE_TESS_EVALUATION_BIT | SHADER_STAGE_TESS_CONTROL_BIT) & caseDef.shaderStage)
564     {
565         if ("gl_SubgroupSize" == caseDef.varName)
566         {
567             return makeTessellationEvaluationFrameBufferTest(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0,
568                                                              checkVertexPipelineStagesSubgroupSize);
569         }
570         else if ("gl_SubgroupInvocationID" == caseDef.varName)
571         {
572             return makeTessellationEvaluationFrameBufferTest(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0,
573                                                              checkVertexPipelineStagesSubgroupInvocationID);
574         }
575         else
576         {
577             return tcu::TestStatus::fail(caseDef.varName + " failed (unhandled error checking case " + caseDef.varName +
578                                          ")!");
579         }
580     }
581     else if (SHADER_STAGE_GEOMETRY_BIT & caseDef.shaderStage)
582     {
583         if ("gl_SubgroupSize" == caseDef.varName)
584         {
585             return makeGeometryFrameBufferTest(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0,
586                                                checkVertexPipelineStagesSubgroupSize);
587         }
588         else if ("gl_SubgroupInvocationID" == caseDef.varName)
589         {
590             return makeGeometryFrameBufferTest(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0,
591                                                checkVertexPipelineStagesSubgroupInvocationID);
592         }
593         else
594         {
595             return tcu::TestStatus::fail(caseDef.varName + " failed (unhandled error checking case " + caseDef.varName +
596                                          ")!");
597         }
598     }
599     else
600     {
601         TCU_THROW(InternalError, "Unhandled shader stage");
602     }
603 }
604 
test(Context & context,const CaseDefinition caseDef)605 tcu::TestStatus test(Context &context, const CaseDefinition caseDef)
606 {
607     if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
608     {
609         if (!areSubgroupOperationsSupportedForStage(context, caseDef.shaderStage))
610         {
611             return tcu::TestStatus::fail("Shader stage " + getShaderStageName(caseDef.shaderStage) +
612                                          " is required to support subgroup operations!");
613         }
614 
615         if ("gl_SubgroupSize" == caseDef.varName)
616         {
617             return makeComputeTest(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0, checkComputeSubgroupSize);
618         }
619         else if ("gl_SubgroupInvocationID" == caseDef.varName)
620         {
621             return makeComputeTest(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0, checkComputeSubgroupInvocationID);
622         }
623         else if ("gl_NumSubgroups" == caseDef.varName)
624         {
625             return makeComputeTest(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0, checkComputeNumSubgroups);
626         }
627         else if ("gl_SubgroupID" == caseDef.varName)
628         {
629             return makeComputeTest(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0, checkComputeSubgroupID);
630         }
631         else
632         {
633             return tcu::TestStatus::fail(caseDef.varName + " failed (unhandled error checking case " + caseDef.varName +
634                                          ")!");
635         }
636     }
637     else
638     {
639         int supportedStages = context.getDeqpContext().getContextInfo().getInt(GL_SUBGROUP_SUPPORTED_STAGES_KHR);
640 
641         subgroups::ShaderStageFlags stages = (subgroups::ShaderStageFlags)(caseDef.shaderStage & supportedStages);
642 
643         if (SHADER_STAGE_FRAGMENT_BIT != stages && !subgroups::isVertexSSBOSupportedForDevice(context))
644         {
645             if ((stages & SHADER_STAGE_FRAGMENT_BIT) == 0)
646                 TCU_THROW(NotSupportedError, "Device does not support vertex stage SSBO writes");
647             else
648                 stages = SHADER_STAGE_FRAGMENT_BIT;
649         }
650 
651         if ((ShaderStageFlags)0u == stages)
652             TCU_THROW(NotSupportedError, "Subgroup operations are not supported for any graphic shader");
653 
654         if ("gl_SubgroupSize" == caseDef.varName)
655         {
656             return subgroups::allStages(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0,
657                                         checkVertexPipelineStagesSubgroupSize, stages);
658         }
659         else if ("gl_SubgroupInvocationID" == caseDef.varName)
660         {
661             return subgroups::allStages(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0,
662                                         checkVertexPipelineStagesSubgroupInvocationID, stages);
663         }
664         else
665         {
666             return tcu::TestStatus::fail(caseDef.varName + " failed (unhandled error checking case " + caseDef.varName +
667                                          ")!");
668         }
669     }
670 }
671 
createSubgroupsBuiltinVarTests(deqp::Context & testCtx)672 deqp::TestCaseGroup *createSubgroupsBuiltinVarTests(deqp::Context &testCtx)
673 {
674     de::MovePtr<deqp::TestCaseGroup> graphicGroup(
675         new deqp::TestCaseGroup(testCtx, "graphics", "Subgroup builtin variable tests: graphics"));
676     de::MovePtr<deqp::TestCaseGroup> computeGroup(
677         new deqp::TestCaseGroup(testCtx, "compute", "Subgroup builtin variable tests: compute"));
678     de::MovePtr<deqp::TestCaseGroup> framebufferGroup(
679         new deqp::TestCaseGroup(testCtx, "framebuffer", "Subgroup builtin variable tests: framebuffer"));
680 
681     const char *const all_stages_vars[] = {"SubgroupSize", "SubgroupInvocationID"};
682 
683     const char *const compute_only_vars[] = {"NumSubgroups", "SubgroupID"};
684 
685     const ShaderStageFlags stages[] = {
686         SHADER_STAGE_VERTEX_BIT,
687         SHADER_STAGE_TESS_EVALUATION_BIT,
688         SHADER_STAGE_TESS_CONTROL_BIT,
689         SHADER_STAGE_GEOMETRY_BIT,
690     };
691 
692     for (int a = 0; a < DE_LENGTH_OF_ARRAY(all_stages_vars); ++a)
693     {
694         const std::string var      = all_stages_vars[a];
695         const std::string varLower = de::toLower(var);
696 
697         {
698             const CaseDefinition caseDef = {"gl_" + var, SHADER_STAGE_ALL_GRAPHICS};
699 
700             SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(graphicGroup.get(), varLower, "",
701                                                                          supportedCheck, initPrograms, test, caseDef);
702         }
703 
704         {
705             const CaseDefinition caseDef = {"gl_" + var, SHADER_STAGE_COMPUTE_BIT};
706             SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(
707                 computeGroup.get(), varLower + "_" + getShaderStageName(caseDef.shaderStage), "", supportedCheck,
708                 initPrograms, test, caseDef);
709         }
710 
711         for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
712         {
713             const CaseDefinition caseDef = {"gl_" + var, stages[stageIndex]};
714             SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(
715                 framebufferGroup.get(), varLower + "_" + getShaderStageName(caseDef.shaderStage), "", supportedCheck,
716                 initFrameBufferPrograms, noSSBOtest, caseDef);
717         }
718     }
719 
720     for (int a = 0; a < DE_LENGTH_OF_ARRAY(compute_only_vars); ++a)
721     {
722         const std::string var = compute_only_vars[a];
723 
724         const CaseDefinition caseDef = {"gl_" + var, SHADER_STAGE_COMPUTE_BIT};
725 
726         SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(computeGroup.get(), de::toLower(var), "",
727                                                                      supportedCheck, initPrograms, test, caseDef);
728     }
729 
730     de::MovePtr<deqp::TestCaseGroup> group(
731         new deqp::TestCaseGroup(testCtx, "builtin_var", "Subgroup builtin variable tests"));
732 
733     group->addChild(graphicGroup.release());
734     group->addChild(computeGroup.release());
735     group->addChild(framebufferGroup.release());
736 
737     return group.release();
738 }
739 
740 } // namespace subgroups
741 } // namespace glc
742