1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2020 Google LLC
6 * Copyright (c) 2020 The Khronos Group Inc.
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 Test new features in VK_KHR_shader_subgroup_uniform_control_flow
23 *//*--------------------------------------------------------------------*/
24
25 #include <amber/amber.h>
26
27 #include "tcuDefs.hpp"
28
29 #include "vkDefs.hpp"
30 #include "vkDeviceUtil.hpp"
31 #include "vktTestGroupUtil.hpp"
32 #include "vktAmberTestCase.hpp"
33 #include "vktSubgroupUniformControlFlowTests.hpp"
34 #include "vktTestGroupUtil.hpp"
35
36 namespace vkt
37 {
38 namespace subgroups
39 {
40 namespace
41 {
42
43 struct Case
44 {
Casevkt::subgroups::__anon076a03b50111::Case45 Case(const char* b, const char* d, bool sw, bool use_ssc, vk::VkShaderStageFlagBits s, vk::VkSubgroupFeatureFlagBits o) :
46 basename(b),
47 description(d),
48 small_workgroups(sw),
49 use_subgroup_size_control(use_ssc),
50 stage(s)
51 {
52 operation = (vk::VkSubgroupFeatureFlagBits)(o | vk::VK_SUBGROUP_FEATURE_BASIC_BIT);
53 }
54 const char* basename;
55 const char* description;
56 bool small_workgroups;
57 bool use_subgroup_size_control;
58 vk::VkShaderStageFlagBits stage;
59 vk::VkSubgroupFeatureFlagBits operation;
60 };
61
62 struct CaseGroup
63 {
CaseGroupvkt::subgroups::__anon076a03b50111::CaseGroup64 CaseGroup(const char* the_data_dir, const char* the_subdir) : data_dir(the_data_dir), subdir(the_subdir) { }
addvkt::subgroups::__anon076a03b50111::CaseGroup65 void add(const char* basename, const char* description, bool small_workgroups, bool use_subgroup_size_control, vk::VkShaderStageFlagBits stage, vk::VkSubgroupFeatureFlagBits operation = vk::VK_SUBGROUP_FEATURE_BASIC_BIT)
66 {
67 cases.push_back(Case(basename, description, small_workgroups, use_subgroup_size_control, stage, operation));
68 }
69
70 const char* data_dir;
71 const char* subdir;
72 std::vector<Case> cases;
73 };
74
75 class SubgroupUniformControlFlowTestCase : public cts_amber::AmberTestCase
76 {
77 public:
SubgroupUniformControlFlowTestCase(tcu::TestContext & testCtx,const char * name,const char * description,const std::string & readFilename,bool small_workgroups,bool use_subgroup_size_control,vk::VkShaderStageFlagBits stage,vk::VkSubgroupFeatureFlagBits operation)78 SubgroupUniformControlFlowTestCase(tcu::TestContext& testCtx,
79 const char* name,
80 const char* description,
81 const std::string& readFilename,
82 bool small_workgroups,
83 bool use_subgroup_size_control,
84 vk::VkShaderStageFlagBits stage,
85 vk::VkSubgroupFeatureFlagBits operation) :
86 cts_amber::AmberTestCase(testCtx, name, description, readFilename),
87 m_small_workgroups(small_workgroups),
88 m_use_subgroup_size_control(use_subgroup_size_control),
89 m_stage(stage),
90 m_operation(operation)
91 { }
92
93 virtual void checkSupport(Context& ctx) const; // override
94 private:
95 bool m_small_workgroups;
96 bool m_use_subgroup_size_control;
97 vk::VkShaderStageFlagBits m_stage;
98 vk::VkSubgroupFeatureFlagBits m_operation;
99 };
100
checkSupport(Context & ctx) const101 void SubgroupUniformControlFlowTestCase::checkSupport(Context& ctx) const
102 {
103 // Check required extensions.
104 ctx.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2");
105 ctx.requireDeviceFunctionality("VK_KHR_shader_subgroup_uniform_control_flow");
106 if (m_use_subgroup_size_control)
107 {
108 ctx.requireDeviceFunctionality("VK_EXT_subgroup_size_control");
109 }
110
111 vk::VkPhysicalDeviceSubgroupProperties subgroupProperties;
112 subgroupProperties.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
113 subgroupProperties.pNext = DE_NULL;
114
115 vk::VkPhysicalDeviceProperties2 properties2;
116 properties2.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
117 properties2.pNext = &subgroupProperties;
118
119 ctx.getInstanceInterface().getPhysicalDeviceProperties2(ctx.getPhysicalDevice(), &properties2);
120
121 vk::VkPhysicalDeviceSubgroupSizeControlFeaturesEXT subgroupSizeControlFeatures;
122 subgroupSizeControlFeatures.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT;
123 subgroupSizeControlFeatures.pNext = DE_NULL;
124
125 vk::VkPhysicalDeviceFeatures2 features2;
126 features2.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
127 features2.pNext = &subgroupSizeControlFeatures;
128
129 ctx.getInstanceInterface().getPhysicalDeviceFeatures2(ctx.getPhysicalDevice(), &features2);
130
131 // Check that the stage supports the required subgroup operations.
132 if ((m_stage & subgroupProperties.supportedStages) == 0)
133 {
134 TCU_THROW(NotSupportedError, "Device does not support subgroup operations in this stage");
135 }
136 if ((m_operation & subgroupProperties.supportedOperations) != m_operation)
137 {
138 TCU_THROW(NotSupportedError, "Device does not support required operations");
139 }
140
141 // For the compute shader tests, there are variants for implementations
142 // that support the subgroup size control extension and variants for those
143 // that do not. It is expected that computeFullSubgroups must be set for
144 // these tests if the extension is supported so tests are only supported
145 // for the extension appropriate version.
146 if (m_stage == vk::VK_SHADER_STAGE_COMPUTE_BIT)
147 {
148 if (m_use_subgroup_size_control)
149 {
150 if (subgroupSizeControlFeatures.computeFullSubgroups != VK_TRUE)
151 {
152 TCU_THROW(NotSupportedError, "Implementation does not support subgroup size control");
153 }
154 }
155 else
156 {
157 if (subgroupSizeControlFeatures.computeFullSubgroups == VK_TRUE)
158 {
159 TCU_THROW(NotSupportedError, "These tests are not enabled for subgroup size control implementations");
160 }
161 }
162 }
163
164 // The are large and small variants of the tests. The large variants
165 // require 256 invocations in a workgroup.
166 if (!m_small_workgroups)
167 {
168 vk::VkPhysicalDeviceProperties properties;
169 ctx.getInstanceInterface().getPhysicalDeviceProperties(ctx.getPhysicalDevice(), &properties);
170 if (properties.limits.maxComputeWorkGroupInvocations < 256)
171 {
172 TCU_THROW(NotSupportedError, "Device supported fewer than 256 invocations per workgroup");
173 }
174 }
175 }
176
addTestsForAmberFiles(tcu::TestCaseGroup * tests,CaseGroup group)177 template<bool requirements> void addTestsForAmberFiles(tcu::TestCaseGroup* tests, CaseGroup group)
178 {
179 tcu::TestContext& testCtx = tests->getTestContext();
180 const std::string data_dir(group.data_dir);
181 const std::string subdir(group.subdir);
182 const std::string category = data_dir + "/" + subdir;
183 std::vector<Case> cases(group.cases);
184
185 for (unsigned i = 0; i < cases.size(); ++i)
186 {
187 const std::string file = std::string(cases[i].basename) + ".amber";
188 std::string readFilename("vulkan/amber/");
189 readFilename.append(category);
190 readFilename.append("/");
191 readFilename.append(file);
192 SubgroupUniformControlFlowTestCase* testCase =
193 new SubgroupUniformControlFlowTestCase(testCtx,
194 cases[i].basename,
195 cases[i].description,
196 readFilename,
197 cases[i].small_workgroups,
198 cases[i].use_subgroup_size_control,
199 cases[i].stage,
200 cases[i].operation);
201 DE_ASSERT(testCase != DE_NULL);
202 if (requirements)
203 {
204 testCase->addRequirement("SubgroupSizeControl.computeFullSubgroups");
205 testCase->addRequirement("SubgroupSizeControl.subgroupSizeControl");
206 }
207 tests->addChild(testCase);
208 }
209 }
210
211 } // anonymous
212
createSubgroupUniformControlFlowTests(tcu::TestContext & testCtx)213 tcu::TestCaseGroup* createSubgroupUniformControlFlowTests(tcu::TestContext& testCtx)
214 {
215 // There are four main groups of tests. Each group runs the same set of base
216 // shaders with minor variations. The groups are with or without compute full
217 // subgroups and a larger or smaller number of invocations. For each group of
218 // tests, shaders test either odd or even subgroups reconverge after
219 // diverging, without reconverging the whole workgroup. For the _partial
220 // tests, the workgroup is launched without a full final subgroup (not enough
221 // invocations).
222 //
223 // It is assumed that if an implementation does not support the compute full
224 // subgroups feature, that it will always launch full subgroups. Therefore,
225 // any given implementation only runs half of the tests. Implementations that
226 // do not support compute full subgroups cannot support the tests that enable
227 // it, while implementations that do support the feature will (likely) not
228 // pass the tests that do not enable the feature.
229
230 de::MovePtr<tcu::TestCaseGroup> uniformControlFlowTests(new tcu::TestCaseGroup(testCtx, "subgroup_uniform_control_flow", "VK_KHR_shader_subgroup_uniform_control_flow tests"));
231
232 // Location of the Amber script files under data/vulkan/amber source tree.
233 const char* data_dir = "subgroup_uniform_control_flow";
234 const char* large_dir = "large";
235 const char* small_dir = "small";
236 const char* large_control_dir = "large_control";
237 const char* small_control_dir = "small_control";
238
239 std::vector<bool> controls = {false, true};
240 for (unsigned c = 0; c < controls.size(); ++c)
241 {
242 // Full subgroups.
243 bool small = false;
244 bool control = controls[c];
245 vk::VkShaderStageFlagBits stage = vk::VK_SHADER_STAGE_COMPUTE_BIT;
246 const char* subdir = (control ? large_control_dir : large_dir);
247 CaseGroup group(data_dir, subdir);
248 group.add("subgroup_reconverge00", "if/else diverge", small, control, stage);
249 group.add("subgroup_reconverge01", "do while diverge", small, control, stage);
250 group.add("subgroup_reconverge02", "while true with break", small, control, stage);
251 group.add("subgroup_reconverge03", "if/else diverge, volatile", small, control, stage);
252 group.add("subgroup_reconverge04", "early return and if/else diverge", small, control, stage);
253 group.add("subgroup_reconverge05", "early return and if/else volatile", small, control, stage);
254 group.add("subgroup_reconverge06", "while true with volatile conditional break and early return", small, control, stage);
255 group.add("subgroup_reconverge07", "while true return and break", small, control, stage);
256 group.add("subgroup_reconverge08", "for loop atomics with conditional break", small, control, stage);
257 group.add("subgroup_reconverge09", "diverge in for loop", small, control, stage);
258 group.add("subgroup_reconverge10", "diverge in for loop and break", small, control, stage);
259 group.add("subgroup_reconverge11", "diverge in for loop and continue", small, control, stage);
260 group.add("subgroup_reconverge12", "early return, divergent switch", small, control, stage);
261 group.add("subgroup_reconverge13", "early return, divergent switch more cases", small, control, stage);
262 group.add("subgroup_reconverge14", "divergent switch, some subgroups terminate", small, control, stage);
263 group.add("subgroup_reconverge15", "switch in switch", small, control, stage);
264 group.add("subgroup_reconverge16", "for loop unequal iterations", small, control, stage);
265 group.add("subgroup_reconverge17", "if/else with nested returns", small, control, stage);
266 group.add("subgroup_reconverge18", "if/else subgroup all equal", small, control, stage, vk::VK_SUBGROUP_FEATURE_VOTE_BIT);
267 group.add("subgroup_reconverge19", "if/else subgroup any nested return", small, control, stage, vk::VK_SUBGROUP_FEATURE_VOTE_BIT);
268 group.add("subgroup_reconverge20", "deeply nested", small, control, stage);
269 const char* group_name = (control ? "large_full_control" : "large_full");
270 uniformControlFlowTests->addChild(createTestGroup(testCtx, group_name,
271 "Large Full subgroups",
272 control?addTestsForAmberFiles<true>:addTestsForAmberFiles<false>, group));
273
274 // Partial subgroup.
275 group = CaseGroup(data_dir, subdir);
276 group.add("subgroup_reconverge_partial00", "if/else diverge", small, control, stage);
277 group.add("subgroup_reconverge_partial01", "do while diverge", small, control, stage);
278 group.add("subgroup_reconverge_partial02", "while true with break", small, control, stage);
279 group.add("subgroup_reconverge_partial03", "if/else diverge, volatile", small, control, stage);
280 group.add("subgroup_reconverge_partial04", "early return and if/else diverge", small, control, stage);
281 group.add("subgroup_reconverge_partial05", "early return and if/else volatile", small, control, stage);
282 group.add("subgroup_reconverge_partial06", "while true with volatile conditional break and early return", small, control, stage);
283 group.add("subgroup_reconverge_partial07", "while true return and break", small, control, stage);
284 group.add("subgroup_reconverge_partial08", "for loop atomics with conditional break", small, control, stage);
285 group.add("subgroup_reconverge_partial09", "diverge in for loop", small, control, stage);
286 group.add("subgroup_reconverge_partial10", "diverge in for loop and break", small, control, stage);
287 group.add("subgroup_reconverge_partial11", "diverge in for loop and continue", small, control, stage);
288 group.add("subgroup_reconverge_partial12", "early return, divergent switch", small, control, stage);
289 group.add("subgroup_reconverge_partial13", "early return, divergent switch more cases", small, control, stage);
290 group.add("subgroup_reconverge_partial14", "divergent switch, some subgroups terminate", small, control, stage);
291 group.add("subgroup_reconverge_partial15", "switch in switch", small, control, stage);
292 group.add("subgroup_reconverge_partial16", "for loop unequal iterations", small, control, stage);
293 group.add("subgroup_reconverge_partial17", "if/else with nested returns", small, control, stage);
294 group.add("subgroup_reconverge_partial18", "if/else subgroup all equal", small, control, stage, vk::VK_SUBGROUP_FEATURE_VOTE_BIT);
295 group.add("subgroup_reconverge_partial19", "if/else subgroup any nested return", small, control, stage, vk::VK_SUBGROUP_FEATURE_VOTE_BIT);
296 group.add("subgroup_reconverge_partial20", "deeply nested", small, control, stage);
297 group_name = (control ? "large_partial_control" : "large_partial");
298 uniformControlFlowTests->addChild(createTestGroup(testCtx, group_name,
299 "Large Partial subgroups",
300 control?addTestsForAmberFiles<true>:addTestsForAmberFiles<false>, group));
301 }
302
303 for (unsigned c = 0; c < controls.size(); ++c)
304 {
305 // Full subgroups.
306 bool small = true;
307 bool control = controls[c];
308 vk::VkShaderStageFlagBits stage = vk::VK_SHADER_STAGE_COMPUTE_BIT;
309 const char* subdir = (control ? small_control_dir : small_dir);
310 CaseGroup group(data_dir, subdir);
311 group.add("small_subgroup_reconverge00", "if/else diverge", small, control, stage);
312 group.add("small_subgroup_reconverge01", "do while diverge", small, control, stage);
313 group.add("small_subgroup_reconverge02", "while true with break", small, control, stage);
314 group.add("small_subgroup_reconverge03", "if/else diverge, volatile", small, control, stage);
315 group.add("small_subgroup_reconverge04", "early return and if/else diverge", small, control, stage);
316 group.add("small_subgroup_reconverge05", "early return and if/else volatile", small, control, stage);
317 group.add("small_subgroup_reconverge06", "while true with volatile conditional break and early return", small, control, stage);
318 group.add("small_subgroup_reconverge07", "while true return and break", small, control, stage);
319 group.add("small_subgroup_reconverge08", "for loop atomics with conditional break", small, control, stage);
320 group.add("small_subgroup_reconverge09", "diverge in for loop", small, control, stage);
321 group.add("small_subgroup_reconverge10", "diverge in for loop and break", small, control, stage);
322 group.add("small_subgroup_reconverge11", "diverge in for loop and continue", small, control, stage);
323 group.add("small_subgroup_reconverge12", "early return, divergent switch", small, control, stage);
324 group.add("small_subgroup_reconverge13", "early return, divergent switch more cases", small, control, stage);
325 group.add("small_subgroup_reconverge14", "divergent switch, some subgroups terminate", small, control, stage);
326 group.add("small_subgroup_reconverge15", "switch in switch", small, control, stage);
327 group.add("small_subgroup_reconverge16", "for loop unequal iterations", small, control, stage);
328 group.add("small_subgroup_reconverge17", "if/else with nested returns", small, control, stage);
329 group.add("small_subgroup_reconverge18", "if/else subgroup all equal", small, control, stage, vk::VK_SUBGROUP_FEATURE_VOTE_BIT);
330 group.add("small_subgroup_reconverge19", "if/else subgroup any nested return", small, control, stage, vk::VK_SUBGROUP_FEATURE_VOTE_BIT);
331 group.add("small_subgroup_reconverge20", "deeply nested", small, control, stage);
332 const char* group_name = (control ? "small_full_control" : "small_full");
333 uniformControlFlowTests->addChild(createTestGroup(testCtx, group_name,
334 "Small Full subgroups",
335 control?addTestsForAmberFiles<true>:addTestsForAmberFiles<false>, group));
336
337 // Partial subgroup.
338 group = CaseGroup(data_dir, subdir);
339 group.add("small_subgroup_reconverge_partial00", "if/else diverge", small, control, stage);
340 group.add("small_subgroup_reconverge_partial01", "do while diverge", small, control, stage);
341 group.add("small_subgroup_reconverge_partial02", "while true with break", small, control, stage);
342 group.add("small_subgroup_reconverge_partial03", "if/else diverge, volatile", small, control, stage);
343 group.add("small_subgroup_reconverge_partial04", "early return and if/else diverge", small, control, stage);
344 group.add("small_subgroup_reconverge_partial05", "early return and if/else volatile", small, control, stage);
345 group.add("small_subgroup_reconverge_partial06", "while true with volatile conditional break and early return", small, control, stage);
346 group.add("small_subgroup_reconverge_partial07", "while true return and break", small, control, stage);
347 group.add("small_subgroup_reconverge_partial08", "for loop atomics with conditional break", small, control, stage);
348 group.add("small_subgroup_reconverge_partial09", "diverge in for loop", small, control, stage);
349 group.add("small_subgroup_reconverge_partial10", "diverge in for loop and break", small, control, stage);
350 group.add("small_subgroup_reconverge_partial11", "diverge in for loop and continue", small, control, stage);
351 group.add("small_subgroup_reconverge_partial12", "early return, divergent switch", small, control, stage);
352 group.add("small_subgroup_reconverge_partial13", "early return, divergent switch more cases", small, control, stage);
353 group.add("small_subgroup_reconverge_partial14", "divergent switch, some subgroups terminate", small, control, stage);
354 group.add("small_subgroup_reconverge_partial15", "switch in switch", small, control, stage);
355 group.add("small_subgroup_reconverge_partial16", "for loop unequal iterations", small, control, stage);
356 group.add("small_subgroup_reconverge_partial17", "if/else with nested returns", small, control, stage);
357 group.add("small_subgroup_reconverge_partial18", "if/else subgroup all equal", small, control, stage, vk::VK_SUBGROUP_FEATURE_VOTE_BIT);
358 group.add("small_subgroup_reconverge_partial19", "if/else subgroup any nested return", small, control, stage, vk::VK_SUBGROUP_FEATURE_VOTE_BIT);
359 group.add("small_subgroup_reconverge_partial20", "deeply nested", small, control, stage);
360 group_name = (control ? "small_partial_control" : "small_partial");
361 uniformControlFlowTests->addChild(createTestGroup(testCtx, group_name,
362 "Small Partial subgroups",
363 control?addTestsForAmberFiles<true>:addTestsForAmberFiles<false>, group));
364 }
365
366 // Discard test
367 CaseGroup group(data_dir, "discard");
368 group.add("subgroup_reconverge_discard00", "discard test", true, false, vk::VK_SHADER_STAGE_FRAGMENT_BIT);
369 uniformControlFlowTests->addChild(createTestGroup(testCtx, "discard",
370 "Discard tests",
371 addTestsForAmberFiles<false>, group));
372
373 return uniformControlFlowTests.release();
374 }
375
376 } // subgroups
377 } // vkt
378