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