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