xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/subgroups/vktSubgroupsVoteTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  * Copyright (c) 2019 Google Inc.
7  * Copyright (c) 2017 Codeplay Software Ltd.
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 "vktSubgroupsVoteTests.hpp"
27 #include "vktSubgroupsTestsUtils.hpp"
28 
29 #include <string>
30 #include <vector>
31 
32 using namespace tcu;
33 using namespace std;
34 using namespace vk;
35 using namespace vkt;
36 
37 namespace
38 {
39 enum OpType
40 {
41     OPTYPE_ALL          = 0,
42     OPTYPE_ANY          = 1,
43     OPTYPE_ALLEQUAL     = 2,
44     OPTYPE_LAST_NON_ARB = 3,
45     OPTYPE_ALL_ARB      = 4,
46     OPTYPE_ANY_ARB      = 5,
47     OPTYPE_ALLEQUAL_ARB = 6,
48     OPTYPE_LAST
49 };
50 
51 struct CaseDefinition
52 {
53     OpType opType;
54     VkShaderStageFlags shaderStage;
55     VkFormat format;
56     de::SharedPtr<bool> geometryPointSizeSupported;
57     bool requiredSubgroupSize;
58     bool requires8BitUniformBuffer;
59     bool requires16BitUniformBuffer;
60 };
61 
checkVertexPipelineStages(const void * internalData,vector<const void * > datas,uint32_t width,uint32_t)62 static bool checkVertexPipelineStages(const void *internalData, vector<const void *> datas, uint32_t width, uint32_t)
63 {
64     DE_UNREF(internalData);
65 
66     return subgroups::check(datas, width, 0x1F);
67 }
68 
checkFragmentPipelineStages(const void * internalData,vector<const void * > datas,uint32_t width,uint32_t height,uint32_t)69 static bool checkFragmentPipelineStages(const void *internalData, vector<const void *> datas, uint32_t width,
70                                         uint32_t height, uint32_t)
71 {
72     DE_UNREF(internalData);
73 
74     const uint32_t *data = reinterpret_cast<const uint32_t *>(datas[0]);
75 
76     for (uint32_t x = 0u; x < width; ++x)
77     {
78         for (uint32_t y = 0u; y < height; ++y)
79         {
80             const uint32_t ndx = (x * height + y);
81             const uint32_t val = data[ndx] & 0x1F;
82 
83             if (data[ndx] & 0x40) //Helper fragment shader invocation was executed
84             {
85                 if (val != 0x1F)
86                     return false;
87             }
88             else //Helper fragment shader invocation was not executed yet
89             {
90                 if (val != 0x1E)
91                     return false;
92             }
93         }
94     }
95 
96     return true;
97 }
98 
checkComputeOrMesh(const void * internalData,vector<const void * > datas,const uint32_t numWorkgroups[3],const uint32_t localSize[3],uint32_t)99 static bool checkComputeOrMesh(const void *internalData, vector<const void *> datas, const uint32_t numWorkgroups[3],
100                                const uint32_t localSize[3], uint32_t)
101 {
102     DE_UNREF(internalData);
103 
104     return subgroups::checkComputeOrMesh(datas, numWorkgroups, localSize, 0x1F);
105 }
106 
getOpTypeName(int opType)107 string getOpTypeName(int opType)
108 {
109     switch (opType)
110     {
111     case OPTYPE_ALL:
112         return "subgroupAll";
113     case OPTYPE_ANY:
114         return "subgroupAny";
115     case OPTYPE_ALLEQUAL:
116         return "subgroupAllEqual";
117     case OPTYPE_ALL_ARB:
118         return "allInvocationsARB";
119     case OPTYPE_ANY_ARB:
120         return "anyInvocationARB";
121     case OPTYPE_ALLEQUAL_ARB:
122         return "allInvocationsEqualARB";
123     default:
124         TCU_THROW(InternalError, "Unsupported op type");
125     }
126 }
127 
fmtIsBoolean(VkFormat format)128 bool fmtIsBoolean(VkFormat format)
129 {
130     // For reasons unknown, the tests use R8_USCALED as the boolean format
131     return format == VK_FORMAT_R8_USCALED || format == VK_FORMAT_R8G8_USCALED || format == VK_FORMAT_R8G8B8_USCALED ||
132            format == VK_FORMAT_R8G8B8A8_USCALED;
133 }
134 
getExtensions(bool arbFunctions)135 const string getExtensions(bool arbFunctions)
136 {
137     return arbFunctions ? "#extension GL_ARB_shader_group_vote: enable\n"
138                           "#extension GL_KHR_shader_subgroup_basic: enable\n" :
139                           "#extension GL_KHR_shader_subgroup_vote: enable\n";
140 }
141 
getStageTestSource(const CaseDefinition & caseDef)142 const string getStageTestSource(const CaseDefinition &caseDef)
143 {
144     const bool formatIsBoolean = fmtIsBoolean(caseDef.format);
145     const string op            = getOpTypeName(caseDef.opType);
146     const string fmt           = subgroups::getFormatNameForGLSL(caseDef.format);
147     const string computePart =
148         isAllComputeStages(caseDef.shaderStage) ? op + "(data[gl_SubgroupInvocationID] > 0) ? 0x4 : 0x0" : "0x4";
149 
150     return (OPTYPE_ALL == caseDef.opType || OPTYPE_ALL_ARB == caseDef.opType) ?
151                "  tempRes = " + op +
152                    "(true) ? 0x1 : 0;\n"
153                    "  tempRes |= " +
154                    op +
155                    "(false) ? 0 : 0x1A;\n"
156                    "  tempRes |= " +
157                    computePart + ";\n" :
158            (OPTYPE_ANY == caseDef.opType || OPTYPE_ANY_ARB == caseDef.opType) ?
159                "  tempRes = " + op +
160                    "(true) ? 0x1 : 0;\n"
161                    "  tempRes |= " +
162                    op +
163                    "(false) ? 0 : 0x1A;\n"
164                    "  tempRes |= " +
165                    computePart + ";\n" :
166            (OPTYPE_ALLEQUAL == caseDef.opType || OPTYPE_ALLEQUAL_ARB == caseDef.opType) ?
167                "  " + fmt + " valueEqual = " + fmt + "(1.25 * float(data[gl_SubgroupInvocationID]) + 5.0);\n" + "  " +
168                    fmt + " valueNoEqual = " + fmt +
169                    (formatIsBoolean ? "(subgroupElect());\n" : "(gl_SubgroupInvocationID);\n") + "  tempRes = " + op +
170                    "(" + fmt +
171                    "(1)) ? 0x1 : 0;\n"
172                    "  tempRes |= " +
173                    (formatIsBoolean ? "0x2" : op + "(" + fmt + "(gl_SubgroupInvocationID)) ? 0 : 0x2") +
174                    ";\n"
175                    "  tempRes |= " +
176                    op +
177                    "(data[0]) ? 0x4 : 0;\n"
178                    "  tempRes |= " +
179                    op +
180                    "(valueEqual) ? 0x8 : 0x0;\n"
181                    "  tempRes |= " +
182                    op +
183                    "(valueNoEqual) ? 0x0 : 0x10;\n"
184                    "  if (subgroupElect()) tempRes |= 0x2 | 0x10;\n" :
185                "";
186 }
187 
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)188 void initFrameBufferPrograms(SourceCollections &programCollection, CaseDefinition caseDef)
189 {
190 #ifndef CTS_USES_VULKANSC
191     const bool spirv14required = isAllRayTracingStages(caseDef.shaderStage);
192 #else
193     const bool spirv14required = false;
194 #endif // CTS_USES_VULKANSC
195     const SpirvVersion spirvVersion = spirv14required ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3;
196     const ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u);
197     const bool arbFunctions = caseDef.opType > OPTYPE_LAST_NON_ARB;
198     const string extensions = getExtensions(arbFunctions) + subgroups::getAdditionalExtensionForFormat(caseDef.format);
199     const bool pointSize    = *caseDef.geometryPointSizeSupported;
200 
201     subgroups::initStdFrameBufferPrograms(programCollection, buildOptions, caseDef.shaderStage, caseDef.format,
202                                           pointSize, extensions, getStageTestSource(caseDef), "");
203 }
204 
getStageTestSourceFrag(const CaseDefinition & caseDef)205 const string getStageTestSourceFrag(const CaseDefinition &caseDef)
206 {
207     const bool formatIsBoolean = fmtIsBoolean(caseDef.format);
208     const string op            = getOpTypeName(caseDef.opType);
209     const string fmt           = subgroups::getFormatNameForGLSL(caseDef.format);
210 
211     return (OPTYPE_ALL == caseDef.opType || OPTYPE_ALL_ARB == caseDef.opType) ?
212                "  tempRes |= " + op +
213                    "(!gl_HelperInvocation) ? 0x0 : 0x1;\n"
214                    "  tempRes |= " +
215                    op +
216                    "(false) ? 0 : 0x1A;\n"
217                    "  tempRes |= 0x4;\n" :
218            (OPTYPE_ANY == caseDef.opType || OPTYPE_ANY_ARB == caseDef.opType) ?
219                "  tempRes |= " + op +
220                    "(gl_HelperInvocation) ? 0x1 : 0x0;\n"
221                    "  tempRes |= " +
222                    op +
223                    "(false) ? 0 : 0x1A;\n"
224                    "  tempRes |= 0x4;\n" :
225            (OPTYPE_ALLEQUAL == caseDef.opType || OPTYPE_ALLEQUAL_ARB == caseDef.opType) ?
226                "  " + fmt + " valueEqual = " + fmt + "(1.25 * float(data[gl_SubgroupInvocationID]) + 5.0);\n" + "  " +
227                    fmt + " valueNoEqual = " + fmt +
228                    (formatIsBoolean ? "(subgroupElect());\n" : "(gl_SubgroupInvocationID);\n") +
229                    "  tempRes |= " + getOpTypeName(caseDef.opType) + "(" + fmt +
230                    "(1)) ? 0x10 : 0;\n"
231                    "  tempRes |= " +
232                    (formatIsBoolean ? "0x2" : op + "(" + fmt + "(gl_SubgroupInvocationID)) ? 0 : 0x2") +
233                    ";\n"
234                    "  tempRes |= " +
235                    op +
236                    "(data[0]) ? 0x4 : 0;\n"
237                    "  tempRes |= " +
238                    op +
239                    "(valueEqual) ? 0x8 : 0x0;\n"
240                    "  tempRes |= " +
241                    op +
242                    "(gl_HelperInvocation) ? 0x0 : 0x1;\n"
243                    "  if (subgroupElect()) tempRes |= 0x2 | 0x10;\n" :
244                "";
245 }
246 
initFrameBufferProgramsFrag(SourceCollections & programCollection,CaseDefinition caseDef)247 void initFrameBufferProgramsFrag(SourceCollections &programCollection, CaseDefinition caseDef)
248 {
249 #ifndef CTS_USES_VULKANSC
250     const bool spirv14required = isAllRayTracingStages(caseDef.shaderStage);
251 #else
252     const bool spirv14required = false;
253 #endif // CTS_USES_VULKANSC
254     const SpirvVersion spirvVersion = spirv14required ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3;
255     const ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u);
256     const bool arbFunctions = caseDef.opType > OPTYPE_LAST_NON_ARB;
257     const string extensions = getExtensions(arbFunctions) + subgroups::getAdditionalExtensionForFormat(caseDef.format);
258 
259     DE_ASSERT(VK_SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage);
260 
261     {
262         const string vertex = "#version 450\n"
263                               "void main (void)\n"
264                               "{\n"
265                               "  vec2 uv = vec2(float(gl_VertexIndex & 1), float((gl_VertexIndex >> 1) & 1));\n"
266                               "  gl_Position = vec4(uv * 4.0f -2.0f, 0.0f, 1.0f);\n"
267                               "  gl_PointSize = 1.0f;\n"
268                               "}\n";
269 
270         programCollection.glslSources.add("vert") << glu::VertexSource(vertex) << buildOptions;
271     }
272 
273     {
274         ostringstream fragmentSource;
275 
276         fragmentSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
277                        << extensions << "layout(location = 0) out uint out_color;\n"
278                        << "layout(set = 0, binding = 0) uniform Buffer1\n"
279                        << "{\n"
280                        << "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data["
281                        << subgroups::maxSupportedSubgroupSize() << "];\n"
282                        << "};\n"
283                        << ""
284                        << "void main()\n"
285                        << "{\n"
286                        << "  uint tempRes = 0u;\n"
287                        << "  if (dFdx(gl_SubgroupInvocationID * gl_FragCoord.x * gl_FragCoord.y) - "
288                           "dFdy(gl_SubgroupInvocationID * gl_FragCoord.x * gl_FragCoord.y) > 0.0f)\n"
289                        << "  {\n"
290                        << "    tempRes |= 0x20;\n" // to be sure that compiler doesn't remove dFdx and dFdy executions
291                        << "  }\n"
292                        << (arbFunctions ? "  bool helper = anyInvocationARB(gl_HelperInvocation);\n" :
293                                           "  bool helper = subgroupAny(gl_HelperInvocation);\n")
294                        << "  if (helper)\n"
295                        << "  {\n"
296                        << "    tempRes |= 0x40;\n"
297                        << "  }\n"
298                        << getStageTestSourceFrag(caseDef) << "  out_color = tempRes;\n"
299                        << "}\n";
300 
301         programCollection.glslSources.add("fragment") << glu::FragmentSource(fragmentSource.str()) << buildOptions;
302     }
303 }
304 
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)305 void initPrograms(SourceCollections &programCollection, CaseDefinition caseDef)
306 {
307 #ifndef CTS_USES_VULKANSC
308     const bool spirv14required =
309         (isAllRayTracingStages(caseDef.shaderStage) || isAllMeshShadingStages(caseDef.shaderStage));
310 #else
311     const bool spirv14required = false;
312 #endif // CTS_USES_VULKANSC
313     const SpirvVersion spirvVersion = spirv14required ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3;
314     const ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, spirvVersion, 0u, spirv14required);
315     const bool arbFunctions = caseDef.opType > OPTYPE_LAST_NON_ARB;
316     const string extensions = getExtensions(arbFunctions) + subgroups::getAdditionalExtensionForFormat(caseDef.format);
317     const bool pointSize    = *caseDef.geometryPointSizeSupported;
318 
319     subgroups::initStdPrograms(programCollection, buildOptions, caseDef.shaderStage, caseDef.format, pointSize,
320                                extensions, getStageTestSource(caseDef), "");
321 }
322 
supportedCheck(Context & context,CaseDefinition caseDef)323 void supportedCheck(Context &context, CaseDefinition caseDef)
324 {
325     if (!subgroups::isSubgroupSupported(context))
326         TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
327 
328     if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_VOTE_BIT))
329     {
330         TCU_THROW(NotSupportedError, "Device does not support subgroup vote operations");
331     }
332 
333     if (!subgroups::isFormatSupportedForDevice(context, caseDef.format))
334         TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
335 
336     if (caseDef.requires16BitUniformBuffer)
337     {
338         if (!subgroups::is16BitUBOStorageSupported(context))
339         {
340             TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
341         }
342     }
343 
344     if (caseDef.requires8BitUniformBuffer)
345     {
346         if (!subgroups::is8BitUBOStorageSupported(context))
347         {
348             TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
349         }
350     }
351 
352     if (caseDef.opType > OPTYPE_LAST_NON_ARB)
353     {
354         context.requireDeviceFunctionality("VK_EXT_shader_subgroup_vote");
355     }
356 
357     if (caseDef.requiredSubgroupSize)
358     {
359         context.requireDeviceFunctionality("VK_EXT_subgroup_size_control");
360 
361 #ifndef CTS_USES_VULKANSC
362         const VkPhysicalDeviceSubgroupSizeControlFeatures &subgroupSizeControlFeatures =
363             context.getSubgroupSizeControlFeatures();
364         const VkPhysicalDeviceSubgroupSizeControlProperties &subgroupSizeControlProperties =
365             context.getSubgroupSizeControlProperties();
366 #else
367         const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT &subgroupSizeControlFeatures =
368             context.getSubgroupSizeControlFeaturesEXT();
369         const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT &subgroupSizeControlProperties =
370             context.getSubgroupSizeControlPropertiesEXT();
371 #endif // CTS_USES_VULKANSC
372 
373         if (subgroupSizeControlFeatures.subgroupSizeControl == false)
374             TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes nor required subgroup size");
375 
376         if (subgroupSizeControlFeatures.computeFullSubgroups == false)
377             TCU_THROW(NotSupportedError, "Device does not support full subgroups in compute shaders");
378 
379         if ((subgroupSizeControlProperties.requiredSubgroupSizeStages & caseDef.shaderStage) != caseDef.shaderStage)
380             TCU_THROW(NotSupportedError, "Required subgroup size is not supported for shader stage");
381     }
382 
383     *caseDef.geometryPointSizeSupported = subgroups::isTessellationAndGeometryPointSizeSupported(context);
384 
385 #ifndef CTS_USES_VULKANSC
386     if (isAllRayTracingStages(caseDef.shaderStage))
387     {
388         context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
389     }
390     else if (isAllMeshShadingStages(caseDef.shaderStage))
391     {
392         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
393         context.requireDeviceFunctionality("VK_EXT_mesh_shader");
394 
395         if ((caseDef.shaderStage & VK_SHADER_STAGE_TASK_BIT_EXT) != 0u)
396         {
397             const auto &features = context.getMeshShaderFeaturesEXT();
398             if (!features.taskShader)
399                 TCU_THROW(NotSupportedError, "Task shaders not supported");
400         }
401     }
402 
403 #endif // CTS_USES_VULKANSC
404 
405     subgroups::supportedCheckShader(context, caseDef.shaderStage);
406 }
407 
noSSBOtest(Context & context,const CaseDefinition caseDef)408 TestStatus noSSBOtest(Context &context, const CaseDefinition caseDef)
409 {
410     if (caseDef.opType > OPTYPE_LAST_NON_ARB)
411     {
412         context.requireDeviceFunctionality("VK_EXT_shader_subgroup_vote");
413     }
414 
415     const subgroups::SSBOData::InputDataInitializeType initializeType =
416         (OPTYPE_ALLEQUAL == caseDef.opType || OPTYPE_ALLEQUAL_ARB == caseDef.opType) ?
417             subgroups::SSBOData::InitializeZero :
418             subgroups::SSBOData::InitializeNonZero;
419     const subgroups::SSBOData inputData{
420         initializeType,                        //  InputDataInitializeType initializeType;
421         subgroups::SSBOData::LayoutStd140,     //  InputDataLayoutType layout;
422         caseDef.format,                        //  vk::VkFormat format;
423         subgroups::maxSupportedSubgroupSize(), //  vk::VkDeviceSize numElements;
424         subgroups::SSBOData::BindingUBO,       //  BindingType bindingType;
425     };
426 
427     switch (caseDef.shaderStage)
428     {
429     case VK_SHADER_STAGE_VERTEX_BIT:
430         return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL,
431                                                     checkVertexPipelineStages);
432     case VK_SHADER_STAGE_GEOMETRY_BIT:
433         return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL,
434                                                       checkVertexPipelineStages);
435     case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
436         return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL,
437                                                                     checkVertexPipelineStages, caseDef.shaderStage);
438     case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
439         return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL,
440                                                                     checkVertexPipelineStages, caseDef.shaderStage);
441     case VK_SHADER_STAGE_FRAGMENT_BIT:
442         return subgroups::makeFragmentFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL,
443                                                       checkFragmentPipelineStages);
444     default:
445         TCU_THROW(InternalError, "Unhandled shader stage");
446     }
447 }
448 
test(Context & context,const CaseDefinition caseDef)449 TestStatus test(Context &context, const CaseDefinition caseDef)
450 {
451     const subgroups::SSBOData::InputDataInitializeType initializeType =
452         (OPTYPE_ALLEQUAL == caseDef.opType || OPTYPE_ALLEQUAL_ARB == caseDef.opType) ?
453             subgroups::SSBOData::InitializeZero :
454             subgroups::SSBOData::InitializeNonZero;
455 
456     const bool isCompute = isAllComputeStages(caseDef.shaderStage);
457 #ifndef CTS_USES_VULKANSC
458     const bool isMesh = isAllMeshShadingStages(caseDef.shaderStage);
459 #else
460     const bool isMesh = false;
461 #endif // CTS_USES_VULKANSC
462     DE_ASSERT(!(isCompute && isMesh));
463 
464     if (isCompute || isMesh)
465     {
466 #ifndef CTS_USES_VULKANSC
467         const VkPhysicalDeviceSubgroupSizeControlProperties &subgroupSizeControlProperties =
468             context.getSubgroupSizeControlProperties();
469 #else
470         const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT &subgroupSizeControlProperties =
471             context.getSubgroupSizeControlPropertiesEXT();
472 #endif // CTS_USES_VULKANSC
473         TestLog &log = context.getTestContext().getLog();
474         const subgroups::SSBOData inputData{
475             initializeType,                        //  InputDataInitializeType initializeType;
476             subgroups::SSBOData::LayoutStd430,     //  InputDataLayoutType layout;
477             caseDef.format,                        //  vk::VkFormat format;
478             subgroups::maxSupportedSubgroupSize(), //  vk::VkDeviceSize numElements;
479         };
480 
481         if (caseDef.requiredSubgroupSize == false)
482         {
483             if (isCompute)
484                 return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL,
485                                                   checkComputeOrMesh);
486             else
487                 return subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkComputeOrMesh);
488         }
489 
490         log << TestLog::Message << "Testing required subgroup size range ["
491             << subgroupSizeControlProperties.minSubgroupSize << ", " << subgroupSizeControlProperties.maxSubgroupSize
492             << "]" << TestLog::EndMessage;
493 
494         // According to the spec, requiredSubgroupSize must be a power-of-two integer.
495         for (uint32_t size = subgroupSizeControlProperties.minSubgroupSize;
496              size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
497         {
498             TestStatus result(QP_TEST_RESULT_INTERNAL_ERROR, "Internal Error");
499 
500             if (isCompute)
501                 result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL,
502                                                     checkComputeOrMesh, size);
503             else
504                 result = subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL,
505                                                  checkComputeOrMesh, size);
506 
507             if (result.getCode() != QP_TEST_RESULT_PASS)
508             {
509                 log << TestLog::Message << "subgroupSize " << size << " failed" << TestLog::EndMessage;
510                 return result;
511             }
512         }
513 
514         return TestStatus::pass("OK");
515     }
516     else if (isAllGraphicsStages(caseDef.shaderStage))
517     {
518         const VkShaderStageFlags stages = subgroups::getPossibleGraphicsSubgroupStages(context, caseDef.shaderStage);
519         const subgroups::SSBOData inputData = {
520             initializeType,                        //  InputDataInitializeType initializeType;
521             subgroups::SSBOData::LayoutStd430,     //  InputDataLayoutType layout;
522             caseDef.format,                        //  vk::VkFormat format;
523             subgroups::maxSupportedSubgroupSize(), //  vk::VkDeviceSize numElements;
524             subgroups::SSBOData::BindingSSBO,      //  bool isImage;
525             4u,                                    //  uint32_t binding;
526             stages,                                //  vk::VkShaderStageFlags stages;
527         };
528 
529         return subgroups::allStages(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages,
530                                     stages);
531     }
532 #ifndef CTS_USES_VULKANSC
533     else if (isAllRayTracingStages(caseDef.shaderStage))
534     {
535         const VkShaderStageFlags stages = subgroups::getPossibleRayTracingSubgroupStages(context, caseDef.shaderStage);
536         const subgroups::SSBOData inputData = {
537             initializeType,                        //  InputDataInitializeType initializeType;
538             subgroups::SSBOData::LayoutStd430,     //  InputDataLayoutType layout;
539             caseDef.format,                        //  vk::VkFormat format;
540             subgroups::maxSupportedSubgroupSize(), //  vk::VkDeviceSize numElements;
541             subgroups::SSBOData::BindingSSBO,      //  bool isImage;
542             6u,                                    //  uint32_t binding;
543             stages,                                //  vk::VkShaderStageFlags stages;
544         };
545 
546         return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL,
547                                               checkVertexPipelineStages, stages);
548     }
549 #endif // CTS_USES_VULKANSC
550     else
551         TCU_THROW(InternalError, "Unknown stage or invalid stage set");
552 }
553 } // namespace
554 
555 namespace vkt
556 {
557 namespace subgroups
558 {
createSubgroupsVoteTests(TestContext & testCtx)559 TestCaseGroup *createSubgroupsVoteTests(TestContext &testCtx)
560 {
561     de::MovePtr<TestCaseGroup> group(new TestCaseGroup(testCtx, "vote"));
562     de::MovePtr<TestCaseGroup> graphicGroup(new TestCaseGroup(testCtx, "graphics"));
563     de::MovePtr<TestCaseGroup> computeGroup(new TestCaseGroup(testCtx, "compute"));
564     de::MovePtr<TestCaseGroup> framebufferGroup(new TestCaseGroup(testCtx, "framebuffer"));
565     de::MovePtr<TestCaseGroup> fragHelperGroup(new TestCaseGroup(testCtx, "frag_helper"));
566 #ifndef CTS_USES_VULKANSC
567     de::MovePtr<TestCaseGroup> raytracingGroup(new TestCaseGroup(testCtx, "ray_tracing"));
568     de::MovePtr<TestCaseGroup> meshGroup(new TestCaseGroup(testCtx, "mesh"));
569     de::MovePtr<TestCaseGroup> meshGroupARB(new TestCaseGroup(testCtx, "mesh"));
570 #endif // CTS_USES_VULKANSC
571 
572     de::MovePtr<TestCaseGroup> groupARB(new TestCaseGroup(testCtx, "ext_shader_subgroup_vote"));
573     de::MovePtr<TestCaseGroup> graphicGroupARB(new TestCaseGroup(testCtx, "graphics"));
574     de::MovePtr<TestCaseGroup> computeGroupARB(new TestCaseGroup(testCtx, "compute"));
575     de::MovePtr<TestCaseGroup> framebufferGroupARB(new TestCaseGroup(testCtx, "framebuffer"));
576     de::MovePtr<TestCaseGroup> fragHelperGroupARB(new TestCaseGroup(testCtx, "frag_helper"));
577     const bool boolValues[] = {false, true};
578 
579     {
580         const VkShaderStageFlags fbStages[] = {
581             VK_SHADER_STAGE_VERTEX_BIT,
582             VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
583             VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
584             VK_SHADER_STAGE_GEOMETRY_BIT,
585         };
586 #ifndef CTS_USES_VULKANSC
587         const VkShaderStageFlags meshStages[] = {
588             VK_SHADER_STAGE_MESH_BIT_EXT,
589             VK_SHADER_STAGE_TASK_BIT_EXT,
590         };
591 #endif // CTS_USES_VULKANSC
592         const vector<VkFormat> formats = subgroups::getAllFormats();
593 
594         for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
595         {
596             const VkFormat format           = formats[formatIndex];
597             const bool needs8BitUBOStorage  = isFormat8bitTy(format);
598             const bool needs16BitUBOStorage = isFormat16BitTy(format);
599             const bool formatIsNotVector    = format == VK_FORMAT_R8_USCALED || format == VK_FORMAT_R32_UINT ||
600                                            format == VK_FORMAT_R32_SINT || format == VK_FORMAT_R32_SFLOAT ||
601                                            format == VK_FORMAT_R64_SFLOAT;
602 
603             for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
604             {
605                 const OpType opType = static_cast<OpType>(opTypeIndex);
606 
607                 // Skip OPTYPE_LAST_NON_ARB because it is not a real op type.
608                 if (opType == OPTYPE_LAST_NON_ARB)
609                     continue;
610 
611                 // Skip the non-nonvector tests because VK_EXT_shader_subgroup_vote functions only supports boolean scalar arguments.
612                 if (opType > OPTYPE_LAST_NON_ARB && !formatIsNotVector)
613                     continue;
614 
615                 // Skip non-boolean formats when testing allInvocationsEqualARB(bool value), because it requires a boolean
616                 // argument that should have the same value for all invocations. For the rest of formats, it won't be a boolean argument,
617                 // so it may give wrong results when converting to bool.
618                 if (opType == OPTYPE_ALLEQUAL_ARB && format != VK_FORMAT_R8_USCALED)
619                     continue;
620 
621                 // Skip the typed tests for all but subgroupAllEqual() and allInvocationsEqualARB()
622                 if ((VK_FORMAT_R32_UINT != format) && (OPTYPE_ALLEQUAL != opType) && (OPTYPE_ALLEQUAL_ARB != opType))
623                 {
624                     continue;
625                 }
626 
627                 const string op                    = de::toLower(getOpTypeName(opType));
628                 const string name                  = op + "_" + subgroups::getFormatNameForGLSL(format);
629                 const bool opNonARB                = (opType < OPTYPE_LAST_NON_ARB);
630                 TestCaseGroup *computeGroupPtr     = opNonARB ? computeGroup.get() : computeGroupARB.get();
631                 TestCaseGroup *graphicGroupPtr     = opNonARB ? graphicGroup.get() : graphicGroupARB.get();
632                 TestCaseGroup *framebufferGroupPtr = opNonARB ? framebufferGroup.get() : framebufferGroupARB.get();
633                 TestCaseGroup *fragHelperGroupPtr  = opNonARB ? fragHelperGroup.get() : fragHelperGroupARB.get();
634 #ifndef CTS_USES_VULKANSC
635                 TestCaseGroup *meshGroupPtr = opNonARB ? meshGroup.get() : meshGroupARB.get();
636 #endif // CTS_USES_VULKANSC
637 
638                 for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
639                 {
640                     const bool requiredSubgroupSize = boolValues[groupSizeNdx];
641                     const string testName           = name + (requiredSubgroupSize ? "_requiredsubgroupsize" : "");
642                     const CaseDefinition caseDef    = {
643                         opType,                        //  OpType opType;
644                         VK_SHADER_STAGE_COMPUTE_BIT,   //  VkShaderStageFlags shaderStage;
645                         format,                        //  VkFormat format;
646                         de::SharedPtr<bool>(new bool), //  de::SharedPtr<bool> geometryPointSizeSupported;
647                         requiredSubgroupSize,          //  bool requiredSubgroupSize;
648                         bool(false),                   //  bool requires8BitUniformBuffer;
649                         bool(false)                    //  bool requires16BitUniformBuffer;
650                     };
651 
652                     addFunctionCaseWithPrograms(computeGroupPtr, testName, supportedCheck, initPrograms, test, caseDef);
653                 }
654 
655 #ifndef CTS_USES_VULKANSC
656                 for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
657                 {
658                     for (const auto &stage : meshStages)
659                     {
660                         const bool requiredSubgroupSize = boolValues[groupSizeNdx];
661                         const string testName = name + (requiredSubgroupSize ? "_requiredsubgroupsize" : "") + "_" +
662                                                 getShaderStageName(stage);
663                         const CaseDefinition caseDef = {
664                             opType,                        //  OpType opType;
665                             stage,                         //  VkShaderStageFlags shaderStage;
666                             format,                        //  VkFormat format;
667                             de::SharedPtr<bool>(new bool), //  de::SharedPtr<bool> geometryPointSizeSupported;
668                             requiredSubgroupSize,          //  bool requiredSubgroupSize;
669                             bool(false),                   //  bool requires8BitUniformBuffer;
670                             bool(false)                    //  bool requires16BitUniformBuffer;
671                         };
672 
673                         addFunctionCaseWithPrograms(meshGroupPtr, testName, supportedCheck, initPrograms, test,
674                                                     caseDef);
675                     }
676                 }
677 #endif // CTS_USES_VULKANSC
678 
679                 {
680                     const CaseDefinition caseDef = {
681                         opType,                        //  OpType opType;
682                         VK_SHADER_STAGE_ALL_GRAPHICS,  //  VkShaderStageFlags shaderStage;
683                         format,                        //  VkFormat format;
684                         de::SharedPtr<bool>(new bool), //  de::SharedPtr<bool> geometryPointSizeSupported;
685                         false,                         //  bool requiredSubgroupSize;
686                         bool(false),                   //  bool requires8BitUniformBuffer;
687                         bool(false)                    //  bool requires16BitUniformBuffer;
688                     };
689 
690                     addFunctionCaseWithPrograms(graphicGroupPtr, name, supportedCheck, initPrograms, test, caseDef);
691                 }
692 
693                 for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(fbStages); ++stageIndex)
694                 {
695                     const CaseDefinition caseDef = {
696                         opType,                        //  OpType opType;
697                         fbStages[stageIndex],          //  VkShaderStageFlags shaderStage;
698                         format,                        //  VkFormat format;
699                         de::SharedPtr<bool>(new bool), //  de::SharedPtr<bool> geometryPointSizeSupported;
700                         false,                         //  bool requiredSubgroupSize;
701                         bool(needs8BitUBOStorage),     //  bool requires8BitUniformBuffer;
702                         bool(needs16BitUBOStorage)     //  bool requires16BitUniformBuffer;
703                     };
704                     const string testName = name + "_" + getShaderStageName(caseDef.shaderStage);
705 
706                     addFunctionCaseWithPrograms(framebufferGroupPtr, testName, supportedCheck, initFrameBufferPrograms,
707                                                 noSSBOtest, caseDef);
708                 }
709 
710                 {
711                     const CaseDefinition caseDef = {
712                         opType,                        //  OpType opType;
713                         VK_SHADER_STAGE_FRAGMENT_BIT,  //  VkShaderStageFlags shaderStage;
714                         format,                        //  VkFormat format;
715                         de::SharedPtr<bool>(new bool), //  de::SharedPtr<bool> geometryPointSizeSupported;
716                         false,                         //  bool requiredSubgroupSize;
717                         bool(needs8BitUBOStorage),     //  bool requires8BitUniformBuffer;
718                         bool(needs16BitUBOStorage)     //  bool requires16BitUniformBuffer;
719                     };
720                     const string testName = name + "_" + getShaderStageName(caseDef.shaderStage);
721 
722                     addFunctionCaseWithPrograms(fragHelperGroupPtr, testName, supportedCheck,
723                                                 initFrameBufferProgramsFrag, noSSBOtest, caseDef);
724                 }
725             }
726         }
727     }
728 
729 #ifndef CTS_USES_VULKANSC
730     {
731         const vector<VkFormat> formats = subgroups::getAllRayTracingFormats();
732 
733         for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
734         {
735             const VkFormat format = formats[formatIndex];
736 
737             for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST_NON_ARB; ++opTypeIndex)
738             {
739                 const OpType opType = static_cast<OpType>(opTypeIndex);
740 
741                 // Skip the typed tests for all but subgroupAllEqual()
742                 if ((VK_FORMAT_R32_UINT != format) && (OPTYPE_ALLEQUAL != opType))
743                 {
744                     continue;
745                 }
746 
747                 const string op              = de::toLower(getOpTypeName(opType));
748                 const string name            = op + "_" + subgroups::getFormatNameForGLSL(format);
749                 const CaseDefinition caseDef = {
750                     opType,                        //  OpType opType;
751                     SHADER_STAGE_ALL_RAY_TRACING,  //  VkShaderStageFlags shaderStage;
752                     format,                        //  VkFormat format;
753                     de::SharedPtr<bool>(new bool), //  de::SharedPtr<bool> geometryPointSizeSupported;
754                     false,                         //  bool requiredSubgroupSize;
755                     false,                         //  bool requires8BitUniformBuffer;
756                     false                          //  bool requires16BitUniformBuffer;
757                 };
758 
759                 addFunctionCaseWithPrograms(raytracingGroup.get(), name, supportedCheck, initPrograms, test, caseDef);
760             }
761         }
762     }
763 #endif // CTS_USES_VULKANSC
764 
765     groupARB->addChild(graphicGroupARB.release());
766     groupARB->addChild(computeGroupARB.release());
767     groupARB->addChild(framebufferGroupARB.release());
768     groupARB->addChild(fragHelperGroupARB.release());
769 
770     group->addChild(graphicGroup.release());
771     group->addChild(computeGroup.release());
772     group->addChild(framebufferGroup.release());
773     group->addChild(fragHelperGroup.release());
774 #ifndef CTS_USES_VULKANSC
775     group->addChild(raytracingGroup.release());
776     group->addChild(meshGroup.release());
777     groupARB->addChild(meshGroupARB.release());
778 #endif // CTS_USES_VULKANSC
779 
780     group->addChild(groupARB.release());
781 
782     return group.release();
783 }
784 
785 } // namespace subgroups
786 } // namespace vkt
787