1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  * Copyright (c) 2019 Google Inc.
7  * Copyright (c) 2017 Codeplay Software Ltd.
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */ /*!
22  * \file
23  * \brief Subgroups Tests
24  */ /*--------------------------------------------------------------------*/
25 
26 #include "vktSubgroupsShuffleTests.hpp"
27 #include "vktSubgroupsTestsUtils.hpp"
28 
29 #include <string>
30 #include <vector>
31 
32 using namespace tcu;
33 using namespace std;
34 using namespace vk;
35 using namespace vkt;
36 
37 namespace
38 {
39 enum OpType
40 {
41 	OPTYPE_SHUFFLE = 0,
42 	OPTYPE_SHUFFLE_XOR,
43 	OPTYPE_SHUFFLE_UP,
44 	OPTYPE_SHUFFLE_DOWN,
45 	OPTYPE_LAST
46 };
47 
48 // For the second arguments of Xor, Up and Down.
49 enum class ArgType
50 {
51 	DYNAMIC = 0,
52 	DYNAMICALLY_UNIFORM,
53 	CONSTANT
54 };
55 
56 struct CaseDefinition
57 {
58 	OpType				opType;
59 	VkShaderStageFlags	shaderStage;
60 	VkFormat			format;
61 	de::SharedPtr<bool>	geometryPointSizeSupported;
62 	deBool				requiredSubgroupSize;
63 	ArgType				argType;
64 	deBool				requires8BitUniformBuffer;
65 	deBool				requires16BitUniformBuffer;
66 };
67 
checkVertexPipelineStages(const void* internalData, vector<const void*> datas, deUint32 width, deUint32)68 static bool checkVertexPipelineStages (const void*			internalData,
69 									   vector<const void*>	datas,
70 									   deUint32				width,
71 									   deUint32)
72 {
73 	DE_UNREF(internalData);
74 
75 	return subgroups::check(datas, width, 1);
76 }
77 
checkComputeOrMesh(const void* internalData, vector<const void*> datas, const deUint32 numWorkgroups[3], const deUint32 localSize[3], deUint32)78 static bool checkComputeOrMesh (const void*			internalData,
79 								vector<const void*>	datas,
80 								const deUint32		numWorkgroups[3],
81 								const deUint32		localSize[3],
82 								deUint32)
83 {
84 	DE_UNREF(internalData);
85 
86 	return subgroups::checkComputeOrMesh(datas, numWorkgroups, localSize, 1);
87 }
88 
getOpTypeName(OpType opType)89 string getOpTypeName (OpType opType)
90 {
91 	switch (opType)
92 	{
93 		case OPTYPE_SHUFFLE:		return "subgroupShuffle";
94 		case OPTYPE_SHUFFLE_XOR:	return "subgroupShuffleXor";
95 		case OPTYPE_SHUFFLE_UP:		return "subgroupShuffleUp";
96 		case OPTYPE_SHUFFLE_DOWN:	return "subgroupShuffleDown";
97 		default:					TCU_THROW(InternalError, "Unsupported op type");
98 	}
99 }
100 
getExtHeader(const CaseDefinition& caseDef)101 string getExtHeader (const CaseDefinition& caseDef)
102 {
103 	const string	eSource		= (OPTYPE_SHUFFLE == caseDef.opType || OPTYPE_SHUFFLE_XOR == caseDef.opType)
104 								? "#extension GL_KHR_shader_subgroup_shuffle: enable\n"
105 								: "#extension GL_KHR_shader_subgroup_shuffle_relative: enable\n";
106 
107 	return	eSource
108 			+ "#extension GL_KHR_shader_subgroup_ballot: enable\n"
109 			+ subgroups::getAdditionalExtensionForFormat(caseDef.format);
110 }
111 
getPerStageHeadDeclarations(const CaseDefinition& caseDef)112 vector<string> getPerStageHeadDeclarations (const CaseDefinition& caseDef)
113 {
114 	const string	formatName	= subgroups::getFormatNameForGLSL(caseDef.format);
115 	const deUint32	stageCount	= subgroups::getStagesCount(caseDef.shaderStage);
116 	const bool		fragment	= (caseDef.shaderStage & VK_SHADER_STAGE_FRAGMENT_BIT) != 0;
117 	const size_t	resultSize	= stageCount + (fragment ? 1 : 0);
118 	vector<string>	result		(resultSize, string());
119 
120 	for (deUint32 i = 0; i < result.size(); ++i)
121 	{
122 		const deUint32	binding0	= i;
123 		const deUint32	binding1	= stageCount;
124 		const deUint32	binding2	= stageCount + 1;
125 		const string	buffer1		= (i == stageCount)
126 									? "layout(location = 0) out uint result;\n"
127 									: "layout(set = 0, binding = " + de::toString(binding0) + ", std430) buffer Buffer1\n"
128 									  "{\n"
129 									  "  uint result[];\n"
130 									  "};\n";
131 
132 		const string	b2Layout	= ((caseDef.argType == ArgType::DYNAMIC) ? "std430"				: "std140");
133 		const string	b2Type		= ((caseDef.argType == ArgType::DYNAMIC) ? "readonly buffer"	: "uniform");
134 
135 		result[i] =
136 			buffer1 +
137 			"layout(set = 0, binding = " + de::toString(binding1) + ", std430) readonly buffer Buffer2\n"
138 			"{\n"
139 			"  " + formatName + " data1[];\n"
140 			"};\n"
141 			"layout(set = 0, binding = " + de::toString(binding2) + ", " + b2Layout + ") " + b2Type + " Buffer3\n"
142 			"{\n"
143 			"  uint data2[];\n"
144 			"};\n";
145 	}
146 
147 	return result;
148 }
149 
getFramebufferPerStageHeadDeclarations(const CaseDefinition& caseDef)150 vector<string> getFramebufferPerStageHeadDeclarations (const CaseDefinition& caseDef)
151 {
152 	const string	formatName	= subgroups::getFormatNameForGLSL(caseDef.format);
153 	const deUint32	stageCount	= subgroups::getStagesCount(caseDef.shaderStage);
154 	vector<string>	result		(stageCount, string());
155 	const auto		b2Len		= ((caseDef.argType == ArgType::DYNAMIC) ? subgroups::maxSupportedSubgroupSize() : 1u);
156 	const string	buffer2
157 	{
158 		"layout(set = 0, binding = 0) uniform Buffer1\n"
159 		"{\n"
160 		"  " + formatName + " data1[" + de::toString(subgroups::maxSupportedSubgroupSize()) + "];\n"
161 		"};\n"
162 		"layout(set = 0, binding = 1) uniform Buffer2\n"
163 		"{\n"
164 		"  uint data2[" + de::toString(b2Len) + "];\n"
165 		"};\n"
166 	};
167 
168 	for (size_t i = 0; i < result.size(); ++i)
169 	{
170 		switch (i)
171 		{
172 			case 0: result[i] = "layout(location = 0) out float result;\n" + buffer2;		break;
173 			case 1: result[i] = "layout(location = 0) out float out_color;\n" + buffer2;	break;
174 			case 2: result[i] = "layout(location = 0) out float out_color[];\n" + buffer2;	break;
175 			case 3: result[i] = "layout(location = 0) out float out_color;\n" + buffer2;	break;
176 			default: TCU_THROW(InternalError, "Unknown stage");
177 		}
178 	}
179 
180 	return result;
181 }
182 
getTestSource(const CaseDefinition& caseDef)183 const string getTestSource (const CaseDefinition& caseDef)
184 {
185 	const string	id			= caseDef.opType == OPTYPE_SHUFFLE		? "id_in"
186 								: caseDef.opType == OPTYPE_SHUFFLE_XOR	? "gl_SubgroupInvocationID ^ id_in"
187 								: caseDef.opType == OPTYPE_SHUFFLE_UP	? "gl_SubgroupInvocationID - id_in"
188 								: caseDef.opType == OPTYPE_SHUFFLE_DOWN	? "gl_SubgroupInvocationID + id_in"
189 								: "";
190 	const string	idInSource	= caseDef.argType == ArgType::DYNAMIC				? "data2[gl_SubgroupInvocationID] & (gl_SubgroupSize - 1)"
191 								: caseDef.argType == ArgType::DYNAMICALLY_UNIFORM	? "data2[0] % 32"
192 								: caseDef.argType == ArgType::CONSTANT				? "5"
193 								: "";
194 	const string	testSource	=
195 		"  uint temp_res;\n"
196 		"  uvec4 mask = subgroupBallot(true);\n"
197 		"  uint id_in = " + idInSource + ";\n"
198 		"  " + subgroups::getFormatNameForGLSL(caseDef.format) + " op = "
199 		+ getOpTypeName(caseDef.opType) + "(data1[gl_SubgroupInvocationID], id_in);\n"
200 		"  uint id = " + id + ";\n"
201 		"  if ((id < gl_SubgroupSize) && subgroupBallotBitExtract(mask, id))\n"
202 		"  {\n"
203 		"    temp_res = (op == data1[id]) ? 1 : 0;\n"
204 		"  }\n"
205 		"  else\n"
206 		"  {\n"
207 		"    temp_res = 1; // Invocation we read from was inactive, so we can't verify results!\n"
208 		"  }\n"
209 		"  tempRes = temp_res;\n";
210 
211 	return testSource;
212 }
213 
initFrameBufferPrograms(SourceCollections& programCollection, CaseDefinition caseDef)214 void initFrameBufferPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
215 {
216 	const ShaderBuildOptions	buildOptions		(programCollection.usedVulkanVersion, SPIRV_VERSION_1_3, 0u);
217 	const string				extHeader			= getExtHeader(caseDef);
218 	const string				testSrc				= getTestSource(caseDef);
219 	const vector<string>		headDeclarations	= getFramebufferPerStageHeadDeclarations(caseDef);
220 	const bool					pointSizeSupported	= *caseDef.geometryPointSizeSupported;
221 
222 	subgroups::initStdFrameBufferPrograms(programCollection, buildOptions, caseDef.shaderStage, VK_FORMAT_R32_UINT, pointSizeSupported, extHeader, testSrc, "", headDeclarations);
223 }
224 
initPrograms(SourceCollections& programCollection, CaseDefinition caseDef)225 void initPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
226 {
227 #ifndef CTS_USES_VULKANSC
228 	const bool					spirv14required		= (isAllRayTracingStages(caseDef.shaderStage) || isAllMeshShadingStages(caseDef.shaderStage));
229 #else
230 	const bool					spirv14required		= false;
231 #endif // CTS_USES_VULKANSC
232 	const SpirvVersion			spirvVersion		= spirv14required ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3;
233 	const ShaderBuildOptions	buildOptions		(programCollection.usedVulkanVersion, spirvVersion, 0u, spirv14required);
234 	const string				extHeader			= getExtHeader(caseDef);
235 	const string				testSrc				= getTestSource(caseDef);
236 	const vector<string>		headDeclarations	= getPerStageHeadDeclarations(caseDef);
237 	const bool					pointSizeSupported	= *caseDef.geometryPointSizeSupported;
238 
239 	subgroups::initStdPrograms(programCollection, buildOptions, caseDef.shaderStage, VK_FORMAT_R32_UINT, pointSizeSupported, extHeader, testSrc, "", headDeclarations);
240 }
241 
supportedCheck(Context& context, CaseDefinition caseDef)242 void supportedCheck (Context& context, CaseDefinition caseDef)
243 {
244 	if (!subgroups::isSubgroupSupported(context))
245 		TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
246 
247 	switch (caseDef.opType)
248 	{
249 		case OPTYPE_SHUFFLE:
250 		case OPTYPE_SHUFFLE_XOR:
251 			if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_SHUFFLE_BIT))
252 			{
253 				TCU_THROW(NotSupportedError, "Device does not support subgroup shuffle operations");
254 			}
255 			break;
256 		default:
257 			if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT))
258 			{
259 				TCU_THROW(NotSupportedError, "Device does not support subgroup shuffle relative operations");
260 			}
261 			break;
262 	}
263 
264 	if (!subgroups::isFormatSupportedForDevice(context, caseDef.format))
265 		TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
266 
267 	if (caseDef.requires16BitUniformBuffer)
268 	{
269 		if (!subgroups::is16BitUBOStorageSupported(context))
270 		{
271 			TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
272 		}
273 	}
274 
275 	if (caseDef.requires8BitUniformBuffer)
276 	{
277 		if (!subgroups::is8BitUBOStorageSupported(context))
278 		{
279 			TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
280 		}
281 	}
282 
283 	if (caseDef.requiredSubgroupSize)
284 	{
285 		context.requireDeviceFunctionality("VK_EXT_subgroup_size_control");
286 
287 #ifndef CTS_USES_VULKANSC
288 		const VkPhysicalDeviceSubgroupSizeControlFeatures&		subgroupSizeControlFeatures		= context.getSubgroupSizeControlFeatures();
289 		const VkPhysicalDeviceSubgroupSizeControlProperties&	subgroupSizeControlProperties	= context.getSubgroupSizeControlProperties();
290 #else
291 		const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT&	subgroupSizeControlFeatures		= context.getSubgroupSizeControlFeaturesEXT();
292 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
293 #endif // CTS_USES_VULKANSC
294 
295 		if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
296 			TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes nor required subgroup size");
297 
298 		if (subgroupSizeControlFeatures.computeFullSubgroups == DE_FALSE)
299 			TCU_THROW(NotSupportedError, "Device does not support full subgroups in compute shaders");
300 
301 		if ((subgroupSizeControlProperties.requiredSubgroupSizeStages & caseDef.shaderStage) != caseDef.shaderStage)
302 			TCU_THROW(NotSupportedError, "Required subgroup size is not supported for shader stage");
303 	}
304 
305 	*caseDef.geometryPointSizeSupported = subgroups::isTessellationAndGeometryPointSizeSupported(context);
306 
307 #ifndef CTS_USES_VULKANSC
308 	if (isAllRayTracingStages(caseDef.shaderStage))
309 	{
310 		context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
311 	}
312 	else if (isAllMeshShadingStages(caseDef.shaderStage))
313 	{
314 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
315 		context.requireDeviceFunctionality("VK_EXT_mesh_shader");
316 
317 		if ((caseDef.shaderStage & VK_SHADER_STAGE_TASK_BIT_EXT) != 0u)
318 		{
319 			const auto& features = context.getMeshShaderFeaturesEXT();
320 			if (!features.taskShader)
321 				TCU_THROW(NotSupportedError, "Task shaders not supported");
322 		}
323 	}
324 #endif // CTS_USES_VULKANSC
325 
326 	subgroups::supportedCheckShader(context, caseDef.shaderStage);
327 }
328 
noSSBOtest(Context& context, const CaseDefinition caseDef)329 TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
330 {
331 	const VkDeviceSize			secondBufferSize = ((caseDef.argType == ArgType::DYNAMIC) ? subgroups::maxSupportedSubgroupSize() : 1u);
332 	const subgroups::SSBOData	inputData[2]
333 	{
334 		{
335 			subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
336 			subgroups::SSBOData::LayoutStd140,		//  InputDataLayoutType			layout;
337 			caseDef.format,							//  vk::VkFormat				format;
338 			subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
339 			subgroups::SSBOData::BindingUBO,		//  BindingType					bindingType;
340 		},
341 		{
342 			subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
343 			subgroups::SSBOData::LayoutStd140,		//  InputDataLayoutType			layout;
344 			VK_FORMAT_R32_UINT,						//  vk::VkFormat				format;
345 			secondBufferSize,						//  vk::VkDeviceSize			numElements;
346 			subgroups::SSBOData::BindingUBO,		//  BindingType					bindingType;
347 		}
348 	};
349 
350 	switch (caseDef.shaderStage)
351 	{
352 		case VK_SHADER_STAGE_VERTEX_BIT:					return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages);
353 		case VK_SHADER_STAGE_GEOMETRY_BIT:					return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages);
354 		case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:		return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
355 		case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:	return subgroups::makeTessellationEvaluationFrameBufferTest(context,  VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
356 		default:											TCU_THROW(InternalError, "Unhandled shader stage");
357 	}
358 }
359 
test(Context& context, const CaseDefinition caseDef)360 TestStatus test (Context& context, const CaseDefinition caseDef)
361 {
362 	const auto			secondBufferLayout	= ((caseDef.argType == ArgType::DYNAMIC)
363 											? subgroups::SSBOData::LayoutStd430
364 											: subgroups::SSBOData::LayoutStd140);
365 	const VkDeviceSize	secondBufferElems	= ((caseDef.argType == ArgType::DYNAMIC)
366 											? subgroups::maxSupportedSubgroupSize()
367 											: 1u);
368 	const auto			secondBufferType	= ((caseDef.argType == ArgType::DYNAMIC)
369 											? subgroups::SSBOData::BindingSSBO
370 											: subgroups::SSBOData::BindingUBO);
371 
372 	const bool			isCompute			= isAllComputeStages(caseDef.shaderStage);
373 #ifndef CTS_USES_VULKANSC
374 	const bool			isMesh				= isAllMeshShadingStages(caseDef.shaderStage);
375 #else
376 	const bool			isMesh				= false;
377 #endif // CTS_USES_VULKANSC
378 	DE_ASSERT(!(isCompute && isMesh));
379 
380 	if (isCompute || isMesh)
381 	{
382 #ifndef CTS_USES_VULKANSC
383 		const VkPhysicalDeviceSubgroupSizeControlProperties&	subgroupSizeControlProperties	= context.getSubgroupSizeControlProperties();
384 #else
385 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
386 #endif // CTS_USES_VULKANSC
387 		TestLog&												log								= context.getTestContext().getLog();
388 		const subgroups::SSBOData								inputData[2]
389 		{
390 			{
391 				subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
392 				subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
393 				caseDef.format,							//  vk::VkFormat				format;
394 				subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
395 			},
396 			{
397 				subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
398 				secondBufferLayout,						//  InputDataLayoutType			layout;
399 				VK_FORMAT_R32_UINT,						//  vk::VkFormat				format;
400 				secondBufferElems,						//  vk::VkDeviceSize			numElements;
401 				secondBufferType,
402 			},
403 		};
404 
405 		if (caseDef.requiredSubgroupSize == DE_FALSE)
406 		{
407 			if (isCompute)
408 				return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkComputeOrMesh);
409 			else
410 				return subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkComputeOrMesh);
411 		}
412 
413 		log << TestLog::Message << "Testing required subgroup size range [" <<  subgroupSizeControlProperties.minSubgroupSize << ", "
414 			<< subgroupSizeControlProperties.maxSubgroupSize << "]" << TestLog::EndMessage;
415 
416 		// According to the spec, requiredSubgroupSize must be a power-of-two integer.
417 		for (deUint32 size = subgroupSizeControlProperties.minSubgroupSize; size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
418 		{
419 			TestStatus result (QP_TEST_RESULT_INTERNAL_ERROR, "Internal Error");
420 
421 			if (isCompute)
422 				result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkComputeOrMesh, size);
423 			else
424 				result = subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkComputeOrMesh, size);
425 
426 			if (result.getCode() != QP_TEST_RESULT_PASS)
427 			{
428 				log << TestLog::Message << "subgroupSize " << size << " failed" << TestLog::EndMessage;
429 				return result;
430 			}
431 		}
432 
433 		return TestStatus::pass("OK");
434 	}
435 	else if (isAllGraphicsStages(caseDef.shaderStage))
436 	{
437 		const VkShaderStageFlags	stages			= subgroups::getPossibleGraphicsSubgroupStages(context, caseDef.shaderStage);
438 		const subgroups::SSBOData	inputData[2]
439 		{
440 			{
441 				subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
442 				subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
443 				caseDef.format,							//  vk::VkFormat				format;
444 				subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
445 				subgroups::SSBOData::BindingSSBO,		//  bool						isImage;
446 				4u,										//  deUint32					binding;
447 				stages,									//  vk::VkShaderStageFlags		stages;
448 			},
449 			{
450 				subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
451 				secondBufferLayout,						//  InputDataLayoutType			layout;
452 				VK_FORMAT_R32_UINT,						//  vk::VkFormat				format;
453 				secondBufferElems,						//  vk::VkDeviceSize			numElements;
454 				secondBufferType,						//  bool						isImage;
455 				5u,										//  deUint32					binding;
456 				stages,									//  vk::VkShaderStageFlags		stages;
457 			},
458 		};
459 
460 		return subgroups::allStages(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages, stages);
461 	}
462 #ifndef CTS_USES_VULKANSC
463 	else if (isAllRayTracingStages(caseDef.shaderStage))
464 	{
465 		const VkShaderStageFlags	stages			= subgroups::getPossibleRayTracingSubgroupStages(context, caseDef.shaderStage);
466 		const subgroups::SSBOData	inputData[2]
467 		{
468 			{
469 				subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
470 				subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
471 				caseDef.format,							//  vk::VkFormat				format;
472 				subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
473 				subgroups::SSBOData::BindingSSBO,		//  bool						isImage;
474 				6u,										//  deUint32					binding;
475 				stages,									//  vk::VkShaderStageFlags		stages;
476 			},
477 			{
478 				subgroups::SSBOData::InitializeNonZero,	//  InputDataInitializeType		initializeType;
479 				secondBufferLayout,						//  InputDataLayoutType			layout;
480 				VK_FORMAT_R32_UINT,						//  vk::VkFormat				format;
481 				secondBufferElems,						//  vk::VkDeviceSize			numElements;
482 				secondBufferType,						//  bool						isImage;
483 				7u,										//  deUint32					binding;
484 				stages,									//  vk::VkShaderStageFlags		stages;
485 			},
486 		};
487 
488 		return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, inputData, 2, DE_NULL, checkVertexPipelineStages, stages);
489 	}
490 #endif // CTS_USES_VULKANSC
491 	else
492 		TCU_THROW(InternalError, "Unknown stage or invalid stage set");
493 }
494 }
495 
496 namespace vkt
497 {
498 namespace subgroups
499 {
createSubgroupsShuffleTests(TestContext& testCtx)500 TestCaseGroup* createSubgroupsShuffleTests (TestContext& testCtx)
501 {
502 	de::MovePtr<TestCaseGroup>	group				(new TestCaseGroup(testCtx, "shuffle", "Subgroup shuffle category tests"));
503 
504 	de::MovePtr<TestCaseGroup>	graphicGroup		(new TestCaseGroup(testCtx, "graphics", "Subgroup shuffle category tests: graphics"));
505 	de::MovePtr<TestCaseGroup>	computeGroup		(new TestCaseGroup(testCtx, "compute", "Subgroup shuffle category tests: compute"));
506 	de::MovePtr<TestCaseGroup>	framebufferGroup	(new TestCaseGroup(testCtx, "framebuffer", "Subgroup shuffle category tests: framebuffer"));
507 #ifndef CTS_USES_VULKANSC
508 	de::MovePtr<TestCaseGroup>	raytracingGroup		(new TestCaseGroup(testCtx, "ray_tracing", "Subgroup shuffle category tests: ray tracing"));
509 	de::MovePtr<TestCaseGroup>	meshGroup			(new TestCaseGroup(testCtx, "mesh", "Subgroup shuffle category tests: mesh shading"));
510 #endif // CTS_USES_VULKANSC
511 
512 	const VkShaderStageFlags	fbStages[]			=
513 	{
514 		VK_SHADER_STAGE_VERTEX_BIT,
515 		VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
516 		VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
517 		VK_SHADER_STAGE_GEOMETRY_BIT,
518 	};
519 
520 #ifndef CTS_USES_VULKANSC
521 	const VkShaderStageFlags	meshStages[]		=
522 	{
523 		VK_SHADER_STAGE_MESH_BIT_EXT,
524 		VK_SHADER_STAGE_TASK_BIT_EXT,
525 	};
526 #endif // CTS_USES_VULKANSC
527 
528 	const deBool				boolValues[]		=
529 	{
530 		DE_FALSE,
531 		DE_TRUE
532 	};
533 
534 	const struct
535 	{
536 		ArgType		argType;
537 		const char*	suffix;
538 	} argCases[] =
539 	{
540 		{	ArgType::DYNAMIC,				""						},
541 		{	ArgType::DYNAMICALLY_UNIFORM,	"_dynamically_uniform"	},
542 		{	ArgType::CONSTANT,				"_constant"				},
543 	};
544 
545 	{
546 		const vector<VkFormat>	formats	= subgroups::getAllFormats();
547 
548 		for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
549 		{
550 			const VkFormat	format					= formats[formatIndex];
551 			const string	formatName				= subgroups::getFormatNameForGLSL(format);
552 			const bool		needs8BitUBOStorage		= isFormat8bitTy(format);
553 			const bool		needs16BitUBOStorage	= isFormat16BitTy(format);
554 
555 			for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
556 			{
557 				for (const auto& argCase : argCases)
558 				{
559 					const OpType opType = static_cast<OpType>(opTypeIndex);
560 
561 					if (opType == OPTYPE_SHUFFLE && argCase.argType != ArgType::DYNAMIC)
562 						continue;
563 
564 					const string name = de::toLower(getOpTypeName(opType)) + "_" + formatName + argCase.suffix;
565 
566 					{
567 						const CaseDefinition	caseDef		=
568 						{
569 							opType,							//  OpType				opType;
570 							VK_SHADER_STAGE_ALL_GRAPHICS,	//  VkShaderStageFlags	shaderStage;
571 							format,							//  VkFormat			format;
572 							de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
573 							DE_FALSE,						//  deBool				requiredSubgroupSize;
574 							argCase.argType,				//  ArgType				argType;
575 							DE_FALSE,						//  deBool				requires8BitUniformBuffer;
576 							DE_FALSE						//  deBool				requires16BitUniformBuffer;
577 						};
578 
579 						addFunctionCaseWithPrograms(graphicGroup.get(), name, supportedCheck, initPrograms, test, caseDef);
580 					}
581 
582 					for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
583 					{
584 						const deBool			requiredSubgroupSize	= boolValues[groupSizeNdx];
585 						const string			testName				= name + (requiredSubgroupSize ? "_requiredsubgroupsize" : "");
586 						const CaseDefinition	caseDef					=
587 						{
588 							opType,							//  OpType				opType;
589 							VK_SHADER_STAGE_COMPUTE_BIT,	//  VkShaderStageFlags	shaderStage;
590 							format,							//  VkFormat			format;
591 							de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
592 							requiredSubgroupSize,			//  deBool				requiredSubgroupSize;
593 							argCase.argType,				//  ArgType				argType;
594 							DE_FALSE,						//  deBool				requires8BitUniformBuffer;
595 							DE_FALSE						//  deBool				requires16BitUniformBuffer;
596 						};
597 
598 						addFunctionCaseWithPrograms(computeGroup.get(), testName,supportedCheck, initPrograms, test, caseDef);
599 					}
600 
601 #ifndef CTS_USES_VULKANSC
602 					for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
603 					{
604 						for (const auto& stage : meshStages)
605 						{
606 							const deBool			requiredSubgroupSize	= boolValues[groupSizeNdx];
607 							const string			testName				= name + (requiredSubgroupSize ? "_requiredsubgroupsize" : "") + "_" + getShaderStageName(stage);
608 							const CaseDefinition	caseDef					=
609 							{
610 								opType,							//  OpType				opType;
611 								stage,							//  VkShaderStageFlags	shaderStage;
612 								format,							//  VkFormat			format;
613 								de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
614 								requiredSubgroupSize,			//  deBool				requiredSubgroupSize;
615 								argCase.argType,				//  ArgType				argType;
616 								DE_FALSE,						//  deBool				requires8BitUniformBuffer;
617 								DE_FALSE,						//  deBool				requires16BitUniformBuffer;
618 							};
619 
620 							addFunctionCaseWithPrograms(meshGroup.get(), testName,supportedCheck, initPrograms, test, caseDef);
621 						}
622 					}
623 #endif // CTS_USES_VULKANSC
624 
625 					for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(fbStages); ++stageIndex)
626 					{
627 						const CaseDefinition	caseDef		=
628 						{
629 							opType,							//  OpType				opType;
630 							fbStages[stageIndex],			//  VkShaderStageFlags	shaderStage;
631 							format,							//  VkFormat			format;
632 							de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
633 							DE_FALSE,						//  deBool				requiredSubgroupSize;
634 							argCase.argType,				//  ArgType				argType;
635 							deBool(needs8BitUBOStorage),	//  deBool				requires8BitUniformBuffer;
636 							deBool(needs16BitUBOStorage)	//  deBool				requires16BitUniformBuffer;
637 						};
638 						const string			testName	= name + "_" + getShaderStageName(caseDef.shaderStage);
639 
640 						addFunctionCaseWithPrograms(framebufferGroup.get(), testName,supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
641 					}
642 				}
643 			}
644 		}
645 	}
646 
647 #ifndef CTS_USES_VULKANSC
648 	{
649 		const vector<VkFormat>	formats	= subgroups::getAllRayTracingFormats();
650 
651 		for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
652 		{
653 			const VkFormat	format		= formats[formatIndex];
654 			const string	formatName	= subgroups::getFormatNameForGLSL(format);
655 
656 			for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
657 			{
658 				for (const auto& argCase : argCases)
659 				{
660 					const OpType opType = static_cast<OpType>(opTypeIndex);
661 
662 					if (opType == OPTYPE_SHUFFLE && argCase.argType != ArgType::DYNAMIC)
663 						continue;
664 
665 					const string			name	= de::toLower(getOpTypeName(opType)) + "_" + formatName + argCase.suffix;
666 					const CaseDefinition	caseDef	=
667 					{
668 						opType,							//  OpType				opType;
669 						SHADER_STAGE_ALL_RAY_TRACING,	//  VkShaderStageFlags	shaderStage;
670 						format,							//  VkFormat			format;
671 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
672 						DE_FALSE,						//  deBool				requiredSubgroupSize;
673 						argCase.argType,				//  ArgType				argType;
674 						DE_FALSE,						//  deBool				requires8BitUniformBuffer;
675 						DE_FALSE						//  deBool				requires16BitUniformBuffer;
676 					};
677 
678 					addFunctionCaseWithPrograms(raytracingGroup.get(), name, supportedCheck, initPrograms, test, caseDef);
679 				}
680 			}
681 		}
682 	}
683 #endif // CTS_USES_VULKANSC
684 
685 	group->addChild(graphicGroup.release());
686 	group->addChild(computeGroup.release());
687 	group->addChild(framebufferGroup.release());
688 #ifndef CTS_USES_VULKANSC
689 	group->addChild(raytracingGroup.release());
690 	group->addChild(meshGroup.release());
691 #endif // CTS_USES_VULKANSC
692 
693 	return group.release();
694 }
695 
696 } // subgroups
697 } // vkt
698