• 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 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 "vktSubgroupsVoteTests.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_ALL			= 0,
42 	OPTYPE_ANY			= 1,
43 	OPTYPE_ALLEQUAL		= 2,
44 	OPTYPE_LAST_NON_ARB	= 3,
45 	OPTYPE_ALL_ARB		= 4,
46 	OPTYPE_ANY_ARB		= 5,
47 	OPTYPE_ALLEQUAL_ARB	= 6,
48 	OPTYPE_LAST
49 };
50 
51 struct CaseDefinition
52 {
53 	OpType				opType;
54 	VkShaderStageFlags	shaderStage;
55 	VkFormat			format;
56 	de::SharedPtr<bool>	geometryPointSizeSupported;
57 	deBool				requiredSubgroupSize;
58 	deBool				requires8BitUniformBuffer;
59 	deBool				requires16BitUniformBuffer;
60 };
61 
checkVertexPipelineStages(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)62 static bool checkVertexPipelineStages (const void*			internalData,
63 									   vector<const void*>	datas,
64 									   deUint32				width,
65 									   deUint32)
66 {
67 	DE_UNREF(internalData);
68 
69 	return subgroups::check(datas, width, 0x1F);
70 }
71 
checkFragmentPipelineStages(const void * internalData,vector<const void * > datas,deUint32 width,deUint32 height,deUint32)72 static bool checkFragmentPipelineStages (const void*			internalData,
73 										 vector<const void*>	datas,
74 										 deUint32				width,
75 										 deUint32				height,
76 										 deUint32)
77 {
78 	DE_UNREF(internalData);
79 
80 	const deUint32* data = reinterpret_cast<const deUint32*>(datas[0]);
81 
82 	for (deUint32 x = 0u; x < width; ++x)
83 	{
84 		for (deUint32 y = 0u; y < height; ++y)
85 		{
86 			const deUint32 ndx = (x * height + y);
87 			const deUint32 val = data[ndx] & 0x1F;
88 
89 			if (data[ndx] & 0x40) //Helper fragment shader invocation was executed
90 			{
91 				if(val != 0x1F)
92 					return false;
93 			}
94 			else //Helper fragment shader invocation was not executed yet
95 			{
96 				if (val != 0x1E)
97 					return false;
98 			}
99 		}
100 	}
101 
102 	return true;
103 }
104 
checkComputeOrMesh(const void * internalData,vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)105 static bool checkComputeOrMesh (const void*			internalData,
106 								vector<const void*>	datas,
107 								const deUint32		numWorkgroups[3],
108 								const deUint32		localSize[3],
109 								deUint32)
110 {
111 	DE_UNREF(internalData);
112 
113 	return subgroups::checkComputeOrMesh(datas, numWorkgroups, localSize, 0x1F);
114 }
115 
getOpTypeName(int opType)116 string getOpTypeName (int opType)
117 {
118 	switch (opType)
119 	{
120 		case OPTYPE_ALL:			return "subgroupAll";
121 		case OPTYPE_ANY:			return "subgroupAny";
122 		case OPTYPE_ALLEQUAL:		return "subgroupAllEqual";
123 		case OPTYPE_ALL_ARB:		return "allInvocationsARB";
124 		case OPTYPE_ANY_ARB:		return "anyInvocationARB";
125 		case OPTYPE_ALLEQUAL_ARB:	return "allInvocationsEqualARB";
126 		default:					TCU_THROW(InternalError, "Unsupported op type");
127 	}
128 }
129 
fmtIsBoolean(VkFormat format)130 bool fmtIsBoolean (VkFormat format)
131 {
132 	// For reasons unknown, the tests use R8_USCALED as the boolean format
133 	return	format == VK_FORMAT_R8_USCALED || format == VK_FORMAT_R8G8_USCALED ||
134 			format == VK_FORMAT_R8G8B8_USCALED || format == VK_FORMAT_R8G8B8A8_USCALED;
135 }
136 
getExtensions(bool arbFunctions)137 const string getExtensions (bool arbFunctions)
138 {
139 	return arbFunctions	?	"#extension GL_ARB_shader_group_vote: enable\n"
140 							"#extension GL_KHR_shader_subgroup_basic: enable\n"
141 						:	"#extension GL_KHR_shader_subgroup_vote: enable\n";
142 }
143 
getStageTestSource(const CaseDefinition & caseDef)144 const string getStageTestSource (const CaseDefinition& caseDef)
145 {
146 	const bool		formatIsBoolean	= fmtIsBoolean(caseDef.format);
147 	const string	op				= getOpTypeName(caseDef.opType);
148 	const string	fmt				= subgroups::getFormatNameForGLSL(caseDef.format);
149 	const string	computePart		= isAllComputeStages(caseDef.shaderStage)
150 									? op + "(data[gl_SubgroupInvocationID] > 0) ? 0x4 : 0x0"
151 									: "0x4";
152 
153 	return
154 		(OPTYPE_ALL == caseDef.opType || OPTYPE_ALL_ARB == caseDef.opType) ?
155 			"  tempRes = " + op + "(true) ? 0x1 : 0;\n"
156 			"  tempRes |= " + op + "(false) ? 0 : 0x1A;\n"
157 			"  tempRes |= " + computePart + ";\n"
158 		: (OPTYPE_ANY == caseDef.opType || OPTYPE_ANY_ARB == caseDef.opType) ?
159 			"  tempRes = " + op + "(true) ? 0x1 : 0;\n"
160 			"  tempRes |= " + op + "(false) ? 0 : 0x1A;\n"
161 			"  tempRes |= " + computePart + ";\n"
162 		: (OPTYPE_ALLEQUAL == caseDef.opType || OPTYPE_ALLEQUAL_ARB == caseDef.opType) ?
163 			"  " + fmt + " valueEqual = " + fmt + "(1.25 * float(data[gl_SubgroupInvocationID]) + 5.0);\n" +
164 			"  " + fmt + " valueNoEqual = " + fmt + (formatIsBoolean ? "(subgroupElect());\n" : "(gl_SubgroupInvocationID);\n") +
165 			"  tempRes = " + op + "(" + fmt + "(1)) ? 0x1 : 0;\n"
166 			"  tempRes |= "
167 				+ (formatIsBoolean ? "0x2" : op + "(" + fmt + "(gl_SubgroupInvocationID)) ? 0 : 0x2")
168 				+ ";\n"
169 			"  tempRes |= " + op + "(data[0]) ? 0x4 : 0;\n"
170 			"  tempRes |= " + op + "(valueEqual) ? 0x8 : 0x0;\n"
171 			"  tempRes |= " + op + "(valueNoEqual) ? 0x0 : 0x10;\n"
172 			"  if (subgroupElect()) tempRes |= 0x2 | 0x10;\n"
173 		: "";
174 }
175 
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)176 void initFrameBufferPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
177 {
178 #ifndef CTS_USES_VULKANSC
179 	const bool					spirv14required	= isAllRayTracingStages(caseDef.shaderStage);
180 #else
181 	const bool					spirv14required	= false;
182 #endif // CTS_USES_VULKANSC
183 	const SpirvVersion			spirvVersion	= spirv14required ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3;
184 	const ShaderBuildOptions	buildOptions	(programCollection.usedVulkanVersion, spirvVersion, 0u);
185 	const bool					arbFunctions	= caseDef.opType > OPTYPE_LAST_NON_ARB;
186 	const string				extensions		= getExtensions(arbFunctions) + subgroups::getAdditionalExtensionForFormat(caseDef.format);
187 	const bool					pointSize		= *caseDef.geometryPointSizeSupported;
188 
189 	subgroups::initStdFrameBufferPrograms(programCollection, buildOptions, caseDef.shaderStage, caseDef.format, pointSize, extensions, getStageTestSource(caseDef), "");
190 }
191 
getStageTestSourceFrag(const CaseDefinition & caseDef)192 const string getStageTestSourceFrag (const CaseDefinition& caseDef)
193 {
194 	const bool		formatIsBoolean	= fmtIsBoolean(caseDef.format);
195 	const string	op				= getOpTypeName(caseDef.opType);
196 	const string	fmt				= subgroups::getFormatNameForGLSL(caseDef.format);
197 
198 	return
199 		(OPTYPE_ALL == caseDef.opType || OPTYPE_ALL_ARB == caseDef.opType) ?
200 			"  tempRes |= " + op + "(!gl_HelperInvocation) ? 0x0 : 0x1;\n"
201 			"  tempRes |= " + op + "(false) ? 0 : 0x1A;\n"
202 			"  tempRes |= 0x4;\n"
203 		: (OPTYPE_ANY == caseDef.opType || OPTYPE_ANY_ARB == caseDef.opType) ?
204 			"  tempRes |= " + op + "(gl_HelperInvocation) ? 0x1 : 0x0;\n"
205 			"  tempRes |= " + op + "(false) ? 0 : 0x1A;\n"
206 			"  tempRes |= 0x4;\n"
207 		: (OPTYPE_ALLEQUAL == caseDef.opType || OPTYPE_ALLEQUAL_ARB == caseDef.opType) ?
208 			"  " + fmt + " valueEqual = " + fmt + "(1.25 * float(data[gl_SubgroupInvocationID]) + 5.0);\n" +
209 			"  " + fmt + " valueNoEqual = " + fmt + (formatIsBoolean ? "(subgroupElect());\n" : "(gl_SubgroupInvocationID);\n") +
210 			"  tempRes |= " + getOpTypeName(caseDef.opType) + "("
211 			+ fmt + "(1)) ? 0x10 : 0;\n"
212 			"  tempRes |= "
213 				+ (formatIsBoolean ? "0x2" : op + "(" + fmt + "(gl_SubgroupInvocationID)) ? 0 : 0x2")
214 				+ ";\n"
215 			"  tempRes |= " + op + "(data[0]) ? 0x4 : 0;\n"
216 			"  tempRes |= " + op + "(valueEqual) ? 0x8 : 0x0;\n"
217 			"  tempRes |= " + op + "(gl_HelperInvocation) ? 0x0 : 0x1;\n"
218 			"  if (subgroupElect()) tempRes |= 0x2 | 0x10;\n"
219 		: "";
220 }
221 
initFrameBufferProgramsFrag(SourceCollections & programCollection,CaseDefinition caseDef)222 void initFrameBufferProgramsFrag (SourceCollections& programCollection, CaseDefinition caseDef)
223 {
224 #ifndef CTS_USES_VULKANSC
225 	const bool					spirv14required	= isAllRayTracingStages(caseDef.shaderStage);
226 #else
227 	const bool					spirv14required	= false;
228 #endif // CTS_USES_VULKANSC
229 	const SpirvVersion			spirvVersion	= spirv14required ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3;
230 	const ShaderBuildOptions	buildOptions	(programCollection.usedVulkanVersion, spirvVersion, 0u);
231 	const bool					arbFunctions	= caseDef.opType > OPTYPE_LAST_NON_ARB;
232 	const string				extensions		= getExtensions(arbFunctions) + subgroups::getAdditionalExtensionForFormat(caseDef.format);
233 
234 	DE_ASSERT(VK_SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage);
235 
236 	{
237 		const string	vertex	=
238 			"#version 450\n"
239 			"void main (void)\n"
240 			"{\n"
241 			"  vec2 uv = vec2(float(gl_VertexIndex & 1), float((gl_VertexIndex >> 1) & 1));\n"
242 			"  gl_Position = vec4(uv * 4.0f -2.0f, 0.0f, 1.0f);\n"
243 			"  gl_PointSize = 1.0f;\n"
244 			"}\n";
245 
246 		programCollection.glslSources.add("vert") << glu::VertexSource(vertex) << buildOptions;
247 	}
248 
249 	{
250 		ostringstream	fragmentSource;
251 
252 		fragmentSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
253 			<< extensions
254 			<< "layout(location = 0) out uint out_color;\n"
255 			<< "layout(set = 0, binding = 0) uniform Buffer1\n"
256 			<< "{\n"
257 			<< "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data[" << subgroups::maxSupportedSubgroupSize() << "];\n"
258 			<< "};\n"
259 			<< ""
260 			<< "void main()\n"
261 			<< "{\n"
262 			<< "  uint tempRes = 0u;\n"
263 			<< "  if (dFdx(gl_SubgroupInvocationID * gl_FragCoord.x * gl_FragCoord.y) - dFdy(gl_SubgroupInvocationID * gl_FragCoord.x * gl_FragCoord.y) > 0.0f)\n"
264 			<< "  {\n"
265 			<< "    tempRes |= 0x20;\n" // to be sure that compiler doesn't remove dFdx and dFdy executions
266 			<< "  }\n"
267 			<< (arbFunctions ?
268 				"  bool helper = anyInvocationARB(gl_HelperInvocation);\n" :
269 				"  bool helper = subgroupAny(gl_HelperInvocation);\n")
270 			<< "  if (helper)\n"
271 			<< "  {\n"
272 			<< "    tempRes |= 0x40;\n"
273 			<< "  }\n"
274 			<< getStageTestSourceFrag(caseDef)
275 			<< "  out_color = tempRes;\n"
276 			<< "}\n";
277 
278 		programCollection.glslSources.add("fragment") << glu::FragmentSource(fragmentSource.str())<< buildOptions;
279 	}
280 }
281 
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)282 void initPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
283 {
284 #ifndef CTS_USES_VULKANSC
285 	const bool					spirv14required	= (isAllRayTracingStages(caseDef.shaderStage) || isAllMeshShadingStages(caseDef.shaderStage));
286 #else
287 	const bool					spirv14required	= false;
288 #endif // CTS_USES_VULKANSC
289 	const SpirvVersion			spirvVersion	= spirv14required ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3;
290 	const ShaderBuildOptions	buildOptions	(programCollection.usedVulkanVersion, spirvVersion, 0u, spirv14required);
291 	const bool					arbFunctions	= caseDef.opType > OPTYPE_LAST_NON_ARB;
292 	const string				extensions		= getExtensions(arbFunctions) + subgroups::getAdditionalExtensionForFormat(caseDef.format);
293 	const bool					pointSize		= *caseDef.geometryPointSizeSupported;
294 
295 	subgroups::initStdPrograms(programCollection, buildOptions, caseDef.shaderStage, caseDef.format, pointSize, extensions, getStageTestSource(caseDef), "");
296 }
297 
supportedCheck(Context & context,CaseDefinition caseDef)298 void supportedCheck (Context& context, CaseDefinition caseDef)
299 {
300 	if (!subgroups::isSubgroupSupported(context))
301 		TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
302 
303 	if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_VOTE_BIT))
304 	{
305 		TCU_THROW(NotSupportedError, "Device does not support subgroup vote operations");
306 	}
307 
308 	if (!subgroups::isFormatSupportedForDevice(context, caseDef.format))
309 		TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
310 
311 	if (caseDef.requires16BitUniformBuffer)
312 	{
313 		if (!subgroups::is16BitUBOStorageSupported(context))
314 		{
315 			TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
316 		}
317 	}
318 
319 	if (caseDef.requires8BitUniformBuffer)
320 	{
321 		if (!subgroups::is8BitUBOStorageSupported(context))
322 		{
323 			TCU_THROW(NotSupportedError, "Device does not support the specified format in subgroup operations");
324 		}
325 	}
326 
327 	if (caseDef.opType > OPTYPE_LAST_NON_ARB)
328 	{
329 		context.requireDeviceFunctionality("VK_EXT_shader_subgroup_vote");
330 	}
331 
332 	if (caseDef.requiredSubgroupSize)
333 	{
334 		context.requireDeviceFunctionality("VK_EXT_subgroup_size_control");
335 
336 #ifndef CTS_USES_VULKANSC
337 		const VkPhysicalDeviceSubgroupSizeControlFeatures&		subgroupSizeControlFeatures		= context.getSubgroupSizeControlFeatures();
338 		const VkPhysicalDeviceSubgroupSizeControlProperties&	subgroupSizeControlProperties	= context.getSubgroupSizeControlProperties();
339 #else
340 		const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT&		subgroupSizeControlFeatures	= context.getSubgroupSizeControlFeaturesEXT();
341 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
342 #endif // CTS_USES_VULKANSC
343 
344 		if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
345 			TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes nor required subgroup size");
346 
347 		if (subgroupSizeControlFeatures.computeFullSubgroups == DE_FALSE)
348 			TCU_THROW(NotSupportedError, "Device does not support full subgroups in compute shaders");
349 
350 		if ((subgroupSizeControlProperties.requiredSubgroupSizeStages & caseDef.shaderStage) != caseDef.shaderStage)
351 			TCU_THROW(NotSupportedError, "Required subgroup size is not supported for shader stage");
352 	}
353 
354 	*caseDef.geometryPointSizeSupported = subgroups::isTessellationAndGeometryPointSizeSupported(context);
355 
356 #ifndef CTS_USES_VULKANSC
357 	if (isAllRayTracingStages(caseDef.shaderStage))
358 	{
359 		context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
360 	}
361 	else if (isAllMeshShadingStages(caseDef.shaderStage))
362 	{
363 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
364 		context.requireDeviceFunctionality("VK_EXT_mesh_shader");
365 
366 		if ((caseDef.shaderStage & VK_SHADER_STAGE_TASK_BIT_EXT) != 0u)
367 		{
368 			const auto& features = context.getMeshShaderFeaturesEXT();
369 			if (!features.taskShader)
370 				TCU_THROW(NotSupportedError, "Task shaders not supported");
371 		}
372 	}
373 
374 #endif // CTS_USES_VULKANSC
375 
376 	subgroups::supportedCheckShader(context, caseDef.shaderStage);
377 }
378 
noSSBOtest(Context & context,const CaseDefinition caseDef)379 TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
380 {
381 	if (caseDef.opType > OPTYPE_LAST_NON_ARB)
382 	{
383 		context.requireDeviceFunctionality("VK_EXT_shader_subgroup_vote");
384 	}
385 
386 	const subgroups::SSBOData::InputDataInitializeType	initializeType	= (OPTYPE_ALLEQUAL == caseDef.opType || OPTYPE_ALLEQUAL_ARB == caseDef.opType)
387 																		? subgroups::SSBOData::InitializeZero
388 																		: subgroups::SSBOData::InitializeNonZero;
389 	const subgroups::SSBOData							inputData
390 	{
391 		initializeType,							//  InputDataInitializeType		initializeType;
392 		subgroups::SSBOData::LayoutStd140,		//  InputDataLayoutType			layout;
393 		caseDef.format,							//  vk::VkFormat				format;
394 		subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
395 		subgroups::SSBOData::BindingUBO,		//  BindingType					bindingType;
396 	};
397 
398 	switch (caseDef.shaderStage)
399 	{
400 		case VK_SHADER_STAGE_VERTEX_BIT:					return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages);
401 		case VK_SHADER_STAGE_GEOMETRY_BIT:					return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages);
402 		case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:		return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
403 		case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:	return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, caseDef.shaderStage);
404 		case VK_SHADER_STAGE_FRAGMENT_BIT:					return subgroups::makeFragmentFrameBufferTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkFragmentPipelineStages);
405 		default:											TCU_THROW(InternalError, "Unhandled shader stage");
406 	}
407 }
408 
test(Context & context,const CaseDefinition caseDef)409 TestStatus test (Context& context, const CaseDefinition caseDef)
410 {
411 	const subgroups::SSBOData::InputDataInitializeType	initializeType	= (OPTYPE_ALLEQUAL == caseDef.opType || OPTYPE_ALLEQUAL_ARB == caseDef.opType)
412 																		? subgroups::SSBOData::InitializeZero
413 																		: subgroups::SSBOData::InitializeNonZero;
414 
415 	const bool isCompute	= isAllComputeStages(caseDef.shaderStage);
416 #ifndef CTS_USES_VULKANSC
417 	const bool isMesh		= isAllMeshShadingStages(caseDef.shaderStage);
418 #else
419 	const bool isMesh		= false;
420 #endif // CTS_USES_VULKANSC
421 	DE_ASSERT(!(isCompute && isMesh));
422 
423 	if (isCompute || isMesh)
424 	{
425 #ifndef CTS_USES_VULKANSC
426 		const VkPhysicalDeviceSubgroupSizeControlProperties&	subgroupSizeControlProperties	= context.getSubgroupSizeControlProperties();
427 #else
428 		const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT&	subgroupSizeControlProperties	= context.getSubgroupSizeControlPropertiesEXT();
429 #endif // CTS_USES_VULKANSC
430 		TestLog&												log								= context.getTestContext().getLog();
431 		const subgroups::SSBOData								inputData
432 		{
433 			initializeType,							//  InputDataInitializeType		initializeType;
434 			subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
435 			caseDef.format,							//  vk::VkFormat				format;
436 			subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
437 		};
438 
439 		if (caseDef.requiredSubgroupSize == DE_FALSE)
440 		{
441 			if (isCompute)
442 				return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkComputeOrMesh);
443 			else
444 				return subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkComputeOrMesh);
445 		}
446 
447 		log << TestLog::Message << "Testing required subgroup size range [" <<  subgroupSizeControlProperties.minSubgroupSize << ", "
448 			<< subgroupSizeControlProperties.maxSubgroupSize << "]" << TestLog::EndMessage;
449 
450 		// According to the spec, requiredSubgroupSize must be a power-of-two integer.
451 		for (deUint32 size = subgroupSizeControlProperties.minSubgroupSize; size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
452 		{
453 			TestStatus result (QP_TEST_RESULT_INTERNAL_ERROR, "Internal Error");
454 
455 			if (isCompute)
456 				result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkComputeOrMesh, size);
457 			else
458 				result = subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkComputeOrMesh, size);
459 
460 			if (result.getCode() != QP_TEST_RESULT_PASS)
461 			{
462 				log << TestLog::Message << "subgroupSize " << size << " failed" << TestLog::EndMessage;
463 				return result;
464 			}
465 		}
466 
467 		return TestStatus::pass("OK");
468 	}
469 	else if (isAllGraphicsStages(caseDef.shaderStage))
470 	{
471 		const VkShaderStageFlags	stages		= subgroups::getPossibleGraphicsSubgroupStages(context, caseDef.shaderStage);
472 		const subgroups::SSBOData	inputData	=
473 		{
474 			initializeType,							//  InputDataInitializeType		initializeType;
475 			subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
476 			caseDef.format,							//  vk::VkFormat				format;
477 			subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
478 			subgroups::SSBOData::BindingSSBO,		//  bool						isImage;
479 			4u,										//  deUint32					binding;
480 			stages,									//  vk::VkShaderStageFlags		stages;
481 		};
482 
483 		return subgroups::allStages(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, stages);
484 	}
485 #ifndef CTS_USES_VULKANSC
486 	else if (isAllRayTracingStages(caseDef.shaderStage))
487 	{
488 		const VkShaderStageFlags	stages		= subgroups::getPossibleRayTracingSubgroupStages(context, caseDef.shaderStage);
489 		const subgroups::SSBOData	inputData	=
490 		{
491 			initializeType,							//  InputDataInitializeType		initializeType;
492 			subgroups::SSBOData::LayoutStd430,		//  InputDataLayoutType			layout;
493 			caseDef.format,							//  vk::VkFormat				format;
494 			subgroups::maxSupportedSubgroupSize(),	//  vk::VkDeviceSize			numElements;
495 			subgroups::SSBOData::BindingSSBO,		//  bool						isImage;
496 			6u,										//  deUint32					binding;
497 			stages,									//  vk::VkShaderStageFlags		stages;
498 		};
499 
500 		return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, &inputData, 1, DE_NULL, checkVertexPipelineStages, stages);
501 	}
502 #endif // CTS_USES_VULKANSC
503 	else
504 		TCU_THROW(InternalError, "Unknown stage or invalid stage set");
505 }
506 }
507 
508 namespace vkt
509 {
510 namespace subgroups
511 {
createSubgroupsVoteTests(TestContext & testCtx)512 TestCaseGroup* createSubgroupsVoteTests (TestContext& testCtx)
513 {
514 	de::MovePtr<TestCaseGroup>	group				(new TestCaseGroup(testCtx, "vote", "Subgroup vote category tests"));
515 	de::MovePtr<TestCaseGroup>	graphicGroup		(new TestCaseGroup(testCtx, "graphics", "Subgroup vote category tests: graphics"));
516 	de::MovePtr<TestCaseGroup>	computeGroup		(new TestCaseGroup(testCtx, "compute", "Subgroup vote category tests: compute"));
517 	de::MovePtr<TestCaseGroup>	framebufferGroup	(new TestCaseGroup(testCtx, "framebuffer", "Subgroup vote category tests: framebuffer"));
518 	de::MovePtr<TestCaseGroup>	fragHelperGroup		(new TestCaseGroup(testCtx, "frag_helper", "Subgroup vote category tests: fragment helper invocation"));
519 #ifndef CTS_USES_VULKANSC
520 	de::MovePtr<TestCaseGroup>	raytracingGroup		(new TestCaseGroup(testCtx, "ray_tracing", "Subgroup vote category tests: raytracing"));
521 	de::MovePtr<TestCaseGroup>	meshGroup			(new TestCaseGroup(testCtx, "mesh", "Subgroup vote category tests: mesh shading"));
522 	de::MovePtr<TestCaseGroup>	meshGroupARB		(new TestCaseGroup(testCtx, "mesh", "Subgroup vote category tests: mesh shading"));
523 #endif // CTS_USES_VULKANSC
524 
525 	de::MovePtr<TestCaseGroup>	groupARB			(new TestCaseGroup(testCtx, "ext_shader_subgroup_vote", "VK_EXT_shader_subgroup_vote category tests"));
526 	de::MovePtr<TestCaseGroup>	graphicGroupARB		(new TestCaseGroup(testCtx, "graphics", "Subgroup vote category tests: graphics"));
527 	de::MovePtr<TestCaseGroup>	computeGroupARB		(new TestCaseGroup(testCtx, "compute", "Subgroup vote category tests: compute"));
528 	de::MovePtr<TestCaseGroup>	framebufferGroupARB	(new TestCaseGroup(testCtx, "framebuffer", "Subgroup vote category tests: framebuffer"));
529 	de::MovePtr<TestCaseGroup>	fragHelperGroupARB	(new TestCaseGroup(testCtx, "frag_helper", "Subgroup vote category tests: fragment helper invocation"));
530 	const deBool				boolValues[]		=
531 	{
532 		DE_FALSE,
533 		DE_TRUE
534 	};
535 
536 	{
537 		const VkShaderStageFlags	fbStages[]		=
538 		{
539 			VK_SHADER_STAGE_VERTEX_BIT,
540 			VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
541 			VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
542 			VK_SHADER_STAGE_GEOMETRY_BIT,
543 		};
544 #ifndef CTS_USES_VULKANSC
545 		const VkShaderStageFlags	meshStages[]	=
546 		{
547 			VK_SHADER_STAGE_MESH_BIT_EXT,
548 			VK_SHADER_STAGE_TASK_BIT_EXT,
549 		};
550 #endif // CTS_USES_VULKANSC
551 		const vector<VkFormat>		formats		= subgroups::getAllFormats();
552 
553 		for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
554 		{
555 			const VkFormat	format					= formats[formatIndex];
556 			const bool		needs8BitUBOStorage		= isFormat8bitTy(format);
557 			const bool		needs16BitUBOStorage	= isFormat16BitTy(format);
558 			const deBool	formatIsNotVector		=  format == VK_FORMAT_R8_USCALED
559 													|| format == VK_FORMAT_R32_UINT
560 													|| format == VK_FORMAT_R32_SINT
561 													|| format == VK_FORMAT_R32_SFLOAT
562 													|| format == VK_FORMAT_R64_SFLOAT;
563 
564 			for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
565 			{
566 				const OpType	opType	= static_cast<OpType>(opTypeIndex);
567 
568 				// Skip OPTYPE_LAST_NON_ARB because it is not a real op type.
569 				if (opType == OPTYPE_LAST_NON_ARB)
570 					continue;
571 
572 				// Skip the non-nonvector tests because VK_EXT_shader_subgroup_vote functions only supports boolean scalar arguments.
573 				if (opType > OPTYPE_LAST_NON_ARB && !formatIsNotVector)
574 					continue;
575 
576 				// Skip non-boolean formats when testing allInvocationsEqualARB(bool value), because it requires a boolean
577 				// argument that should have the same value for all invocations. For the rest of formats, it won't be a boolean argument,
578 				// so it may give wrong results when converting to bool.
579 				if (opType == OPTYPE_ALLEQUAL_ARB && format != VK_FORMAT_R8_USCALED)
580 					continue;
581 
582 				// Skip the typed tests for all but subgroupAllEqual() and allInvocationsEqualARB()
583 				if ((VK_FORMAT_R32_UINT != format) && (OPTYPE_ALLEQUAL != opType) && (OPTYPE_ALLEQUAL_ARB != opType))
584 				{
585 					continue;
586 				}
587 
588 				const string	op					= de::toLower(getOpTypeName(opType));
589 				const string	name				= op + "_" + subgroups::getFormatNameForGLSL(format);
590 				const bool		opNonARB			= (opType < OPTYPE_LAST_NON_ARB);
591 				TestCaseGroup*	computeGroupPtr		= opNonARB ? computeGroup.get() : computeGroupARB.get();
592 				TestCaseGroup*	graphicGroupPtr		= opNonARB ? graphicGroup.get() : graphicGroupARB.get();
593 				TestCaseGroup*	framebufferGroupPtr	= opNonARB ? framebufferGroup.get() : framebufferGroupARB.get();
594 				TestCaseGroup*	fragHelperGroupPtr	= opNonARB ? fragHelperGroup.get() : fragHelperGroupARB.get();
595 #ifndef CTS_USES_VULKANSC
596 				TestCaseGroup*	meshGroupPtr		= opNonARB ? meshGroup.get() : meshGroupARB.get();
597 #endif // CTS_USES_VULKANSC
598 
599 				for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
600 				{
601 					const deBool			requiredSubgroupSize	= boolValues[groupSizeNdx];
602 					const string			testName				= name + (requiredSubgroupSize ? "_requiredsubgroupsize" : "");
603 					const CaseDefinition	caseDef					=
604 					{
605 						opType,							//  OpType				opType;
606 						VK_SHADER_STAGE_COMPUTE_BIT,	//  VkShaderStageFlags	shaderStage;
607 						format,							//  VkFormat			format;
608 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
609 						requiredSubgroupSize,			//  deBool				requiredSubgroupSize;
610 						deBool(false),					//  deBool				requires8BitUniformBuffer;
611 						deBool(false)					//  deBool				requires16BitUniformBuffer;
612 					};
613 
614 					addFunctionCaseWithPrograms(computeGroupPtr, testName, "", supportedCheck, initPrograms, test, caseDef);
615 				}
616 
617 #ifndef CTS_USES_VULKANSC
618 				for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
619 				{
620 					for (const auto& stage : meshStages)
621 					{
622 						const deBool			requiredSubgroupSize	= boolValues[groupSizeNdx];
623 						const string			testName				= name + (requiredSubgroupSize ? "_requiredsubgroupsize" : "") + "_" + getShaderStageName(stage);
624 						const CaseDefinition	caseDef					=
625 						{
626 							opType,							//  OpType				opType;
627 							stage,							//  VkShaderStageFlags	shaderStage;
628 							format,							//  VkFormat			format;
629 							de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
630 							requiredSubgroupSize,			//  deBool				requiredSubgroupSize;
631 							deBool(false),					//  deBool				requires8BitUniformBuffer;
632 							deBool(false)					//  deBool				requires16BitUniformBuffer;
633 						};
634 
635 						addFunctionCaseWithPrograms(meshGroupPtr, testName, "", supportedCheck, initPrograms, test, caseDef);
636 					}
637 				}
638 #endif // CTS_USES_VULKANSC
639 
640 				{
641 					const CaseDefinition	caseDef		=
642 					{
643 						opType,							//  OpType				opType;
644 						VK_SHADER_STAGE_ALL_GRAPHICS,	//  VkShaderStageFlags	shaderStage;
645 						format,							//  VkFormat			format;
646 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
647 						DE_FALSE,						//  deBool				requiredSubgroupSize;
648 						deBool(false),					//  deBool				requires8BitUniformBuffer;
649 						deBool(false)					//  deBool				requires16BitUniformBuffer;
650 					};
651 
652 					addFunctionCaseWithPrograms(graphicGroupPtr, name, "", supportedCheck, initPrograms, test, caseDef);
653 				}
654 
655 				for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(fbStages); ++stageIndex)
656 				{
657 					const CaseDefinition	caseDef		=
658 					{
659 						opType,							//  OpType				opType;
660 						fbStages[stageIndex],			//  VkShaderStageFlags	shaderStage;
661 						format,							//  VkFormat			format;
662 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
663 						DE_FALSE,						//  deBool				requiredSubgroupSize;
664 						deBool(false),					//  deBool				requires8BitUniformBuffer;
665 						deBool(false)					//  deBool				requires16BitUniformBuffer;
666 					};
667 					const string			testName	= name + "_" + getShaderStageName(caseDef.shaderStage);
668 
669 					addFunctionCaseWithPrograms(framebufferGroupPtr, testName, "", supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
670 				}
671 
672 				{
673 					const CaseDefinition	caseDef		=
674 					{
675 						opType,							//  OpType				opType;
676 						VK_SHADER_STAGE_FRAGMENT_BIT,	//  VkShaderStageFlags	shaderStage;
677 						format,							//  VkFormat			format;
678 						de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
679 						DE_FALSE,						//  deBool				requiredSubgroupSize;
680 						deBool(needs8BitUBOStorage),	//  deBool				requires8BitUniformBuffer;
681 						deBool(needs16BitUBOStorage)	//  deBool				requires16BitUniformBuffer;
682 					};
683 					const string			testName	= name + "_" + getShaderStageName(caseDef.shaderStage);
684 
685 					addFunctionCaseWithPrograms(fragHelperGroupPtr, testName, "", supportedCheck, initFrameBufferProgramsFrag, noSSBOtest, caseDef);
686 				}
687 			}
688 		}
689 	}
690 
691 #ifndef CTS_USES_VULKANSC
692 	{
693 		const vector<VkFormat>	formats		= subgroups::getAllRayTracingFormats();
694 
695 		for (size_t formatIndex = 0; formatIndex < formats.size(); ++formatIndex)
696 		{
697 			const VkFormat	format	= formats[formatIndex];
698 
699 			for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST_NON_ARB; ++opTypeIndex)
700 			{
701 				const OpType	opType	= static_cast<OpType>(opTypeIndex);
702 
703 				// Skip the typed tests for all but subgroupAllEqual()
704 				if ((VK_FORMAT_R32_UINT != format) && (OPTYPE_ALLEQUAL != opType))
705 				{
706 					continue;
707 				}
708 
709 				const string			op		= de::toLower(getOpTypeName(opType));
710 				const string			name	= op + "_" + subgroups::getFormatNameForGLSL(format);
711 				const CaseDefinition	caseDef	=
712 				{
713 					opType,							//  OpType				opType;
714 					SHADER_STAGE_ALL_RAY_TRACING,	//  VkShaderStageFlags	shaderStage;
715 					format,							//  VkFormat			format;
716 					de::SharedPtr<bool>(new bool),	//  de::SharedPtr<bool>	geometryPointSizeSupported;
717 					DE_FALSE,						//  deBool				requiredSubgroupSize;
718 					DE_FALSE,						//  deBool				requires8BitUniformBuffer;
719 					DE_FALSE						//  deBool				requires16BitUniformBuffer;
720 				};
721 
722 				addFunctionCaseWithPrograms(raytracingGroup.get(), name, "", supportedCheck, initPrograms, test, caseDef);
723 			}
724 		}
725 	}
726 #endif // CTS_USES_VULKANSC
727 
728 	groupARB->addChild(graphicGroupARB.release());
729 	groupARB->addChild(computeGroupARB.release());
730 	groupARB->addChild(framebufferGroupARB.release());
731 	groupARB->addChild(fragHelperGroupARB.release());
732 
733 	group->addChild(graphicGroup.release());
734 	group->addChild(computeGroup.release());
735 	group->addChild(framebufferGroup.release());
736 	group->addChild(fragHelperGroup.release());
737 #ifndef CTS_USES_VULKANSC
738 	group->addChild(raytracingGroup.release());
739 	group->addChild(meshGroup.release());
740 	groupARB->addChild(meshGroupARB.release());
741 #endif // CTS_USES_VULKANSC
742 
743 	group->addChild(groupARB.release());
744 
745 	return group.release();
746 }
747 
748 } // subgroups
749 } // vkt
750