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 "glcSubgroupsBuiltinMaskVarTests.hpp"
27 #include "glcSubgroupsTestsUtils.hpp"
40 static bool checkVertexPipelineStages(std::vector<const void*> datas,
41 deUint32 width, deUint32)
43 return check(datas, width, 1);
46 static bool checkComputeStage(std::vector<const void*> datas,
47 const deUint32 numWorkgroups[3], const deUint32 localSize[3],
50 return checkCompute(datas, numWorkgroups, localSize, 1);
58 ShaderStageFlags shaderStage;
62 std::string subgroupMask (const CaseDefinition& caseDef)
64 std::ostringstream bdy;
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"
74 if ("gl_SubgroupEqMask" == caseDef.varName)
76 bdy << " if ((i == gl_SubgroupInvocationID) ^^ subgroupBallotBitExtract(var, i))\n"
78 << " tempResult = 0;\n"
81 else if ("gl_SubgroupGeMask" == caseDef.varName)
83 bdy << " if ((i >= gl_SubgroupInvocationID) ^^ subgroupBallotBitExtract(var, i))\n"
85 << " tempResult = 0;\n"
88 else if ("gl_SubgroupGtMask" == caseDef.varName)
90 bdy << " if ((i > gl_SubgroupInvocationID) ^^ subgroupBallotBitExtract(var, i))\n"
92 << " tempResult = 0;\n"
95 else if ("gl_SubgroupLeMask" == caseDef.varName)
97 bdy << " if ((i <= gl_SubgroupInvocationID) ^^ subgroupBallotBitExtract(var, i))\n"
99 << " tempResult = 0;\n"
102 else if ("gl_SubgroupLtMask" == caseDef.varName)
104 bdy << " if ((i < gl_SubgroupInvocationID) ^^ subgroupBallotBitExtract(var, i))\n"
106 << " tempResult = 0;\n"
111 << " for (uint i = 0; i < 32; i++)\n"
113 << " if ((var.x & bit) > 0)\n"
117 << " if ((var.y & bit) > 0)\n"
121 << " if ((var.z & bit) > 0)\n"
125 << " if ((var.w & bit) > 0)\n"
129 << " bit = bit<<1;\n"
131 << " if (subgroupBallotBitCount(var) != bitCount)\n"
133 << " tempResult = 0;\n"
138 void initFrameBufferPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
140 subgroups::setFragmentShaderFrameBuffer(programCollection);
142 if (SHADER_STAGE_VERTEX_BIT != caseDef.shaderStage)
143 subgroups::setVertexShaderFrameBuffer(programCollection);
145 if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
147 const string bdy = subgroupMask(caseDef);
148 const string vertexGLSL =
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"
157 " out_color = float(tempResult);\n"
158 " gl_Position = in_position;\n"
159 " gl_PointSize = 1.0f;\n"
161 programCollection.add("vert") << glu::VertexSource(vertexGLSL);
163 else if (SHADER_STAGE_TESS_EVALUATION_BIT == caseDef.shaderStage)
165 const string bdy = subgroupMask(caseDef);
166 const string evaluationSourceGLSL =
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"
176 " out_color = float(tempResult);\n"
177 " gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
179 programCollection.add("tese") << glu::TessellationEvaluationSource(evaluationSourceGLSL);
180 subgroups::setTesCtrlShaderFrameBuffer(programCollection);
182 else if (SHADER_STAGE_TESS_CONTROL_BIT == caseDef.shaderStage)
184 const string bdy = subgroupMask(caseDef);
185 const string controlSourceGLSL =
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"
193 " if (gl_InvocationID == 0)\n"
195 " gl_TessLevelOuter[0] = 1.0f;\n"
196 " gl_TessLevelOuter[1] = 1.0f;\n"
199 " out_color[gl_InvocationID] = float(tempResult);\n"
200 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
202 programCollection.add("tesc") << glu::TessellationControlSource(controlSourceGLSL);
203 subgroups::setTesEvalShaderFrameBuffer(programCollection);
205 else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
207 const string bdy = subgroupMask(caseDef);
208 const string geometryGLSL =
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"
218 " out_color = float(tempResult);\n"
219 " gl_Position = gl_in[0].gl_Position;\n"
223 programCollection.add("geometry") << glu::GeometrySource(geometryGLSL);
227 DE_FATAL("Unsupported shader stage");
232 void initPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
234 const string bdy = subgroupMask(caseDef);
236 if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
238 std::ostringstream src;
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"
245 << " uint result[];\n"
248 << "void main (void)\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"
255 << " result[offset] = tempResult;\n"
258 programCollection.add("comp") << glu::ComputeSource(src.str());
263 const string vertex =
265 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
266 "layout(binding = 0, std430) buffer Output0\n"
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"
280 programCollection.add("vert") << glu::VertexSource(vertex);
286 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
287 "layout(vertices=1) out;\n"
288 "layout(binding = 1, std430) buffer Output1\n"
296 " b1.result[gl_PrimitiveID] = tempResult;\n"
297 " if (gl_InvocationID == 0)\n"
299 " gl_TessLevelOuter[0] = 1.0f;\n"
300 " gl_TessLevelOuter[1] = 1.0f;\n"
302 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
304 programCollection.add("tesc") << glu::TessellationControlSource(tesc);
310 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
311 "layout(isolines) in;\n"
312 "layout(binding = 2, std430) buffer Output2\n"
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"
325 programCollection.add("tese") << glu::TessellationEvaluationSource(tese);
329 const string geometry =
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"
342 " b3.result[gl_PrimitiveIDIn] = tempResult;\n"
343 " gl_Position = gl_in[0].gl_Position;\n"
348 subgroups::addGeometryShadersFromTemplate(geometry, programCollection);
352 const string fragment =
354 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
355 "layout(location = 0) out uint result;\n"
359 " result = tempResult;\n"
362 programCollection.add("fragment") << glu::FragmentSource(fragment);
365 subgroups::addNoSubgroupShader(programCollection);
369 void supportedCheck (Context& context, CaseDefinition caseDef)
372 if (!subgroups::isSubgroupSupported(context))
373 TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
376 tcu::TestStatus noSSBOtest(Context& context, const CaseDefinition caseDef)
378 if (!areSubgroupOperationsSupportedForStage(
379 context, caseDef.shaderStage))
381 if (areSubgroupOperationsRequiredForStage(caseDef.shaderStage))
383 return tcu::TestStatus::fail(
384 "Shader stage " + getShaderStageName(caseDef.shaderStage) +
385 " is required to support subgroup operations!");
389 TCU_THROW(NotSupportedError, "Device does not support subgroup operations for this stage");
393 if (!subgroups::isSubgroupFeatureSupportedForDevice(context, SUBGROUP_FEATURE_BALLOT_BIT))
395 TCU_THROW(NotSupportedError, "Device does not support subgroup ballot operations");
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);
403 return makeGeometryFrameBufferTest(context, FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages);
407 tcu::TestStatus test(Context& context, const CaseDefinition caseDef)
409 if (!subgroups::isSubgroupFeatureSupportedForDevice(context, SUBGROUP_FEATURE_BALLOT_BIT))
411 TCU_THROW(NotSupportedError, "Device does not support subgroup ballot operations");
414 if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
416 if (!areSubgroupOperationsSupportedForStage(context, caseDef.shaderStage))
418 return tcu::TestStatus::fail(
419 "Shader stage " + getShaderStageName(caseDef.shaderStage) +
420 " is required to support subgroup operations!");
422 return makeComputeTest(context, FORMAT_R32_UINT, DE_NULL, 0, checkComputeStage);
426 int supportedStages = context.getDeqpContext().getContextInfo().getInt(GL_SUBGROUP_SUPPORTED_STAGES_KHR);
428 subgroups::ShaderStageFlags stages = (subgroups::ShaderStageFlags)(caseDef.shaderStage & supportedStages);
430 if ( SHADER_STAGE_FRAGMENT_BIT != stages && !subgroups::isVertexSSBOSupportedForDevice(context))
432 if ( (stages & SHADER_STAGE_FRAGMENT_BIT) == 0)
433 TCU_THROW(NotSupportedError, "Device does not support vertex stage SSBO writes");
435 stages = SHADER_STAGE_FRAGMENT_BIT;
438 if ((ShaderStageFlags)0u == stages)
439 TCU_THROW(NotSupportedError, "Subgroup operations are not supported for any graphic shader");
441 return subgroups::allStages(context, FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages, stages);
445 deqp::TestCaseGroup* createSubgroupsBuiltinMaskVarTests(deqp::Context& testCtx)
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"));
454 const char* const all_stages_vars[] =
463 const subgroups::ShaderStageFlags stages[] =
465 SHADER_STAGE_VERTEX_BIT,
466 SHADER_STAGE_TESS_EVALUATION_BIT,
467 SHADER_STAGE_TESS_CONTROL_BIT,
468 SHADER_STAGE_GEOMETRY_BIT,
472 for (int a = 0; a < DE_LENGTH_OF_ARRAY(all_stages_vars); ++a)
474 const std::string var = all_stages_vars[a];
475 const std::string varLower = de::toLower(var);
478 const CaseDefinition caseDef = {"gl_" + var, SHADER_STAGE_ALL_GRAPHICS};
479 SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(graphicGroup.get(),
481 supportedCheck, initPrograms, test, caseDef);
485 const CaseDefinition caseDef = {"gl_" + var, SHADER_STAGE_COMPUTE_BIT};
486 SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(computeGroup.get(),
488 supportedCheck, initPrograms, test, caseDef);
491 for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
493 const CaseDefinition caseDef = {"gl_" + var, stages[stageIndex]};
494 SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(framebufferGroup.get(),
496 getShaderStageName(caseDef.shaderStage), "",
497 supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
501 de::MovePtr<deqp::TestCaseGroup> group(new deqp::TestCaseGroup(
502 testCtx, "builtin_mask_var", "Subgroup builtin mask variable tests"));
504 group->addChild(graphicGroup.release());
505 group->addChild(computeGroup.release());
506 group->addChild(framebufferGroup.release());
508 return group.release();