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