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