• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * OpenGL Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017-2019 The Khronos Group Inc.
6  * Copyright (c) 2017 Codeplay Software Ltd.
7  * Copyright (c) 2019 NVIDIA Corporation.
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 "glcSubgroupsBallotTests.hpp"
27 #include "glcSubgroupsTestsUtils.hpp"
28 
29 #include <string>
30 #include <vector>
31 
32 using namespace tcu;
33 using namespace std;
34 
35 namespace glc
36 {
37 namespace subgroups
38 {
39 namespace
40 {
checkVertexPipelineStages(std::vector<const void * > datas,deUint32 width,deUint32)41 static bool checkVertexPipelineStages(std::vector<const void*> datas,
42 									  deUint32 width, deUint32)
43 {
44 	return glc::subgroups::check(datas, width, 0x7);
45 }
46 
checkComputeStage(std::vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)47 static bool checkComputeStage(std::vector<const void*> datas,
48 						 const deUint32 numWorkgroups[3], const deUint32 localSize[3],
49 						 deUint32)
50 {
51 	return glc::subgroups::checkCompute(datas, numWorkgroups, localSize, 0x7);
52 }
53 
54 struct CaseDefinition
55 {
56 	glc::subgroups::ShaderStageFlags	shaderStage;
57 };
58 
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)59 void initFrameBufferPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
60 {
61 	std::ostringstream				subgroupSizeStr;
62 	subgroupSizeStr << subgroups::maxSupportedSubgroupSize();
63 
64 	subgroups::setFragmentShaderFrameBuffer(programCollection);
65 
66 	if (SHADER_STAGE_VERTEX_BIT != caseDef.shaderStage)
67 		subgroups::setVertexShaderFrameBuffer(programCollection);
68 
69 	if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
70 	{
71 		const string vertexGLSL =
72 			"${VERSION_DECL}\n"
73 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
74 			"layout(location = 0) in highp vec4 in_position;\n"
75 			"layout(location = 0) out float out_color;\n"
76 			"layout(binding = 0, std140) uniform Buffer1\n"
77 			"{\n"
78 			"  uint data[" + subgroupSizeStr.str() + "];\n"
79 			"};\n"
80 			"\n"
81 			"void main (void)\n"
82 			"{\n"
83 			"  uint tempResult = 0u;\n"
84 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1u : 0u;\n"
85 			"  bool bData = data[gl_SubgroupInvocationID] != 0u;\n"
86 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2u : 0u;\n"
87 			"  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4u : 0u;\n"
88 			"  out_color = float(tempResult);\n"
89 			"  gl_Position = in_position;\n"
90 			"  gl_PointSize = 1.0f;\n"
91 			"}\n";
92 		programCollection.add("vert") << glu::VertexSource(vertexGLSL);
93 	}
94 	else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
95 	{
96 		const string geometryGLSL =
97 			"${VERSION_DECL}\n"
98 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
99 			"layout(points) in;\n"
100 			"layout(points, max_vertices = 1) out;\n"
101 			"layout(location = 0) out float out_color;\n"
102 			"layout(binding = 0, std140) uniform Buffer1\n"
103 			"{\n"
104 			"  uint data[" + subgroupSizeStr.str() + "];\n"
105 			"};\n"
106 			"\n"
107 			"void main (void)\n"
108 			"{\n"
109 			"  uint tempResult = 0u;\n"
110 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1u : 0u;\n"
111 			"  bool bData = data[gl_SubgroupInvocationID] != 0u;\n"
112 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2u : 0u;\n"
113 			"  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4u : 0u;\n"
114 			"  out_color = float(tempResult);\n"
115 			"  gl_Position = gl_in[0].gl_Position;\n"
116 			"  EmitVertex();\n"
117 			"  EndPrimitive();\n"
118 			"}\n";
119 		programCollection.add("geometry") << glu::GeometrySource(geometryGLSL);
120 	}
121 	else if (SHADER_STAGE_TESS_CONTROL_BIT == caseDef.shaderStage)
122 	{
123 		const string controlSourceGLSL =
124 			"${VERSION_DECL}\n"
125 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
126 			"layout(vertices = 2) out;\n"
127 			"layout(location = 0) out float out_color[];\n"
128 			"layout(binding = 0, std140) uniform Buffer1\n"
129 			"{\n"
130 			"  uint data[" + subgroupSizeStr.str() + "];\n"
131 			"};\n"
132 			"\n"
133 			"void main (void)\n"
134 			"{\n"
135 			"  if (gl_InvocationID == 0)\n"
136 			"  {\n"
137 			"    gl_TessLevelOuter[0] = 1.0f;\n"
138 			"    gl_TessLevelOuter[1] = 1.0f;\n"
139 			"  }\n"
140 			"  uint tempResult = 0u;\n"
141 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1u : 0u;\n"
142 			"  bool bData = data[gl_SubgroupInvocationID] != 0u;\n"
143 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2u : 0u;\n"
144 			"  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4u : 0u;\n"
145 			"  out_color[gl_InvocationID] = float(tempResult);\n"
146 			"  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
147 			"}\n";
148 		programCollection.add("tesc") << glu::TessellationControlSource(controlSourceGLSL);
149 		subgroups::setTesEvalShaderFrameBuffer(programCollection);
150 
151 	}
152 	else if (SHADER_STAGE_TESS_EVALUATION_BIT == caseDef.shaderStage)
153 	{
154 		const string evaluationSourceGLSL =
155 			"${VERSION_DECL}\n"
156 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
157 			"layout(isolines, equal_spacing, ccw ) in;\n"
158 			"layout(location = 0) out float out_color;\n"
159 			"layout(binding = 0, std140) uniform Buffer1\n"
160 			"{\n"
161 			"  uint data[" + subgroupSizeStr.str() + "];\n"
162 			"};\n"
163 			"\n"
164 			"void main (void)\n"
165 			"{\n"
166 			"  uint tempResult = 0u;\n"
167 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1u : 0u;\n"
168 			"  bool bData = data[gl_SubgroupInvocationID] != 0u;\n"
169 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2u : 0u;\n"
170 			"  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4u : 0u;\n"
171 			"  out_color = float(tempResult);\n"
172 			"  gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
173 			"}\n";
174 		programCollection.add("tese") << glu::TessellationEvaluationSource(evaluationSourceGLSL);
175 
176 		subgroups::setTesCtrlShaderFrameBuffer(programCollection);
177 	}
178 	else
179 	{
180 		DE_FATAL("Unsupported shader stage");
181 	}
182 }
183 
184 
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)185 void initPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
186 {
187 	if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
188 	{
189 		std::ostringstream src;
190 
191 		src << "${VERSION_DECL}\n"
192 			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
193 			<< "layout (${LOCAL_SIZE_X}, ${LOCAL_SIZE_Y}, ${LOCAL_SIZE_Z}) in;\n"
194 			<< "layout(binding = 0, std430) buffer Buffer1\n"
195 			<< "{\n"
196 			<< "  uint result[];\n"
197 			<< "};\n"
198 			<< "layout(binding = 1, std430) buffer Buffer2\n"
199 			<< "{\n"
200 			<< "  uint data[];\n"
201 			<< "};\n"
202 			<< "\n"
203 			<< subgroups::getSharedMemoryBallotHelper()
204 			<< "void main (void)\n"
205 			<< "{\n"
206 			<< "  uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
207 			<< "  highp uint offset = globalSize.x * ((globalSize.y * "
208 			"gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + "
209 			"gl_GlobalInvocationID.x;\n"
210 			<< "  uint tempResult = 0u;\n"
211 			<< "  tempResult |= sharedMemoryBallot(true) == subgroupBallot(true) ? 0x1u : 0u;\n"
212 			<< "  bool bData = data[gl_SubgroupInvocationID] != 0u;\n"
213 			<< "  tempResult |= sharedMemoryBallot(bData) == subgroupBallot(bData) ? 0x2u : 0u;\n"
214 			<< "  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4u : 0u;\n"
215 			<< "  result[offset] = tempResult;\n"
216 			<< "}\n";
217 
218 		programCollection.add("comp") << glu::ComputeSource(src.str());
219 	}
220 	else
221 	{
222 		const string vertex =
223 			"${VERSION_DECL}\n"
224 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
225 			"layout(binding = 0, std430) buffer Buffer0\n"
226 			"{\n"
227 			"  uint result[];\n"
228 			"} b0;\n"
229 			"layout(binding = 4, std430) readonly buffer Buffer4\n"
230 			"{\n"
231 			"  uint data[];\n"
232 			"};\n"
233 			"\n"
234 			"void main (void)\n"
235 			"{\n"
236 			"  uint tempResult = 0u;\n"
237 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1u : 0u;\n"
238 			"  bool bData = data[gl_SubgroupInvocationID] != 0u;\n"
239 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2u : 0u;\n"
240 			"  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4u : 0u;\n"
241 			"  b0.result[gl_VertexID] = tempResult;\n"
242 			"  float pixelSize = 2.0f/1024.0f;\n"
243 			"  float pixelPosition = pixelSize/2.0f - 1.0f;\n"
244 			"  gl_Position = vec4(float(gl_VertexID) * pixelSize + pixelPosition, 0.0f, 0.0f, 1.0f);\n"
245 			"  gl_PointSize = 1.0f;\n"
246 			"}\n";
247 
248 		const string tesc =
249 			"${VERSION_DECL}\n"
250 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
251 			"layout(vertices=1) out;\n"
252 			"layout(binding = 1, std430) buffer Buffer1\n"
253 			"{\n"
254 			"  uint result[];\n"
255 			"} b1;\n"
256 			"layout(binding = 4, std430) readonly buffer Buffer4\n"
257 			"{\n"
258 			"  uint data[];\n"
259 			"};\n"
260 			"\n"
261 			"void main (void)\n"
262 			"{\n"
263 			"  uint tempResult = 0u;\n"
264 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1u : 0u;\n"
265 			"  bool bData = data[gl_SubgroupInvocationID] != 0u;\n"
266 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2u : 0u;\n"
267 			"  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4u : 0u;\n"
268 			"  b1.result[gl_PrimitiveID] = tempResult;\n"
269 			"  if (gl_InvocationID == 0)\n"
270 			"  {\n"
271 			"    gl_TessLevelOuter[0] = 1.0f;\n"
272 			"    gl_TessLevelOuter[1] = 1.0f;\n"
273 			"  }\n"
274 			"  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
275 			"}\n";
276 
277 		const string tese =
278 			"${VERSION_DECL}\n"
279 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
280 			"layout(isolines) in;\n"
281 			"layout(binding = 2, std430) buffer Buffer2\n"
282 			"{\n"
283 			"  uint result[];\n"
284 			"} b2;\n"
285 			"layout(binding = 4, std430) readonly buffer Buffer4\n"
286 			"{\n"
287 			"  uint data[];\n"
288 			"};\n"
289 			"\n"
290 			"void main (void)\n"
291 			"{\n"
292 			"  uint tempResult = 0u;\n"
293 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1u : 0u;\n"
294 			"  bool bData = data[gl_SubgroupInvocationID] != 0u;\n"
295 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2u : 0u;\n"
296 			"  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4u : 0u;\n"
297 			"  b2.result[gl_PrimitiveID * 2 + int(gl_TessCoord.x + 0.5)] = tempResult;\n"
298 			"  float pixelSize = 2.0f/1024.0f;\n"
299 			"  gl_Position = gl_in[0].gl_Position + gl_TessCoord.x * pixelSize / 2.0f;\n"
300 			"}\n";
301 
302 		const string geometry =
303 			// version string added by addGeometryShadersFromTemplate
304 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
305 			"layout(${TOPOLOGY}) in;\n"
306 			"layout(points, max_vertices = 1) out;\n"
307 			"layout(binding = 3, std430) buffer Buffer3\n"
308 			"{\n"
309 			"  uint result[];\n"
310 			"} b3;\n"
311 			"layout(binding = 4, std430) readonly buffer Buffer4\n"
312 			"{\n"
313 			"  uint data[];\n"
314 			"};\n"
315 			"\n"
316 			"void main (void)\n"
317 			"{\n"
318 			"  uint tempResult = 0u;\n"
319 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1u : 0u;\n"
320 			"  bool bData = data[gl_SubgroupInvocationID] != 0u;\n"
321 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2u : 0u;\n"
322 			"  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4u : 0u;\n"
323 			"  b3.result[gl_PrimitiveIDIn] = tempResult;\n"
324 			"  gl_Position = gl_in[0].gl_Position;\n"
325 			"  EmitVertex();\n"
326 			"  EndPrimitive();\n"
327 			"}\n";
328 
329 		const string fragment =
330 			"${VERSION_DECL}\n"
331 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
332 			"precision highp int;\n"
333 			"layout(location = 0) out uint result;\n"
334 			"layout(binding = 4, std430) readonly buffer Buffer4\n"
335 			"{\n"
336 			"  uint data[];\n"
337 			"};\n"
338 			"void main (void)\n"
339 			"{\n"
340 			"  uint tempResult = 0u;\n"
341 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(true)) ? 0x1u : 0u;\n"
342 			"  bool bData = data[gl_SubgroupInvocationID] != 0u;\n"
343 			"  tempResult |= !bool(uvec4(0) == subgroupBallot(bData)) ? 0x2u : 0u;\n"
344 			"  tempResult |= uvec4(0) == subgroupBallot(false) ? 0x4u : 0u;\n"
345 			"  result = tempResult;\n"
346 			"}\n";
347 
348 		subgroups::addNoSubgroupShader(programCollection);
349 
350 		programCollection.add("vert") << glu::VertexSource(vertex);
351 		programCollection.add("tesc") << glu::TessellationControlSource(tesc);
352 		programCollection.add("tese") << glu::TessellationEvaluationSource(tese);
353 		subgroups::addGeometryShadersFromTemplate(geometry, programCollection);
354 		programCollection.add("fragment") << glu::FragmentSource(fragment);
355 	}
356 }
357 
supportedCheck(Context & context,CaseDefinition caseDef)358 void supportedCheck (Context& context, CaseDefinition caseDef)
359 {
360 	DE_UNREF(caseDef);
361 	if (!subgroups::isSubgroupSupported(context))
362 		TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
363 
364 	if (!subgroups::isSubgroupFeatureSupportedForDevice(context, SUBGROUP_FEATURE_BALLOT_BIT))
365 	{
366 		TCU_THROW(NotSupportedError, "Device does not support subgroup ballot operations");
367 	}
368 }
369 
noSSBOtest(Context & context,const CaseDefinition caseDef)370 tcu::TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
371 {
372 	if (!subgroups::areSubgroupOperationsSupportedForStage(
373 			context, caseDef.shaderStage))
374 	{
375 		if (subgroups::areSubgroupOperationsRequiredForStage(caseDef.shaderStage))
376 		{
377 			return tcu::TestStatus::fail(
378 					   "Shader stage " +
379 					   subgroups::getShaderStageName(caseDef.shaderStage) +
380 					   " is required to support subgroup operations!");
381 		}
382 		else
383 		{
384 			TCU_THROW(NotSupportedError, "Device does not support subgroup operations for this stage");
385 		}
386 	}
387 
388 	subgroups::SSBOData inputData[1];
389 	inputData[0].format = FORMAT_R32_UINT;
390 	inputData[0].layout = subgroups::SSBOData::LayoutStd140;
391 	inputData[0].numElements = subgroups::maxSupportedSubgroupSize();
392 	inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero;
393 	inputData[0].binding = 0u;
394 
395 	if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
396 		return subgroups::makeVertexFrameBufferTest(context, FORMAT_R32_UINT, inputData, 1, checkVertexPipelineStages);
397 	else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
398 		return subgroups::makeGeometryFrameBufferTest(context, FORMAT_R32_UINT, inputData, 1, checkVertexPipelineStages);
399 	else if (SHADER_STAGE_TESS_CONTROL_BIT == caseDef.shaderStage)
400 		return subgroups::makeTessellationEvaluationFrameBufferTest(context, FORMAT_R32_UINT, inputData, 1, checkVertexPipelineStages, SHADER_STAGE_TESS_CONTROL_BIT);
401 	else if (SHADER_STAGE_TESS_EVALUATION_BIT == caseDef.shaderStage)
402 		return subgroups::makeTessellationEvaluationFrameBufferTest(context, FORMAT_R32_UINT, inputData, 1, checkVertexPipelineStages, SHADER_STAGE_TESS_EVALUATION_BIT);
403 	else
404 		TCU_THROW(InternalError, "Unhandled shader stage");
405 }
406 
test(Context & context,const CaseDefinition caseDef)407 tcu::TestStatus test(Context& context, const CaseDefinition caseDef)
408 {
409 	if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
410 	{
411 		if (!subgroups::areSubgroupOperationsSupportedForStage(context, caseDef.shaderStage))
412 		{
413 				return tcu::TestStatus::fail(
414 						   "Shader stage " +
415 						   subgroups::getShaderStageName(caseDef.shaderStage) +
416 						   " is required to support subgroup operations!");
417 		}
418 		subgroups::SSBOData inputData[1];
419 		inputData[0].format = FORMAT_R32_UINT;
420 		inputData[0].layout = subgroups::SSBOData::LayoutStd430;
421 		inputData[0].numElements = subgroups::maxSupportedSubgroupSize();
422 		inputData[0].initializeType = subgroups::SSBOData::InitializeNonZero;
423 		inputData[0].binding = 1u;
424 
425 		return subgroups::makeComputeTest(context, FORMAT_R32_UINT, inputData, 1, checkComputeStage);
426 	}
427 	else
428 	{
429 		int supportedStages = context.getDeqpContext().getContextInfo().getInt(GL_SUBGROUP_SUPPORTED_STAGES_KHR);
430 
431 		ShaderStageFlags stages = (ShaderStageFlags)(caseDef.shaderStage & supportedStages);
432 
433 		if ( SHADER_STAGE_FRAGMENT_BIT != stages && !subgroups::isVertexSSBOSupportedForDevice(context))
434 		{
435 			if ( (stages & SHADER_STAGE_FRAGMENT_BIT) == 0)
436 				TCU_THROW(NotSupportedError, "Device does not support vertex stage SSBO writes");
437 			else
438 				stages = SHADER_STAGE_FRAGMENT_BIT;
439 		}
440 
441 		if ((ShaderStageFlags)0u == stages)
442 			TCU_THROW(NotSupportedError, "Subgroup operations are not supported for any graphic shader");
443 
444 		subgroups::SSBOData inputData;
445 		inputData.format			= FORMAT_R32_UINT;
446 		inputData.layout            = subgroups::SSBOData::LayoutStd430;
447 		inputData.numElements		= subgroups::maxSupportedSubgroupSize();
448 		inputData.initializeType	= subgroups::SSBOData::InitializeNonZero;
449 		inputData.binding			= 4u;
450 		inputData.stages			= stages;
451 
452 		return subgroups::allStages(context, FORMAT_R32_UINT, &inputData, 1, checkVertexPipelineStages, stages);
453 	}
454 }
455 }
456 
createSubgroupsBallotTests(deqp::Context & testCtx)457 deqp::TestCaseGroup* createSubgroupsBallotTests(deqp::Context& testCtx)
458 {
459 	de::MovePtr<deqp::TestCaseGroup> graphicGroup(new deqp::TestCaseGroup(
460 		testCtx, "graphics", "Subgroup ballot category tests: graphics"));
461 	de::MovePtr<deqp::TestCaseGroup> computeGroup(new deqp::TestCaseGroup(
462 		testCtx, "compute", "Subgroup ballot category tests: compute"));
463 	de::MovePtr<deqp::TestCaseGroup> framebufferGroup(new deqp::TestCaseGroup(
464 		testCtx, "framebuffer", "Subgroup ballot category tests: framebuffer"));
465 
466 	const ShaderStageFlags stages[] =
467 	{
468 		SHADER_STAGE_TESS_EVALUATION_BIT,
469 		SHADER_STAGE_TESS_CONTROL_BIT,
470 		SHADER_STAGE_GEOMETRY_BIT,
471 		SHADER_STAGE_VERTEX_BIT
472 	};
473 
474 	{
475 		const CaseDefinition caseDef = {SHADER_STAGE_COMPUTE_BIT};
476 		SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(computeGroup.get(),
477 									getShaderStageName(caseDef.shaderStage), "",
478 									supportedCheck, initPrograms, test, caseDef);
479 	}
480 
481 	{
482 			const CaseDefinition caseDef = {SHADER_STAGE_ALL_GRAPHICS};
483 			SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(graphicGroup.get(), "graphic", "", supportedCheck, initPrograms, test, caseDef);
484 	}
485 
486 	for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
487 	{
488 		const CaseDefinition caseDef = {stages[stageIndex]};
489 		SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(framebufferGroup.get(), getShaderStageName(caseDef.shaderStage), "",
490 					supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
491 	}
492 
493 	de::MovePtr<deqp::TestCaseGroup> group(new deqp::TestCaseGroup(
494 		testCtx, "ballot", "Subgroup ballot category tests"));
495 
496 	group->addChild(graphicGroup.release());
497 	group->addChild(computeGroup.release());
498 	group->addChild(framebufferGroup.release());
499 
500 	return group.release();
501 }
502 
503 } // subgroups
504 } // glc
505