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