1 /*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2017 The Khronos Group Inc. 6 * Copyright (c) 2017 Codeplay Software Ltd. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 */ /*! 21 * \file 22 * \brief Subgroups Tests 23 */ /*--------------------------------------------------------------------*/ 24 25 #include "vktSubgroupsBallotTests.hpp" 26 #include "vktSubgroupsTestsUtils.hpp" 27 28 #include <string> 29 #include <vector> 30 31 using namespace tcu; 32 using namespace std; 33 using namespace vk; 34 using namespace vkt; 35 36 namespace 37 { 38 static bool checkVertexPipelineStages(std::vector<const void*> datas, 39 deUint32 width, deUint32) 40 { 41 const deUint32* data = 42 reinterpret_cast<const deUint32*>(datas[0]); 43 for (deUint32 x = 0; x < width; ++x) 44 { 45 deUint32 val = data[x]; 46 47 if (0x7 != val) 48 { 49 return false; 50 } 51 } 52 53 return true; 54 } 55 56 static bool checkFragment(std::vector<const void*> datas, 57 deUint32 width, deUint32 height, deUint32) 58 { 59 const deUint32* data = 60 reinterpret_cast<const deUint32*>(datas[0]); 61 for (deUint32 x = 0; x < width; ++x) 62 { 63 for (deUint32 y = 0; y < height; ++y) 64 { 65 deUint32 val = data[x * height + y]; 66 67 if (0x7 != val) 68 { 69 return false; 70 } 71 } 72 } 73 74 return true; 75 } 76 77 static bool checkCompute(std::vector<const void*> datas, 78 const deUint32 numWorkgroups[3], const deUint32 localSize[3], 79 deUint32) 80 { 81 const deUint32* data = 82 reinterpret_cast<const deUint32*>(datas[0]); 83 84 for (deUint32 nX = 0; nX < numWorkgroups[0]; ++nX) 85 { 86 for (deUint32 nY = 0; nY < numWorkgroups[1]; ++nY) 87 { 88 for (deUint32 nZ = 0; nZ < numWorkgroups[2]; ++nZ) 89 { 90 for (deUint32 lX = 0; lX < localSize[0]; ++lX) 91 { 92 for (deUint32 lY = 0; lY < localSize[1]; ++lY) 93 { 94 for (deUint32 lZ = 0; lZ < localSize[2]; 95 ++lZ) 96 { 97 const deUint32 globalInvocationX = 98 nX * localSize[0] + lX; 99 const deUint32 globalInvocationY = 100 nY * localSize[1] + lY; 101 const deUint32 globalInvocationZ = 102 nZ * localSize[2] + lZ; 103 104 const deUint32 globalSizeX = 105 numWorkgroups[0] * localSize[0]; 106 const deUint32 globalSizeY = 107 numWorkgroups[1] * localSize[1]; 108 109 const deUint32 offset = 110 globalSizeX * 111 ((globalSizeY * 112 globalInvocationZ) + 113 globalInvocationY) + 114 globalInvocationX; 115 116 if (0x7 != data[offset]) 117 { 118 return false; 119 } 120 } 121 } 122 } 123 } 124 } 125 } 126 127 return true; 128 } 129 130 struct CaseDefinition 131 { 132 VkShaderStageFlags shaderStage; 133 bool noSSBO; 134 }; 135 136 void initFrameBufferPrograms(SourceCollections& programCollection, CaseDefinition caseDef) 137 { 138 std::ostringstream fragmentSrc; 139 140 if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage) 141 { 142 std::ostringstream vertexSrc; 143 144 vertexSrc << "#version 450\n" 145 << "#extension GL_KHR_shader_subgroup_ballot: enable\n" 146 << "layout(location = 0) in highp vec4 in_position;\n" 147 << "layout(location = 0) out float out_color;\n" 148 << "layout(set = 0, binding = 0) uniform Buffer1\n" 149 << "{\n" 150 << " uint data[" << subgroups::maxSupportedSubgroupSize() << "];\n" 151 << "};\n" 152 << "\n" 153 << "void main (void)\n" 154 << "{\n" 155 << " uint tempResult = 0;\n" 156 << " tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1 : 0;\n" 157 << " bool bData = data[gl_SubgroupInvocationID] != 0;\n" 158 << " tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2 : 0;\n" 159 << " tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4 : 0;\n" 160 << " out_color = float(tempResult);\n" 161 << " gl_Position = in_position;\n" 162 << " gl_PointSize = 1.0f;\n" 163 << "}\n"; 164 165 programCollection.glslSources.add("vert") << glu::VertexSource(vertexSrc.str()) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u); 166 167 fragmentSrc << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n" 168 << "layout(location = 0) in float in_color;\n" 169 << "layout(location = 0) out uint out_color;\n" 170 << "void main()\n" 171 <<"{\n" 172 << " out_color = uint(in_color);\n" 173 << "}\n"; 174 programCollection.glslSources.add("fragment") << glu::FragmentSource(fragmentSrc.str()) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u); 175 } 176 else 177 { 178 DE_FATAL("Unsupported shader stage"); 179 } 180 } 181 182 void initPrograms(SourceCollections& programCollection, CaseDefinition caseDef) 183 { 184 if (VK_SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage) 185 { 186 std::ostringstream src; 187 188 src << "#version 450\n" 189 << "#extension GL_KHR_shader_subgroup_ballot: enable\n" 190 << "layout (local_size_x_id = 0, local_size_y_id = 1, " 191 "local_size_z_id = 2) in;\n" 192 << "layout(set = 0, binding = 0, std430) buffer Buffer1\n" 193 << "{\n" 194 << " uint result[];\n" 195 << "};\n" 196 << "layout(set = 0, binding = 1, std430) buffer Buffer2\n" 197 << "{\n" 198 << " uint data[];\n" 199 << "};\n" 200 << "\n" 201 << subgroups::getSharedMemoryBallotHelper() 202 << "void main (void)\n" 203 << "{\n" 204 << " uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n" 205 << " highp uint offset = globalSize.x * ((globalSize.y * " 206 "gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + " 207 "gl_GlobalInvocationID.x;\n" 208 << " uint tempResult = 0;\n" 209 << " tempResult |= sharedMemoryBallot(true) == subgroupBallot(true) ? 0x1 : 0;\n" 210 << " bool bData = data[gl_SubgroupInvocationID] != 0;\n" 211 << " tempResult |= sharedMemoryBallot(bData) == subgroupBallot(bData) ? 0x2 : 0;\n" 212 << " tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4 : 0;\n" 213 << " result[offset] = tempResult;\n" 214 << "}\n"; 215 216 programCollection.glslSources.add("comp") 217 << glu::ComputeSource(src.str()) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u); 218 } 219 else if (VK_SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage) 220 { 221 programCollection.glslSources.add("vert") 222 << glu::VertexSource(subgroups::getVertShaderForStage(caseDef.shaderStage)) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u); 223 224 std::ostringstream frag; 225 226 frag << "#version 450\n" 227 << "#extension GL_KHR_shader_subgroup_ballot: enable\n" 228 << "layout(location = 0) out uint result;\n" 229 << "layout(set = 0, binding = 0, std430) readonly buffer Buffer1\n" 230 << "{\n" 231 << " uint data[];\n" 232 << "};\n" 233 << "void main (void)\n" 234 << "{\n" 235 << " uint tempResult = 0;\n" 236 << " tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1 : 0;\n" 237 << " bool bData = data[gl_SubgroupInvocationID] != 0;\n" 238 << " tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2 : 0;\n" 239 << " tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4 : 0;\n" 240 << " result = tempResult;\n" 241 << "}\n"; 242 243 programCollection.glslSources.add("frag") 244 << glu::FragmentSource(frag.str()) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u); 245 } 246 else if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage) 247 { 248 std::ostringstream src; 249 250 src << "#version 450\n" 251 << "#extension GL_KHR_shader_subgroup_ballot: enable\n" 252 << "layout(set = 0, binding = 0, std430) buffer Buffer1\n" 253 << "{\n" 254 << " uint result[];\n" 255 << "};\n" 256 << "layout(set = 0, binding = 1, std430) buffer Buffer2\n" 257 << "{\n" 258 << " uint data[];\n" 259 << "};\n" 260 << "\n" 261 << "void main (void)\n" 262 << "{\n" 263 << " uint tempResult = 0;\n" 264 << " tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1 : 0;\n" 265 << " bool bData = data[gl_SubgroupInvocationID] != 0;\n" 266 << " tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2 : 0;\n" 267 << " tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4 : 0;\n" 268 << " result[gl_VertexIndex] = tempResult;\n" 269 << " gl_PointSize = 1.0f;\n" 270 << "}\n"; 271 272 programCollection.glslSources.add("vert") 273 << glu::VertexSource(src.str()) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u); 274 } 275 else if (VK_SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage) 276 { 277 programCollection.glslSources.add("vert") 278 << glu::VertexSource(subgroups::getVertShaderForStage(caseDef.shaderStage)) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u); 279 280 std::ostringstream src; 281 282 src << "#version 450\n" 283 << "#extension GL_KHR_shader_subgroup_ballot: enable\n" 284 << "layout(points) in;\n" 285 << "layout(points, max_vertices = 1) out;\n" 286 << "layout(set = 0, binding = 0, std430) buffer Buffer1\n" 287 << "{\n" 288 << " uint result[];\n" 289 << "};\n" 290 << "layout(set = 0, binding = 1, std430) buffer Buffer2\n" 291 << "{\n" 292 << " uint data[];\n" 293 << "};\n" 294 << "\n" 295 << "void main (void)\n" 296 << "{\n" 297 << " uint tempResult = 0;\n" 298 << " tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1 : 0;\n" 299 << " bool bData = data[gl_SubgroupInvocationID] != 0;\n" 300 << " tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2 : 0;\n" 301 << " tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4 : 0;\n" 302 << " result[gl_PrimitiveIDIn] = tempResult;\n" 303 << "}\n"; 304 305 programCollection.glslSources.add("geom") 306 << glu::GeometrySource(src.str()) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u); 307 } 308 else if (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage) 309 { 310 programCollection.glslSources.add("vert") 311 << glu::VertexSource(subgroups::getVertShaderForStage(caseDef.shaderStage)) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u); 312 313 programCollection.glslSources.add("tese") 314 << glu::TessellationEvaluationSource("#version 450\nlayout(isolines) in;\nvoid main (void) {}\n"); 315 316 std::ostringstream src; 317 318 src << "#version 450\n" 319 << "#extension GL_KHR_shader_subgroup_ballot: enable\n" 320 << "layout(vertices=1) out;\n" 321 << "layout(set = 0, binding = 0, std430) buffer Buffer1\n" 322 << "{\n" 323 << " uint result[];\n" 324 << "};\n" 325 << "layout(set = 0, binding = 1, std430) buffer Buffer2\n" 326 << "{\n" 327 << " uint data[];\n" 328 << "};\n" 329 << "\n" 330 << "void main (void)\n" 331 << "{\n" 332 << " uint tempResult = 0;\n" 333 << " tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1 : 0;\n" 334 << " bool bData = data[gl_SubgroupInvocationID] != 0;\n" 335 << " tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2 : 0;\n" 336 << " tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4 : 0;\n" 337 << " result[gl_PrimitiveID] = tempResult;\n" 338 << "}\n"; 339 340 programCollection.glslSources.add("tesc") 341 << glu::TessellationControlSource(src.str()) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u); 342 } 343 else if (VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT == caseDef.shaderStage) 344 { 345 programCollection.glslSources.add("vert") 346 << glu::VertexSource(subgroups::getVertShaderForStage(caseDef.shaderStage)) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u); 347 348 programCollection.glslSources.add("tesc") 349 << glu::TessellationControlSource("#version 450\nlayout(vertices=1) out;\nvoid main (void) { for(uint i = 0; i < 4; i++) { gl_TessLevelOuter[i] = 1.0f; } }\n"); 350 351 std::ostringstream src; 352 353 src << "#version 450\n" 354 << "#extension GL_KHR_shader_subgroup_ballot: enable\n" 355 << "layout(isolines) in;\n" 356 << "layout(set = 0, binding = 0, std430) buffer Buffer1\n" 357 << "{\n" 358 << " uint result[];\n" 359 << "};\n" 360 << "layout(set = 0, binding = 1, std430) buffer Buffer2\n" 361 << "{\n" 362 << " uint data[];\n" 363 << "};\n" 364 << "\n" 365 << "void main (void)\n" 366 << "{\n" 367 << " uint tempResult = 0;\n" 368 << " tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1 : 0;\n" 369 << " bool bData = data[gl_SubgroupInvocationID] != 0;\n" 370 << " tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2 : 0;\n" 371 << " tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4 : 0;\n" 372 << " result[gl_PrimitiveID * 2 + uint(gl_TessCoord.x + 0.5)] = tempResult;\n" 373 << "}\n"; 374 375 programCollection.glslSources.add("tese") 376 << glu::TessellationEvaluationSource(src.str()) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u); 377 } 378 else 379 { 380 DE_FATAL("Unsupported shader stage"); 381 } 382 } 383 384 tcu::TestStatus test(Context& context, const CaseDefinition caseDef) 385 { 386 if (!subgroups::isSubgroupSupported(context)) 387 TCU_THROW(NotSupportedError, "Subgroup operations are not supported"); 388 389 if (!subgroups::areSubgroupOperationsSupportedForStage( 390 context, caseDef.shaderStage)) 391 { 392 if (subgroups::areSubgroupOperationsRequiredForStage( 393 caseDef.shaderStage)) 394 { 395 return tcu::TestStatus::fail( 396 "Shader stage " + 397 subgroups::getShaderStageName(caseDef.shaderStage) + 398 " is required to support subgroup operations!"); 399 } 400 else 401 { 402 TCU_THROW(NotSupportedError, "Device does not support subgroup operations for this stage"); 403 } 404 } 405 406 if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_BALLOT_BIT)) 407 { 408 TCU_THROW(NotSupportedError, "Device does not support subgroup ballot operations"); 409 } 410 411 //Tests which don't use the SSBO 412 if (caseDef.noSSBO && VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage) 413 { 414 subgroups::SSBOData inputData[1]; 415 inputData[0].format = VK_FORMAT_R32_UINT; 416 inputData[0].numElements = subgroups::maxSupportedSubgroupSize(); 417 inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero; 418 419 return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32_UINT, inputData, 1, checkVertexPipelineStages); 420 } 421 422 if ((VK_SHADER_STAGE_FRAGMENT_BIT != caseDef.shaderStage) && 423 (VK_SHADER_STAGE_COMPUTE_BIT != caseDef.shaderStage)) 424 { 425 if (!subgroups::isVertexSSBOSupportedForDevice(context)) 426 { 427 TCU_THROW(NotSupportedError, "Device does not support vertex stage SSBO writes"); 428 } 429 } 430 431 if (VK_SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage) 432 { 433 subgroups::SSBOData inputData[1]; 434 inputData[0].format = VK_FORMAT_R32_UINT; 435 inputData[0].numElements = subgroups::maxSupportedSubgroupSize(); 436 inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero; 437 438 return subgroups::makeFragmentTest(context, VK_FORMAT_R32_UINT, 439 inputData, 1, checkFragment); 440 } 441 else if (VK_SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage) 442 { 443 subgroups::SSBOData inputData[1]; 444 inputData[0].format = VK_FORMAT_R32_UINT; 445 inputData[0].numElements = subgroups::maxSupportedSubgroupSize(); 446 inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero; 447 448 return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, 449 inputData, 1, checkCompute); 450 } 451 else if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage) 452 { 453 subgroups::SSBOData inputData[1]; 454 inputData[0].format = VK_FORMAT_R32_UINT; 455 inputData[0].numElements = subgroups::maxSupportedSubgroupSize(); 456 inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero; 457 458 return subgroups::makeVertexTest(context, VK_FORMAT_R32_UINT, 459 inputData, 1, checkVertexPipelineStages); 460 } 461 else if (VK_SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage) 462 { 463 subgroups::SSBOData inputData[1]; 464 inputData[0].format = VK_FORMAT_R32_UINT; 465 inputData[0].numElements = subgroups::maxSupportedSubgroupSize(); 466 inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero; 467 468 return subgroups::makeGeometryTest(context, VK_FORMAT_R32_UINT, 469 inputData, 1, checkVertexPipelineStages); 470 } 471 else if (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage) 472 { 473 subgroups::SSBOData inputData[1]; 474 inputData[0].format = VK_FORMAT_R32_UINT; 475 inputData[0].numElements = subgroups::maxSupportedSubgroupSize(); 476 inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero; 477 478 return subgroups::makeTessellationControlTest(context, VK_FORMAT_R32_UINT, 479 inputData, 1, checkVertexPipelineStages); 480 } 481 else if (VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT == caseDef.shaderStage) 482 { 483 subgroups::SSBOData inputData[1]; 484 inputData[0].format = VK_FORMAT_R32_UINT; 485 inputData[0].numElements = subgroups::maxSupportedSubgroupSize(); 486 inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero; 487 488 return subgroups::makeTessellationEvaluationTest(context, VK_FORMAT_R32_UINT, 489 inputData, 1, checkVertexPipelineStages); 490 } 491 else 492 { 493 TCU_THROW(InternalError, "Unhandled shader stage"); 494 } 495 } 496 } 497 498 namespace vkt 499 { 500 namespace subgroups 501 { 502 tcu::TestCaseGroup* createSubgroupsBallotTests(tcu::TestContext& testCtx) 503 { 504 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup( 505 testCtx, "ballot", "Subgroup ballot category tests")); 506 507 const VkShaderStageFlags stages[] = 508 { 509 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, 510 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, 511 VK_SHADER_STAGE_GEOMETRY_BIT, 512 VK_SHADER_STAGE_VERTEX_BIT, 513 VK_SHADER_STAGE_FRAGMENT_BIT, 514 VK_SHADER_STAGE_COMPUTE_BIT 515 }; 516 517 for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex) 518 { 519 const VkShaderStageFlags stage = stages[stageIndex]; 520 521 CaseDefinition caseDef = {stage, false}; 522 523 std::ostringstream name; 524 525 name << getShaderStageName(stage); 526 527 addFunctionCaseWithPrograms(group.get(), name.str(), 528 "", initPrograms, test, caseDef); 529 530 if (VK_SHADER_STAGE_VERTEX_BIT == stage ) 531 { 532 caseDef.noSSBO = true; 533 addFunctionCaseWithPrograms(group.get(), name.str()+"_framebuffer", "", 534 initFrameBufferPrograms, test, caseDef); 535 } 536 } 537 538 return group.release(); 539 } 540 541 } // subgroups 542 } // vkt 543