1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2019 The Khronos Group Inc.
6 * Copyright (c) 2019 Valve Corporation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 */ /*!
21 * \file
22 * \brief Subgroups Tests
23 */ /*--------------------------------------------------------------------*/
24
25 #include "vktSubgroupsBallotMasksTests.hpp"
26 #include "vktSubgroupsTestsUtils.hpp"
27
28 #include <string>
29 #include <vector>
30
31 using namespace tcu;
32 using namespace std;
33 using namespace vk;
34 using namespace vkt;
35
36 namespace
37 {
38
39 enum MaskType
40 {
41 MASKTYPE_EQ = 0,
42 MASKTYPE_GE,
43 MASKTYPE_GT,
44 MASKTYPE_LE,
45 MASKTYPE_LT,
46 MASKTYPE_LAST
47 };
48
49 struct CaseDefinition
50 {
51 MaskType maskType;
52 VkShaderStageFlags shaderStage;
53 de::SharedPtr<bool> geometryPointSizeSupported;
54 deBool requiredSubgroupSize;
55 };
56
checkVertexPipelineStages(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)57 static bool checkVertexPipelineStages (const void* internalData,
58 vector<const void*> datas,
59 deUint32 width,
60 deUint32)
61 {
62 DE_UNREF(internalData);
63
64 return subgroups::check(datas, width, 0xf);
65 }
66
checkCompute(const void * internalData,vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)67 static bool checkCompute (const void* internalData,
68 vector<const void*> datas,
69 const deUint32 numWorkgroups[3],
70 const deUint32 localSize[3],
71 deUint32)
72 {
73 DE_UNREF(internalData);
74
75 return subgroups::checkCompute(datas, numWorkgroups, localSize, 0xf);
76 }
77
getMaskTypeName(const MaskType maskType)78 string getMaskTypeName (const MaskType maskType)
79 {
80 switch (maskType)
81 {
82 case MASKTYPE_EQ: return "gl_SubGroupEqMaskARB";
83 case MASKTYPE_GE: return "gl_SubGroupGeMaskARB";
84 case MASKTYPE_GT: return "gl_SubGroupGtMaskARB";
85 case MASKTYPE_LE: return "gl_SubGroupLeMaskARB";
86 case MASKTYPE_LT: return "gl_SubGroupLtMaskARB";
87 default: TCU_THROW(InternalError, "Unsupported mask type");
88 }
89 }
90
getBodySource(const CaseDefinition & caseDef)91 string getBodySource (const CaseDefinition& caseDef)
92 {
93 string body =
94 " uint64_t value = " + getMaskTypeName(caseDef.maskType) + ";\n"
95 " bool temp = true;\n";
96
97 switch(caseDef.maskType)
98 {
99 case MASKTYPE_EQ:
100 body += " uint64_t mask = uint64_t(1) << gl_SubGroupInvocationARB;\n"
101 " temp = (value & mask) != 0;\n";
102 break;
103 case MASKTYPE_GE:
104 body += " for (uint i = 0; i < gl_SubGroupSizeARB; i++) {\n"
105 " uint64_t mask = uint64_t(1) << i;\n"
106 " if (i >= gl_SubGroupInvocationARB && (value & mask) == 0)\n"
107 " temp = false;\n"
108 " if (i < gl_SubGroupInvocationARB && (value & mask) != 0)\n"
109 " temp = false;\n"
110 " };\n";
111 break;
112 case MASKTYPE_GT:
113 body += " for (uint i = 0; i < gl_SubGroupSizeARB; i++) {\n"
114 " uint64_t mask = uint64_t(1) << i;\n"
115 " if (i > gl_SubGroupInvocationARB && (value & mask) == 0)\n"
116 " temp = false;\n"
117 " if (i <= gl_SubGroupInvocationARB && (value & mask) != 0)\n"
118 " temp = false;\n"
119 " };\n";
120 break;
121 case MASKTYPE_LE:
122 body += " for (uint i = 0; i < gl_SubGroupSizeARB; i++) {\n"
123 " uint64_t mask = uint64_t(1) << i;\n"
124 " if (i <= gl_SubGroupInvocationARB && (value & mask) == 0)\n"
125 " temp = false;\n"
126 " if (i > gl_SubGroupInvocationARB && (value & mask) != 0)\n"
127 " temp = false;\n"
128 " };\n";
129 break;
130 case MASKTYPE_LT:
131 body += " for (uint i = 0; i < gl_SubGroupSizeARB; i++) {\n"
132 " uint64_t mask = uint64_t(1) << i;\n"
133 " if (i < gl_SubGroupInvocationARB && (value & mask) == 0)\n"
134 " temp = false;\n"
135 " if (i >= gl_SubGroupInvocationARB && (value & mask) != 0)\n"
136 " temp = false;\n"
137 " };\n";
138 break;
139 default:
140 TCU_THROW(InternalError, "Unknown mask type");
141 }
142
143 body += " uint tempResult = temp ? 0xf : 0x2;\n";
144 body += " tempRes = tempResult;\n";
145
146 return body;
147 }
148
getExtHeader(const CaseDefinition &)149 string getExtHeader (const CaseDefinition&)
150 {
151 return
152 "#extension GL_ARB_shader_ballot: enable\n"
153 "#extension GL_ARB_gpu_shader_int64: enable\n";
154 }
155
getPerStageHeadDeclarations(const CaseDefinition & caseDef)156 vector<string> getPerStageHeadDeclarations (const CaseDefinition& caseDef)
157 {
158 const deUint32 stageCount = subgroups::getStagesCount(caseDef.shaderStage);
159 const bool fragment = (caseDef.shaderStage & VK_SHADER_STAGE_FRAGMENT_BIT) != 0;
160 vector<string> result (stageCount, string());
161
162 if (fragment)
163 result.reserve(result.size() + 1);
164
165 for (size_t i = 0; i < result.size(); ++i)
166 {
167 result[i] =
168 "layout(set = 0, binding = " + de::toString(i) + ", std430) buffer Buffer1\n"
169 "{\n"
170 " uint result[];\n"
171 "};\n";
172 }
173
174 if (fragment)
175 {
176 const string fragPart =
177 "layout(location = 0) out uint result;\n";
178
179 result.push_back(fragPart);
180 }
181
182 return result;
183 }
184
getFramebufferPerStageHeadDeclarations(const CaseDefinition & caseDef)185 vector<string> getFramebufferPerStageHeadDeclarations (const CaseDefinition& caseDef)
186 {
187 vector<string> result;
188
189 DE_UNREF(caseDef);
190
191 result.push_back("layout(location = 0) out float result;\n");
192 result.push_back("layout(location = 0) out float out_color;\n");
193 result.push_back("layout(location = 0) out float out_color[];\n");
194 result.push_back("layout(location = 0) out float out_color;\n");
195
196 return result;
197 }
198
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)199 void initFrameBufferPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
200 {
201 const ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, SPIRV_VERSION_1_3, 0u);
202 const string extHeader = getExtHeader(caseDef);
203 const string testSrc = getBodySource(caseDef);
204 const vector<string> headDeclarations = getFramebufferPerStageHeadDeclarations(caseDef);
205 const bool pointSizeSupported = *caseDef.geometryPointSizeSupported;
206
207 subgroups::initStdFrameBufferPrograms(programCollection, buildOptions, caseDef.shaderStage, VK_FORMAT_R32_UINT, pointSizeSupported, extHeader, testSrc, "", headDeclarations);
208 }
209
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)210 void initPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
211 {
212 const SpirvVersion spirvVersion = isAllRayTracingStages(caseDef.shaderStage) ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3;
213 const ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, spirvVersion, 0u);
214 const string extHeader = getExtHeader(caseDef);
215 const string testSrc = getBodySource(caseDef);
216 const vector<string> headDeclarations = getPerStageHeadDeclarations(caseDef);
217 const bool pointSizeSupport = *caseDef.geometryPointSizeSupported;
218
219 subgroups::initStdPrograms(programCollection, buildOptions, caseDef.shaderStage, VK_FORMAT_R32_UINT, pointSizeSupport, extHeader, testSrc, "", headDeclarations);
220 }
221
supportedCheck(Context & context,CaseDefinition caseDef)222 void supportedCheck (Context& context, CaseDefinition caseDef)
223 {
224 if (!subgroups::isSubgroupSupported(context))
225 TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
226
227 if (!context.requireDeviceFunctionality("VK_EXT_shader_subgroup_ballot"))
228 {
229 TCU_THROW(NotSupportedError, "Device does not support VK_EXT_shader_subgroup_ballot extension");
230 }
231
232 if (!subgroups::isInt64SupportedForDevice(context))
233 TCU_THROW(NotSupportedError, "Int64 is not supported");
234
235 if (caseDef.requiredSubgroupSize)
236 {
237 context.requireDeviceFunctionality("VK_EXT_subgroup_size_control");
238
239 const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT& subgroupSizeControlFeatures = context.getSubgroupSizeControlFeaturesEXT();
240 const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT& subgroupSizeControlProperties = context.getSubgroupSizeControlPropertiesEXT();
241
242 if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
243 TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes nor required subgroup size");
244
245 if (subgroupSizeControlFeatures.computeFullSubgroups == DE_FALSE)
246 TCU_THROW(NotSupportedError, "Device does not support full subgroups in compute shaders");
247
248 if ((subgroupSizeControlProperties.requiredSubgroupSizeStages & caseDef.shaderStage) != caseDef.shaderStage)
249 TCU_THROW(NotSupportedError, "Required subgroup size is not supported for shader stage");
250 }
251
252 *caseDef.geometryPointSizeSupported = subgroups::isTessellationAndGeometryPointSizeSupported(context);
253
254 if (isAllRayTracingStages(caseDef.shaderStage))
255 {
256 context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
257 }
258
259 subgroups::supportedCheckShader(context, caseDef.shaderStage);
260 }
261
noSSBOtest(Context & context,const CaseDefinition caseDef)262 TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
263 {
264 switch (caseDef.shaderStage)
265 {
266 case VK_SHADER_STAGE_VERTEX_BIT: return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages);
267 case VK_SHADER_STAGE_GEOMETRY_BIT: return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages);
268 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages);
269 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages);
270 default: TCU_THROW(InternalError, "Unhandled shader stage");
271 }
272 }
273
test(Context & context,const CaseDefinition caseDef)274 TestStatus test (Context& context, const CaseDefinition caseDef)
275 {
276 if (isAllComputeStages(caseDef.shaderStage))
277 {
278 const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT& subgroupSizeControlProperties = context.getSubgroupSizeControlPropertiesEXT();
279 TestLog& log = context.getTestContext().getLog();
280
281 if (caseDef.requiredSubgroupSize == DE_FALSE)
282 return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkCompute);
283
284 log << TestLog::Message << "Testing required subgroup size range [" << subgroupSizeControlProperties.minSubgroupSize << ", "
285 << subgroupSizeControlProperties.maxSubgroupSize << "]" << TestLog::EndMessage;
286
287 // According to the spec, requiredSubgroupSize must be a power-of-two integer.
288 for (deUint32 size = subgroupSizeControlProperties.minSubgroupSize; size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
289 {
290 TestStatus result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0u, DE_NULL, checkCompute,
291 size, VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT);
292 if (result.getCode() != QP_TEST_RESULT_PASS)
293 {
294 log << TestLog::Message << "subgroupSize " << size << " failed" << TestLog::EndMessage;
295 return result;
296 }
297 }
298
299 return TestStatus::pass("OK");
300 }
301 else if (isAllGraphicsStages(caseDef.shaderStage))
302 {
303 const VkShaderStageFlags stages = subgroups::getPossibleGraphicsSubgroupStages(context, caseDef.shaderStage);
304
305 return subgroups::allStages(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages, stages);
306 }
307 else if (isAllRayTracingStages(caseDef.shaderStage))
308 {
309 const VkShaderStageFlags stages = subgroups::getPossibleRayTracingSubgroupStages(context, caseDef.shaderStage);
310
311 return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkVertexPipelineStages, stages);
312 }
313 else
314 TCU_THROW(InternalError, "Unknown stage or invalid stage set");
315 }
316 }
317
318 namespace vkt
319 {
320 namespace subgroups
321 {
createSubgroupsBallotMasksTests(TestContext & testCtx)322 TestCaseGroup* createSubgroupsBallotMasksTests (TestContext& testCtx)
323 {
324 de::MovePtr<TestCaseGroup> group (new TestCaseGroup(testCtx, "ballot_mask", "VK_EXT_shader_subgroup_ballot mask category tests"));
325 de::MovePtr<TestCaseGroup> groupARB (new TestCaseGroup(testCtx, "ext_shader_subgroup_ballot", "VK_EXT_shader_subgroup_ballot masks category tests"));
326 de::MovePtr<TestCaseGroup> graphicGroup (new TestCaseGroup(testCtx, "graphics", "VK_EXT_shader_subgroup_ballot masks category tests: graphics"));
327 de::MovePtr<TestCaseGroup> computeGroup (new TestCaseGroup(testCtx, "compute", "VK_EXT_shader_subgroup_ballot masks category tests: compute"));
328 de::MovePtr<TestCaseGroup> framebufferGroup (new TestCaseGroup(testCtx, "framebuffer", "VK_EXT_shader_subgroup_ballot masks category tests: framebuffer"));
329 de::MovePtr<TestCaseGroup> raytracingGroup (new TestCaseGroup(testCtx, "ray_tracing", "VK_EXT_shader_subgroup_ballot masks category tests: ray tracing"));
330 const VkShaderStageFlags stages[] =
331 {
332 VK_SHADER_STAGE_VERTEX_BIT,
333 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
334 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
335 VK_SHADER_STAGE_GEOMETRY_BIT,
336 };
337 const deBool boolValues[] =
338 {
339 DE_FALSE,
340 DE_TRUE
341 };
342
343 for (int maskTypeIndex = 0; maskTypeIndex < MASKTYPE_LAST; ++maskTypeIndex)
344 {
345 const MaskType maskType = static_cast<MaskType>(maskTypeIndex);
346 const string mask = de::toLower(getMaskTypeName(maskType));
347
348 for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
349 {
350 const deBool requiredSubgroupSize = boolValues[groupSizeNdx];
351 const string testName = mask + (requiredSubgroupSize ? "_requiredsubgroupsize" : "");
352 const CaseDefinition caseDef =
353 {
354 maskType, // MaskType maskType;
355 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlags shaderStage;
356 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
357 requiredSubgroupSize, // deBool requiredSubgroupSize;
358 };
359
360 addFunctionCaseWithPrograms(computeGroup.get(), testName, "", supportedCheck, initPrograms, test, caseDef);
361 }
362
363 {
364 const CaseDefinition caseDef =
365 {
366 maskType, // MaskType maskType;
367 VK_SHADER_STAGE_ALL_GRAPHICS, // VkShaderStageFlags shaderStage;
368 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
369 DE_FALSE // deBool requiredSubgroupSize;
370 };
371
372 addFunctionCaseWithPrograms(graphicGroup.get(), mask, "", supportedCheck, initPrograms, test, caseDef);
373 }
374
375 {
376 const CaseDefinition caseDef =
377 {
378 maskType, // MaskType maskType;
379 SHADER_STAGE_ALL_RAY_TRACING, // VkShaderStageFlags shaderStage;
380 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
381 DE_FALSE // deBool requiredSubgroupSize;
382 };
383
384 addFunctionCaseWithPrograms(raytracingGroup.get(), mask, "", supportedCheck, initPrograms, test, caseDef);
385 }
386
387 for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
388 {
389 const CaseDefinition caseDef =
390 {
391 maskType, // MaskType maskType;
392 stages[stageIndex], // VkShaderStageFlags shaderStage;
393 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
394 DE_FALSE // deBool requiredSubgroupSize;
395 };
396 const string testName = mask + "_" + getShaderStageName(caseDef.shaderStage);
397
398 addFunctionCaseWithPrograms(framebufferGroup.get(), testName, "", supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
399 }
400 }
401
402 groupARB->addChild(graphicGroup.release());
403 groupARB->addChild(computeGroup.release());
404 groupARB->addChild(framebufferGroup.release());
405 groupARB->addChild(raytracingGroup.release());
406 group->addChild(groupARB.release());
407
408 return group.release();
409 }
410
411 } // subgroups
412 } // vkt
413