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 * Copyright (c) 2018 NVIDIA Corporation
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 */ /*!
23 * \file
24 * \brief Subgroups Tests
25 */ /*--------------------------------------------------------------------*/
26
27 #include "vktSubgroupsPartitionedTests.hpp"
28 #include "vktSubgroupsScanHelpers.hpp"
29 #include "vktSubgroupsTestsUtils.hpp"
30
31 #include <string>
32 #include <vector>
33
34 using namespace tcu;
35 using namespace std;
36 using namespace vk;
37 using namespace vkt;
38
39 namespace
40 {
41 enum OpType
42 {
43 OPTYPE_ADD = 0,
44 OPTYPE_MUL,
45 OPTYPE_MIN,
46 OPTYPE_MAX,
47 OPTYPE_AND,
48 OPTYPE_OR,
49 OPTYPE_XOR,
50 OPTYPE_INCLUSIVE_ADD,
51 OPTYPE_INCLUSIVE_MUL,
52 OPTYPE_INCLUSIVE_MIN,
53 OPTYPE_INCLUSIVE_MAX,
54 OPTYPE_INCLUSIVE_AND,
55 OPTYPE_INCLUSIVE_OR,
56 OPTYPE_INCLUSIVE_XOR,
57 OPTYPE_EXCLUSIVE_ADD,
58 OPTYPE_EXCLUSIVE_MUL,
59 OPTYPE_EXCLUSIVE_MIN,
60 OPTYPE_EXCLUSIVE_MAX,
61 OPTYPE_EXCLUSIVE_AND,
62 OPTYPE_EXCLUSIVE_OR,
63 OPTYPE_EXCLUSIVE_XOR,
64 OPTYPE_LAST
65 };
66
67 struct CaseDefinition
68 {
69 Operator op;
70 ScanType scanType;
71 VkShaderStageFlags shaderStage;
72 VkFormat format;
73 de::SharedPtr<bool> geometryPointSizeSupported;
74 deBool requiredSubgroupSize;
75 };
76
getOperator(OpType opType)77 static Operator getOperator (OpType opType)
78 {
79 switch (opType)
80 {
81 case OPTYPE_ADD:
82 case OPTYPE_INCLUSIVE_ADD:
83 case OPTYPE_EXCLUSIVE_ADD:
84 return OPERATOR_ADD;
85 case OPTYPE_MUL:
86 case OPTYPE_INCLUSIVE_MUL:
87 case OPTYPE_EXCLUSIVE_MUL:
88 return OPERATOR_MUL;
89 case OPTYPE_MIN:
90 case OPTYPE_INCLUSIVE_MIN:
91 case OPTYPE_EXCLUSIVE_MIN:
92 return OPERATOR_MIN;
93 case OPTYPE_MAX:
94 case OPTYPE_INCLUSIVE_MAX:
95 case OPTYPE_EXCLUSIVE_MAX:
96 return OPERATOR_MAX;
97 case OPTYPE_AND:
98 case OPTYPE_INCLUSIVE_AND:
99 case OPTYPE_EXCLUSIVE_AND:
100 return OPERATOR_AND;
101 case OPTYPE_OR:
102 case OPTYPE_INCLUSIVE_OR:
103 case OPTYPE_EXCLUSIVE_OR:
104 return OPERATOR_OR;
105 case OPTYPE_XOR:
106 case OPTYPE_INCLUSIVE_XOR:
107 case OPTYPE_EXCLUSIVE_XOR:
108 return OPERATOR_XOR;
109 default:
110 DE_FATAL("Unsupported op type");
111 return OPERATOR_ADD;
112 }
113 }
114
getScanType(OpType opType)115 static ScanType getScanType (OpType opType)
116 {
117 switch (opType)
118 {
119 case OPTYPE_ADD:
120 case OPTYPE_MUL:
121 case OPTYPE_MIN:
122 case OPTYPE_MAX:
123 case OPTYPE_AND:
124 case OPTYPE_OR:
125 case OPTYPE_XOR:
126 return SCAN_REDUCE;
127 case OPTYPE_INCLUSIVE_ADD:
128 case OPTYPE_INCLUSIVE_MUL:
129 case OPTYPE_INCLUSIVE_MIN:
130 case OPTYPE_INCLUSIVE_MAX:
131 case OPTYPE_INCLUSIVE_AND:
132 case OPTYPE_INCLUSIVE_OR:
133 case OPTYPE_INCLUSIVE_XOR:
134 return SCAN_INCLUSIVE;
135 case OPTYPE_EXCLUSIVE_ADD:
136 case OPTYPE_EXCLUSIVE_MUL:
137 case OPTYPE_EXCLUSIVE_MIN:
138 case OPTYPE_EXCLUSIVE_MAX:
139 case OPTYPE_EXCLUSIVE_AND:
140 case OPTYPE_EXCLUSIVE_OR:
141 case OPTYPE_EXCLUSIVE_XOR:
142 return SCAN_EXCLUSIVE;
143 default:
144 DE_FATAL("Unsupported op type");
145 return SCAN_REDUCE;
146 }
147 }
148
checkVertexPipelineStages(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)149 static bool checkVertexPipelineStages (const void* internalData,
150 vector<const void*> datas,
151 deUint32 width,
152 deUint32)
153 {
154 DE_UNREF(internalData);
155
156 return subgroups::check(datas, width, 0xFFFFFF);
157 }
158
checkCompute(const void * internalData,vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)159 static bool checkCompute (const void* internalData,
160 vector<const void*> datas,
161 const deUint32 numWorkgroups[3],
162 const deUint32 localSize[3],
163 deUint32)
164 {
165 DE_UNREF(internalData);
166
167 return subgroups::checkCompute(datas, numWorkgroups, localSize, 0xFFFFFF);
168 }
169
getOpTypeName(Operator op,ScanType scanType)170 string getOpTypeName (Operator op, ScanType scanType)
171 {
172 return getScanOpName("subgroup", "", op, scanType);
173 }
174
getOpTypeNamePartitioned(Operator op,ScanType scanType)175 string getOpTypeNamePartitioned (Operator op, ScanType scanType)
176 {
177 return getScanOpName("subgroupPartitioned", "NV", op, scanType);
178 }
179
getExtHeader(const CaseDefinition & caseDef)180 string getExtHeader (const CaseDefinition& caseDef)
181 {
182 return "#extension GL_NV_shader_subgroup_partitioned: enable\n"
183 "#extension GL_KHR_shader_subgroup_arithmetic: enable\n"
184 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
185 + subgroups::getAdditionalExtensionForFormat(caseDef.format);
186 }
187
getTestString(const CaseDefinition & caseDef)188 string getTestString (const CaseDefinition& caseDef)
189 {
190 Operator op = caseDef.op;
191 ScanType st = caseDef.scanType;
192
193 // NOTE: tempResult can't have anything in bits 31:24 to avoid int->float
194 // conversion overflow in framebuffer tests.
195 string fmt = subgroups::getFormatNameForGLSL(caseDef.format);
196 string bdy =
197 " uvec4 mask = subgroupBallot(true);\n"
198 " uint tempResult = 0;\n"
199 " uint id = gl_SubgroupInvocationID;\n";
200
201 // Test the case where the partition has a single subset with all invocations in it.
202 // This should generate the same result as the non-partitioned function.
203 bdy +=
204 " uvec4 allBallot = mask;\n"
205 " " + fmt + " allResult = " + getOpTypeNamePartitioned(op, st) + "(data[gl_SubgroupInvocationID], allBallot);\n"
206 " " + fmt + " refResult = " + getOpTypeName(op, st) + "(data[gl_SubgroupInvocationID]);\n"
207 " if (" + getCompare(op, caseDef.format, "allResult", "refResult") + ") {\n"
208 " tempResult |= 0x1;\n"
209 " }\n";
210
211 // The definition of a partition doesn't forbid bits corresponding to inactive
212 // invocations being in the subset with active invocations. In other words, test that
213 // bits corresponding to inactive invocations are ignored.
214 bdy +=
215 " if (0 == (gl_SubgroupInvocationID % 2)) {\n"
216 " " + fmt + " allResult = " + getOpTypeNamePartitioned(op, st) + "(data[gl_SubgroupInvocationID], allBallot);\n"
217 " " + fmt + " refResult = " + getOpTypeName(op, st) + "(data[gl_SubgroupInvocationID]);\n"
218 " if (" + getCompare(op, caseDef.format, "allResult", "refResult") + ") {\n"
219 " tempResult |= 0x2;\n"
220 " }\n"
221 " } else {\n"
222 " tempResult |= 0x2;\n"
223 " }\n";
224
225 // Test the case where the partition has each invocation in a unique subset. For
226 // exclusive ops, the result is identity. For reduce/inclusive, it's the original value.
227 string expectedSelfResult = "data[gl_SubgroupInvocationID]";
228 if (st == SCAN_EXCLUSIVE)
229 expectedSelfResult = getIdentity(op, caseDef.format);
230
231 bdy +=
232 " uvec4 selfBallot = subgroupPartitionNV(gl_SubgroupInvocationID);\n"
233 " " + fmt + " selfResult = " + getOpTypeNamePartitioned(op, st) + "(data[gl_SubgroupInvocationID], selfBallot);\n"
234 " if (" + getCompare(op, caseDef.format, "selfResult", expectedSelfResult) + ") {\n"
235 " tempResult |= 0x4;\n"
236 " }\n";
237
238 // Test "random" partitions based on a hash of the invocation id.
239 // This "hash" function produces interesting/randomish partitions.
240 static const char *idhash = "((id%N)+(id%(N+1))-(id%2)+(id/2))%((N+1)/2)";
241
242 bdy +=
243 " for (uint N = 1; N < 16; ++N) {\n"
244 " " + fmt + " idhashFmt = " + fmt + "(" + idhash + ");\n"
245 " uvec4 partitionBallot = subgroupPartitionNV(idhashFmt) & mask;\n"
246 " " + fmt + " partitionedResult = " + getOpTypeNamePartitioned(op, st) + "(data[gl_SubgroupInvocationID], partitionBallot);\n"
247 " for (uint i = 0; i < N; ++i) {\n"
248 " " + fmt + " iFmt = " + fmt + "(i);\n"
249 " if (" + getCompare(op, caseDef.format, "idhashFmt", "iFmt") + ") {\n"
250 " " + fmt + " subsetResult = " + getOpTypeName(op, st) + "(data[gl_SubgroupInvocationID]);\n"
251 " tempResult |= " + getCompare(op, caseDef.format, "partitionedResult", "subsetResult") + " ? (0x4 << N) : 0;\n"
252 " }\n"
253 " }\n"
254 " }\n"
255 // tests in flow control:
256 " if (1 == (gl_SubgroupInvocationID % 2)) {\n"
257 " for (uint N = 1; N < 7; ++N) {\n"
258 " " + fmt + " idhashFmt = " + fmt + "(" + idhash + ");\n"
259 " uvec4 partitionBallot = subgroupPartitionNV(idhashFmt) & mask;\n"
260 " " + fmt + " partitionedResult = " + getOpTypeNamePartitioned(op, st) + "(data[gl_SubgroupInvocationID], partitionBallot);\n"
261 " for (uint i = 0; i < N; ++i) {\n"
262 " " + fmt + " iFmt = " + fmt + "(i);\n"
263 " if (" + getCompare(op, caseDef.format, "idhashFmt", "iFmt") + ") {\n"
264 " " + fmt + " subsetResult = " + getOpTypeName(op, st) + "(data[gl_SubgroupInvocationID]);\n"
265 " tempResult |= " + getCompare(op, caseDef.format, "partitionedResult", "subsetResult") + " ? (0x20000 << N) : 0;\n"
266 " }\n"
267 " }\n"
268 " }\n"
269 " } else {\n"
270 " tempResult |= 0xFC0000;\n"
271 " }\n"
272 " tempRes = tempResult;\n"
273 ;
274
275 return bdy;
276 }
277
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)278 void initFrameBufferPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
279 {
280 const ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, SPIRV_VERSION_1_3, 0u);
281 const string extHeader = getExtHeader(caseDef);
282 const string testSrc = getTestString(caseDef);
283 const bool pointSizeSupport = *caseDef.geometryPointSizeSupported;
284
285 subgroups::initStdFrameBufferPrograms(programCollection, buildOptions, caseDef.shaderStage, caseDef.format, pointSizeSupport, extHeader, testSrc, "");
286 }
287
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)288 void initPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
289 {
290 const SpirvVersion spirvVersion = isAllRayTracingStages(caseDef.shaderStage) ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3;
291 const ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, spirvVersion, 0u);
292 const string extHeader = getExtHeader(caseDef);
293 const string testSrc = getTestString(caseDef);
294 const bool pointSizeSupport = false;
295
296 subgroups::initStdPrograms(programCollection, buildOptions, caseDef.shaderStage, caseDef.format, pointSizeSupport, extHeader, testSrc, "");
297 }
298
supportedCheck(Context & context,CaseDefinition caseDef)299 void supportedCheck (Context& context, CaseDefinition caseDef)
300 {
301 if (!subgroups::isSubgroupSupported(context))
302 TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
303
304 if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV))
305 TCU_THROW(NotSupportedError, "Device does not support subgroup partitioned operations");
306
307 if (!subgroups::isFormatSupportedForDevice(context, caseDef.format))
308 TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
309
310 if (caseDef.requiredSubgroupSize)
311 {
312 context.requireDeviceFunctionality("VK_EXT_subgroup_size_control");
313
314 const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT& subgroupSizeControlFeatures = context.getSubgroupSizeControlFeaturesEXT();
315 const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT& subgroupSizeControlProperties = context.getSubgroupSizeControlPropertiesEXT();
316
317 if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
318 TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes nor required subgroup size");
319
320 if (subgroupSizeControlFeatures.computeFullSubgroups == DE_FALSE)
321 TCU_THROW(NotSupportedError, "Device does not support full subgroups in compute shaders");
322
323 if ((subgroupSizeControlProperties.requiredSubgroupSizeStages & caseDef.shaderStage) != caseDef.shaderStage)
324 TCU_THROW(NotSupportedError, "Required subgroup size is not supported for shader stage");
325 }
326
327 *caseDef.geometryPointSizeSupported = subgroups::isTessellationAndGeometryPointSizeSupported(context);
328
329 if (isAllRayTracingStages(caseDef.shaderStage))
330 {
331 context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
332 }
333
334 subgroups::supportedCheckShader(context, caseDef.shaderStage);
335 }
336
noSSBOtest(Context & context,const CaseDefinition caseDef)337 TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
338 {
339 const subgroups::SSBOData inputData
340 {
341 subgroups::SSBOData::InitializeNonZero, // InputDataInitializeType initializeType;
342 subgroups::SSBOData::LayoutStd140, // InputDataLayoutType layout;
343 caseDef.format, // vk::VkFormat format;
344 subgroups::maxSupportedSubgroupSize(), // vk::VkDeviceSize numElements;
345 };
346
347 switch (caseDef.shaderStage)
348 {
349 case VK_SHADER_STAGE_VERTEX_BIT: return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages);
350 case VK_SHADER_STAGE_GEOMETRY_BIT: return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages);
351 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
352 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
353 default: TCU_THROW(InternalError, "Unhandled shader stage");
354 }
355 }
356
test(Context & context,const CaseDefinition caseDef)357 TestStatus test (Context& context, const CaseDefinition caseDef)
358 {
359 if (isAllComputeStages(caseDef.shaderStage))
360 {
361 const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT& subgroupSizeControlProperties = context.getSubgroupSizeControlPropertiesEXT();
362 TestLog& log = context.getTestContext().getLog();
363 const subgroups::SSBOData inputData =
364 {
365 subgroups::SSBOData::InitializeNonZero, // InputDataInitializeType initializeType;
366 subgroups::SSBOData::LayoutStd430, // InputDataLayoutType layout;
367 caseDef.format, // vk::VkFormat format;
368 subgroups::maxSupportedSubgroupSize(), // vk::VkDeviceSize numElements;
369 };
370
371 if (caseDef.requiredSubgroupSize == DE_FALSE)
372 return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkCompute);
373
374 log << TestLog::Message << "Testing required subgroup size range [" << subgroupSizeControlProperties.minSubgroupSize << ", "
375 << subgroupSizeControlProperties.maxSubgroupSize << "]" << TestLog::EndMessage;
376
377 // According to the spec, requiredSubgroupSize must be a power-of-two integer.
378 for (deUint32 size = subgroupSizeControlProperties.minSubgroupSize; size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
379 {
380 TestStatus result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkCompute,
381 size, VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT);
382 if (result.getCode() != QP_TEST_RESULT_PASS)
383 {
384 log << TestLog::Message << "subgroupSize " << size << " failed" << TestLog::EndMessage;
385 return result;
386 }
387 }
388
389 return TestStatus::pass("OK");
390 }
391 else if (isAllGraphicsStages(caseDef.shaderStage))
392 {
393 const VkShaderStageFlags stages = subgroups::getPossibleGraphicsSubgroupStages(context, caseDef.shaderStage);
394 const subgroups::SSBOData inputData
395 {
396 subgroups::SSBOData::InitializeNonZero, // InputDataInitializeType initializeType;
397 subgroups::SSBOData::LayoutStd430, // InputDataLayoutType layout;
398 caseDef.format, // vk::VkFormat format;
399 subgroups::maxSupportedSubgroupSize(), // vk::VkDeviceSize numElements;
400 false, // bool isImage;
401 4u, // deUint32 binding;
402 stages, // vk::VkShaderStageFlags stages;
403 };
404
405 return subgroups::allStages(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, stages);
406 }
407 else if (isAllRayTracingStages(caseDef.shaderStage))
408 {
409 const VkShaderStageFlags stages = subgroups::getPossibleRayTracingSubgroupStages(context, caseDef.shaderStage);
410 const subgroups::SSBOData inputData
411 {
412 subgroups::SSBOData::InitializeNonZero, // InputDataInitializeType initializeType;
413 subgroups::SSBOData::LayoutStd430, // InputDataLayoutType layout;
414 caseDef.format, // vk::VkFormat format;
415 subgroups::maxSupportedSubgroupSize(), // vk::VkDeviceSize numElements;
416 false, // bool isImage;
417 6u, // deUint32 binding;
418 stages, // vk::VkShaderStageFlags stages;
419 };
420
421 return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, stages);
422 }
423 else
424 TCU_THROW(InternalError, "Unknown stage or invalid stage set");
425 }
426 }
427
428 namespace vkt
429 {
430 namespace subgroups
431 {
createSubgroupsPartitionedTests(TestContext & testCtx)432 TestCaseGroup* createSubgroupsPartitionedTests (TestContext& testCtx)
433 {
434 de::MovePtr<TestCaseGroup> group (new TestCaseGroup(testCtx, "partitioned", "Subgroup partitioned category tests"));
435 de::MovePtr<TestCaseGroup> graphicGroup (new TestCaseGroup(testCtx, "graphics", "Subgroup partitioned category tests: graphics"));
436 de::MovePtr<TestCaseGroup> computeGroup (new TestCaseGroup(testCtx, "compute", "Subgroup partitioned category tests: compute"));
437 de::MovePtr<TestCaseGroup> framebufferGroup (new TestCaseGroup(testCtx, "framebuffer", "Subgroup partitioned category tests: framebuffer"));
438 de::MovePtr<TestCaseGroup> raytracingGroup (new TestCaseGroup(testCtx, "ray_tracing", "Subgroup partitioned category tests: ray tracing"));
439 const VkShaderStageFlags stages[] =
440 {
441 VK_SHADER_STAGE_VERTEX_BIT,
442 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
443 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
444 VK_SHADER_STAGE_GEOMETRY_BIT,
445 };
446 const deBool boolValues[] =
447 {
448 DE_FALSE,
449 DE_TRUE
450 };
451
452 {
453 const vector<VkFormat> formats = subgroups::getAllFormats();
454
455 for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
456 {
457 const VkFormat format = formats[formatIndex];
458 const string formatName = subgroups::getFormatNameForGLSL(format);
459 const bool isBool = subgroups::isFormatBool(format);
460 const bool isFloat = subgroups::isFormatFloat(format);
461
462 for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
463 {
464 const OpType opType = static_cast<OpType>(opTypeIndex);
465 const Operator op = getOperator(opType);
466 const ScanType st = getScanType(opType);
467 const bool isBitwiseOp = (op == OPERATOR_AND || op == OPERATOR_OR || op == OPERATOR_XOR);
468
469 // Skip float with bitwise category.
470 if (isFloat && isBitwiseOp)
471 continue;
472
473 // Skip bool when its not the bitwise category.
474 if (isBool && !isBitwiseOp)
475 continue;
476
477 const string name = de::toLower(getOpTypeName(op, st)) + "_" + formatName;
478
479 for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
480 {
481 const deBool requiredSubgroupSize = boolValues[groupSizeNdx];
482 const string testName = name + (requiredSubgroupSize ? "_requiredsubgroupsize" : "");
483 const CaseDefinition caseDef =
484 {
485 op, // Operator op;
486 st, // ScanType scanType;
487 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlags shaderStage;
488 format, // VkFormat format;
489 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
490 requiredSubgroupSize // deBool requiredSubgroupSize;
491 };
492
493 addFunctionCaseWithPrograms(computeGroup.get(), testName, "", supportedCheck, initPrograms, test, caseDef);
494 }
495
496 {
497 const CaseDefinition caseDef =
498 {
499 op, // Operator op;
500 st, // ScanType scanType;
501 VK_SHADER_STAGE_ALL_GRAPHICS, // VkShaderStageFlags shaderStage;
502 format, // VkFormat format;
503 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
504 DE_FALSE // deBool requiredSubgroupSize;
505 };
506
507 addFunctionCaseWithPrograms(graphicGroup.get(), name, "", supportedCheck, initPrograms, test, caseDef);
508 }
509
510 for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
511 {
512 const CaseDefinition caseDef =
513 {
514 op, // Operator op;
515 st, // ScanType scanType;
516 stages[stageIndex], // VkShaderStageFlags shaderStage;
517 format, // VkFormat format;
518 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
519 DE_FALSE // deBool requiredSubgroupSize;
520 };
521 const string testName = name + "_" + getShaderStageName(caseDef.shaderStage);
522
523 addFunctionCaseWithPrograms(framebufferGroup.get(), testName, "", supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
524 }
525 }
526 }
527 }
528
529 {
530 const vector<VkFormat> formats = subgroups::getAllRayTracingFormats();
531
532 for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
533 {
534 const VkFormat format = formats[formatIndex];
535 const string formatName = subgroups::getFormatNameForGLSL(format);
536 const bool isBool = subgroups::isFormatBool(format);
537 const bool isFloat = subgroups::isFormatFloat(format);
538
539 for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
540 {
541 const OpType opType = static_cast<OpType>(opTypeIndex);
542 const Operator op = getOperator(opType);
543 const ScanType st = getScanType(opType);
544 const bool isBitwiseOp = (op == OPERATOR_AND || op == OPERATOR_OR || op == OPERATOR_XOR);
545
546 // Skip float with bitwise category.
547 if (isFloat && isBitwiseOp)
548 continue;
549
550 // Skip bool when its not the bitwise category.
551 if (isBool && !isBitwiseOp)
552 continue;
553
554 {
555 const CaseDefinition caseDef =
556 {
557 op, // Operator op;
558 st, // ScanType scanType;
559 SHADER_STAGE_ALL_RAY_TRACING, // VkShaderStageFlags shaderStage;
560 format, // VkFormat format;
561 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
562 DE_FALSE // deBool requiredSubgroupSize;
563 };
564 const string name = de::toLower(getOpTypeName(op, st)) + "_" + formatName;
565
566 addFunctionCaseWithPrograms(raytracingGroup.get(), name, "", supportedCheck, initPrograms, test, caseDef);
567 }
568 }
569 }
570 }
571
572 group->addChild(graphicGroup.release());
573 group->addChild(computeGroup.release());
574 group->addChild(framebufferGroup.release());
575 group->addChild(raytracingGroup.release());
576
577 return group.release();
578 }
579 } // subgroups
580 } // vkt
581