• 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::__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