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