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 "vktSubgroupsBallotOtherTests.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_INVERSE_BALLOT = 0,
42 OPTYPE_BALLOT_BIT_EXTRACT,
43 OPTYPE_BALLOT_BIT_COUNT,
44 OPTYPE_BALLOT_INCLUSIVE_BIT_COUNT,
45 OPTYPE_BALLOT_EXCLUSIVE_BIT_COUNT,
46 OPTYPE_BALLOT_FIND_LSB,
47 OPTYPE_BALLOT_FIND_MSB,
48 OPTYPE_LAST
49 };
50
51 struct CaseDefinition
52 {
53 OpType opType;
54 VkShaderStageFlags shaderStage;
55 de::SharedPtr<bool> geometryPointSizeSupported;
56 deBool requiredSubgroupSize;
57 };
58
checkVertexPipelineStages(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)59 bool checkVertexPipelineStages (const void* internalData,
60 vector<const void*> datas,
61 deUint32 width,
62 deUint32)
63 {
64 DE_UNREF(internalData);
65
66 return subgroups::check(datas, width, 0xf);
67 }
68
checkCompute(const void * internalData,vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)69 bool checkCompute (const void* internalData,
70 vector<const void*> datas,
71 const deUint32 numWorkgroups[3],
72 const deUint32 localSize[3],
73 deUint32)
74 {
75 DE_UNREF(internalData);
76
77 return subgroups::checkCompute(datas, numWorkgroups, localSize, 0xf);
78 }
79
getOpTypeName(OpType opType)80 string getOpTypeName (OpType opType)
81 {
82 switch (opType)
83 {
84 case OPTYPE_INVERSE_BALLOT: return "subgroupInverseBallot";
85 case OPTYPE_BALLOT_BIT_EXTRACT: return "subgroupBallotBitExtract";
86 case OPTYPE_BALLOT_BIT_COUNT: return "subgroupBallotBitCount";
87 case OPTYPE_BALLOT_INCLUSIVE_BIT_COUNT: return "subgroupBallotInclusiveBitCount";
88 case OPTYPE_BALLOT_EXCLUSIVE_BIT_COUNT: return "subgroupBallotExclusiveBitCount";
89 case OPTYPE_BALLOT_FIND_LSB: return "subgroupBallotFindLSB";
90 case OPTYPE_BALLOT_FIND_MSB: return "subgroupBallotFindMSB";
91 default: TCU_THROW(InternalError, "Unsupported op type");
92 }
93 }
94
getExtHeader(const CaseDefinition &)95 string getExtHeader (const CaseDefinition&)
96 {
97 return "#extension GL_KHR_shader_subgroup_ballot: enable\n";
98 }
99
getPerStageHeadDeclarations(const CaseDefinition & caseDef)100 vector<string> getPerStageHeadDeclarations (const CaseDefinition& caseDef)
101 {
102 const deUint32 stageCount = subgroups::getStagesCount(caseDef.shaderStage);
103 const bool fragment = (caseDef.shaderStage & VK_SHADER_STAGE_FRAGMENT_BIT) != 0;
104 vector<string> result (stageCount, string());
105
106 if (fragment)
107 result.reserve(result.size() + 1);
108
109 for (size_t i = 0; i < result.size(); ++i)
110 {
111 result[i] =
112 "layout(set = 0, binding = " + de::toString(i) + ", std430) buffer Buffer1\n"
113 "{\n"
114 " uint result[];\n"
115 "};\n";
116 }
117
118 if (fragment)
119 {
120 const string fragPart =
121 "layout(location = 0) out uint result;\n"
122 "precision highp int;\n";
123
124 result.push_back(fragPart);
125 }
126
127 return result;
128 }
129
getFramebufferPerStageHeadDeclarations(const CaseDefinition & caseDef)130 vector<string> getFramebufferPerStageHeadDeclarations (const CaseDefinition& caseDef)
131 {
132 vector<string> result;
133
134 DE_UNREF(caseDef);
135
136 result.push_back("layout(location = 0) out float result;\n");
137 result.push_back("layout(location = 0) out float out_color;\n");
138 result.push_back("layout(location = 0) out float out_color[];\n");
139 result.push_back("layout(location = 0) out float out_color;\n");
140
141 return result;
142 }
143
getTestString(const CaseDefinition & caseDef)144 string getTestString (const CaseDefinition& caseDef)
145 {
146 ostringstream bdy;
147
148 bdy << " uvec4 allOnes = uvec4(0xFFFFFFFF);\n"
149 << " uvec4 allZeros = uvec4(0);\n"
150 << " uint tempResult = 0;\n"
151 << "#define MAKE_HIGH_BALLOT_RESULT(i) uvec4("
152 << "i >= 32 ? 0 : (0xFFFFFFFF << i), "
153 << "i >= 64 ? 0 : (0xFFFFFFFF << ((i < 32) ? 0 : (i - 32))), "
154 << "i >= 96 ? 0 : (0xFFFFFFFF << ((i < 64) ? 0 : (i - 64))), "
155 << "i >= 128 ? 0 : (0xFFFFFFFF << ((i < 96) ? 0 : (i - 96))))\n"
156 << "#define MAKE_SINGLE_BIT_BALLOT_RESULT(i) uvec4("
157 << "i >= 32 ? 0 : 0x1 << i, "
158 << "i < 32 || i >= 64 ? 0 : 0x1 << (i - 32), "
159 << "i < 64 || i >= 96 ? 0 : 0x1 << (i - 64), "
160 << "i < 96 || i >= 128 ? 0 : 0x1 << (i - 96))\n";
161
162 switch (caseDef.opType)
163 {
164 default:
165 DE_FATAL("Unknown op type!");
166 break;
167 case OPTYPE_INVERSE_BALLOT:
168 bdy << " tempResult |= subgroupInverseBallot(allOnes) ? 0x1 : 0;\n"
169 << " tempResult |= subgroupInverseBallot(allZeros) ? 0 : 0x2;\n"
170 << " tempResult |= subgroupInverseBallot(subgroupBallot(true)) ? 0x4 : 0;\n"
171 << " tempResult |= 0x8;\n";
172 break;
173 case OPTYPE_BALLOT_BIT_EXTRACT:
174 bdy << " tempResult |= subgroupBallotBitExtract(allOnes, gl_SubgroupInvocationID) ? 0x1 : 0;\n"
175 << " tempResult |= subgroupBallotBitExtract(allZeros, gl_SubgroupInvocationID) ? 0 : 0x2;\n"
176 << " tempResult |= subgroupBallotBitExtract(subgroupBallot(true), gl_SubgroupInvocationID) ? 0x4 : 0;\n"
177 << " tempResult |= 0x8;\n"
178 << " for (uint i = 0; i < gl_SubgroupSize; i++)\n"
179 << " {\n"
180 << " if (!subgroupBallotBitExtract(allOnes, gl_SubgroupInvocationID))\n"
181 << " {\n"
182 << " tempResult &= ~0x8;\n"
183 << " }\n"
184 << " }\n";
185 break;
186 case OPTYPE_BALLOT_BIT_COUNT:
187 bdy << " /* To ensure a 32-bit computation, use a variable with default highp precision. */\n"
188 << " uint SubgroupSize = gl_SubgroupSize;\n"
189 << " tempResult |= SubgroupSize == subgroupBallotBitCount(allOnes) ? 0x1 : 0;\n"
190 << " tempResult |= 0 == subgroupBallotBitCount(allZeros) ? 0x2 : 0;\n"
191 << " tempResult |= 0 < subgroupBallotBitCount(subgroupBallot(true)) ? 0x4 : 0;\n"
192 << " tempResult |= 0 == subgroupBallotBitCount(MAKE_HIGH_BALLOT_RESULT(SubgroupSize)) ? 0x8 : 0;\n";
193 break;
194 case OPTYPE_BALLOT_INCLUSIVE_BIT_COUNT:
195 bdy << " uint inclusiveOffset = gl_SubgroupInvocationID + 1;\n"
196 << " tempResult |= inclusiveOffset == subgroupBallotInclusiveBitCount(allOnes) ? 0x1 : 0;\n"
197 << " tempResult |= 0 == subgroupBallotInclusiveBitCount(allZeros) ? 0x2 : 0;\n"
198 << " tempResult |= 0 < subgroupBallotInclusiveBitCount(subgroupBallot(true)) ? 0x4 : 0;\n"
199 << " tempResult |= 0x8;\n"
200 << " for (uint i = 0; i < 128; i++)\n"
201 << " {\n"
202 << " uint ref = inclusiveOffset - min(inclusiveOffset, i);\n"
203 << " uvec4 b = MAKE_HIGH_BALLOT_RESULT(i);\n"
204 << " uint inclusiveBitCount = subgroupBallotInclusiveBitCount(b);\n"
205 << " if (inclusiveBitCount != ref)\n"
206 << " {\n"
207 << " tempResult &= ~0x8;\n"
208 << " }\n"
209 << " }\n";
210 break;
211 case OPTYPE_BALLOT_EXCLUSIVE_BIT_COUNT:
212 bdy << " uint exclusiveOffset = gl_SubgroupInvocationID;\n"
213 << " tempResult |= exclusiveOffset == subgroupBallotExclusiveBitCount(allOnes) ? 0x1 : 0;\n"
214 << " tempResult |= 0 == subgroupBallotExclusiveBitCount(allZeros) ? 0x2 : 0;\n"
215 << " tempResult |= 0x4;\n"
216 << " tempResult |= 0x8;\n"
217 << " for (uint i = 0; i < 128; i++)\n"
218 << " {\n"
219 << " uint ref = exclusiveOffset - min(exclusiveOffset, i);\n"
220 << " uvec4 b = MAKE_HIGH_BALLOT_RESULT(i);\n"
221 << " uint exclusiveBitCount = subgroupBallotExclusiveBitCount(b);\n"
222 << " if (exclusiveBitCount != ref)\n"
223 << " {\n"
224 << " tempResult &= ~0x8;\n"
225 << " }\n"
226 << " }\n";
227 break;
228 case OPTYPE_BALLOT_FIND_LSB:
229 bdy << " tempResult |= 0 == subgroupBallotFindLSB(allOnes) ? 0x1 : 0;\n"
230 << " if (subgroupElect())\n"
231 << " {\n"
232 << " tempResult |= 0x2;\n"
233 << " }\n"
234 << " else\n"
235 << " {\n"
236 << " tempResult |= 0 < subgroupBallotFindLSB(subgroupBallot(true)) ? 0x2 : 0;\n"
237 << " }\n"
238 << " tempResult |= gl_SubgroupSize > subgroupBallotFindLSB(subgroupBallot(true)) ? 0x4 : 0;\n"
239 << " tempResult |= 0x8;\n"
240 << " for (uint i = 0; i < gl_SubgroupSize; i++)\n"
241 << " {\n"
242 << " if (i != subgroupBallotFindLSB(MAKE_HIGH_BALLOT_RESULT(i)))\n"
243 << " {\n"
244 << " tempResult &= ~0x8;\n"
245 << " }\n"
246 << " }\n";
247 break;
248 case OPTYPE_BALLOT_FIND_MSB:
249 bdy << " tempResult |= (gl_SubgroupSize - 1) == subgroupBallotFindMSB(allOnes) ? 0x1 : 0;\n"
250 << " if (subgroupElect())\n"
251 << " {\n"
252 << " tempResult |= 0x2;\n"
253 << " }\n"
254 << " else\n"
255 << " {\n"
256 << " tempResult |= 0 < subgroupBallotFindMSB(subgroupBallot(true)) ? 0x2 : 0;\n"
257 << " }\n"
258 << " tempResult |= gl_SubgroupSize > subgroupBallotFindMSB(subgroupBallot(true)) ? 0x4 : 0;\n"
259 << " tempResult |= 0x8;\n"
260 << " for (uint i = 0; i < gl_SubgroupSize; i++)\n"
261 << " {\n"
262 << " if (i != subgroupBallotFindMSB(MAKE_SINGLE_BIT_BALLOT_RESULT(i)))\n"
263 << " {\n"
264 << " tempResult &= ~0x8;\n"
265 << " }\n"
266 << " }\n";
267 break;
268 }
269
270 bdy << " tempRes = tempResult;\n";
271
272 return bdy.str();
273 }
274
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)275 void initFrameBufferPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
276 {
277 const ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, SPIRV_VERSION_1_3, 0u);
278 const string extHeader = getExtHeader(caseDef);
279 const string testSrc = getTestString(caseDef);
280 const vector<string> headDeclarations = getFramebufferPerStageHeadDeclarations(caseDef);
281 const bool pointSizeSupported = *caseDef.geometryPointSizeSupported;
282
283 subgroups::initStdFrameBufferPrograms(programCollection, buildOptions, caseDef.shaderStage, VK_FORMAT_R32_UINT, pointSizeSupported, extHeader, testSrc, "", headDeclarations);
284 }
285
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)286 void initPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
287 {
288 const SpirvVersion spirvVersion = isAllRayTracingStages(caseDef.shaderStage) ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3;
289 const ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, spirvVersion, 0u);
290 const string extHeader = getExtHeader(caseDef);
291 const string testSrc = getTestString(caseDef);
292 const vector<string> headDeclarations = getPerStageHeadDeclarations(caseDef);
293 const bool pointSizeSupported = *caseDef.geometryPointSizeSupported;
294
295 subgroups::initStdPrograms(programCollection, buildOptions, caseDef.shaderStage, VK_FORMAT_R32_UINT, pointSizeSupported, extHeader, testSrc, "", headDeclarations);
296 }
297
supportedCheck(Context & context,CaseDefinition caseDef)298 void supportedCheck (Context& context, CaseDefinition caseDef)
299 {
300 if (!subgroups::isSubgroupSupported(context))
301 TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
302
303 if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_BALLOT_BIT))
304 {
305 TCU_THROW(NotSupportedError, "Device does not support subgroup ballot operations");
306 }
307
308 if (caseDef.requiredSubgroupSize)
309 {
310 context.requireDeviceFunctionality("VK_EXT_subgroup_size_control");
311
312 const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT& subgroupSizeControlFeatures = context.getSubgroupSizeControlFeaturesEXT();
313 const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT& subgroupSizeControlProperties = context.getSubgroupSizeControlPropertiesEXT();
314
315 if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
316 TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes nor required subgroup size");
317
318 if (subgroupSizeControlFeatures.computeFullSubgroups == DE_FALSE)
319 TCU_THROW(NotSupportedError, "Device does not support full subgroups in compute shaders");
320
321 if ((subgroupSizeControlProperties.requiredSubgroupSizeStages & caseDef.shaderStage) != caseDef.shaderStage)
322 TCU_THROW(NotSupportedError, "Required subgroup size is not supported for shader stage");
323 }
324
325 *caseDef.geometryPointSizeSupported = subgroups::isTessellationAndGeometryPointSizeSupported(context);
326
327 if (isAllRayTracingStages(caseDef.shaderStage))
328 {
329 context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
330 }
331
332 subgroups::supportedCheckShader(context, caseDef.shaderStage);
333 }
334
noSSBOtest(Context & context,const CaseDefinition caseDef)335 TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
336 {
337 switch (caseDef.shaderStage)
338 {
339 case VK_SHADER_STAGE_VERTEX_BIT: return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages);
340 case VK_SHADER_STAGE_GEOMETRY_BIT: return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages);
341 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages);
342 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages);
343 default: TCU_THROW(InternalError, "Unhandled shader stage");
344 }
345 }
346
test(Context & context,const CaseDefinition caseDef)347 TestStatus test (Context& context, const CaseDefinition caseDef)
348 {
349 if (isAllComputeStages(caseDef.shaderStage))
350 {
351 const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT& subgroupSizeControlProperties = context.getSubgroupSizeControlPropertiesEXT();
352 TestLog& log = context.getTestContext().getLog();
353
354 if (caseDef.requiredSubgroupSize == DE_FALSE)
355 return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkCompute);
356
357 log << TestLog::Message << "Testing required subgroup size range [" << subgroupSizeControlProperties.minSubgroupSize << ", "
358 << subgroupSizeControlProperties.maxSubgroupSize << "]" << TestLog::EndMessage;
359
360 // According to the spec, requiredSubgroupSize must be a power-of-two integer.
361 for (deUint32 size = subgroupSizeControlProperties.minSubgroupSize; size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
362 {
363 TestStatus result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0u, DE_NULL, checkCompute,
364 size, VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT);
365 if (result.getCode() != QP_TEST_RESULT_PASS)
366 {
367 log << TestLog::Message << "subgroupSize " << size << " failed" << TestLog::EndMessage;
368
369 return result;
370 }
371 }
372
373 return TestStatus::pass("OK");
374 }
375 else if (isAllGraphicsStages(caseDef.shaderStage))
376 {
377 const VkShaderStageFlags stages = subgroups::getPossibleGraphicsSubgroupStages(context, caseDef.shaderStage);
378
379 return subgroups::allStages(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages, stages);
380 }
381 else if (isAllRayTracingStages(caseDef.shaderStage))
382 {
383 const VkShaderStageFlags stages = subgroups::getPossibleRayTracingSubgroupStages(context, caseDef.shaderStage);
384
385 return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages, stages);
386 }
387 else
388 TCU_THROW(InternalError, "Unknown stage or invalid stage set");
389
390 return TestStatus::pass("OK");
391 }
392 }
393
394 namespace vkt
395 {
396 namespace subgroups
397 {
createSubgroupsBallotOtherTests(TestContext & testCtx)398 TestCaseGroup* createSubgroupsBallotOtherTests (TestContext& testCtx)
399 {
400 de::MovePtr<TestCaseGroup> group (new TestCaseGroup(testCtx, "ballot_other", "Subgroup ballot other category tests"));
401 de::MovePtr<TestCaseGroup> graphicGroup (new TestCaseGroup(testCtx, "graphics", "Subgroup ballot other category tests: graphics"));
402 de::MovePtr<TestCaseGroup> computeGroup (new TestCaseGroup(testCtx, "compute", "Subgroup ballot other category tests: compute"));
403 de::MovePtr<TestCaseGroup> framebufferGroup (new TestCaseGroup(testCtx, "framebuffer", "Subgroup ballot other category tests: framebuffer"));
404 de::MovePtr<TestCaseGroup> raytracingGroup (new TestCaseGroup(testCtx, "ray_tracing", "Subgroup ballot other category tests: ray tracing"));
405 const VkShaderStageFlags stages[] =
406 {
407 VK_SHADER_STAGE_VERTEX_BIT,
408 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
409 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
410 VK_SHADER_STAGE_GEOMETRY_BIT,
411 };
412 const deBool boolValues[] =
413 {
414 DE_FALSE,
415 DE_TRUE
416 };
417
418 for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
419 {
420 const OpType opType = static_cast<OpType>(opTypeIndex);
421 const string op = de::toLower(getOpTypeName(opType));
422
423 for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
424 {
425 const deBool requiredSubgroupSize = boolValues[groupSizeNdx];
426 const string testName = op + (requiredSubgroupSize ? "_requiredsubgroupsize" : "");
427 const CaseDefinition caseDef =
428 {
429 opType, // OpType opType;
430 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlags shaderStage;
431 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
432 requiredSubgroupSize // deBool requiredSubgroupSize;
433 };
434
435 addFunctionCaseWithPrograms(computeGroup.get(), testName, "", supportedCheck, initPrograms, test, caseDef);
436 }
437
438 {
439 const CaseDefinition caseDef =
440 {
441 opType, // OpType opType;
442 VK_SHADER_STAGE_ALL_GRAPHICS, // VkShaderStageFlags shaderStage;
443 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
444 DE_FALSE // deBool requiredSubgroupSize;
445 };
446
447 addFunctionCaseWithPrograms(graphicGroup.get(), op, "", supportedCheck, initPrograms, test, caseDef);
448 }
449
450 {
451 const CaseDefinition caseDef =
452 {
453 opType, // OpType opType;
454 SHADER_STAGE_ALL_RAY_TRACING, // VkShaderStageFlags shaderStage;
455 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
456 DE_FALSE // deBool requiredSubgroupSize;
457 };
458
459 addFunctionCaseWithPrograms(raytracingGroup.get(), op, "", supportedCheck, initPrograms, test, caseDef);
460 }
461
462 for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
463 {
464 const CaseDefinition caseDef =
465 {
466 opType, // OpType opType;
467 stages[stageIndex], // VkShaderStageFlags shaderStage;
468 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
469 DE_FALSE // deBool requiredSubgroupSize;
470 };
471 const string testName = op + "_" + getShaderStageName(caseDef.shaderStage);
472
473 addFunctionCaseWithPrograms(framebufferGroup.get(), testName, "", supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
474 }
475 }
476
477 group->addChild(graphicGroup.release());
478 group->addChild(computeGroup.release());
479 group->addChild(framebufferGroup.release());
480 group->addChild(raytracingGroup.release());
481
482 return group.release();
483 }
484
485 } // subgroups
486 } // vkt
487