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