1 /*------------------------------------------------------------------------
2 * OpenGL Conformance Tests
3 * ------------------------
5 * Copyright (c) 2017-2019 The Khronos Group Inc.
6 * Copyright (c) 2017 Codeplay Software Ltd.
7 * Copyright (c) 2019 NVIDIA Corporation.
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 * \brief Subgroups Tests
24 */ /*--------------------------------------------------------------------*/
26 #include "glcSubgroupsBuiltinVarTests.hpp"
27 #include "glcSubgroupsTestsUtils.hpp"
40 bool checkVertexPipelineStagesSubgroupSize(std::vector<const void*> datas,
41 deUint32 width, deUint32 subgroupSize)
43 const deUint32* data =
44 reinterpret_cast<const deUint32*>(datas[0]);
45 for (deUint32 x = 0; x < width; ++x)
47 deUint32 val = data[x * 4];
49 if (subgroupSize != val)
56 bool checkVertexPipelineStagesSubgroupInvocationID(std::vector<const void*> datas,
57 deUint32 width, deUint32 subgroupSize)
59 const deUint32* data =
60 reinterpret_cast<const deUint32*>(datas[0]);
61 vector<deUint32> subgroupInvocationHits(subgroupSize, 0);
63 for (deUint32 x = 0; x < width; ++x)
65 deUint32 subgroupInvocationID = data[(x * 4) + 1];
67 if (subgroupInvocationID >= subgroupSize)
69 subgroupInvocationHits[subgroupInvocationID]++;
72 const deUint32 totalSize = width;
74 deUint32 totalInvocationsRun = 0;
75 for (deUint32 i = 0; i < subgroupSize; ++i)
77 totalInvocationsRun += subgroupInvocationHits[i];
80 if (totalInvocationsRun != totalSize)
86 static bool checkComputeSubgroupSize(std::vector<const void*> datas,
87 const deUint32 numWorkgroups[3], const deUint32 localSize[3],
88 deUint32 subgroupSize)
90 const deUint32* data = reinterpret_cast<const deUint32*>(datas[0]);
92 for (deUint32 nX = 0; nX < numWorkgroups[0]; ++nX)
94 for (deUint32 nY = 0; nY < numWorkgroups[1]; ++nY)
96 for (deUint32 nZ = 0; nZ < numWorkgroups[2]; ++nZ)
98 for (deUint32 lX = 0; lX < localSize[0]; ++lX)
100 for (deUint32 lY = 0; lY < localSize[1]; ++lY)
102 for (deUint32 lZ = 0; lZ < localSize[2];
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;
112 const deUint32 globalSizeX =
113 numWorkgroups[0] * localSize[0];
114 const deUint32 globalSizeY =
115 numWorkgroups[1] * localSize[1];
117 const deUint32 offset =
124 if (subgroupSize != data[offset * 4])
136 static bool checkComputeSubgroupInvocationID(std::vector<const void*> datas,
137 const deUint32 numWorkgroups[3], const deUint32 localSize[3],
138 deUint32 subgroupSize)
140 const deUint32* data = reinterpret_cast<const deUint32*>(datas[0]);
142 for (deUint32 nX = 0; nX < numWorkgroups[0]; ++nX)
144 for (deUint32 nY = 0; nY < numWorkgroups[1]; ++nY)
146 for (deUint32 nZ = 0; nZ < numWorkgroups[2]; ++nZ)
148 const deUint32 totalLocalSize =
149 localSize[0] * localSize[1] * localSize[2];
150 vector<deUint32> subgroupInvocationHits(subgroupSize, 0);
152 for (deUint32 lX = 0; lX < localSize[0]; ++lX)
154 for (deUint32 lY = 0; lY < localSize[1]; ++lY)
156 for (deUint32 lZ = 0; lZ < localSize[2];
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;
166 const deUint32 globalSizeX =
167 numWorkgroups[0] * localSize[0];
168 const deUint32 globalSizeY =
169 numWorkgroups[1] * localSize[1];
171 const deUint32 offset =
178 deUint32 subgroupInvocationID = data[(offset * 4) + 1];
180 if (subgroupInvocationID >= subgroupSize)
183 subgroupInvocationHits[subgroupInvocationID]++;
188 deUint32 totalInvocationsRun = 0;
189 for (deUint32 i = 0; i < subgroupSize; ++i)
191 totalInvocationsRun += subgroupInvocationHits[i];
194 if (totalInvocationsRun != totalLocalSize)
203 static bool checkComputeNumSubgroups (std::vector<const void*> datas,
204 const deUint32 numWorkgroups[3],
205 const deUint32 localSize[3],
208 const deUint32* data = reinterpret_cast<const deUint32*>(datas[0]);
210 for (deUint32 nX = 0; nX < numWorkgroups[0]; ++nX)
212 for (deUint32 nY = 0; nY < numWorkgroups[1]; ++nY)
214 for (deUint32 nZ = 0; nZ < numWorkgroups[2]; ++nZ)
216 const deUint32 totalLocalSize =
217 localSize[0] * localSize[1] * localSize[2];
219 for (deUint32 lX = 0; lX < localSize[0]; ++lX)
221 for (deUint32 lY = 0; lY < localSize[1]; ++lY)
223 for (deUint32 lZ = 0; lZ < localSize[2];
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;
233 const deUint32 globalSizeX =
234 numWorkgroups[0] * localSize[0];
235 const deUint32 globalSizeY =
236 numWorkgroups[1] * localSize[1];
238 const deUint32 offset =
245 deUint32 numSubgroups = data[(offset * 4) + 2];
247 if (numSubgroups > totalLocalSize)
259 static bool checkComputeSubgroupID (std::vector<const void*> datas,
260 const deUint32 numWorkgroups[3],
261 const deUint32 localSize[3],
264 const deUint32* data = reinterpret_cast<const deUint32*>(datas[0]);
266 for (deUint32 nX = 0; nX < numWorkgroups[0]; ++nX)
268 for (deUint32 nY = 0; nY < numWorkgroups[1]; ++nY)
270 for (deUint32 nZ = 0; nZ < numWorkgroups[2]; ++nZ)
272 for (deUint32 lX = 0; lX < localSize[0]; ++lX)
274 for (deUint32 lY = 0; lY < localSize[1]; ++lY)
276 for (deUint32 lZ = 0; lZ < localSize[2];
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;
286 const deUint32 globalSizeX =
287 numWorkgroups[0] * localSize[0];
288 const deUint32 globalSizeY =
289 numWorkgroups[1] * localSize[1];
291 const deUint32 offset =
298 deUint32 numSubgroups = data[(offset * 4) + 2];
299 deUint32 subgroupID = data[(offset * 4) + 3];
301 if (subgroupID >= numSubgroups)
315 struct CaseDefinition
318 ShaderStageFlags shaderStage;
322 void initFrameBufferPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
325 const string fragmentGLSL =
327 "layout(location = 0) in vec4 in_color;\n"
328 "layout(location = 0) out uvec4 out_color;\n"
331 " out_color = uvec4(in_color);\n"
333 programCollection.add("fragment") << glu::FragmentSource(fragmentGLSL);
336 if (SHADER_STAGE_VERTEX_BIT != caseDef.shaderStage)
337 subgroups::setVertexShaderFrameBuffer(programCollection);
339 if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
341 const string vertexGLSL =
343 "#extension GL_KHR_shader_subgroup_basic: enable\n"
344 "layout(location = 0) out vec4 out_color;\n"
345 "layout(location = 0) in highp vec4 in_position;\n"
349 " out_color = vec4(gl_SubgroupSize, gl_SubgroupInvocationID, 1.0f, 1.0f);\n"
350 " gl_Position = in_position;\n"
351 " gl_PointSize = 1.0f;\n"
353 programCollection.add("vert") << glu::VertexSource(vertexGLSL);
355 else if (SHADER_STAGE_TESS_EVALUATION_BIT == caseDef.shaderStage)
357 const string controlSourceGLSL =
359 "#extension GL_EXT_tessellation_shader : require\n"
360 "layout(vertices = 2) out;\n"
361 "layout(location = 0) out vec4 out_color[];\n"
364 " if (gl_InvocationID == 0)\n"
366 " gl_TessLevelOuter[0] = 1.0f;\n"
367 " gl_TessLevelOuter[1] = 1.0f;\n"
369 " out_color[gl_InvocationID] = vec4(0.0f);\n"
370 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
372 programCollection.add("tesc") << glu::TessellationControlSource(controlSourceGLSL);
374 const string evaluationSourceGLSL =
376 "#extension GL_KHR_shader_subgroup_basic: enable\n"
377 "#extension GL_EXT_tessellation_shader : require\n"
378 "layout(isolines, equal_spacing, ccw ) in;\n"
379 "layout(location = 0) in vec4 in_color[];\n"
380 "layout(location = 0) out vec4 out_color;\n"
384 " gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
385 " out_color = vec4(gl_SubgroupSize, gl_SubgroupInvocationID, 0.0f, 0.0f);\n"
387 programCollection.add("tese") << glu::TessellationEvaluationSource(evaluationSourceGLSL);
389 else if (SHADER_STAGE_TESS_CONTROL_BIT == caseDef.shaderStage)
391 const string controlSourceGLSL =
393 "#extension GL_EXT_tessellation_shader : require\n"
394 "#extension GL_KHR_shader_subgroup_basic: enable\n"
395 "layout(vertices = 2) out;\n"
396 "layout(location = 0) out vec4 out_color[];\n"
399 " if (gl_InvocationID == 0)\n"
401 " gl_TessLevelOuter[0] = 1.0f;\n"
402 " gl_TessLevelOuter[1] = 1.0f;\n"
404 " out_color[gl_InvocationID] = vec4(gl_SubgroupSize, gl_SubgroupInvocationID, 0, 0);\n"
405 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
407 programCollection.add("tesc") << glu::TessellationControlSource(controlSourceGLSL);
409 const string evaluationSourceGLSL =
411 "#extension GL_KHR_shader_subgroup_basic: enable\n"
412 "#extension GL_EXT_tessellation_shader : require\n"
413 "layout(isolines, equal_spacing, ccw ) in;\n"
414 "layout(location = 0) in vec4 in_color[];\n"
415 "layout(location = 0) out vec4 out_color;\n"
419 " gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
420 " out_color = in_color[0];\n"
422 programCollection.add("tese") << glu::TessellationEvaluationSource(evaluationSourceGLSL);
424 else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
426 const string geometryGLSL =
428 "#extension GL_KHR_shader_subgroup_basic: enable\n"
429 "layout(points) in;\n"
430 "layout(points, max_vertices = 1) out;\n"
431 "layout(location = 0) out vec4 out_color;\n"
434 " out_color = vec4(gl_SubgroupSize, gl_SubgroupInvocationID, 0, 0);\n"
435 " gl_Position = gl_in[0].gl_Position;\n"
439 programCollection.add("geometry") << glu::GeometrySource(geometryGLSL);
443 DE_FATAL("Unsupported shader stage");
447 void initPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
449 if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
451 std::ostringstream src;
453 src << "#version 450\n"
454 << "#extension GL_KHR_shader_subgroup_basic: enable\n"
455 << "layout (${LOCAL_SIZE_X}, ${LOCAL_SIZE_Y}, ${LOCAL_SIZE_Z}) in;\n"
456 << "layout(binding = 0, std430) buffer Output\n"
458 << " uvec4 result[];\n"
461 << "void main (void)\n"
463 << " uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
464 << " highp uint offset = globalSize.x * ((globalSize.y * "
465 "gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + "
466 "gl_GlobalInvocationID.x;\n"
467 << " result[offset] = uvec4(gl_SubgroupSize, gl_SubgroupInvocationID, gl_NumSubgroups, gl_SubgroupID);\n"
470 programCollection.add("comp") << glu::ComputeSource(src.str());
475 const string vertexGLSL =
477 "#extension GL_KHR_shader_subgroup_basic: enable\n"
478 "layout(binding = 0, std430) buffer Output0\n"
485 " b0.result[gl_VertexID] = uvec4(gl_SubgroupSize, gl_SubgroupInvocationID, 0, 0);\n"
486 " float pixelSize = 2.0f/1024.0f;\n"
487 " float pixelPosition = pixelSize/2.0f - 1.0f;\n"
488 " gl_Position = vec4(float(gl_VertexID) * pixelSize + pixelPosition, 0.0f, 0.0f, 1.0f);\n"
489 " gl_PointSize = 1.0f;\n"
491 programCollection.add("vert") << glu::VertexSource(vertexGLSL);
495 const string tescGLSL =
497 "#extension GL_KHR_shader_subgroup_basic: enable\n"
498 "layout(vertices=1) out;\n"
499 "layout(binding = 1, std430) buffer Output1\n"
506 " b1.result[gl_PrimitiveID] = uvec4(gl_SubgroupSize, gl_SubgroupInvocationID, 0, 0);\n"
507 " if (gl_InvocationID == 0)\n"
509 " gl_TessLevelOuter[0] = 1.0f;\n"
510 " gl_TessLevelOuter[1] = 1.0f;\n"
512 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
514 programCollection.add("tesc") << glu::TessellationControlSource(tescGLSL);
518 const string teseGLSL =
520 "#extension GL_KHR_shader_subgroup_basic: enable\n"
521 "layout(isolines) in;\n"
522 "layout(binding = 2, std430) buffer Output2\n"
529 " b2.result[gl_PrimitiveID * 2 + uint(gl_TessCoord.x + 0.5)] = uvec4(gl_SubgroupSize, gl_SubgroupInvocationID, 0, 0);\n"
530 " float pixelSize = 2.0f/1024.0f;\n"
531 " gl_Position = gl_in[0].gl_Position + gl_TessCoord.x * pixelSize / 2.0f;\n"
533 programCollection.add("tese") << glu::TessellationEvaluationSource(teseGLSL);
537 const string geometryGLSL =
539 "#extension GL_KHR_shader_subgroup_basic: enable\n"
540 "layout(${TOPOLOGY}) in;\n"
541 "layout(points, max_vertices = 1) out;\n"
542 "layout(binding = 3, std430) buffer Output3\n"
549 " b3.result[gl_PrimitiveIDIn] = uvec4(gl_SubgroupSize, gl_SubgroupInvocationID, 0, 0);\n"
550 " gl_Position = gl_in[0].gl_Position;\n"
554 addGeometryShadersFromTemplate(geometryGLSL, programCollection);
558 const string fragmentGLSL =
560 "#extension GL_KHR_shader_subgroup_basic: enable\n"
561 "layout(location = 0) out uvec4 data;\n"
564 " data = uvec4(gl_SubgroupSize, gl_SubgroupInvocationID, 0, 0);\n"
566 programCollection.add("fragment") << glu::FragmentSource(fragmentGLSL);
569 subgroups::addNoSubgroupShader(programCollection);
573 void supportedCheck (Context& context, CaseDefinition caseDef)
576 if (!subgroups::isSubgroupSupported(context))
577 TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
580 tcu::TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
582 if (!areSubgroupOperationsSupportedForStage(
583 context, caseDef.shaderStage))
585 if (areSubgroupOperationsRequiredForStage(caseDef.shaderStage))
587 return tcu::TestStatus::fail(
588 "Shader stage " + getShaderStageName(caseDef.shaderStage) +
589 " is required to support subgroup operations!");
593 TCU_THROW(NotSupportedError, "Device does not support subgroup operations for this stage");
597 if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
599 if ("gl_SubgroupSize" == caseDef.varName)
601 return makeVertexFrameBufferTest(
602 context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0, checkVertexPipelineStagesSubgroupSize);
604 else if ("gl_SubgroupInvocationID" == caseDef.varName)
606 return makeVertexFrameBufferTest(
607 context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0, checkVertexPipelineStagesSubgroupInvocationID);
611 return tcu::TestStatus::fail(
612 caseDef.varName + " failed (unhandled error checking case " +
613 caseDef.varName + ")!");
616 else if ((SHADER_STAGE_TESS_EVALUATION_BIT | SHADER_STAGE_TESS_CONTROL_BIT) & caseDef.shaderStage )
618 if ("gl_SubgroupSize" == caseDef.varName)
620 return makeTessellationEvaluationFrameBufferTest(
621 context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0, checkVertexPipelineStagesSubgroupSize);
623 else if ("gl_SubgroupInvocationID" == caseDef.varName)
625 return makeTessellationEvaluationFrameBufferTest(
626 context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0, checkVertexPipelineStagesSubgroupInvocationID);
630 return tcu::TestStatus::fail(
631 caseDef.varName + " failed (unhandled error checking case " +
632 caseDef.varName + ")!");
635 else if (SHADER_STAGE_GEOMETRY_BIT & caseDef.shaderStage )
637 if ("gl_SubgroupSize" == caseDef.varName)
639 return makeGeometryFrameBufferTest(
640 context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0, checkVertexPipelineStagesSubgroupSize);
642 else if ("gl_SubgroupInvocationID" == caseDef.varName)
644 return makeGeometryFrameBufferTest(
645 context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0, checkVertexPipelineStagesSubgroupInvocationID);
649 return tcu::TestStatus::fail(
650 caseDef.varName + " failed (unhandled error checking case " +
651 caseDef.varName + ")!");
656 TCU_THROW(InternalError, "Unhandled shader stage");
661 tcu::TestStatus test(Context& context, const CaseDefinition caseDef)
663 if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
665 if (!areSubgroupOperationsSupportedForStage(context, caseDef.shaderStage))
667 return tcu::TestStatus::fail(
668 "Shader stage " + getShaderStageName(caseDef.shaderStage) +
669 " is required to support subgroup operations!");
672 if ("gl_SubgroupSize" == caseDef.varName)
674 return makeComputeTest(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0, checkComputeSubgroupSize);
676 else if ("gl_SubgroupInvocationID" == caseDef.varName)
678 return makeComputeTest(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0, checkComputeSubgroupInvocationID);
680 else if ("gl_NumSubgroups" == caseDef.varName)
682 return makeComputeTest(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0, checkComputeNumSubgroups);
684 else if ("gl_SubgroupID" == caseDef.varName)
686 return makeComputeTest(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0, checkComputeSubgroupID);
690 return tcu::TestStatus::fail(
691 caseDef.varName + " failed (unhandled error checking case " +
692 caseDef.varName + ")!");
697 int supportedStages = context.getDeqpContext().getContextInfo().getInt(GL_SUBGROUP_SUPPORTED_STAGES_KHR);
699 subgroups::ShaderStageFlags stages = (subgroups::ShaderStageFlags)(caseDef.shaderStage & supportedStages);
701 if (SHADER_STAGE_FRAGMENT_BIT != stages && !subgroups::isVertexSSBOSupportedForDevice(context))
703 if ( (stages & SHADER_STAGE_FRAGMENT_BIT) == 0)
704 TCU_THROW(NotSupportedError, "Device does not support vertex stage SSBO writes");
706 stages = SHADER_STAGE_FRAGMENT_BIT;
709 if ((ShaderStageFlags)0u == stages)
710 TCU_THROW(NotSupportedError, "Subgroup operations are not supported for any graphic shader");
712 if ("gl_SubgroupSize" == caseDef.varName)
714 return subgroups::allStages(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0, checkVertexPipelineStagesSubgroupSize, stages);
716 else if ("gl_SubgroupInvocationID" == caseDef.varName)
718 return subgroups::allStages(context, FORMAT_R32G32B32A32_UINT, DE_NULL, 0, checkVertexPipelineStagesSubgroupInvocationID, stages);
722 return tcu::TestStatus::fail(
723 caseDef.varName + " failed (unhandled error checking case " +
724 caseDef.varName + ")!");
729 deqp::TestCaseGroup* createSubgroupsBuiltinVarTests(deqp::Context& testCtx)
731 de::MovePtr<deqp::TestCaseGroup> graphicGroup(new deqp::TestCaseGroup(
732 testCtx, "graphics", "Subgroup builtin variable tests: graphics"));
733 de::MovePtr<deqp::TestCaseGroup> computeGroup(new deqp::TestCaseGroup(
734 testCtx, "compute", "Subgroup builtin variable tests: compute"));
735 de::MovePtr<deqp::TestCaseGroup> framebufferGroup(new deqp::TestCaseGroup(
736 testCtx, "framebuffer", "Subgroup builtin variable tests: framebuffer"));
738 const char* const all_stages_vars[] =
741 "SubgroupInvocationID"
744 const char* const compute_only_vars[] =
750 const ShaderStageFlags stages[] =
752 SHADER_STAGE_VERTEX_BIT,
753 SHADER_STAGE_TESS_EVALUATION_BIT,
754 SHADER_STAGE_TESS_CONTROL_BIT,
755 SHADER_STAGE_GEOMETRY_BIT,
758 for (int a = 0; a < DE_LENGTH_OF_ARRAY(all_stages_vars); ++a)
760 const std::string var = all_stages_vars[a];
761 const std::string varLower = de::toLower(var);
764 const CaseDefinition caseDef = { "gl_" + var, SHADER_STAGE_ALL_GRAPHICS};
766 SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(graphicGroup.get(),
768 supportedCheck, initPrograms, test, caseDef);
772 const CaseDefinition caseDef = {"gl_" + var, SHADER_STAGE_COMPUTE_BIT};
773 SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(computeGroup.get(),
774 varLower + "_" + getShaderStageName(caseDef.shaderStage), "",
775 supportedCheck, initPrograms, test, caseDef);
778 for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
780 const CaseDefinition caseDef = {"gl_" + var, stages[stageIndex]};
781 SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(framebufferGroup.get(),
782 varLower + "_" + getShaderStageName(caseDef.shaderStage), "",
783 supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
787 for (int a = 0; a < DE_LENGTH_OF_ARRAY(compute_only_vars); ++a)
789 const std::string var = compute_only_vars[a];
791 const CaseDefinition caseDef = {"gl_" + var, SHADER_STAGE_COMPUTE_BIT};
793 SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(computeGroup.get(), de::toLower(var), "",
794 supportedCheck, initPrograms, test, caseDef);
797 de::MovePtr<deqp::TestCaseGroup> group(new deqp::TestCaseGroup(
798 testCtx, "builtin_var", "Subgroup builtin variable tests"));
800 group->addChild(graphicGroup.release());
801 group->addChild(computeGroup.release());
802 group->addChild(framebufferGroup.release());
804 return group.release();