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 "vktSubgroupsShuffleTests.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_SHUFFLE = 0,
42 OPTYPE_SHUFFLE_XOR,
43 OPTYPE_SHUFFLE_UP,
44 OPTYPE_SHUFFLE_DOWN,
45 OPTYPE_LAST
46 };
47
48 // For the second arguments of Xor, Up and Down.
49 enum class ArgType
50 {
51 DYNAMIC = 0,
52 DYNAMICALLY_UNIFORM,
53 CONSTANT
54 };
55
56 struct CaseDefinition
57 {
58 OpType opType;
59 VkShaderStageFlags shaderStage;
60 VkFormat format;
61 de::SharedPtr<bool> geometryPointSizeSupported;
62 deBool requiredSubgroupSize;
63 ArgType argType;
64 deBool requires8BitUniformBuffer;
65 deBool requires16BitUniformBuffer;
66 };
67
checkVertexPipelineStages(const void* internalData, vector<const void*> datas, deUint32 width, deUint32)68 static bool checkVertexPipelineStages (const void* internalData,
69 vector<const void*> datas,
70 deUint32 width,
71 deUint32)
72 {
73 DE_UNREF(internalData);
74
75 return subgroups::check(datas, width, 1);
76 }
77
checkComputeOrMesh(const void* internalData, vector<const void*> datas, const deUint32 numWorkgroups[3], const deUint32 localSize[3], deUint32)78 static bool checkComputeOrMesh (const void* internalData,
79 vector<const void*> datas,
80 const deUint32 numWorkgroups[3],
81 const deUint32 localSize[3],
82 deUint32)
83 {
84 DE_UNREF(internalData);
85
86 return subgroups::checkComputeOrMesh(datas, numWorkgroups, localSize, 1);
87 }
88
getOpTypeName(OpType opType)89 string getOpTypeName (OpType opType)
90 {
91 switch (opType)
92 {
93 case OPTYPE_SHUFFLE: return "subgroupShuffle";
94 case OPTYPE_SHUFFLE_XOR: return "subgroupShuffleXor";
95 case OPTYPE_SHUFFLE_UP: return "subgroupShuffleUp";
96 case OPTYPE_SHUFFLE_DOWN: return "subgroupShuffleDown";
97 default: TCU_THROW(InternalError, "Unsupported op type");
98 }
99 }
100
getExtHeader(const CaseDefinition& caseDef)101 string getExtHeader (const CaseDefinition& caseDef)
102 {
103 const string eSource = (OPTYPE_SHUFFLE == caseDef.opType || OPTYPE_SHUFFLE_XOR == caseDef.opType)
104 ? "#extension GL_KHR_shader_subgroup_shuffle: enable\n"
105 : "#extension GL_KHR_shader_subgroup_shuffle_relative: enable\n";
106
107 return eSource
108 + "#extension GL_KHR_shader_subgroup_ballot: enable\n"
109 + subgroups::getAdditionalExtensionForFormat(caseDef.format);
110 }
111
getPerStageHeadDeclarations(const CaseDefinition& caseDef)112 vector<string> getPerStageHeadDeclarations (const CaseDefinition& caseDef)
113 {
114 const string formatName = subgroups::getFormatNameForGLSL(caseDef.format);
115 const deUint32 stageCount = subgroups::getStagesCount(caseDef.shaderStage);
116 const bool fragment = (caseDef.shaderStage & VK_SHADER_STAGE_FRAGMENT_BIT) != 0;
117 const size_t resultSize = stageCount + (fragment ? 1 : 0);
118 vector<string> result (resultSize, string());
119
120 for (deUint32 i = 0; i < result.size(); ++i)
121 {
122 const deUint32 binding0 = i;
123 const deUint32 binding1 = stageCount;
124 const deUint32 binding2 = stageCount + 1;
125 const string buffer1 = (i == stageCount)
126 ? "layout(location = 0) out uint result;\n"
127 : "layout(set = 0, binding = " + de::toString(binding0) + ", std430) buffer Buffer1\n"
128 "{\n"
129 " uint result[];\n"
130 "};\n";
131
132 const string b2Layout = ((caseDef.argType == ArgType::DYNAMIC) ? "std430" : "std140");
133 const string b2Type = ((caseDef.argType == ArgType::DYNAMIC) ? "readonly buffer" : "uniform");
134
135 result[i] =
136 buffer1 +
137 "layout(set = 0, binding = " + de::toString(binding1) + ", std430) readonly buffer Buffer2\n"
138 "{\n"
139 " " + formatName + " data1[];\n"
140 "};\n"
141 "layout(set = 0, binding = " + de::toString(binding2) + ", " + b2Layout + ") " + b2Type + " Buffer3\n"
142 "{\n"
143 " uint data2[];\n"
144 "};\n";
145 }
146
147 return result;
148 }
149
getFramebufferPerStageHeadDeclarations(const CaseDefinition& caseDef)150 vector<string> getFramebufferPerStageHeadDeclarations (const CaseDefinition& caseDef)
151 {
152 const string formatName = subgroups::getFormatNameForGLSL(caseDef.format);
153 const deUint32 stageCount = subgroups::getStagesCount(caseDef.shaderStage);
154 vector<string> result (stageCount, string());
155 const auto b2Len = ((caseDef.argType == ArgType::DYNAMIC) ? subgroups::maxSupportedSubgroupSize() : 1u);
156 const string buffer2
157 {
158 "layout(set = 0, binding = 0) uniform Buffer1\n"
159 "{\n"
160 " " + formatName + " data1[" + de::toString(subgroups::maxSupportedSubgroupSize()) + "];\n"
161 "};\n"
162 "layout(set = 0, binding = 1) uniform Buffer2\n"
163 "{\n"
164 " uint data2[" + de::toString(b2Len) + "];\n"
165 "};\n"
166 };
167
168 for (size_t i = 0; i < result.size(); ++i)
169 {
170 switch (i)
171 {
172 case 0: result[i] = "layout(location = 0) out float result;\n" + buffer2; break;
173 case 1: result[i] = "layout(location = 0) out float out_color;\n" + buffer2; break;
174 case 2: result[i] = "layout(location = 0) out float out_color[];\n" + buffer2; break;
175 case 3: result[i] = "layout(location = 0) out float out_color;\n" + buffer2; break;
176 default: TCU_THROW(InternalError, "Unknown stage");
177 }
178 }
179
180 return result;
181 }
182
getTestSource(const CaseDefinition& caseDef)183 const string getTestSource (const CaseDefinition& caseDef)
184 {
185 const string id = caseDef.opType == OPTYPE_SHUFFLE ? "id_in"
186 : caseDef.opType == OPTYPE_SHUFFLE_XOR ? "gl_SubgroupInvocationID ^ id_in"
187 : caseDef.opType == OPTYPE_SHUFFLE_UP ? "gl_SubgroupInvocationID - id_in"
188 : caseDef.opType == OPTYPE_SHUFFLE_DOWN ? "gl_SubgroupInvocationID + id_in"
189 : "";
190 const string idInSource = caseDef.argType == ArgType::DYNAMIC ? "data2[gl_SubgroupInvocationID] & (gl_SubgroupSize - 1)"
191 : caseDef.argType == ArgType::DYNAMICALLY_UNIFORM ? "data2[0] % 32"
192 : caseDef.argType == ArgType::CONSTANT ? "5"
193 : "";
194 const string testSource =
195 " uint temp_res;\n"
196 " uvec4 mask = subgroupBallot(true);\n"
197 " uint id_in = " + idInSource + ";\n"
198 " " + subgroups::getFormatNameForGLSL(caseDef.format) + " op = "
199 + getOpTypeName(caseDef.opType) + "(data1[gl_SubgroupInvocationID], id_in);\n"
200 " uint id = " + id + ";\n"
201 " if ((id < gl_SubgroupSize) && subgroupBallotBitExtract(mask, id))\n"
202 " {\n"
203 " temp_res = (op == data1[id]) ? 1 : 0;\n"
204 " }\n"
205 " else\n"
206 " {\n"
207 " temp_res = 1; // Invocation we read from was inactive, so we can't verify results!\n"
208 " }\n"
209 " tempRes = temp_res;\n";
210
211 return testSource;
212 }
213
initFrameBufferPrograms(SourceCollections& programCollection, CaseDefinition caseDef)214 void initFrameBufferPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
215 {
216 const ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, SPIRV_VERSION_1_3, 0u);
217 const string extHeader = getExtHeader(caseDef);
218 const string testSrc = getTestSource(caseDef);
219 const vector<string> headDeclarations = getFramebufferPerStageHeadDeclarations(caseDef);
220 const bool pointSizeSupported = *caseDef.geometryPointSizeSupported;
221
222 subgroups::initStdFrameBufferPrograms(programCollection, buildOptions, caseDef.shaderStage, VK_FORMAT_R32_UINT, pointSizeSupported, extHeader, testSrc, "", headDeclarations);
223 }
224
initPrograms(SourceCollections& programCollection, CaseDefinition caseDef)225 void initPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
226 {
227 #ifndef CTS_USES_VULKANSC
228 const bool spirv14required = (isAllRayTracingStages(caseDef.shaderStage) || isAllMeshShadingStages(caseDef.shaderStage));
229 #else
230 const bool spirv14required = false;
231 #endif // CTS_USES_VULKANSC
232 const SpirvVersion spirvVersion = spirv14required ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3;
233 const ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, spirvVersion, 0u, spirv14required);
234 const string extHeader = getExtHeader(caseDef);
235 const string testSrc = getTestSource(caseDef);
236 const vector<string> headDeclarations = getPerStageHeadDeclarations(caseDef);
237 const bool pointSizeSupported = *caseDef.geometryPointSizeSupported;
238
239 subgroups::initStdPrograms(programCollection, buildOptions, caseDef.shaderStage, VK_FORMAT_R32_UINT, pointSizeSupported, extHeader, testSrc, "", headDeclarations);
240 }
241
supportedCheck(Context& context, CaseDefinition caseDef)242 void supportedCheck (Context& context, CaseDefinition caseDef)
243 {
244 if (!subgroups::isSubgroupSupported(context))
245 TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
246
247 switch (caseDef.opType)
248 {
249 case OPTYPE_SHUFFLE:
250 case OPTYPE_SHUFFLE_XOR:
251 if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_SHUFFLE_BIT))
252 {
253 TCU_THROW(NotSupportedError, "Device does not support subgroup shuffle operations");
254 }
255 break;
256 default:
257 if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT))
258 {
259 TCU_THROW(NotSupportedError, "Device does not support subgroup shuffle relative operations");
260 }
261 break;
262 }
263
264 if (!subgroups::isFormatSupportedForDevice(context, caseDef.format))
265 TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
266
267 if (caseDef.requires16BitUniformBuffer)
268 {
269 if (!subgroups::is16BitUBOStorageSupported(context))
270 {
271 TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
272 }
273 }
274
275 if (caseDef.requires8BitUniformBuffer)
276 {
277 if (!subgroups::is8BitUBOStorageSupported(context))
278 {
279 TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
280 }
281 }
282
283 if (caseDef.requiredSubgroupSize)
284 {
285 context.requireDeviceFunctionality("VK_EXT_subgroup_size_control");
286
287 #ifndef CTS_USES_VULKANSC
288 const VkPhysicalDeviceSubgroupSizeControlFeatures& subgroupSizeControlFeatures = context.getSubgroupSizeControlFeatures();
289 const VkPhysicalDeviceSubgroupSizeControlProperties& subgroupSizeControlProperties = context.getSubgroupSizeControlProperties();
290 #else
291 const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT& subgroupSizeControlFeatures = context.getSubgroupSizeControlFeaturesEXT();
292 const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT& subgroupSizeControlProperties = context.getSubgroupSizeControlPropertiesEXT();
293 #endif // CTS_USES_VULKANSC
294
295 if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
296 TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes nor required subgroup size");
297
298 if (subgroupSizeControlFeatures.computeFullSubgroups == DE_FALSE)
299 TCU_THROW(NotSupportedError, "Device does not support full subgroups in compute shaders");
300
301 if ((subgroupSizeControlProperties.requiredSubgroupSizeStages & caseDef.shaderStage) != caseDef.shaderStage)
302 TCU_THROW(NotSupportedError, "Required subgroup size is not supported for shader stage");
303 }
304
305 *caseDef.geometryPointSizeSupported = subgroups::isTessellationAndGeometryPointSizeSupported(context);
306
307 #ifndef CTS_USES_VULKANSC
308 if (isAllRayTracingStages(caseDef.shaderStage))
309 {
310 context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
311 }
312 else if (isAllMeshShadingStages(caseDef.shaderStage))
313 {
314 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
315 context.requireDeviceFunctionality("VK_EXT_mesh_shader");
316
317 if ((caseDef.shaderStage & VK_SHADER_STAGE_TASK_BIT_EXT) != 0u)
318 {
319 const auto& features = context.getMeshShaderFeaturesEXT();
320 if (!features.taskShader)
321 TCU_THROW(NotSupportedError, "Task shaders not supported");
322 }
323 }
324 #endif // CTS_USES_VULKANSC
325
326 subgroups::supportedCheckShader(context, caseDef.shaderStage);
327 }
328
noSSBOtest(Context& context, const CaseDefinition caseDef)329 TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
330 {
331 const VkDeviceSize secondBufferSize = ((caseDef.argType == ArgType::DYNAMIC) ? subgroups::maxSupportedSubgroupSize() : 1u);
332 const subgroups::SSBOData inputData[2]
333 {
334 {
335 subgroups::SSBOData::InitializeNonZero, // InputDataInitializeType initializeType;
336 subgroups::SSBOData::LayoutStd140, // InputDataLayoutType layout;
337 caseDef.format, // vk::VkFormat format;
338 subgroups::maxSupportedSubgroupSize(), // vk::VkDeviceSize numElements;
339 subgroups::SSBOData::BindingUBO, // BindingType bindingType;
340 },
341 {
342 subgroups::SSBOData::InitializeNonZero, // InputDataInitializeType initializeType;
343 subgroups::SSBOData::LayoutStd140, // InputDataLayoutType layout;
344 VK_FORMAT_R32_UINT, // vk::VkFormat format;
345 secondBufferSize, // vk::VkDeviceSize numElements;
346 subgroups::SSBOData::BindingUBO, // BindingType bindingType;
347 }
348 };
349
350 switch (caseDef.shaderStage)
351 {
352 case VK_SHADER_STAGE_VERTEX_BIT: return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages);
353 case VK_SHADER_STAGE_GEOMETRY_BIT: return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages);
354 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
355 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
356 default: TCU_THROW(InternalError, "Unhandled shader stage");
357 }
358 }
359
test(Context& context, const CaseDefinition caseDef)360 TestStatus test (Context& context, const CaseDefinition caseDef)
361 {
362 const auto secondBufferLayout = ((caseDef.argType == ArgType::DYNAMIC)
363 ? subgroups::SSBOData::LayoutStd430
364 : subgroups::SSBOData::LayoutStd140);
365 const VkDeviceSize secondBufferElems = ((caseDef.argType == ArgType::DYNAMIC)
366 ? subgroups::maxSupportedSubgroupSize()
367 : 1u);
368 const auto secondBufferType = ((caseDef.argType == ArgType::DYNAMIC)
369 ? subgroups::SSBOData::BindingSSBO
370 : subgroups::SSBOData::BindingUBO);
371
372 const bool isCompute = isAllComputeStages(caseDef.shaderStage);
373 #ifndef CTS_USES_VULKANSC
374 const bool isMesh = isAllMeshShadingStages(caseDef.shaderStage);
375 #else
376 const bool isMesh = false;
377 #endif // CTS_USES_VULKANSC
378 DE_ASSERT(!(isCompute && isMesh));
379
380 if (isCompute || isMesh)
381 {
382 #ifndef CTS_USES_VULKANSC
383 const VkPhysicalDeviceSubgroupSizeControlProperties& subgroupSizeControlProperties = context.getSubgroupSizeControlProperties();
384 #else
385 const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT& subgroupSizeControlProperties = context.getSubgroupSizeControlPropertiesEXT();
386 #endif // CTS_USES_VULKANSC
387 TestLog& log = context.getTestContext().getLog();
388 const subgroups::SSBOData inputData[2]
389 {
390 {
391 subgroups::SSBOData::InitializeNonZero, // InputDataInitializeType initializeType;
392 subgroups::SSBOData::LayoutStd430, // InputDataLayoutType layout;
393 caseDef.format, // vk::VkFormat format;
394 subgroups::maxSupportedSubgroupSize(), // vk::VkDeviceSize numElements;
395 },
396 {
397 subgroups::SSBOData::InitializeNonZero, // InputDataInitializeType initializeType;
398 secondBufferLayout, // InputDataLayoutType layout;
399 VK_FORMAT_R32_UINT, // vk::VkFormat format;
400 secondBufferElems, // vk::VkDeviceSize numElements;
401 secondBufferType,
402 },
403 };
404
405 if (caseDef.requiredSubgroupSize == DE_FALSE)
406 {
407 if (isCompute)
408 return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkComputeOrMesh);
409 else
410 return subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkComputeOrMesh);
411 }
412
413 log << TestLog::Message << "Testing required subgroup size range [" << subgroupSizeControlProperties.minSubgroupSize << ", "
414 << subgroupSizeControlProperties.maxSubgroupSize << "]" << TestLog::EndMessage;
415
416 // According to the spec, requiredSubgroupSize must be a power-of-two integer.
417 for (deUint32 size = subgroupSizeControlProperties.minSubgroupSize; size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
418 {
419 TestStatus result (QP_TEST_RESULT_INTERNAL_ERROR, "Internal Error");
420
421 if (isCompute)
422 result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkComputeOrMesh, size);
423 else
424 result = subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkComputeOrMesh, size);
425
426 if (result.getCode() != QP_TEST_RESULT_PASS)
427 {
428 log << TestLog::Message << "subgroupSize " << size << " failed" << TestLog::EndMessage;
429 return result;
430 }
431 }
432
433 return TestStatus::pass("OK");
434 }
435 else if (isAllGraphicsStages(caseDef.shaderStage))
436 {
437 const VkShaderStageFlags stages = subgroups::getPossibleGraphicsSubgroupStages(context, caseDef.shaderStage);
438 const subgroups::SSBOData inputData[2]
439 {
440 {
441 subgroups::SSBOData::InitializeNonZero, // InputDataInitializeType initializeType;
442 subgroups::SSBOData::LayoutStd430, // InputDataLayoutType layout;
443 caseDef.format, // vk::VkFormat format;
444 subgroups::maxSupportedSubgroupSize(), // vk::VkDeviceSize numElements;
445 subgroups::SSBOData::BindingSSBO, // bool isImage;
446 4u, // deUint32 binding;
447 stages, // vk::VkShaderStageFlags stages;
448 },
449 {
450 subgroups::SSBOData::InitializeNonZero, // InputDataInitializeType initializeType;
451 secondBufferLayout, // InputDataLayoutType layout;
452 VK_FORMAT_R32_UINT, // vk::VkFormat format;
453 secondBufferElems, // vk::VkDeviceSize numElements;
454 secondBufferType, // bool isImage;
455 5u, // deUint32 binding;
456 stages, // vk::VkShaderStageFlags stages;
457 },
458 };
459
460 return subgroups::allStages(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages, stages);
461 }
462 #ifndef CTS_USES_VULKANSC
463 else if (isAllRayTracingStages(caseDef.shaderStage))
464 {
465 const VkShaderStageFlags stages = subgroups::getPossibleRayTracingSubgroupStages(context, caseDef.shaderStage);
466 const subgroups::SSBOData inputData[2]
467 {
468 {
469 subgroups::SSBOData::InitializeNonZero, // InputDataInitializeType initializeType;
470 subgroups::SSBOData::LayoutStd430, // InputDataLayoutType layout;
471 caseDef.format, // vk::VkFormat format;
472 subgroups::maxSupportedSubgroupSize(), // vk::VkDeviceSize numElements;
473 subgroups::SSBOData::BindingSSBO, // bool isImage;
474 6u, // deUint32 binding;
475 stages, // vk::VkShaderStageFlags stages;
476 },
477 {
478 subgroups::SSBOData::InitializeNonZero, // InputDataInitializeType initializeType;
479 secondBufferLayout, // InputDataLayoutType layout;
480 VK_FORMAT_R32_UINT, // vk::VkFormat format;
481 secondBufferElems, // vk::VkDeviceSize numElements;
482 secondBufferType, // bool isImage;
483 7u, // deUint32 binding;
484 stages, // vk::VkShaderStageFlags stages;
485 },
486 };
487
488 return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages, stages);
489 }
490 #endif // CTS_USES_VULKANSC
491 else
492 TCU_THROW(InternalError, "Unknown stage or invalid stage set");
493 }
494 }
495
496 namespace vkt
497 {
498 namespace subgroups
499 {
createSubgroupsShuffleTests(TestContext& testCtx)500 TestCaseGroup* createSubgroupsShuffleTests (TestContext& testCtx)
501 {
502 de::MovePtr<TestCaseGroup> group (new TestCaseGroup(testCtx, "shuffle", "Subgroup shuffle category tests"));
503
504 de::MovePtr<TestCaseGroup> graphicGroup (new TestCaseGroup(testCtx, "graphics", "Subgroup shuffle category tests: graphics"));
505 de::MovePtr<TestCaseGroup> computeGroup (new TestCaseGroup(testCtx, "compute", "Subgroup shuffle category tests: compute"));
506 de::MovePtr<TestCaseGroup> framebufferGroup (new TestCaseGroup(testCtx, "framebuffer", "Subgroup shuffle category tests: framebuffer"));
507 #ifndef CTS_USES_VULKANSC
508 de::MovePtr<TestCaseGroup> raytracingGroup (new TestCaseGroup(testCtx, "ray_tracing", "Subgroup shuffle category tests: ray tracing"));
509 de::MovePtr<TestCaseGroup> meshGroup (new TestCaseGroup(testCtx, "mesh", "Subgroup shuffle category tests: mesh shading"));
510 #endif // CTS_USES_VULKANSC
511
512 const VkShaderStageFlags fbStages[] =
513 {
514 VK_SHADER_STAGE_VERTEX_BIT,
515 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
516 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
517 VK_SHADER_STAGE_GEOMETRY_BIT,
518 };
519
520 #ifndef CTS_USES_VULKANSC
521 const VkShaderStageFlags meshStages[] =
522 {
523 VK_SHADER_STAGE_MESH_BIT_EXT,
524 VK_SHADER_STAGE_TASK_BIT_EXT,
525 };
526 #endif // CTS_USES_VULKANSC
527
528 const deBool boolValues[] =
529 {
530 DE_FALSE,
531 DE_TRUE
532 };
533
534 const struct
535 {
536 ArgType argType;
537 const char* suffix;
538 } argCases[] =
539 {
540 { ArgType::DYNAMIC, "" },
541 { ArgType::DYNAMICALLY_UNIFORM, "_dynamically_uniform" },
542 { ArgType::CONSTANT, "_constant" },
543 };
544
545 {
546 const vector<VkFormat> formats = subgroups::getAllFormats();
547
548 for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
549 {
550 const VkFormat format = formats[formatIndex];
551 const string formatName = subgroups::getFormatNameForGLSL(format);
552 const bool needs8BitUBOStorage = isFormat8bitTy(format);
553 const bool needs16BitUBOStorage = isFormat16BitTy(format);
554
555 for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
556 {
557 for (const auto& argCase : argCases)
558 {
559 const OpType opType = static_cast<OpType>(opTypeIndex);
560
561 if (opType == OPTYPE_SHUFFLE && argCase.argType != ArgType::DYNAMIC)
562 continue;
563
564 const string name = de::toLower(getOpTypeName(opType)) + "_" + formatName + argCase.suffix;
565
566 {
567 const CaseDefinition caseDef =
568 {
569 opType, // OpType opType;
570 VK_SHADER_STAGE_ALL_GRAPHICS, // VkShaderStageFlags shaderStage;
571 format, // VkFormat format;
572 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
573 DE_FALSE, // deBool requiredSubgroupSize;
574 argCase.argType, // ArgType argType;
575 DE_FALSE, // deBool requires8BitUniformBuffer;
576 DE_FALSE // deBool requires16BitUniformBuffer;
577 };
578
579 addFunctionCaseWithPrograms(graphicGroup.get(), name, supportedCheck, initPrograms, test, caseDef);
580 }
581
582 for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
583 {
584 const deBool requiredSubgroupSize = boolValues[groupSizeNdx];
585 const string testName = name + (requiredSubgroupSize ? "_requiredsubgroupsize" : "");
586 const CaseDefinition caseDef =
587 {
588 opType, // OpType opType;
589 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlags shaderStage;
590 format, // VkFormat format;
591 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
592 requiredSubgroupSize, // deBool requiredSubgroupSize;
593 argCase.argType, // ArgType argType;
594 DE_FALSE, // deBool requires8BitUniformBuffer;
595 DE_FALSE // deBool requires16BitUniformBuffer;
596 };
597
598 addFunctionCaseWithPrograms(computeGroup.get(), testName,supportedCheck, initPrograms, test, caseDef);
599 }
600
601 #ifndef CTS_USES_VULKANSC
602 for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
603 {
604 for (const auto& stage : meshStages)
605 {
606 const deBool requiredSubgroupSize = boolValues[groupSizeNdx];
607 const string testName = name + (requiredSubgroupSize ? "_requiredsubgroupsize" : "") + "_" + getShaderStageName(stage);
608 const CaseDefinition caseDef =
609 {
610 opType, // OpType opType;
611 stage, // VkShaderStageFlags shaderStage;
612 format, // VkFormat format;
613 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
614 requiredSubgroupSize, // deBool requiredSubgroupSize;
615 argCase.argType, // ArgType argType;
616 DE_FALSE, // deBool requires8BitUniformBuffer;
617 DE_FALSE, // deBool requires16BitUniformBuffer;
618 };
619
620 addFunctionCaseWithPrograms(meshGroup.get(), testName,supportedCheck, initPrograms, test, caseDef);
621 }
622 }
623 #endif // CTS_USES_VULKANSC
624
625 for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(fbStages); ++stageIndex)
626 {
627 const CaseDefinition caseDef =
628 {
629 opType, // OpType opType;
630 fbStages[stageIndex], // VkShaderStageFlags shaderStage;
631 format, // VkFormat format;
632 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
633 DE_FALSE, // deBool requiredSubgroupSize;
634 argCase.argType, // ArgType argType;
635 deBool(needs8BitUBOStorage), // deBool requires8BitUniformBuffer;
636 deBool(needs16BitUBOStorage) // deBool requires16BitUniformBuffer;
637 };
638 const string testName = name + "_" + getShaderStageName(caseDef.shaderStage);
639
640 addFunctionCaseWithPrograms(framebufferGroup.get(), testName,supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
641 }
642 }
643 }
644 }
645 }
646
647 #ifndef CTS_USES_VULKANSC
648 {
649 const vector<VkFormat> formats = subgroups::getAllRayTracingFormats();
650
651 for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
652 {
653 const VkFormat format = formats[formatIndex];
654 const string formatName = subgroups::getFormatNameForGLSL(format);
655
656 for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
657 {
658 for (const auto& argCase : argCases)
659 {
660 const OpType opType = static_cast<OpType>(opTypeIndex);
661
662 if (opType == OPTYPE_SHUFFLE && argCase.argType != ArgType::DYNAMIC)
663 continue;
664
665 const string name = de::toLower(getOpTypeName(opType)) + "_" + formatName + argCase.suffix;
666 const CaseDefinition caseDef =
667 {
668 opType, // OpType opType;
669 SHADER_STAGE_ALL_RAY_TRACING, // VkShaderStageFlags shaderStage;
670 format, // VkFormat format;
671 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
672 DE_FALSE, // deBool requiredSubgroupSize;
673 argCase.argType, // ArgType argType;
674 DE_FALSE, // deBool requires8BitUniformBuffer;
675 DE_FALSE // deBool requires16BitUniformBuffer;
676 };
677
678 addFunctionCaseWithPrograms(raytracingGroup.get(), name, supportedCheck, initPrograms, test, caseDef);
679 }
680 }
681 }
682 }
683 #endif // CTS_USES_VULKANSC
684
685 group->addChild(graphicGroup.release());
686 group->addChild(computeGroup.release());
687 group->addChild(framebufferGroup.release());
688 #ifndef CTS_USES_VULKANSC
689 group->addChild(raytracingGroup.release());
690 group->addChild(meshGroup.release());
691 #endif // CTS_USES_VULKANSC
692
693 return group.release();
694 }
695
696 } // subgroups
697 } // vkt
698