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