• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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