xref: /aosp_15_r20/external/deqp/external/openglcts/modules/common/subgroups/glcSubgroupsVoteTests.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 "glcSubgroupsVoteTests.hpp"
27 #include "glcSubgroupsTestsUtils.hpp"
28 
29 #include <string>
30 #include <vector>
31 #include "tcuStringTemplate.hpp"
32 
33 using namespace tcu;
34 using namespace std;
35 
36 namespace glc
37 {
38 namespace subgroups
39 {
40 
41 namespace
42 {
43 
44 enum OpType
45 {
46     OPTYPE_ALL = 0,
47     OPTYPE_ANY,
48     OPTYPE_ALLEQUAL,
49     OPTYPE_LAST
50 };
51 
checkVertexPipelineStages(std::vector<const void * > datas,uint32_t width,uint32_t)52 static bool checkVertexPipelineStages(std::vector<const void *> datas, uint32_t width, uint32_t)
53 {
54     return glc::subgroups::check(datas, width, 0x1F);
55 }
56 
checkFragmentPipelineStages(std::vector<const void * > datas,uint32_t width,uint32_t height,uint32_t)57 static bool checkFragmentPipelineStages(std::vector<const void *> datas, uint32_t width, uint32_t height, uint32_t)
58 {
59     const uint32_t *data = reinterpret_cast<const uint32_t *>(datas[0]);
60     for (uint32_t x = 0u; x < width; ++x)
61     {
62         for (uint32_t y = 0u; y < height; ++y)
63         {
64             const uint32_t ndx = (x * height + y);
65             uint32_t val       = data[ndx] & 0x1F;
66 
67             if (data[ndx] & 0x40) //Helper fragment shader invocation was executed
68             {
69                 if (val != 0x1F)
70                     return false;
71             }
72             else //Helper fragment shader invocation was not executed yet
73             {
74                 if (val != 0x1E)
75                     return false;
76             }
77         }
78     }
79     return true;
80 }
81 
checkComputeStage(std::vector<const void * > datas,const uint32_t numWorkgroups[3],const uint32_t localSize[3],uint32_t)82 static bool checkComputeStage(std::vector<const void *> datas, const uint32_t numWorkgroups[3],
83                               const uint32_t localSize[3], uint32_t)
84 {
85     return glc::subgroups::checkCompute(datas, numWorkgroups, localSize, 0x1F);
86 }
87 
getOpTypeName(int opType)88 std::string getOpTypeName(int opType)
89 {
90     switch (opType)
91     {
92     default:
93         DE_FATAL("Unsupported op type");
94         return "";
95     case OPTYPE_ALL:
96         return "subgroupAll";
97     case OPTYPE_ANY:
98         return "subgroupAny";
99     case OPTYPE_ALLEQUAL:
100         return "subgroupAllEqual";
101     }
102 }
103 
104 struct CaseDefinition
105 {
106     int opType;
107     ShaderStageFlags shaderStage;
108     Format format;
109 };
110 
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)111 void initFrameBufferPrograms(SourceCollections &programCollection, CaseDefinition caseDef)
112 {
113     const bool formatIsBoolean = FORMAT_R32_BOOL == caseDef.format || FORMAT_R32G32_BOOL == caseDef.format ||
114                                  FORMAT_R32G32B32_BOOL == caseDef.format || FORMAT_R32G32B32A32_BOOL == caseDef.format;
115 
116     if (SHADER_STAGE_FRAGMENT_BIT != caseDef.shaderStage)
117         subgroups::setFragmentShaderFrameBuffer(programCollection);
118 
119     if (SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
120     {
121         const string vertex = "${VERSION_DECL}\n"
122                               "void main (void)\n"
123                               "{\n"
124                               "  vec2 uv = vec2(float(gl_VertexID & 1), float((gl_VertexID >> 1) & 1));\n"
125                               "  gl_Position = vec4(uv * 4.0f -2.0f, 0.0f, 1.0f);\n"
126                               "  gl_PointSize = 1.0f;\n"
127                               "}\n";
128         programCollection.add("vert") << glu::VertexSource(vertex);
129     }
130     else if (SHADER_STAGE_VERTEX_BIT != caseDef.shaderStage)
131         subgroups::setVertexShaderFrameBuffer(programCollection);
132 
133     const string source =
134         (OPTYPE_ALL == caseDef.opType) ?
135             "  result = " + getOpTypeName(caseDef.opType) +
136                 "(true) ? 0x1u : 0u;\n"
137                 "  result |= " +
138                 getOpTypeName(caseDef.opType) +
139                 "(false) ? 0u : 0x1Au;\n"
140                 "  result |= 0x4u;\n" :
141         (OPTYPE_ANY == caseDef.opType) ?
142             "  result = " + getOpTypeName(caseDef.opType) +
143                 "(true) ? 0x1u : 0u;\n"
144                 "  result |= " +
145                 getOpTypeName(caseDef.opType) +
146                 "(false) ? 0u : 0x1Au;\n"
147                 "  result |= 0x4u;\n" :
148         (OPTYPE_ALLEQUAL == caseDef.opType) ?
149             "  " + subgroups::getFormatNameForGLSL(caseDef.format) +
150                 " valueEqual = " + subgroups::getFormatNameForGLSL(caseDef.format) +
151                 "(1.25 * float(data[gl_SubgroupInvocationID]) + 5.0);\n" + "  " +
152                 subgroups::getFormatNameForGLSL(caseDef.format) +
153                 " valueNoEqual = " + subgroups::getFormatNameForGLSL(caseDef.format) +
154                 (formatIsBoolean ?
155                      "(subgroupElect())\n;" :
156                      "(12.0 * float(data[gl_SubgroupInvocationID]) + float(gl_SubgroupInvocationID));\n") +
157                 "  result = " + getOpTypeName(caseDef.opType) + "(" + subgroups::getFormatNameForGLSL(caseDef.format) +
158                 "(1)) ? 0x1u : 0u;\n"
159                 "  result |= " +
160                 getOpTypeName(caseDef.opType) +
161                 "(gl_SubgroupInvocationID) ? 0u : 0x2u;\n"
162                 "  result |= " +
163                 getOpTypeName(caseDef.opType) +
164                 "(data[0]) ? 0x4u : 0u;\n"
165                 "  result |= " +
166                 getOpTypeName(caseDef.opType) +
167                 "(valueEqual) ? 0x8u : 0x0u;\n"
168                 "  result |= " +
169                 getOpTypeName(caseDef.opType) +
170                 "(valueNoEqual) ? 0x0u : 0x10u;\n"
171                 "  if (subgroupElect()) result |= 0x2u | 0x10u;\n" :
172             "";
173 
174     if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
175     {
176         std::ostringstream vertexSrc;
177         vertexSrc << "${VERSION_DECL}\n"
178                   << "#extension GL_KHR_shader_subgroup_vote: enable\n"
179                   << "layout(location = 0) out float out_color;\n"
180                   << "layout(location = 0) in highp vec4 in_position;\n"
181                   << "layout(binding = 0, std140) uniform Buffer1\n"
182                   << "{\n"
183                   << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data["
184                   << subgroups::maxSupportedSubgroupSize() << "];\n"
185                   << "};\n"
186                   << "\n"
187                   << "void main (void)\n"
188                   << "{\n"
189                   << "  uint result;\n"
190                   << source << "  out_color = float(result);\n"
191                   << "  gl_Position = in_position;\n"
192                   << "  gl_PointSize = 1.0f;\n"
193                   << "}\n";
194 
195         programCollection.add("vert") << glu::VertexSource(vertexSrc.str());
196     }
197     else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
198     {
199         std::ostringstream geometry;
200 
201         geometry << "${VERSION_DECL}\n"
202                  << "#extension GL_KHR_shader_subgroup_vote: enable\n"
203                  << "layout(points) in;\n"
204                  << "layout(points, max_vertices = 1) out;\n"
205                  << "layout(location = 0) out float out_color;\n"
206                  << "layout(binding = 0, std140) uniform Buffer1\n"
207                  << "{\n"
208                  << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data["
209                  << subgroups::maxSupportedSubgroupSize() << "];\n"
210                  << "};\n"
211                  << "\n"
212                  << "void main (void)\n"
213                  << "{\n"
214                  << "  uint result;\n"
215                  << source << "  out_color = float(result);\n"
216                  << "  gl_Position = gl_in[0].gl_Position;\n"
217                  << "  EmitVertex();\n"
218                  << "  EndPrimitive();\n"
219                  << "}\n";
220 
221         programCollection.add("geometry") << glu::GeometrySource(geometry.str());
222     }
223     else if (SHADER_STAGE_TESS_CONTROL_BIT == caseDef.shaderStage)
224     {
225         std::ostringstream controlSource;
226         controlSource << "${VERSION_DECL}\n"
227                       << "#extension GL_KHR_shader_subgroup_vote: enable\n"
228                       << "layout(vertices = 2) out;\n"
229                       << "layout(location = 0) out float out_color[];\n"
230                       << "layout(binding = 0, std140) uniform Buffer1\n"
231                       << "{\n"
232                       << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data["
233                       << subgroups::maxSupportedSubgroupSize() << "];\n"
234                       << "};\n"
235                       << "\n"
236                       << "void main (void)\n"
237                       << "{\n"
238                       << "  uint result;\n"
239                       << "  if (gl_InvocationID == 0)\n"
240                       << "  {\n"
241                       << "    gl_TessLevelOuter[0] = 1.0f;\n"
242                       << "    gl_TessLevelOuter[1] = 1.0f;\n"
243                       << "  }\n"
244                       << source << "  out_color[gl_InvocationID] = float(result);"
245                       << "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
246                       << "}\n";
247 
248         programCollection.add("tesc") << glu::TessellationControlSource(controlSource.str());
249         subgroups::setTesEvalShaderFrameBuffer(programCollection);
250     }
251     else if (SHADER_STAGE_TESS_EVALUATION_BIT == caseDef.shaderStage)
252     {
253         std::ostringstream evaluationSource;
254         evaluationSource << "${VERSION_DECL}\n"
255                          << "#extension GL_KHR_shader_subgroup_vote: enable\n"
256                          << "${TESS_EXTENSION}\n"
257                          << "layout(isolines, equal_spacing, ccw ) in;\n"
258                          << "layout(location = 0) out float out_color;\n"
259                          << "layout(binding = 0, std140) uniform Buffer1\n"
260                          << "{\n"
261                          << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data["
262                          << subgroups::maxSupportedSubgroupSize() << "];\n"
263                          << "};\n"
264                          << "\n"
265                          << "void main (void)\n"
266                          << "{\n"
267                          << "  uint result;\n"
268                          << "  highp uint offset = uint(gl_PrimitiveID) * 2u + uint(gl_TessCoord.x + 0.5);\n"
269                          << source << "  out_color = float(result);\n"
270                          << "  gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
271                          << "}\n";
272 
273         subgroups::setTesCtrlShaderFrameBuffer(programCollection);
274         programCollection.add("tese") << glu::TessellationEvaluationSource(evaluationSource.str());
275     }
276     else if (SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
277     {
278         const string sourceFragment =
279             (OPTYPE_ALL == caseDef.opType) ? "  result |= " + getOpTypeName(caseDef.opType) +
280                                                  "(!gl_HelperInvocation) ? 0x0u : 0x1u;\n"
281                                                  "  result |= " +
282                                                  getOpTypeName(caseDef.opType) +
283                                                  "(false) ? 0u : 0x1Au;\n"
284                                                  "  result |= 0x4u;\n" :
285             (OPTYPE_ANY == caseDef.opType) ? "  result |= " + getOpTypeName(caseDef.opType) +
286                                                  "(gl_HelperInvocation) ? 0x1u : 0x0u;\n"
287                                                  "  result |= " +
288                                                  getOpTypeName(caseDef.opType) +
289                                                  "(false) ? 0u : 0x1Au;\n"
290                                                  "  result |= 0x4u;\n" :
291             (OPTYPE_ALLEQUAL == caseDef.opType) ?
292                                              "  " + subgroups::getFormatNameForGLSL(caseDef.format) +
293                                                  " valueEqual = " + subgroups::getFormatNameForGLSL(caseDef.format) +
294                                                  "(1.25 * float(data[gl_SubgroupInvocationID]) + 5.0);\n" + "  " +
295                                                  subgroups::getFormatNameForGLSL(caseDef.format) +
296                                                  " valueNoEqual = " + subgroups::getFormatNameForGLSL(caseDef.format) +
297                                                  (formatIsBoolean ?
298                                                       "(subgroupElect());\n" :
299                                                       "(12.0 * float(data[gl_SubgroupInvocationID]) + gl_FragCoord.x * "
300                                                       "float(gl_SubgroupInvocationID));\n") +
301                                                  "  result |= " + getOpTypeName(caseDef.opType) + "(" +
302                                                  subgroups::getFormatNameForGLSL(caseDef.format) +
303                                                  "(1)) ? 0x10u : 0u;\n"
304                                                  "  result |= " +
305                                                  getOpTypeName(caseDef.opType) +
306                                                  "(gl_SubgroupInvocationID) ? 0u : 0x2u;\n"
307                                                  "  result |= " +
308                                                  getOpTypeName(caseDef.opType) +
309                                                  "(data[0]) ? 0x4u : 0u;\n"
310                                                  "  result |= " +
311                                                  getOpTypeName(caseDef.opType) +
312                                                  "(valueEqual) ? 0x8u : 0x0u;\n"
313                                                  "  result |= " +
314                                                  getOpTypeName(caseDef.opType) +
315                                                  "(gl_HelperInvocation) ? 0x0u : 0x1u;\n"
316                                                  "  if (subgroupElect()) result |= 0x2u | 0x10u;\n" :
317                                              "";
318 
319         std::ostringstream fragmentSource;
320         fragmentSource << "${VERSION_DECL}\n"
321                        << "#extension GL_KHR_shader_subgroup_vote: enable\n"
322                        << "precision highp float;\n"
323                        << "layout(location = 0) out uint out_color;\n"
324                        << "layout(binding = 0, std140) uniform Buffer1\n"
325                        << "{\n"
326                        << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data["
327                        << subgroups::maxSupportedSubgroupSize() << "];\n"
328                        << "};\n"
329                        << ""
330                        << "void main()\n"
331                        << "{\n"
332                        << "  uint result = 0u;\n"
333                        << "  if (dFdx(float(gl_SubgroupInvocationID) * gl_FragCoord.x * gl_FragCoord.y) - "
334                           "dFdy(float(gl_SubgroupInvocationID) * gl_FragCoord.x * gl_FragCoord.y) > 0.0f)\n"
335                        << "  {\n"
336                        << "    result |= 0x20u;\n" // to be sure that compiler doesn't remove dFdx and dFdy executions
337                        << "  }\n"
338                        << "  bool helper = subgroupAny(gl_HelperInvocation);\n"
339                        << "  if (helper)\n"
340                        << "  {\n"
341                        << "    result |= 0x40u;\n"
342                        << "  }\n"
343                        << sourceFragment << "  out_color = result;\n"
344                        << "}\n";
345 
346         programCollection.add("fragment") << glu::FragmentSource(fragmentSource.str());
347     }
348     else
349     {
350         DE_FATAL("Unsupported shader stage");
351     }
352 }
353 
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)354 void initPrograms(SourceCollections &programCollection, CaseDefinition caseDef)
355 {
356     const bool formatIsBoolean = FORMAT_R32_BOOL == caseDef.format || FORMAT_R32G32_BOOL == caseDef.format ||
357                                  FORMAT_R32G32B32_BOOL == caseDef.format || FORMAT_R32G32B32A32_BOOL == caseDef.format;
358     if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
359     {
360         std::ostringstream src;
361 
362         src << "${VERSION_DECL}\n"
363             << "#extension GL_KHR_shader_subgroup_vote: enable\n"
364             << "layout (${LOCAL_SIZE_X}, ${LOCAL_SIZE_Y}, ${LOCAL_SIZE_Z}) in;\n"
365             << "layout(binding = 0, std430) buffer Buffer1\n"
366             << "{\n"
367             << "  uint result[];\n"
368             << "};\n"
369             << "layout(binding = 1, std430) buffer Buffer2\n"
370             << "{\n"
371             << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data[];\n"
372             << "};\n"
373             << "\n"
374             << "void main (void)\n"
375             << "{\n"
376             << "  uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
377             << "  highp uint offset = globalSize.x * ((globalSize.y * "
378                "gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + "
379                "gl_GlobalInvocationID.x;\n";
380         if (OPTYPE_ALL == caseDef.opType)
381         {
382             src << "  result[offset] = " << getOpTypeName(caseDef.opType) << "(true) ? 0x1u : 0u;\n"
383                 << "  result[offset] |= " << getOpTypeName(caseDef.opType) << "(false) ? 0u : 0x1Au;\n"
384                 << "  result[offset] |= " << getOpTypeName(caseDef.opType)
385                 << "(data[gl_SubgroupInvocationID] > 0u) ? 0x4u : 0u;\n";
386         }
387         else if (OPTYPE_ANY == caseDef.opType)
388         {
389             src << "  result[offset] = " << getOpTypeName(caseDef.opType) << "(true) ? 0x1u : 0u;\n"
390                 << "  result[offset] |= " << getOpTypeName(caseDef.opType) << "(false) ? 0u : 0x1Au;\n"
391                 << "  result[offset] |= " << getOpTypeName(caseDef.opType)
392                 << "(data[gl_SubgroupInvocationID] == data[0]) ? 0x4u : 0u;\n";
393         }
394 
395         else if (OPTYPE_ALLEQUAL == caseDef.opType)
396         {
397             src << "  " << subgroups::getFormatNameForGLSL(caseDef.format)
398                 << " valueEqual = " << subgroups::getFormatNameForGLSL(caseDef.format)
399                 << "(1.25 * float(data[gl_SubgroupInvocationID]) + 5.0);\n"
400                 << "  " << subgroups::getFormatNameForGLSL(caseDef.format)
401                 << " valueNoEqual = " << subgroups::getFormatNameForGLSL(caseDef.format)
402                 << (formatIsBoolean ? "(subgroupElect());\n" :
403                                       "(12.0 * float(data[gl_SubgroupInvocationID]) + float(offset));\n")
404                 << "  result[offset] = " << getOpTypeName(caseDef.opType) << "("
405                 << subgroups::getFormatNameForGLSL(caseDef.format) << "(1)) ? 0x1u : 0x0u;\n"
406                 << "  result[offset] |= " << getOpTypeName(caseDef.opType)
407                 << "(gl_SubgroupInvocationID) ? 0x0u : 0x2u;\n"
408                 << "  result[offset] |= " << getOpTypeName(caseDef.opType) << "(data[0]) ? 0x4u : 0x0u;\n"
409                 << "  result[offset] |= " << getOpTypeName(caseDef.opType) << "(valueEqual) ? 0x8u : 0x0u;\n"
410                 << "  result[offset] |= " << getOpTypeName(caseDef.opType) << "(valueNoEqual) ? 0x0u : 0x10u;\n"
411                 << "  if (subgroupElect()) result[offset] |= 0x2u | 0x10u;\n";
412         }
413 
414         src << "}\n";
415 
416         programCollection.add("comp") << glu::ComputeSource(src.str());
417     }
418     else
419     {
420         const string source =
421             (OPTYPE_ALL == caseDef.opType) ?
422                 "  b${SSBO1}.result[offset] = " + getOpTypeName(caseDef.opType) +
423                     "(true) ? 0x1u : 0u;\n"
424                     "  b${SSBO1}.result[offset] |= " +
425                     getOpTypeName(caseDef.opType) +
426                     "(false) ? 0u : 0x1Au;\n"
427                     "  b${SSBO1}.result[offset] |= 0x4u;\n" :
428             (OPTYPE_ANY == caseDef.opType) ?
429                 "  b${SSBO1}.result[offset] = " + getOpTypeName(caseDef.opType) +
430                     "(true) ? 0x1u : 0u;\n"
431                     "  b${SSBO1}.result[offset] |= " +
432                     getOpTypeName(caseDef.opType) +
433                     "(false) ? 0u : 0x1Au;\n"
434                     "  b${SSBO1}.result[offset] |= 0x4u;\n" :
435             (OPTYPE_ALLEQUAL == caseDef.opType) ?
436                 "  " + subgroups::getFormatNameForGLSL(caseDef.format) +
437                     " valueEqual = " + subgroups::getFormatNameForGLSL(caseDef.format) +
438                     "(1.25 * float(data[gl_SubgroupInvocationID]) + 5.0);\n" + "  " +
439                     subgroups::getFormatNameForGLSL(caseDef.format) +
440                     " valueNoEqual = " + subgroups::getFormatNameForGLSL(caseDef.format) +
441                     (formatIsBoolean ?
442                          "(subgroupElect());\n" :
443                          "(12.0 * float(data[gl_SubgroupInvocationID]) + float(gl_SubgroupInvocationID));\n") +
444                     "  b${SSBO1}.result[offset] = " + getOpTypeName(caseDef.opType) + "(" +
445                     subgroups::getFormatNameForGLSL(caseDef.format) +
446                     "(1)) ? 0x1u : 0u;\n"
447                     "  b${SSBO1}.result[offset] |= " +
448                     getOpTypeName(caseDef.opType) +
449                     "(gl_SubgroupInvocationID) ? 0u : 0x2u;\n"
450                     "  b${SSBO1}.result[offset] |= " +
451                     getOpTypeName(caseDef.opType) +
452                     "(data[0]) ? 0x4u : 0u;\n"
453                     "  b${SSBO1}.result[offset] |= " +
454                     getOpTypeName(caseDef.opType) +
455                     "(valueEqual) ? 0x8u : 0x0u;\n"
456                     "  b${SSBO1}.result[offset] |= " +
457                     getOpTypeName(caseDef.opType) +
458                     "(valueNoEqual) ? 0x0u : 0x10u;\n"
459                     "  if (subgroupElect()) b${SSBO1}.result[offset] |= 0x2u | 0x10u;\n" :
460                 "";
461 
462         tcu::StringTemplate sourceTemplate(source);
463 
464         const string formatString = subgroups::getFormatNameForGLSL(caseDef.format);
465 
466         {
467             map<string, string> bufferNameMapping;
468             bufferNameMapping.insert(pair<string, string>("SSBO1", "0"));
469 
470             const string vertex =
471                 "${VERSION_DECL}\n"
472                 "#extension GL_KHR_shader_subgroup_vote: enable\n"
473                 "layout(binding = 0, std430) buffer Buffer0\n"
474                 "{\n"
475                 "  uint result[];\n"
476                 "} b0;\n"
477                 "layout(binding = 4, std430) readonly buffer Buffer4\n"
478                 "{\n"
479                 "  " +
480                 formatString +
481                 " data[];\n"
482                 "};\n"
483                 "\n"
484                 "void main (void)\n"
485                 "{\n"
486                 "  highp int offset = gl_VertexID;\n" +
487                 sourceTemplate.specialize(bufferNameMapping) +
488                 "  float pixelSize = 2.0f/1024.0f;\n"
489                 "  float pixelPosition = pixelSize/2.0f - 1.0f;\n"
490                 "  gl_Position = vec4(float(gl_VertexID) * pixelSize + pixelPosition, 0.0f, 0.0f, 1.0f);\n"
491                 "  gl_PointSize = 1.0f;\n"
492                 "}\n";
493             programCollection.add("vert") << glu::VertexSource(vertex);
494         }
495 
496         {
497             map<string, string> bufferNameMapping;
498             bufferNameMapping.insert(pair<string, string>("SSBO1", "1"));
499 
500             const string tesc = "${VERSION_DECL}\n"
501                                 "#extension GL_KHR_shader_subgroup_vote: enable\n"
502                                 "layout(vertices=1) out;\n"
503                                 "layout(binding = 1, std430) buffer Buffer1\n"
504                                 "{\n"
505                                 "  uint result[];\n"
506                                 "} b1;\n"
507                                 "layout(binding = 4, std430) readonly buffer Buffer4\n"
508                                 "{\n"
509                                 "  " +
510                                 formatString +
511                                 " data[];\n"
512                                 "};\n"
513                                 "\n"
514                                 "void main (void)\n"
515                                 "{\n"
516                                 "  highp int offset = gl_PrimitiveID;\n" +
517                                 sourceTemplate.specialize(bufferNameMapping) +
518                                 "  if (gl_InvocationID == 0)\n"
519                                 "  {\n"
520                                 "    gl_TessLevelOuter[0] = 1.0f;\n"
521                                 "    gl_TessLevelOuter[1] = 1.0f;\n"
522                                 "  }\n"
523                                 "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
524                                 "}\n";
525 
526             programCollection.add("tesc") << glu::TessellationControlSource(tesc);
527         }
528 
529         {
530             map<string, string> bufferNameMapping;
531             bufferNameMapping.insert(pair<string, string>("SSBO1", "2"));
532 
533             const string tese = "${VERSION_DECL}\n"
534                                 "#extension GL_KHR_shader_subgroup_vote: enable\n"
535                                 "layout(isolines) in;\n"
536                                 "layout(binding = 2, std430) buffer Buffer2\n"
537                                 "{\n"
538                                 "  uint result[];\n"
539                                 "} b2;\n"
540                                 "layout(binding = 4, std430) readonly buffer Buffer4\n"
541                                 "{\n"
542                                 "  " +
543                                 formatString +
544                                 " data[];\n"
545                                 "};\n"
546                                 "\n"
547                                 "void main (void)\n"
548                                 "{\n"
549                                 "  highp uint offset = uint(gl_PrimitiveID * 2) + uint(gl_TessCoord.x + 0.5);\n" +
550                                 sourceTemplate.specialize(bufferNameMapping) +
551                                 "  float pixelSize = 2.0f/1024.0f;\n"
552                                 "  gl_Position = gl_in[0].gl_Position + gl_TessCoord.x * pixelSize / 2.0f;\n"
553                                 "}\n";
554 
555             programCollection.add("tese") << glu::TessellationEvaluationSource(tese);
556         }
557 
558         {
559             map<string, string> bufferNameMapping;
560             bufferNameMapping.insert(pair<string, string>("SSBO1", "3"));
561 
562             const string geometry =
563                 // version string added by addGeometryShadersFromTemplate
564                 "#extension GL_KHR_shader_subgroup_vote: enable\n"
565                 "layout(${TOPOLOGY}) in;\n"
566                 "layout(points, max_vertices = 1) out;\n"
567                 "layout(binding = 3, std430) buffer Buffer3\n"
568                 "{\n"
569                 "  uint result[];\n"
570                 "} b3;\n"
571                 "layout(binding = 4, std430) readonly buffer Buffer4\n"
572                 "{\n"
573                 "  " +
574                 formatString +
575                 " data[];\n"
576                 "};\n"
577                 "\n"
578                 "void main (void)\n"
579                 "{\n"
580                 "  highp int offset = gl_PrimitiveIDIn;\n" +
581                 sourceTemplate.specialize(bufferNameMapping) +
582                 "  gl_Position = gl_in[0].gl_Position;\n"
583                 "  EmitVertex();\n"
584                 "  EndPrimitive();\n"
585                 "}\n";
586 
587             subgroups::addGeometryShadersFromTemplate(geometry, programCollection);
588         }
589 
590         {
591             const string sourceFragment =
592                 (OPTYPE_ALL == caseDef.opType) ?
593                     "  result = " + getOpTypeName(caseDef.opType) +
594                         "(true) ? 0x1u : 0u;\n"
595                         "  result |= " +
596                         getOpTypeName(caseDef.opType) +
597                         "(false) ? 0u : 0x1Au;\n"
598                         "  result |= 0x4u;\n" :
599                 (OPTYPE_ANY == caseDef.opType) ?
600                     "  result = " + getOpTypeName(caseDef.opType) +
601                         "(true) ? 0x1u : 0u;\n"
602                         "  result |= " +
603                         getOpTypeName(caseDef.opType) +
604                         "(false) ? 0u : 0x1Au;\n"
605                         "  result |= 0x4u;\n" :
606                 (OPTYPE_ALLEQUAL == caseDef.opType) ?
607                     "  " + subgroups::getFormatNameForGLSL(caseDef.format) +
608                         " valueEqual = " + subgroups::getFormatNameForGLSL(caseDef.format) +
609                         "(1.25 * float(data[gl_SubgroupInvocationID]) + 5.0);\n" + "  " +
610                         subgroups::getFormatNameForGLSL(caseDef.format) +
611                         " valueNoEqual = " + subgroups::getFormatNameForGLSL(caseDef.format) +
612                         (formatIsBoolean ? "(subgroupElect());\n" :
613                                            "(12.0 * float(data[gl_SubgroupInvocationID]) + gl_FragCoord.x * "
614                                            "float(gl_SubgroupInvocationID));\n") +
615                         "  result = " + getOpTypeName(caseDef.opType) + "(" +
616                         subgroups::getFormatNameForGLSL(caseDef.format) +
617                         "(1)) ? 0x1u : 0u;\n"
618                         "  result |= " +
619                         getOpTypeName(caseDef.opType) +
620                         "(gl_SubgroupInvocationID) ? 0u : 0x2u;\n"
621                         "  result |= " +
622                         getOpTypeName(caseDef.opType) +
623                         "(data[0]) ? 0x4u : 0u;\n"
624                         "  result |= " +
625                         getOpTypeName(caseDef.opType) +
626                         "(valueEqual) ? 0x8u : 0x0u;\n"
627                         "  result |= " +
628                         getOpTypeName(caseDef.opType) +
629                         "(valueNoEqual) ? 0x0u : 0x10u;\n"
630                         "  if (subgroupElect()) result |= 0x2u | 0x10u;\n" :
631                     "";
632             const string fragment = "${VERSION_DECL}\n"
633                                     "#extension GL_KHR_shader_subgroup_vote: enable\n"
634                                     "precision highp float;\n"
635                                     "layout(location = 0) out uint result;\n"
636                                     "layout(binding = 4, std430) readonly buffer Buffer4\n"
637                                     "{\n"
638                                     "  " +
639                                     formatString +
640                                     " data[];\n"
641                                     "};\n"
642                                     "void main (void)\n"
643                                     "{\n" +
644                                     sourceFragment + "}\n";
645 
646             programCollection.add("fragment") << glu::FragmentSource(fragment);
647         }
648 
649         subgroups::addNoSubgroupShader(programCollection);
650     }
651 }
652 
supportedCheck(Context & context,CaseDefinition caseDef)653 void supportedCheck(Context &context, CaseDefinition caseDef)
654 {
655     if (!subgroups::isSubgroupSupported(context))
656         TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
657 
658     if (!subgroups::isSubgroupFeatureSupportedForDevice(context, subgroups::SUBGROUP_FEATURE_VOTE_BIT))
659     {
660         TCU_THROW(NotSupportedError, "Device does not support subgroup vote operations");
661     }
662 
663     if (subgroups::isDoubleFormat(caseDef.format) && !subgroups::isDoubleSupportedForDevice(context))
664     {
665         TCU_THROW(NotSupportedError, "Device does not support subgroup double operations");
666     }
667 }
668 
noSSBOtest(Context & context,const CaseDefinition caseDef)669 tcu::TestStatus noSSBOtest(Context &context, const CaseDefinition caseDef)
670 {
671     if (!subgroups::areSubgroupOperationsSupportedForStage(context, caseDef.shaderStage))
672     {
673         if (subgroups::areSubgroupOperationsRequiredForStage(caseDef.shaderStage))
674         {
675             return tcu::TestStatus::fail("Shader stage " + subgroups::getShaderStageName(caseDef.shaderStage) +
676                                          " is required to support subgroup operations!");
677         }
678         else
679         {
680             TCU_THROW(NotSupportedError, "Device does not support subgroup operations for this stage");
681         }
682     }
683 
684     subgroups::SSBOData inputData;
685     inputData.format         = caseDef.format;
686     inputData.layout         = subgroups::SSBOData::LayoutStd140;
687     inputData.numElements    = subgroups::maxSupportedSubgroupSize();
688     inputData.initializeType = OPTYPE_ALLEQUAL == caseDef.opType ? subgroups::SSBOData::InitializeZero :
689                                                                    subgroups::SSBOData::InitializeNonZero;
690 
691     if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
692         return subgroups::makeVertexFrameBufferTest(context, FORMAT_R32_UINT, &inputData, 1, checkVertexPipelineStages);
693     else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
694         return subgroups::makeGeometryFrameBufferTest(context, FORMAT_R32_UINT, &inputData, 1,
695                                                       checkVertexPipelineStages);
696     else if (SHADER_STAGE_TESS_CONTROL_BIT == caseDef.shaderStage)
697         return subgroups::makeTessellationEvaluationFrameBufferTest(
698             context, FORMAT_R32_UINT, &inputData, 1, checkVertexPipelineStages, SHADER_STAGE_TESS_CONTROL_BIT);
699     else if (SHADER_STAGE_TESS_EVALUATION_BIT == caseDef.shaderStage)
700         return subgroups::makeTessellationEvaluationFrameBufferTest(
701             context, FORMAT_R32_UINT, &inputData, 1, checkVertexPipelineStages, SHADER_STAGE_TESS_EVALUATION_BIT);
702     else if (SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
703         return subgroups::makeFragmentFrameBufferTest(context, FORMAT_R32_UINT, &inputData, 1,
704                                                       checkFragmentPipelineStages);
705     else
706         TCU_THROW(InternalError, "Unhandled shader stage");
707 }
708 
test(Context & context,const CaseDefinition caseDef)709 tcu::TestStatus test(Context &context, const CaseDefinition caseDef)
710 {
711     if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
712     {
713         if (!subgroups::areSubgroupOperationsSupportedForStage(context, caseDef.shaderStage))
714         {
715             return tcu::TestStatus::fail("Shader stage " + subgroups::getShaderStageName(caseDef.shaderStage) +
716                                          " is required to support subgroup operations!");
717         }
718 
719         subgroups::SSBOData inputData;
720         inputData.format         = caseDef.format;
721         inputData.layout         = subgroups::SSBOData::LayoutStd430;
722         inputData.numElements    = subgroups::maxSupportedSubgroupSize();
723         inputData.initializeType = OPTYPE_ALLEQUAL == caseDef.opType ? subgroups::SSBOData::InitializeZero :
724                                                                        subgroups::SSBOData::InitializeNonZero;
725         inputData.binding        = 1u;
726 
727         return subgroups::makeComputeTest(context, FORMAT_R32_UINT, &inputData, 1, checkComputeStage);
728     }
729     else
730     {
731         int supportedStages = context.getDeqpContext().getContextInfo().getInt(GL_SUBGROUP_SUPPORTED_STAGES_KHR);
732 
733         ShaderStageFlags stages = (ShaderStageFlags)(caseDef.shaderStage & supportedStages);
734 
735         if (SHADER_STAGE_FRAGMENT_BIT != stages && !subgroups::isVertexSSBOSupportedForDevice(context))
736         {
737             if ((stages & SHADER_STAGE_FRAGMENT_BIT) == 0)
738                 TCU_THROW(NotSupportedError, "Device does not support vertex stage SSBO writes");
739             else
740                 stages = SHADER_STAGE_FRAGMENT_BIT;
741         }
742 
743         if ((ShaderStageFlags)0u == stages)
744             TCU_THROW(NotSupportedError, "Subgroup operations are not supported for any graphic shader");
745 
746         subgroups::SSBOData inputData;
747         inputData.format         = caseDef.format;
748         inputData.layout         = subgroups::SSBOData::LayoutStd430;
749         inputData.numElements    = subgroups::maxSupportedSubgroupSize();
750         inputData.initializeType = OPTYPE_ALLEQUAL == caseDef.opType ? subgroups::SSBOData::InitializeZero :
751                                                                        subgroups::SSBOData::InitializeNonZero;
752         inputData.binding        = 4u;
753         inputData.stages         = stages;
754 
755         return subgroups::allStages(context, FORMAT_R32_UINT, &inputData, 1, checkVertexPipelineStages, stages);
756     }
757 }
758 
759 } // namespace
760 
createSubgroupsVoteTests(deqp::Context & testCtx)761 deqp::TestCaseGroup *createSubgroupsVoteTests(deqp::Context &testCtx)
762 {
763     de::MovePtr<deqp::TestCaseGroup> graphicGroup(
764         new deqp::TestCaseGroup(testCtx, "graphics", "Subgroup arithmetic category tests: graphics"));
765     de::MovePtr<deqp::TestCaseGroup> computeGroup(
766         new deqp::TestCaseGroup(testCtx, "compute", "Subgroup arithmetic category tests: compute"));
767     de::MovePtr<deqp::TestCaseGroup> framebufferGroup(
768         new deqp::TestCaseGroup(testCtx, "framebuffer", "Subgroup arithmetic category tests: framebuffer"));
769 
770     de::MovePtr<deqp::TestCaseGroup> fragHelperGroup(new deqp::TestCaseGroup(
771         testCtx, "frag_helper", "Subgroup arithmetic category tests: fragment helper invocation"));
772 
773     const ShaderStageFlags stages[] = {
774         SHADER_STAGE_VERTEX_BIT,
775         SHADER_STAGE_TESS_EVALUATION_BIT,
776         SHADER_STAGE_TESS_CONTROL_BIT,
777         SHADER_STAGE_GEOMETRY_BIT,
778     };
779 
780     const Format formats[] = {
781         FORMAT_R32_SINT,   FORMAT_R32G32_SINT,   FORMAT_R32G32B32_SINT,   FORMAT_R32G32B32A32_SINT,
782         FORMAT_R32_UINT,   FORMAT_R32G32_UINT,   FORMAT_R32G32B32_UINT,   FORMAT_R32G32B32A32_UINT,
783         FORMAT_R32_SFLOAT, FORMAT_R32G32_SFLOAT, FORMAT_R32G32B32_SFLOAT, FORMAT_R32G32B32A32_SFLOAT,
784         FORMAT_R64_SFLOAT, FORMAT_R64G64_SFLOAT, FORMAT_R64G64B64_SFLOAT, FORMAT_R64G64B64A64_SFLOAT,
785         FORMAT_R32_BOOL,   FORMAT_R32G32_BOOL,   FORMAT_R32G32B32_BOOL,   FORMAT_R32G32B32A32_BOOL,
786     };
787 
788     for (int formatIndex = 0; formatIndex < DE_LENGTH_OF_ARRAY(formats); ++formatIndex)
789     {
790         const Format format = formats[formatIndex];
791 
792         for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
793         {
794             // Skip the typed tests for all but subgroupAllEqual()
795             if ((FORMAT_R32_UINT != format) && (OPTYPE_ALLEQUAL != opTypeIndex))
796             {
797                 continue;
798             }
799 
800             const std::string op = de::toLower(getOpTypeName(opTypeIndex));
801 
802             {
803                 const CaseDefinition caseDef = {opTypeIndex, SHADER_STAGE_COMPUTE_BIT, format};
804                 SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(
805                     computeGroup.get(), op + "_" + subgroups::getFormatNameForGLSL(format), "", supportedCheck,
806                     initPrograms, test, caseDef);
807             }
808 
809             {
810                 const CaseDefinition caseDef = {opTypeIndex, SHADER_STAGE_ALL_GRAPHICS, format};
811                 SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(
812                     graphicGroup.get(), op + "_" + subgroups::getFormatNameForGLSL(format), "", supportedCheck,
813                     initPrograms, test, caseDef);
814             }
815 
816             for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
817             {
818                 const CaseDefinition caseDef = {opTypeIndex, stages[stageIndex], format};
819                 SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(
820                     framebufferGroup.get(),
821                     op + "_" + subgroups::getFormatNameForGLSL(format) + "_" + getShaderStageName(caseDef.shaderStage),
822                     "", supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
823             }
824 
825             const CaseDefinition caseDef = {opTypeIndex, SHADER_STAGE_FRAGMENT_BIT, format};
826             SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(
827                 fragHelperGroup.get(),
828                 op + "_" + subgroups::getFormatNameForGLSL(format) + "_" + getShaderStageName(caseDef.shaderStage), "",
829                 supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
830         }
831     }
832 
833     de::MovePtr<deqp::TestCaseGroup> group(new deqp::TestCaseGroup(testCtx, "vote", "Subgroup vote category tests"));
834 
835     group->addChild(graphicGroup.release());
836     group->addChild(computeGroup.release());
837     group->addChild(framebufferGroup.release());
838     group->addChild(fragHelperGroup.release());
839 
840     return group.release();
841 }
842 
843 } // namespace subgroups
844 } // namespace glc
845