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 32using namespace tcu; 33using namespace std; 34 35namespace glc 36{ 37namespace subgroups 38{ 39 40static bool checkVertexPipelineStages(std::vector<const void*> datas, 41 deUint32 width, deUint32) 42{ 43 return check(datas, width, 1); 44} 45 46static 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 53namespace 54{ 55struct CaseDefinition 56{ 57 std::string varName; 58 ShaderStageFlags shaderStage; 59}; 60} 61 62std::string subgroupMask (const CaseDefinition& caseDef) 63{ 64 std::ostringstream bdy; 65 66 bdy << " uint tempResult = 0x1u;\n" 67 << " uint bit = 0x1u;\n" 68 << " uint bitCount = 0x0u;\n" 69 << " uvec4 mask = subgroupBallot(true);\n" 70 << " uvec4 var = " << caseDef.varName << ";\n" 71 << " for (uint i = 0u; 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 = 0u;\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 = 0u;\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 = 0u;\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 = 0u;\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 = 0u;\n" 107 << " }\n"; 108 } 109 110 bdy << " }\n" 111 << " for (uint i = 0u; i < 32u; i++)\n" 112 << " {\n" 113 << " if ((var.x & bit) > 0u)\n" 114 << " {\n" 115 << " bitCount++;\n" 116 << " }\n" 117 << " if ((var.y & bit) > 0u)\n" 118 << " {\n" 119 << " bitCount++;\n" 120 << " }\n" 121 << " if ((var.z & bit) > 0u)\n" 122 << " {\n" 123 << " bitCount++;\n" 124 << " }\n" 125 << " if ((var.w & bit) > 0u)\n" 126 << " {\n" 127 << " bitCount++;\n" 128 << " }\n" 129 << " bit = bit << 1u;\n" 130 << " }\n" 131 << " if (subgroupBallotBitCount(var) != bitCount)\n" 132 << " {\n" 133 << " tempResult = 0u;\n" 134 << " }\n"; 135 return bdy.str(); 136} 137 138void 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_DECL}\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_DECL}\n" 168 "#extension GL_KHR_shader_subgroup_ballot: enable\n" 169 "${TESS_EXTENSION}\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_DECL}\n" 187 "${TESS_EXTENSION}\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_DECL}\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 232void 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_DECL}\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_DECL}\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_DECL}\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_DECL}\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 + int(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 "#extension GL_KHR_shader_subgroup_ballot: enable\n" 331 "layout(${TOPOLOGY}) in;\n" 332 "layout(points, max_vertices = 1) out;\n" 333 "layout(binding = 3, std430) buffer Output3\n" 334 "{\n" 335 " uint result[];\n" 336 "} b3;\n" 337 "\n" 338 "void main (void)\n" 339 "{\n" 340 + bdy + 341 " b3.result[gl_PrimitiveIDIn] = tempResult;\n" 342 " gl_Position = gl_in[0].gl_Position;\n" 343 " EmitVertex();\n" 344 " EndPrimitive();\n" 345 "}\n"; 346 347 subgroups::addGeometryShadersFromTemplate(geometry, programCollection); 348 } 349 350 { 351 const string fragment = 352 "${VERSION_DECL}\n" 353 "#extension GL_KHR_shader_subgroup_ballot: enable\n" 354 "precision highp int;\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 369void 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 376tcu::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 407tcu::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 445deqp::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 512