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