Home | History | Annotate | Download | only in subgroups
      1 /*------------------------------------------------------------------------
      2  * Vulkan Conformance Tests
      3  * ------------------------
      4  *
      5  * Copyright (c) 2017 The Khronos Group Inc.
      6  * Copyright (c) 2017 Codeplay Software Ltd.
      7  *
      8  * Licensed under the Apache License, Version 2.0 (the "License");
      9  * you may not use this file except in compliance with the License.
     10  * You may obtain a copy of the License at
     11  *
     12  *      http://www.apache.org/licenses/LICENSE-2.0
     13  *
     14  * Unless required by applicable law or agreed to in writing, software
     15  * distributed under the License is distributed on an "AS IS" BASIS,
     16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     17  * See the License for the specific language governing permissions and
     18  * limitations under the License.
     19  *
     20  */ /*!
     21  * \file
     22  * \brief Subgroups Tests
     23  */ /*--------------------------------------------------------------------*/
     24 
     25 #include "vktSubgroupsBallotTests.hpp"
     26 #include "vktSubgroupsTestsUtils.hpp"
     27 
     28 #include <string>
     29 #include <vector>
     30 
     31 using namespace tcu;
     32 using namespace std;
     33 using namespace vk;
     34 using namespace vkt;
     35 
     36 namespace
     37 {
     38 static bool checkVertexPipelineStages(std::vector<const void*> datas,
     39 									  deUint32 width, deUint32)
     40 {
     41 	const deUint32* data =
     42 		reinterpret_cast<const deUint32*>(datas[0]);
     43 	for (deUint32 x = 0; x < width; ++x)
     44 	{
     45 		deUint32 val = data[x];
     46 
     47 		if (0x7 != val)
     48 		{
     49 			return false;
     50 		}
     51 	}
     52 
     53 	return true;
     54 }
     55 
     56 static bool checkFragment(std::vector<const void*> datas,
     57 						  deUint32 width, deUint32 height, deUint32)
     58 {
     59 	const deUint32* data =
     60 		reinterpret_cast<const deUint32*>(datas[0]);
     61 	for (deUint32 x = 0; x < width; ++x)
     62 	{
     63 		for (deUint32 y = 0; y < height; ++y)
     64 		{
     65 			deUint32 val = data[x * height + y];
     66 
     67 			if (0x7 != val)
     68 			{
     69 				return false;
     70 			}
     71 		}
     72 	}
     73 
     74 	return true;
     75 }
     76 
     77 static bool checkCompute(std::vector<const void*> datas,
     78 						 const deUint32 numWorkgroups[3], const deUint32 localSize[3],
     79 						 deUint32)
     80 {
     81 	const deUint32* data =
     82 		reinterpret_cast<const deUint32*>(datas[0]);
     83 
     84 	for (deUint32 nX = 0; nX < numWorkgroups[0]; ++nX)
     85 	{
     86 		for (deUint32 nY = 0; nY < numWorkgroups[1]; ++nY)
     87 		{
     88 			for (deUint32 nZ = 0; nZ < numWorkgroups[2]; ++nZ)
     89 			{
     90 				for (deUint32 lX = 0; lX < localSize[0]; ++lX)
     91 				{
     92 					for (deUint32 lY = 0; lY < localSize[1]; ++lY)
     93 					{
     94 						for (deUint32 lZ = 0; lZ < localSize[2];
     95 								++lZ)
     96 						{
     97 							const deUint32 globalInvocationX =
     98 								nX * localSize[0] + lX;
     99 							const deUint32 globalInvocationY =
    100 								nY * localSize[1] + lY;
    101 							const deUint32 globalInvocationZ =
    102 								nZ * localSize[2] + lZ;
    103 
    104 							const deUint32 globalSizeX =
    105 								numWorkgroups[0] * localSize[0];
    106 							const deUint32 globalSizeY =
    107 								numWorkgroups[1] * localSize[1];
    108 
    109 							const deUint32 offset =
    110 								globalSizeX *
    111 								((globalSizeY *
    112 								  globalInvocationZ) +
    113 								 globalInvocationY) +
    114 								globalInvocationX;
    115 
    116 							if (0x7 != data[offset])
    117 							{
    118 								return false;
    119 							}
    120 						}
    121 					}
    122 				}
    123 			}
    124 		}
    125 	}
    126 
    127 	return true;
    128 }
    129 
    130 struct CaseDefinition
    131 {
    132 	VkShaderStageFlags	shaderStage;
    133 	bool				noSSBO;
    134 };
    135 
    136 void initFrameBufferPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
    137 {
    138 	std::ostringstream	fragmentSrc;
    139 
    140 	if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
    141 	{
    142 		std::ostringstream	vertexSrc;
    143 
    144 		vertexSrc << "#version 450\n"
    145 			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
    146 			<< "layout(location = 0) in highp vec4 in_position;\n"
    147 			<< "layout(location = 0) out float out_color;\n"
    148 			<< "layout(set = 0, binding = 0) uniform Buffer1\n"
    149 			<< "{\n"
    150 			<< "  uint data[" << subgroups::maxSupportedSubgroupSize() << "];\n"
    151 			<< "};\n"
    152 			<< "\n"
    153 			<< "void main (void)\n"
    154 			<< "{\n"
    155 			<< "  uint tempResult = 0;\n"
    156 			<< "  tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1 : 0;\n"
    157 			<< "  bool bData = data[gl_SubgroupInvocationID] != 0;\n"
    158 			<< "  tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2 : 0;\n"
    159 			<< "  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4 : 0;\n"
    160 			<< "  out_color = float(tempResult);\n"
    161 			<< "  gl_Position = in_position;\n"
    162 			<< "  gl_PointSize = 1.0f;\n"
    163 			<< "}\n";
    164 
    165 		programCollection.glslSources.add("vert") << glu::VertexSource(vertexSrc.str()) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u);
    166 
    167 		fragmentSrc << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
    168 			<< "layout(location = 0) in float in_color;\n"
    169 			<< "layout(location = 0) out uint out_color;\n"
    170 			<< "void main()\n"
    171 			<<"{\n"
    172 			<< "	out_color = uint(in_color);\n"
    173 			<< "}\n";
    174 		programCollection.glslSources.add("fragment") << glu::FragmentSource(fragmentSrc.str()) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u);
    175 	}
    176 	else
    177 	{
    178 		DE_FATAL("Unsupported shader stage");
    179 	}
    180 }
    181 
    182 void initPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
    183 {
    184 	if (VK_SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
    185 	{
    186 		std::ostringstream src;
    187 
    188 		src << "#version 450\n"
    189 			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
    190 			<< "layout (local_size_x_id = 0, local_size_y_id = 1, "
    191 			"local_size_z_id = 2) in;\n"
    192 			<< "layout(set = 0, binding = 0, std430) buffer Buffer1\n"
    193 			<< "{\n"
    194 			<< "  uint result[];\n"
    195 			<< "};\n"
    196 			<< "layout(set = 0, binding = 1, std430) buffer Buffer2\n"
    197 			<< "{\n"
    198 			<< "  uint data[];\n"
    199 			<< "};\n"
    200 			<< "\n"
    201 			<< subgroups::getSharedMemoryBallotHelper()
    202 			<< "void main (void)\n"
    203 			<< "{\n"
    204 			<< "  uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
    205 			<< "  highp uint offset = globalSize.x * ((globalSize.y * "
    206 			"gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + "
    207 			"gl_GlobalInvocationID.x;\n"
    208 			<< "  uint tempResult = 0;\n"
    209 			<< "  tempResult |= sharedMemoryBallot(true) == subgroupBallot(true) ? 0x1 : 0;\n"
    210 			<< "  bool bData = data[gl_SubgroupInvocationID] != 0;\n"
    211 			<< "  tempResult |= sharedMemoryBallot(bData) == subgroupBallot(bData) ? 0x2 : 0;\n"
    212 			<< "  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4 : 0;\n"
    213 			<< "  result[offset] = tempResult;\n"
    214 			<< "}\n";
    215 
    216 		programCollection.glslSources.add("comp")
    217 				<< glu::ComputeSource(src.str()) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u);
    218 	}
    219 	else if (VK_SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
    220 	{
    221 		programCollection.glslSources.add("vert")
    222 				<< glu::VertexSource(subgroups::getVertShaderForStage(caseDef.shaderStage)) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u);
    223 
    224 		std::ostringstream frag;
    225 
    226 		frag << "#version 450\n"
    227 			 << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
    228 			 << "layout(location = 0) out uint result;\n"
    229 			 << "layout(set = 0, binding = 0, std430) readonly buffer Buffer1\n"
    230 			 << "{\n"
    231 			 << "  uint data[];\n"
    232 			 << "};\n"
    233 			 << "void main (void)\n"
    234 			 << "{\n"
    235 			 << "  uint tempResult = 0;\n"
    236 			 << "  tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1 : 0;\n"
    237 			 << "  bool bData = data[gl_SubgroupInvocationID] != 0;\n"
    238 			 << "  tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2 : 0;\n"
    239 			 << "  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4 : 0;\n"
    240 			 << "  result = tempResult;\n"
    241 			 << "}\n";
    242 
    243 		programCollection.glslSources.add("frag")
    244 				<< glu::FragmentSource(frag.str()) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u);
    245 	}
    246 	else if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
    247 	{
    248 		std::ostringstream src;
    249 
    250 		src << "#version 450\n"
    251 			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
    252 			<< "layout(set = 0, binding = 0, std430) buffer Buffer1\n"
    253 			<< "{\n"
    254 			<< "  uint result[];\n"
    255 			<< "};\n"
    256 			<< "layout(set = 0, binding = 1, std430) buffer Buffer2\n"
    257 			<< "{\n"
    258 			<< "  uint data[];\n"
    259 			<< "};\n"
    260 			<< "\n"
    261 			<< "void main (void)\n"
    262 			<< "{\n"
    263 			<< "  uint tempResult = 0;\n"
    264 			<< "  tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1 : 0;\n"
    265 			<< "  bool bData = data[gl_SubgroupInvocationID] != 0;\n"
    266 			<< "  tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2 : 0;\n"
    267 			<< "  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4 : 0;\n"
    268 			<< "  result[gl_VertexIndex] = tempResult;\n"
    269 			<< "  gl_PointSize = 1.0f;\n"
    270 			<< "}\n";
    271 
    272 		programCollection.glslSources.add("vert")
    273 				<< glu::VertexSource(src.str()) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u);
    274 	}
    275 	else if (VK_SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
    276 	{
    277 		programCollection.glslSources.add("vert")
    278 				<< glu::VertexSource(subgroups::getVertShaderForStage(caseDef.shaderStage)) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u);
    279 
    280 		std::ostringstream src;
    281 
    282 		src << "#version 450\n"
    283 			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
    284 			<< "layout(points) in;\n"
    285 			<< "layout(points, max_vertices = 1) out;\n"
    286 			<< "layout(set = 0, binding = 0, std430) buffer Buffer1\n"
    287 			<< "{\n"
    288 			<< "  uint result[];\n"
    289 			<< "};\n"
    290 			<< "layout(set = 0, binding = 1, std430) buffer Buffer2\n"
    291 			<< "{\n"
    292 			<< "  uint data[];\n"
    293 			<< "};\n"
    294 			<< "\n"
    295 			<< "void main (void)\n"
    296 			<< "{\n"
    297 			<< "  uint tempResult = 0;\n"
    298 			<< "  tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1 : 0;\n"
    299 			<< "  bool bData = data[gl_SubgroupInvocationID] != 0;\n"
    300 			<< "  tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2 : 0;\n"
    301 			<< "  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4 : 0;\n"
    302 			<< "  result[gl_PrimitiveIDIn] = tempResult;\n"
    303 			<< "}\n";
    304 
    305 		programCollection.glslSources.add("geom")
    306 				<< glu::GeometrySource(src.str()) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u);
    307 	}
    308 	else if (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage)
    309 	{
    310 		programCollection.glslSources.add("vert")
    311 				<< glu::VertexSource(subgroups::getVertShaderForStage(caseDef.shaderStage)) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u);
    312 
    313 		programCollection.glslSources.add("tese")
    314 				<< glu::TessellationEvaluationSource("#version 450\nlayout(isolines) in;\nvoid main (void) {}\n");
    315 
    316 		std::ostringstream src;
    317 
    318 		src << "#version 450\n"
    319 			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
    320 			<< "layout(vertices=1) out;\n"
    321 			<< "layout(set = 0, binding = 0, std430) buffer Buffer1\n"
    322 			<< "{\n"
    323 			<< "  uint result[];\n"
    324 			<< "};\n"
    325 			<< "layout(set = 0, binding = 1, std430) buffer Buffer2\n"
    326 			<< "{\n"
    327 			<< "  uint data[];\n"
    328 			<< "};\n"
    329 			<< "\n"
    330 			<< "void main (void)\n"
    331 			<< "{\n"
    332 			<< "  uint tempResult = 0;\n"
    333 			<< "  tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1 : 0;\n"
    334 			<< "  bool bData = data[gl_SubgroupInvocationID] != 0;\n"
    335 			<< "  tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2 : 0;\n"
    336 			<< "  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4 : 0;\n"
    337 			<< "  result[gl_PrimitiveID] = tempResult;\n"
    338 			<< "}\n";
    339 
    340 		programCollection.glslSources.add("tesc")
    341 				<< glu::TessellationControlSource(src.str()) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u);
    342 	}
    343 	else if (VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT == caseDef.shaderStage)
    344 	{
    345 		programCollection.glslSources.add("vert")
    346 				<< glu::VertexSource(subgroups::getVertShaderForStage(caseDef.shaderStage)) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u);
    347 
    348 		programCollection.glslSources.add("tesc")
    349 				<< glu::TessellationControlSource("#version 450\nlayout(vertices=1) out;\nvoid main (void) { for(uint i = 0; i < 4; i++) { gl_TessLevelOuter[i] = 1.0f; } }\n");
    350 
    351 		std::ostringstream src;
    352 
    353 		src << "#version 450\n"
    354 			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
    355 			<< "layout(isolines) in;\n"
    356 			<< "layout(set = 0, binding = 0, std430) buffer Buffer1\n"
    357 			<< "{\n"
    358 			<< "  uint result[];\n"
    359 			<< "};\n"
    360 			<< "layout(set = 0, binding = 1, std430) buffer Buffer2\n"
    361 			<< "{\n"
    362 			<< "  uint data[];\n"
    363 			<< "};\n"
    364 			<< "\n"
    365 			<< "void main (void)\n"
    366 			<< "{\n"
    367 			<< "  uint tempResult = 0;\n"
    368 			<< "  tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1 : 0;\n"
    369 			<< "  bool bData = data[gl_SubgroupInvocationID] != 0;\n"
    370 			<< "  tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2 : 0;\n"
    371 			<< "  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4 : 0;\n"
    372 			<< "  result[gl_PrimitiveID * 2 + uint(gl_TessCoord.x + 0.5)] = tempResult;\n"
    373 			<< "}\n";
    374 
    375 		programCollection.glslSources.add("tese")
    376 				<< glu::TessellationEvaluationSource(src.str()) << vk::ShaderBuildOptions(vk::SPIRV_VERSION_1_3, 0u);
    377 	}
    378 	else
    379 	{
    380 		DE_FATAL("Unsupported shader stage");
    381 	}
    382 }
    383 
    384 tcu::TestStatus test(Context& context, const CaseDefinition caseDef)
    385 {
    386 	if (!subgroups::isSubgroupSupported(context))
    387 		TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
    388 
    389 	if (!subgroups::areSubgroupOperationsSupportedForStage(
    390 				context, caseDef.shaderStage))
    391 	{
    392 		if (subgroups::areSubgroupOperationsRequiredForStage(
    393 					caseDef.shaderStage))
    394 		{
    395 			return tcu::TestStatus::fail(
    396 					   "Shader stage " +
    397 					   subgroups::getShaderStageName(caseDef.shaderStage) +
    398 					   " is required to support subgroup operations!");
    399 		}
    400 		else
    401 		{
    402 			TCU_THROW(NotSupportedError, "Device does not support subgroup operations for this stage");
    403 		}
    404 	}
    405 
    406 	if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_BALLOT_BIT))
    407 	{
    408 		TCU_THROW(NotSupportedError, "Device does not support subgroup ballot operations");
    409 	}
    410 
    411 	//Tests which don't use the SSBO
    412 	if (caseDef.noSSBO && VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
    413 	{
    414 		subgroups::SSBOData inputData[1];
    415 		inputData[0].format = VK_FORMAT_R32_UINT;
    416 		inputData[0].numElements = subgroups::maxSupportedSubgroupSize();
    417 		inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero;
    418 
    419 		return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32_UINT, inputData, 1, checkVertexPipelineStages);
    420 	}
    421 
    422 	if ((VK_SHADER_STAGE_FRAGMENT_BIT != caseDef.shaderStage) &&
    423 			(VK_SHADER_STAGE_COMPUTE_BIT != caseDef.shaderStage))
    424 	{
    425 		if (!subgroups::isVertexSSBOSupportedForDevice(context))
    426 		{
    427 			TCU_THROW(NotSupportedError, "Device does not support vertex stage SSBO writes");
    428 		}
    429 	}
    430 
    431 	if (VK_SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
    432 	{
    433 		subgroups::SSBOData inputData[1];
    434 		inputData[0].format = VK_FORMAT_R32_UINT;
    435 		inputData[0].numElements = subgroups::maxSupportedSubgroupSize();
    436 		inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero;
    437 
    438 		return subgroups::makeFragmentTest(context, VK_FORMAT_R32_UINT,
    439 										   inputData, 1, checkFragment);
    440 	}
    441 	else if (VK_SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
    442 	{
    443 		subgroups::SSBOData inputData[1];
    444 		inputData[0].format = VK_FORMAT_R32_UINT;
    445 		inputData[0].numElements = subgroups::maxSupportedSubgroupSize();
    446 		inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero;
    447 
    448 		return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT,
    449 										  inputData, 1, checkCompute);
    450 	}
    451 	else if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
    452 	{
    453 		subgroups::SSBOData inputData[1];
    454 		inputData[0].format = VK_FORMAT_R32_UINT;
    455 		inputData[0].numElements = subgroups::maxSupportedSubgroupSize();
    456 		inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero;
    457 
    458 		return subgroups::makeVertexTest(context, VK_FORMAT_R32_UINT,
    459 										 inputData, 1, checkVertexPipelineStages);
    460 	}
    461 	else if (VK_SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
    462 	{
    463 		subgroups::SSBOData inputData[1];
    464 		inputData[0].format = VK_FORMAT_R32_UINT;
    465 		inputData[0].numElements = subgroups::maxSupportedSubgroupSize();
    466 		inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero;
    467 
    468 		return subgroups::makeGeometryTest(context, VK_FORMAT_R32_UINT,
    469 										   inputData, 1, checkVertexPipelineStages);
    470 	}
    471 	else if (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage)
    472 	{
    473 		subgroups::SSBOData inputData[1];
    474 		inputData[0].format = VK_FORMAT_R32_UINT;
    475 		inputData[0].numElements = subgroups::maxSupportedSubgroupSize();
    476 		inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero;
    477 
    478 		return subgroups::makeTessellationControlTest(context, VK_FORMAT_R32_UINT,
    479 				inputData, 1, checkVertexPipelineStages);
    480 	}
    481 	else if (VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT == caseDef.shaderStage)
    482 	{
    483 		subgroups::SSBOData inputData[1];
    484 		inputData[0].format = VK_FORMAT_R32_UINT;
    485 		inputData[0].numElements = subgroups::maxSupportedSubgroupSize();
    486 		inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero;
    487 
    488 		return subgroups::makeTessellationEvaluationTest(context, VK_FORMAT_R32_UINT,
    489 				inputData, 1, checkVertexPipelineStages);
    490 	}
    491 	else
    492 	{
    493 		TCU_THROW(InternalError, "Unhandled shader stage");
    494 	}
    495 }
    496 }
    497 
    498 namespace vkt
    499 {
    500 namespace subgroups
    501 {
    502 tcu::TestCaseGroup* createSubgroupsBallotTests(tcu::TestContext& testCtx)
    503 {
    504 	de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(
    505 			testCtx, "ballot", "Subgroup ballot category tests"));
    506 
    507 	const VkShaderStageFlags stages[] =
    508 	{
    509 		VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
    510 		VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
    511 		VK_SHADER_STAGE_GEOMETRY_BIT,
    512 		VK_SHADER_STAGE_VERTEX_BIT,
    513 		VK_SHADER_STAGE_FRAGMENT_BIT,
    514 		VK_SHADER_STAGE_COMPUTE_BIT
    515 	};
    516 
    517 	for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
    518 	{
    519 		const VkShaderStageFlags stage = stages[stageIndex];
    520 
    521 		CaseDefinition caseDef = {stage, false};
    522 
    523 		std::ostringstream name;
    524 
    525 		name << getShaderStageName(stage);
    526 
    527 		addFunctionCaseWithPrograms(group.get(), name.str(),
    528 									"", initPrograms, test, caseDef);
    529 
    530 		if (VK_SHADER_STAGE_VERTEX_BIT == stage )
    531 		{
    532 			caseDef.noSSBO = true;
    533 			addFunctionCaseWithPrograms(group.get(), name.str()+"_framebuffer", "",
    534 						initFrameBufferPrograms, test, caseDef);
    535 		}
    536 	}
    537 
    538 	return group.release();
    539 }
    540 
    541 } // subgroups
    542 } // vkt
    543