porting changes for OpenGL Subgroup tests
[platform/upstream/VK-GL-CTS.git] / external / openglcts / modules / common / subgroups / glcSubgroupsBuiltinMaskVarTests.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 "glcSubgroupsBuiltinMaskVarTests.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
40 static bool checkVertexPipelineStages(std::vector<const void*> datas,
41                                                                           deUint32 width, deUint32)
42 {
43         return check(datas, width, 1);
44 }
45
46 static bool checkComputeStage(std::vector<const void*> datas,
47                                                  const deUint32 numWorkgroups[3], const deUint32 localSize[3],
48                                                  deUint32)
49 {
50         return checkCompute(datas, numWorkgroups, localSize, 1);
51 }
52
53 namespace
54 {
55 struct CaseDefinition
56 {
57         std::string                     varName;
58         ShaderStageFlags        shaderStage;
59 };
60 }
61
62 std::string subgroupMask (const CaseDefinition& caseDef)
63 {
64         std::ostringstream bdy;
65
66         bdy << "  uint tempResult = 0x1;\n"
67                 << "  uint bit        = 0x1;\n"
68                 << "  uint bitCount   = 0x0;\n"
69                 << "  uvec4 mask = subgroupBallot(true);\n"
70                 << "  const uvec4 var = " << caseDef.varName << ";\n"
71                 << "  for (uint i = 0; i < gl_SubgroupSize; i++)\n"
72                 << "  {\n";
73
74         if ("gl_SubgroupEqMask" == caseDef.varName)
75         {
76                 bdy << "    if ((i == gl_SubgroupInvocationID) ^^ subgroupBallotBitExtract(var, i))\n"
77                         << "    {\n"
78                         << "      tempResult = 0;\n"
79                         << "    }\n";
80         }
81         else if ("gl_SubgroupGeMask" == caseDef.varName)
82         {
83                 bdy << "    if ((i >= gl_SubgroupInvocationID) ^^ subgroupBallotBitExtract(var, i))\n"
84                         << "    {\n"
85                         << "      tempResult = 0;\n"
86                         << "    }\n";
87         }
88         else if ("gl_SubgroupGtMask" == caseDef.varName)
89         {
90                 bdy << "    if ((i > gl_SubgroupInvocationID) ^^ subgroupBallotBitExtract(var, i))\n"
91                         << "    {\n"
92                         << "      tempResult = 0;\n"
93                         << "    }\n";
94         }
95         else if ("gl_SubgroupLeMask" == caseDef.varName)
96         {
97                 bdy << "    if ((i <= gl_SubgroupInvocationID) ^^ subgroupBallotBitExtract(var, i))\n"
98                         << "    {\n"
99                         << "      tempResult = 0;\n"
100                         << "    }\n";
101         }
102         else if ("gl_SubgroupLtMask" == caseDef.varName)
103         {
104                 bdy << "    if ((i < gl_SubgroupInvocationID) ^^ subgroupBallotBitExtract(var, i))\n"
105                         << "    {\n"
106                         << "      tempResult = 0;\n"
107                         << "    }\n";
108         }
109
110         bdy << "  }\n"
111                 << "  for (uint i = 0; i < 32; i++)\n"
112                 << "  {\n"
113                 << "    if ((var.x & bit) > 0)\n"
114                 << "    {\n"
115                 << "      bitCount++;\n"
116                 << "    }\n"
117                 << "    if ((var.y & bit) > 0)\n"
118                 << "    {\n"
119                 << "      bitCount++;\n"
120                 << "    }\n"
121                 << "    if ((var.z & bit) > 0)\n"
122                 << "    {\n"
123                 << "      bitCount++;\n"
124                 << "    }\n"
125                 << "    if ((var.w & bit) > 0)\n"
126                 << "    {\n"
127                 << "      bitCount++;\n"
128                 << "    }\n"
129                 << "    bit = bit<<1;\n"
130                 << "  }\n"
131                 << "  if (subgroupBallotBitCount(var) != bitCount)\n"
132                 << "  {\n"
133                 << "    tempResult = 0;\n"
134                 << "  }\n";
135         return bdy.str();
136 }
137
138 void initFrameBufferPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
139 {
140         subgroups::setFragmentShaderFrameBuffer(programCollection);
141
142         if (SHADER_STAGE_VERTEX_BIT != caseDef.shaderStage)
143                 subgroups::setVertexShaderFrameBuffer(programCollection);
144
145         if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
146         {
147                 const string bdy = subgroupMask(caseDef);
148                 const string vertexGLSL =
149                         "#version 450\n"
150                         "#extension GL_KHR_shader_subgroup_ballot: enable\n"
151                         "layout(location = 0) out float out_color;\n"
152                         "layout(location = 0) in highp vec4 in_position;\n"
153                         "\n"
154                         "void main (void)\n"
155                         "{\n"
156                         + bdy +
157                         "  out_color = float(tempResult);\n"
158                         "  gl_Position = in_position;\n"
159                         "  gl_PointSize = 1.0f;\n"
160                         "}\n";
161                 programCollection.add("vert") << glu::VertexSource(vertexGLSL);
162         }
163         else if (SHADER_STAGE_TESS_EVALUATION_BIT == caseDef.shaderStage)
164         {
165                 const string bdy = subgroupMask(caseDef);
166                 const string  evaluationSourceGLSL =
167                         "#version 450\n"
168                         "#extension GL_KHR_shader_subgroup_ballot: enable\n"
169                         "#extension GL_EXT_tessellation_shader : require\n"
170                         "layout(isolines, equal_spacing, ccw ) in;\n"
171                         "layout(location = 0) out float out_color;\n"
172                         "\n"
173                         "void main (void)\n"
174                         "{\n"
175                         + bdy +
176                         "  out_color = float(tempResult);\n"
177                         "  gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
178                         "}\n";
179                 programCollection.add("tese") << glu::TessellationEvaluationSource(evaluationSourceGLSL);
180                 subgroups::setTesCtrlShaderFrameBuffer(programCollection);
181         }
182         else if (SHADER_STAGE_TESS_CONTROL_BIT == caseDef.shaderStage)
183         {
184                 const string bdy = subgroupMask(caseDef);
185                 const string  controlSourceGLSL =
186                         "#version 450\n"
187                         "#extension GL_EXT_tessellation_shader : require\n"
188                         "#extension GL_KHR_shader_subgroup_ballot: enable\n"
189                         "layout(vertices = 2) out;\n"
190                         "layout(location = 0) out float out_color[];\n"
191                         "void main (void)\n"
192                         "{\n"
193                         "  if (gl_InvocationID == 0)\n"
194                         "  {\n"
195                         "    gl_TessLevelOuter[0] = 1.0f;\n"
196                         "    gl_TessLevelOuter[1] = 1.0f;\n"
197                         "  }\n"
198                         + bdy +
199                         "  out_color[gl_InvocationID] = float(tempResult);\n"
200                         "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
201                         "}\n";
202                 programCollection.add("tesc") << glu::TessellationControlSource(controlSourceGLSL);
203                 subgroups::setTesEvalShaderFrameBuffer(programCollection);
204         }
205         else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
206         {
207                 const string bdy = subgroupMask(caseDef);
208                 const string geometryGLSL =
209                         "#version 450\n"
210                         "#extension GL_KHR_shader_subgroup_ballot: enable\n"
211                         "layout(points) in;\n"
212                         "layout(points, max_vertices = 1) out;\n"
213                         "layout(location = 0) out float out_color;\n"
214                         "\n"
215                         "void main (void)\n"
216                         "{\n"
217                         + bdy +
218                         "  out_color = float(tempResult);\n"
219                         "  gl_Position = gl_in[0].gl_Position;\n"
220                         "  EmitVertex();\n"
221                         "  EndPrimitive();\n"
222                         "}\n";
223                 programCollection.add("geometry") << glu::GeometrySource(geometryGLSL);
224         }
225         else
226         {
227                 DE_FATAL("Unsupported shader stage");
228         }
229 }
230
231
232 void initPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
233 {
234         const string bdy = subgroupMask(caseDef);
235
236         if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
237         {
238                 std::ostringstream src;
239
240                 src << "#version 450\n"
241                         << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
242                         << "layout (${LOCAL_SIZE_X}, ${LOCAL_SIZE_Y}, ${LOCAL_SIZE_Z}) in;\n"
243                         << "layout(binding = 0, std430) buffer Output\n"
244                         << "{\n"
245                         << "  uint result[];\n"
246                         << "};\n"
247                         << "\n"
248                         << "void main (void)\n"
249                         << "{\n"
250                         << "  uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
251                         << "  highp uint offset = globalSize.x * ((globalSize.y * "
252                         "gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + "
253                         "gl_GlobalInvocationID.x;\n"
254                         << bdy
255                         << "  result[offset] = tempResult;\n"
256                         << "}\n";
257
258                 programCollection.add("comp") << glu::ComputeSource(src.str());
259         }
260         else
261         {
262                 {
263                         const string vertex =
264                                 "#version 450\n"
265                                 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
266                                 "layout(binding = 0, std430) buffer Output0\n"
267                                 "{\n"
268                                 "  uint result[];\n"
269                                 "} b0;\n"
270                                 "\n"
271                                 "void main (void)\n"
272                                 "{\n"
273                                 + bdy +
274                                 "  b0.result[gl_VertexID] = tempResult;\n"
275                                 "  float pixelSize = 2.0f/1024.0f;\n"
276                                 "  float pixelPosition = pixelSize/2.0f - 1.0f;\n"
277                                 "  gl_Position = vec4(float(gl_VertexID) * pixelSize + pixelPosition, 0.0f, 0.0f, 1.0f);\n"
278                                 "  gl_PointSize = 1.0f;\n"
279                                 "}\n";
280                         programCollection.add("vert") << glu::VertexSource(vertex);
281                 }
282
283                 {
284                         const string tesc =
285                                 "#version 450\n"
286                                 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
287                                 "layout(vertices=1) out;\n"
288                                 "layout(binding = 1, std430) buffer Output1\n"
289                                 "{\n"
290                                 "  uint result[];\n"
291                                 "} b1;\n"
292                                 "\n"
293                                 "void main (void)\n"
294                                 "{\n"
295                                 + bdy +
296                                 "  b1.result[gl_PrimitiveID] = tempResult;\n"
297                                 "  if (gl_InvocationID == 0)\n"
298                                 "  {\n"
299                                 "    gl_TessLevelOuter[0] = 1.0f;\n"
300                                 "    gl_TessLevelOuter[1] = 1.0f;\n"
301                                 "  }\n"
302                                 "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
303                                 "}\n";
304                         programCollection.add("tesc") << glu::TessellationControlSource(tesc);
305                 }
306
307                 {
308                         const string tese =
309                                 "#version 450\n"
310                                 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
311                                 "layout(isolines) in;\n"
312                                 "layout(binding = 2, std430) buffer Output2\n"
313                                 "{\n"
314                                 "  uint result[];\n"
315                                 "} b2;\n"
316                                 "\n"
317                                 "void main (void)\n"
318                                 "{\n"
319                                 + bdy +
320                                 "  b2.result[gl_PrimitiveID * 2 + uint(gl_TessCoord.x + 0.5)] = tempResult;\n"
321                                 "  float pixelSize = 2.0f/1024.0f;\n"
322                                 "  gl_Position = gl_in[0].gl_Position + gl_TessCoord.x * pixelSize / 2.0f;\n"
323                                 "}\n";
324
325                         programCollection.add("tese") << glu::TessellationEvaluationSource(tese);
326                 }
327
328                 {
329                         const string geometry =
330                                 "#version 450\n"
331                                 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
332                                 "layout(${TOPOLOGY}) in;\n"
333                                 "layout(points, max_vertices = 1) out;\n"
334                                 "layout(binding = 3, std430) buffer Output3\n"
335                                 "{\n"
336                                 "  uint result[];\n"
337                                 "} b3;\n"
338                                 "\n"
339                                 "void main (void)\n"
340                                 "{\n"
341                                 + bdy +
342                                 "  b3.result[gl_PrimitiveIDIn] = tempResult;\n"
343                                 "  gl_Position = gl_in[0].gl_Position;\n"
344                                 "  EmitVertex();\n"
345                                 "  EndPrimitive();\n"
346                                 "}\n";
347
348                         subgroups::addGeometryShadersFromTemplate(geometry, programCollection);
349                 }
350
351                 {
352                         const string fragment =
353                                 "#version 450\n"
354                                 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
355                                 "layout(location = 0) out uint result;\n"
356                                 "void main (void)\n"
357                                 "{\n"
358                                 + bdy +
359                                 "  result = tempResult;\n"
360                                 "}\n";
361
362                         programCollection.add("fragment") << glu::FragmentSource(fragment);
363                 }
364
365                 subgroups::addNoSubgroupShader(programCollection);
366         }
367 }
368
369 void supportedCheck (Context& context, CaseDefinition caseDef)
370 {
371         DE_UNREF(caseDef);
372         if (!subgroups::isSubgroupSupported(context))
373                 TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
374 }
375
376 tcu::TestStatus noSSBOtest(Context& context, const CaseDefinition caseDef)
377 {
378         if (!areSubgroupOperationsSupportedForStage(
379                                 context, caseDef.shaderStage))
380         {
381                 if (areSubgroupOperationsRequiredForStage(caseDef.shaderStage))
382                 {
383                         return tcu::TestStatus::fail(
384                                            "Shader stage " + getShaderStageName(caseDef.shaderStage) +
385                                            " is required to support subgroup operations!");
386                 }
387                 else
388                 {
389                         TCU_THROW(NotSupportedError, "Device does not support subgroup operations for this stage");
390                 }
391         }
392
393         if (!subgroups::isSubgroupFeatureSupportedForDevice(context, SUBGROUP_FEATURE_BALLOT_BIT))
394         {
395                 TCU_THROW(NotSupportedError, "Device does not support subgroup ballot operations");
396         }
397
398         if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
399                 return makeVertexFrameBufferTest(context, FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages);
400         else if ((SHADER_STAGE_TESS_EVALUATION_BIT | SHADER_STAGE_TESS_CONTROL_BIT) & caseDef.shaderStage )
401                 return makeTessellationEvaluationFrameBufferTest(context, FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages);
402
403         return makeGeometryFrameBufferTest(context, FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages);
404 }
405
406
407 tcu::TestStatus test(Context& context, const CaseDefinition caseDef)
408 {
409         if (!subgroups::isSubgroupFeatureSupportedForDevice(context, SUBGROUP_FEATURE_BALLOT_BIT))
410         {
411                 TCU_THROW(NotSupportedError, "Device does not support subgroup ballot operations");
412         }
413
414         if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
415         {
416                 if (!areSubgroupOperationsSupportedForStage(context, caseDef.shaderStage))
417                 {
418                                 return tcu::TestStatus::fail(
419                                                    "Shader stage " + getShaderStageName(caseDef.shaderStage) +
420                                                    " is required to support subgroup operations!");
421                 }
422                 return makeComputeTest(context, FORMAT_R32_UINT, DE_NULL, 0, checkComputeStage);
423         }
424         else
425         {
426                 int supportedStages = context.getDeqpContext().getContextInfo().getInt(GL_SUBGROUP_SUPPORTED_STAGES_KHR);
427
428                 subgroups::ShaderStageFlags stages = (subgroups::ShaderStageFlags)(caseDef.shaderStage & supportedStages);
429
430                 if ( SHADER_STAGE_FRAGMENT_BIT != stages && !subgroups::isVertexSSBOSupportedForDevice(context))
431                 {
432                         if ( (stages & SHADER_STAGE_FRAGMENT_BIT) == 0)
433                                 TCU_THROW(NotSupportedError, "Device does not support vertex stage SSBO writes");
434                         else
435                                 stages = SHADER_STAGE_FRAGMENT_BIT;
436                 }
437
438                 if ((ShaderStageFlags)0u == stages)
439                         TCU_THROW(NotSupportedError, "Subgroup operations are not supported for any graphic shader");
440
441                 return subgroups::allStages(context, FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages, stages);
442         }
443 }
444
445 deqp::TestCaseGroup* createSubgroupsBuiltinMaskVarTests(deqp::Context& testCtx)
446 {
447         de::MovePtr<deqp::TestCaseGroup> graphicGroup(new deqp::TestCaseGroup(
448                 testCtx, "graphics", "Subgroup builtin mask category    tests: graphics"));
449         de::MovePtr<deqp::TestCaseGroup> computeGroup(new deqp::TestCaseGroup(
450                 testCtx, "compute", "Subgroup builtin mask category tests: compute"));
451         de::MovePtr<deqp::TestCaseGroup> framebufferGroup(new deqp::TestCaseGroup(
452                 testCtx, "framebuffer", "Subgroup builtin mask category tests: framebuffer"));
453
454         const char* const all_stages_vars[] =
455         {
456                 "SubgroupEqMask",
457                 "SubgroupGeMask",
458                 "SubgroupGtMask",
459                 "SubgroupLeMask",
460                 "SubgroupLtMask",
461         };
462
463         const subgroups::ShaderStageFlags stages[] =
464         {
465                 SHADER_STAGE_VERTEX_BIT,
466                 SHADER_STAGE_TESS_EVALUATION_BIT,
467                 SHADER_STAGE_TESS_CONTROL_BIT,
468                 SHADER_STAGE_GEOMETRY_BIT,
469         };
470
471
472         for (int a = 0; a < DE_LENGTH_OF_ARRAY(all_stages_vars); ++a)
473         {
474                 const std::string var = all_stages_vars[a];
475                 const std::string varLower = de::toLower(var);
476
477                 {
478                         const CaseDefinition caseDef = {"gl_" + var, SHADER_STAGE_ALL_GRAPHICS};
479                         SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(graphicGroup.get(),
480                                                                                 varLower, "",
481                                                                                 supportedCheck, initPrograms, test, caseDef);
482                 }
483
484                 {
485                         const CaseDefinition caseDef = {"gl_" + var, SHADER_STAGE_COMPUTE_BIT};
486                         SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(computeGroup.get(),
487                                                                                 varLower, "",
488                                                                                 supportedCheck, initPrograms, test, caseDef);
489                 }
490
491                 for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
492                 {
493                         const CaseDefinition caseDef = {"gl_" + var, stages[stageIndex]};
494                         SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(framebufferGroup.get(),
495                                                 varLower + "_" +
496                                                 getShaderStageName(caseDef.shaderStage), "",
497                                                 supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
498                 }
499         }
500
501         de::MovePtr<deqp::TestCaseGroup> group(new deqp::TestCaseGroup(
502                 testCtx, "builtin_mask_var", "Subgroup builtin mask variable tests"));
503
504         group->addChild(graphicGroup.release());
505         group->addChild(computeGroup.release());
506         group->addChild(framebufferGroup.release());
507
508         return group.release();
509 }
510 } // subgroups
511 } // glc