• 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 "glcSubgroupsBallotOtherTests.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 {
41 enum OpType
42 {
43 	OPTYPE_INVERSE_BALLOT = 0,
44 	OPTYPE_BALLOT_BIT_EXTRACT,
45 	OPTYPE_BALLOT_BIT_COUNT,
46 	OPTYPE_BALLOT_INCLUSIVE_BIT_COUNT,
47 	OPTYPE_BALLOT_EXCLUSIVE_BIT_COUNT,
48 	OPTYPE_BALLOT_FIND_LSB,
49 	OPTYPE_BALLOT_FIND_MSB,
50 	OPTYPE_LAST
51 };
52 
checkVertexPipelineStages(std::vector<const void * > datas,deUint32 width,deUint32)53 static bool checkVertexPipelineStages(std::vector<const void*> datas,
54 									  deUint32 width, deUint32)
55 {
56 	return glc::subgroups::check(datas, width, 0xf);
57 }
58 
checkComputeStage(std::vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)59 static bool checkComputeStage(std::vector<const void*> datas,
60 						 const deUint32 numWorkgroups[3], const deUint32 localSize[3],
61 						 deUint32)
62 {
63 	return glc::subgroups::checkCompute(datas, numWorkgroups, localSize, 0xf);
64 }
65 
getOpTypeName(int opType)66 std::string getOpTypeName(int opType)
67 {
68 	switch (opType)
69 	{
70 		default:
71 			DE_FATAL("Unsupported op type");
72 			return "";
73 		case OPTYPE_INVERSE_BALLOT:
74 			return "subgroupInverseBallot";
75 		case OPTYPE_BALLOT_BIT_EXTRACT:
76 			return "subgroupBallotBitExtract";
77 		case OPTYPE_BALLOT_BIT_COUNT:
78 			return "subgroupBallotBitCount";
79 		case OPTYPE_BALLOT_INCLUSIVE_BIT_COUNT:
80 			return "subgroupBallotInclusiveBitCount";
81 		case OPTYPE_BALLOT_EXCLUSIVE_BIT_COUNT:
82 			return "subgroupBallotExclusiveBitCount";
83 		case OPTYPE_BALLOT_FIND_LSB:
84 			return "subgroupBallotFindLSB";
85 		case OPTYPE_BALLOT_FIND_MSB:
86 			return "subgroupBallotFindMSB";
87 	}
88 }
89 
90 struct CaseDefinition
91 {
92 	int					opType;
93 	ShaderStageFlags	shaderStage;
94 };
95 
getBodySource(CaseDefinition caseDef)96 std::string getBodySource(CaseDefinition caseDef)
97 {
98 	std::ostringstream bdy;
99 
100 	bdy << "  uvec4 allOnes = uvec4(0xFFFFFFFF);\n"
101 		<< "  uvec4 allZeros = uvec4(0);\n"
102 		<< "  uint tempResult = 0u;\n"
103 		<< "#define MAKE_HIGH_BALLOT_RESULT(i) uvec4("
104 		<< "i >= 32u ? 0u : (0xFFFFFFFFu << i), "
105 		<< "i >= 64u ? 0u : (0xFFFFFFFFu << ((i < 32u) ? 0u : (i - 32u))), "
106 		<< "i >= 96u ? 0u : (0xFFFFFFFFu << ((i < 64u) ? 0u : (i - 64u))), "
107 		<< " 0xFFFFFFFFu << ((i < 96u) ? 0u : (i - 96u)))\n"
108 		<< "#define MAKE_SINGLE_BIT_BALLOT_RESULT(i) uvec4("
109 		<< "i >= 32u ? 0u : 0x1u << i, "
110 		<< "i < 32u || i >= 64u ? 0u : 0x1u << (i - 32u), "
111 		<< "i < 64u || i >= 96u ? 0u : 0x1u << (i - 64u), "
112 		<< "i < 96u ? 0u : 0x1u << (i - 96u))\n";
113 
114 	switch (caseDef.opType)
115 	{
116 		default:
117 			DE_FATAL("Unknown op type!");
118 			break;
119 		case OPTYPE_INVERSE_BALLOT:
120 			bdy << "  tempResult |= subgroupInverseBallot(allOnes) ? 0x1u : 0u;\n"
121 				<< "  tempResult |= subgroupInverseBallot(allZeros) ? 0u : 0x2u;\n"
122 				<< "  tempResult |= subgroupInverseBallot(subgroupBallot(true)) ? 0x4u : 0u;\n"
123 				<< "  tempResult |= 0x8u;\n";
124 			break;
125 		case OPTYPE_BALLOT_BIT_EXTRACT:
126 			bdy << "  tempResult |= subgroupBallotBitExtract(allOnes, gl_SubgroupInvocationID) ? 0x1u : 0u;\n"
127 				<< "  tempResult |= subgroupBallotBitExtract(allZeros, gl_SubgroupInvocationID) ? 0u : 0x2u;\n"
128 				<< "  tempResult |= subgroupBallotBitExtract(subgroupBallot(true), gl_SubgroupInvocationID) ? 0x4u : 0u;\n"
129 				<< "  tempResult |= 0x8u;\n"
130 				<< "  for (uint i = 0u; i < gl_SubgroupSize; i++)\n"
131 				<< "  {\n"
132 				<< "    if (!subgroupBallotBitExtract(allOnes, gl_SubgroupInvocationID))\n"
133 				<< "    {\n"
134 				<< "      tempResult &= ~0x8u;\n"
135 				<< "    }\n"
136 				<< "  }\n";
137 			break;
138 		case OPTYPE_BALLOT_BIT_COUNT:
139 			bdy << "  tempResult |= gl_SubgroupSize == subgroupBallotBitCount(allOnes) ? 0x1u : 0u;\n"
140 				<< "  tempResult |= 0u == subgroupBallotBitCount(allZeros) ? 0x2u : 0u;\n"
141 				<< "  tempResult |= 0u < subgroupBallotBitCount(subgroupBallot(true)) ? 0x4u : 0u;\n"
142 				<< "  tempResult |= 0u == subgroupBallotBitCount(MAKE_HIGH_BALLOT_RESULT(gl_SubgroupSize)) ? 0x8u : 0u;\n";
143 			break;
144 		case OPTYPE_BALLOT_INCLUSIVE_BIT_COUNT:
145 			bdy << "  uint inclusiveOffset = gl_SubgroupInvocationID + 1u;\n"
146 				<< "  tempResult |= inclusiveOffset == subgroupBallotInclusiveBitCount(allOnes) ? 0x1u : 0u;\n"
147 				<< "  tempResult |= 0u == subgroupBallotInclusiveBitCount(allZeros) ? 0x2u : 0u;\n"
148 				<< "  tempResult |= 0u < subgroupBallotInclusiveBitCount(subgroupBallot(true)) ? 0x4u : 0u;\n"
149 				<< "  tempResult |= 0x8u;\n"
150 				<< "  uvec4 inclusiveUndef = MAKE_HIGH_BALLOT_RESULT(inclusiveOffset);\n"
151 				<< "  bool undefTerritory = false;\n"
152 				<< "  for (uint i = 0u; i <= 128u; i++)\n"
153 				<< "  {\n"
154 				<< "    uvec4 iUndef = MAKE_HIGH_BALLOT_RESULT(i);\n"
155 				<< "    if (iUndef == inclusiveUndef)"
156 				<< "    {\n"
157 				<< "      undefTerritory = true;\n"
158 				<< "    }\n"
159 				<< "    uint inclusiveBitCount = subgroupBallotInclusiveBitCount(iUndef);\n"
160 				<< "    if (undefTerritory && (0u != inclusiveBitCount))\n"
161 				<< "    {\n"
162 				<< "      tempResult &= ~0x8u;\n"
163 				<< "    }\n"
164 				<< "    else if (!undefTerritory && (0u == inclusiveBitCount))\n"
165 				<< "    {\n"
166 				<< "      tempResult &= ~0x8u;\n"
167 				<< "    }\n"
168 				<< "  }\n";
169 			break;
170 		case OPTYPE_BALLOT_EXCLUSIVE_BIT_COUNT:
171 			bdy << "  uint exclusiveOffset = gl_SubgroupInvocationID;\n"
172 				<< "  tempResult |= exclusiveOffset == subgroupBallotExclusiveBitCount(allOnes) ? 0x1u : 0u;\n"
173 				<< "  tempResult |= 0u == subgroupBallotExclusiveBitCount(allZeros) ? 0x2u : 0u;\n"
174 				<< "  tempResult |= 0x4u;\n"
175 				<< "  tempResult |= 0x8u;\n"
176 				<< "  uvec4 exclusiveUndef = MAKE_HIGH_BALLOT_RESULT(exclusiveOffset);\n"
177 				<< "  bool undefTerritory = false;\n"
178 				<< "  for (uint i = 0u; i <= 128u; i++)\n"
179 				<< "  {\n"
180 				<< "    uvec4 iUndef = MAKE_HIGH_BALLOT_RESULT(i);\n"
181 				<< "    if (iUndef == exclusiveUndef)"
182 				<< "    {\n"
183 				<< "      undefTerritory = true;\n"
184 				<< "    }\n"
185 				<< "    uint exclusiveBitCount = subgroupBallotExclusiveBitCount(iUndef);\n"
186 				<< "    if (undefTerritory && (0u != exclusiveBitCount))\n"
187 				<< "    {\n"
188 				<< "      tempResult &= ~0x4u;\n"
189 				<< "    }\n"
190 				<< "    else if (!undefTerritory && (0u == exclusiveBitCount))\n"
191 				<< "    {\n"
192 				<< "      tempResult &= ~0x8u;\n"
193 				<< "    }\n"
194 				<< "  }\n";
195 			break;
196 		case OPTYPE_BALLOT_FIND_LSB:
197 			bdy << "  tempResult |= 0u == subgroupBallotFindLSB(allOnes) ? 0x1u : 0u;\n"
198 				<< "  if (subgroupElect())\n"
199 				<< "  {\n"
200 				<< "    tempResult |= 0x2u;\n"
201 				<< "  }\n"
202 				<< "  else\n"
203 				<< "  {\n"
204 				<< "    tempResult |= 0u < subgroupBallotFindLSB(subgroupBallot(true)) ? 0x2u : 0u;\n"
205 				<< "  }\n"
206 				<< "  tempResult |= gl_SubgroupSize > subgroupBallotFindLSB(subgroupBallot(true)) ? 0x4u : 0u;\n"
207 				<< "  tempResult |= 0x8u;\n"
208 				<< "  for (uint i = 0u; i < gl_SubgroupSize; i++)\n"
209 				<< "  {\n"
210 				<< "    if (i != subgroupBallotFindLSB(MAKE_HIGH_BALLOT_RESULT(i)))\n"
211 				<< "    {\n"
212 				<< "      tempResult &= ~0x8u;\n"
213 				<< "    }\n"
214 				<< "  }\n";
215 			break;
216 		case OPTYPE_BALLOT_FIND_MSB:
217 			bdy << "  tempResult |= (gl_SubgroupSize - 1u) == subgroupBallotFindMSB(allOnes) ? 0x1u : 0u;\n"
218 				<< "  if (subgroupElect())\n"
219 				<< "  {\n"
220 				<< "    tempResult |= 0x2u;\n"
221 				<< "  }\n"
222 				<< "  else\n"
223 				<< "  {\n"
224 				<< "    tempResult |= 0u < subgroupBallotFindMSB(subgroupBallot(true)) ? 0x2u : 0u;\n"
225 				<< "  }\n"
226 				<< "  tempResult |= gl_SubgroupSize > subgroupBallotFindMSB(subgroupBallot(true)) ? 0x4u : 0u;\n"
227 				<< "  tempResult |= 0x8u;\n"
228 				<< "  for (uint i = 0u; i < gl_SubgroupSize; i++)\n"
229 				<< "  {\n"
230 				<< "    if (i != subgroupBallotFindMSB(MAKE_SINGLE_BIT_BALLOT_RESULT(i)))\n"
231 				<< "    {\n"
232 				<< "      tempResult &= ~0x8u;\n"
233 				<< "    }\n"
234 				<< "  }\n";
235 			break;
236 	}
237    return bdy.str();
238 }
239 
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)240 void initFrameBufferPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
241 {
242 	subgroups::setFragmentShaderFrameBuffer(programCollection);
243 
244 	if (SHADER_STAGE_VERTEX_BIT != caseDef.shaderStage)
245 		subgroups::setVertexShaderFrameBuffer(programCollection);
246 
247 	std::string bdyStr = getBodySource(caseDef);
248 
249 	if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
250 	{
251 		std::ostringstream				vertex;
252 		vertex << "${VERSION_DECL}\n"
253 			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
254 			<< "layout(location = 0) in highp vec4 in_position;\n"
255 			<< "layout(location = 0) out float out_color;\n"
256 			<< "\n"
257 			<< "void main (void)\n"
258 			<< "{\n"
259 			<< bdyStr
260 			<< "  out_color = float(tempResult);\n"
261 			<< "  gl_Position = in_position;\n"
262 			<< "  gl_PointSize = 1.0f;\n"
263 			<< "}\n";
264 		programCollection.add("vert") << glu::VertexSource(vertex.str());
265 	}
266 	else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
267 	{
268 		std::ostringstream geometry;
269 
270 		geometry << "${VERSION_DECL}\n"
271 			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
272 			<< "layout(points) in;\n"
273 			<< "layout(points, max_vertices = 1) out;\n"
274 			<< "layout(location = 0) out float out_color;\n"
275 			<< "void main (void)\n"
276 			<< "{\n"
277 			<< bdyStr
278 			<< "  out_color = float(tempResult);\n"
279 			<< "  gl_Position = gl_in[0].gl_Position;\n"
280 			<< "  EmitVertex();\n"
281 			<< "  EndPrimitive();\n"
282 			<< "}\n";
283 
284 		programCollection.add("geometry") << glu::GeometrySource(geometry.str());
285 	}
286 	else if (SHADER_STAGE_TESS_CONTROL_BIT == caseDef.shaderStage)
287 	{
288 		std::ostringstream controlSource;
289 
290 		controlSource << "${VERSION_DECL}\n"
291 			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
292 			<< "layout(vertices = 2) out;\n"
293 			<< "layout(location = 0) out float out_color[];\n"
294 			<< "\n"
295 			<< "void main (void)\n"
296 			<< "{\n"
297 			<< "  if (gl_InvocationID == 0)\n"
298 			<< "  {\n"
299 			<< "    gl_TessLevelOuter[0] = 1.0f;\n"
300 			<< "    gl_TessLevelOuter[1] = 1.0f;\n"
301 			<< "  }\n"
302 			<< bdyStr
303 			<< "  out_color[gl_InvocationID ] = float(tempResult);\n"
304 			<< "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
305 			<< "}\n";
306 
307 		programCollection.add("tesc") << glu::TessellationControlSource(controlSource.str());
308 		subgroups::setTesEvalShaderFrameBuffer(programCollection);
309 	}
310 	else if (SHADER_STAGE_TESS_EVALUATION_BIT == caseDef.shaderStage)
311 	{
312 		std::ostringstream evaluationSource;
313 		evaluationSource << "${VERSION_DECL}\n"
314 			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
315 			<< "layout(isolines, equal_spacing, ccw ) in;\n"
316 			<< "layout(location = 0) out float out_color;\n"
317 			<< "void main (void)\n"
318 			<< "{\n"
319 			<< bdyStr
320 			<< "  out_color  = float(tempResult);\n"
321 			<< "  gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
322 			<< "}\n";
323 
324 		subgroups::setTesCtrlShaderFrameBuffer(programCollection);
325 		programCollection.add("tese") << glu::TessellationEvaluationSource(evaluationSource.str());
326 	}
327 	else
328 	{
329 		DE_FATAL("Unsupported shader stage");
330 	}
331 }
332 
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)333 void initPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
334 {
335 	std::string bdyStr = getBodySource(caseDef);
336 
337 	if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
338 	{
339 		std::ostringstream src;
340 
341 		src << "${VERSION_DECL}\n"
342 			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
343 			<< "layout (${LOCAL_SIZE_X}, ${LOCAL_SIZE_Y}, ${LOCAL_SIZE_Z}) in;\n"
344 			<< "layout(binding = 0, std430) buffer Buffer0\n"
345 			<< "{\n"
346 			<< "  uint result[];\n"
347 			<< "};\n"
348 			<< "\n"
349 			<< "void main (void)\n"
350 			<< "{\n"
351 			<< "  uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
352 			<< "  highp uint offset = globalSize.x * ((globalSize.y * "
353 			"gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + "
354 			"gl_GlobalInvocationID.x;\n"
355 			<< bdyStr
356 			<< "  result[offset] = tempResult;\n"
357 			<< "}\n";
358 
359 		programCollection.add("comp") << glu::ComputeSource(src.str());
360 	}
361 	else
362 	{
363 		const string vertex =
364 			"${VERSION_DECL}\n"
365 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
366 			"layout(binding = 0, std430) buffer Buffer0\n"
367 			"{\n"
368 			"  uint result[];\n"
369 			"} b0;\n"
370 			"\n"
371 			"void main (void)\n"
372 			"{\n"
373 			+ bdyStr +
374 			"  b0.result[gl_VertexID] = tempResult;\n"
375 			"  float pixelSize = 2.0f/1024.0f;\n"
376 			"  float pixelPosition = pixelSize/2.0f - 1.0f;\n"
377 			"  gl_Position = vec4(float(gl_VertexID) * pixelSize + pixelPosition, 0.0f, 0.0f, 1.0f);\n"
378 			"  gl_PointSize = 1.0f;\n"
379 			"}\n";
380 
381 		const string tesc =
382 			"${VERSION_DECL}\n"
383 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
384 			"layout(vertices=1) out;\n"
385 			"layout(binding = 1, std430) buffer Buffer1\n"
386 			"{\n"
387 			"  uint result[];\n"
388 			"} b1;\n"
389 			"\n"
390 			"void main (void)\n"
391 			"{\n"
392 			+ bdyStr +
393 			"  b1.result[gl_PrimitiveID] = tempResult;\n"
394 			"  if (gl_InvocationID == 0)\n"
395 			"  {\n"
396 			"    gl_TessLevelOuter[0] = 1.0f;\n"
397 			"    gl_TessLevelOuter[1] = 1.0f;\n"
398 			"  }\n"
399 			"  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
400 			"}\n";
401 
402 		const string tese =
403 			"${VERSION_DECL}\n"
404 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
405 			"layout(isolines) in;\n"
406 			"layout(binding = 2, std430) buffer Buffer2\n"
407 			"{\n"
408 			"  uint result[];\n"
409 			"} b2;\n"
410 			"\n"
411 			"void main (void)\n"
412 			"{\n"
413 			+ bdyStr +
414 			"  b2.result[gl_PrimitiveID * 2 + int(gl_TessCoord.x + 0.5)] = tempResult;\n"
415 			"  float pixelSize = 2.0f/1024.0f;\n"
416 			"  gl_Position = gl_in[0].gl_Position + gl_TessCoord.x * pixelSize / 2.0f;\n"
417 			"}\n";
418 
419 		const string geometry =
420 			// version string added by addGeometryShadersFromTemplate
421 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
422 			"layout(${TOPOLOGY}) in;\n"
423 			"layout(points, max_vertices = 1) out;\n"
424 			"layout(binding = 3, std430) buffer Buffer3\n"
425 			"{\n"
426 			"  uint result[];\n"
427 			"} b3;\n"
428 			"\n"
429 			"void main (void)\n"
430 			"{\n"
431 			+ bdyStr +
432 			"  b3.result[gl_PrimitiveIDIn] = tempResult;\n"
433 			"  gl_Position = gl_in[0].gl_Position;\n"
434 			"  EmitVertex();\n"
435 			"  EndPrimitive();\n"
436 			"}\n";
437 
438 		const string fragment =
439 			"${VERSION_DECL}\n"
440 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
441 			"precision highp int;\n"
442 			"layout(location = 0) out uint result;\n"
443 			"void main (void)\n"
444 			"{\n"
445 			+ bdyStr +
446 			"  result = tempResult;\n"
447 			"}\n";
448 
449 		subgroups::addNoSubgroupShader(programCollection);
450 
451 		programCollection.add("vert") << glu::VertexSource(vertex);
452 		programCollection.add("tesc") << glu::TessellationControlSource(tesc);
453 		programCollection.add("tese") << glu::TessellationEvaluationSource(tese);
454 		subgroups::addGeometryShadersFromTemplate(geometry, programCollection);
455 		programCollection.add("fragment") << glu::FragmentSource(fragment);
456 	}
457 }
458 
supportedCheck(Context & context,CaseDefinition caseDef)459 void supportedCheck (Context& context, CaseDefinition caseDef)
460 {
461 	DE_UNREF(caseDef);
462 	if (!subgroups::isSubgroupSupported(context))
463 		TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
464 
465 	if (!subgroups::isSubgroupFeatureSupportedForDevice(context, SUBGROUP_FEATURE_BALLOT_BIT))
466 	{
467 		TCU_THROW(NotSupportedError, "Device does not support subgroup ballot operations");
468 	}
469 }
470 
noSSBOtest(Context & context,const CaseDefinition caseDef)471 tcu::TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
472 {
473 	if (!subgroups::areSubgroupOperationsSupportedForStage(
474 			context, caseDef.shaderStage))
475 	{
476 		if (subgroups::areSubgroupOperationsRequiredForStage(caseDef.shaderStage))
477 		{
478 			return tcu::TestStatus::fail(
479 					   "Shader stage " +
480 					   subgroups::getShaderStageName(caseDef.shaderStage) +
481 					   " is required to support subgroup operations!");
482 		}
483 		else
484 		{
485 			TCU_THROW(NotSupportedError, "Device does not support subgroup operations for this stage");
486 		}
487 	}
488 
489 	if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
490 		return subgroups::makeVertexFrameBufferTest(context, FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages);
491 	else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
492 		return subgroups::makeGeometryFrameBufferTest(context, FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages);
493 	else if ((SHADER_STAGE_TESS_CONTROL_BIT | SHADER_STAGE_TESS_EVALUATION_BIT) & caseDef.shaderStage)
494 		return subgroups::makeTessellationEvaluationFrameBufferTest(context, FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages);
495 	else
496 		TCU_THROW(InternalError, "Unhandled shader stage");
497 }
498 
test(Context & context,const CaseDefinition caseDef)499 tcu::TestStatus test (Context& context, const CaseDefinition caseDef)
500 {
501 	if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
502 	{
503 		if (!subgroups::areSubgroupOperationsSupportedForStage(context, caseDef.shaderStage))
504 		{
505 			return tcu::TestStatus::fail(
506 					   "Shader stage " +
507 				subgroups::getShaderStageName(caseDef.shaderStage) +
508 				" is required to support subgroup operations!");
509 		}
510 		return subgroups::makeComputeTest(context, FORMAT_R32_UINT, DE_NULL, 0, checkComputeStage);
511 	}
512 	else
513 	{
514 		int supportedStages = context.getDeqpContext().getContextInfo().getInt(GL_SUBGROUP_SUPPORTED_STAGES_KHR);
515 
516 		ShaderStageFlags stages = (ShaderStageFlags)(caseDef.shaderStage & supportedStages);
517 
518 		if ( SHADER_STAGE_FRAGMENT_BIT != stages && !subgroups::isVertexSSBOSupportedForDevice(context))
519 		{
520 			if ( (stages & SHADER_STAGE_FRAGMENT_BIT) == 0)
521 				TCU_THROW(NotSupportedError, "Device does not support vertex stage SSBO writes");
522 			else
523 				stages = SHADER_STAGE_FRAGMENT_BIT;
524 		}
525 
526 		if ((ShaderStageFlags)0u == stages)
527 			TCU_THROW(NotSupportedError, "Subgroup operations are not supported for any graphic shader");
528 
529 		return subgroups::allStages(context, FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages, stages);
530 	}
531 	return tcu::TestStatus::pass("OK");
532 }
533 }
534 
createSubgroupsBallotOtherTests(deqp::Context & testCtx)535 deqp::TestCaseGroup* createSubgroupsBallotOtherTests(deqp::Context& testCtx)
536 {
537 	de::MovePtr<deqp::TestCaseGroup> graphicGroup(new deqp::TestCaseGroup(
538 		testCtx, "graphics", "Subgroup ballot other category tests: graphics"));
539 	de::MovePtr<deqp::TestCaseGroup> computeGroup(new deqp::TestCaseGroup(
540 		testCtx, "compute", "Subgroup ballot other category tests: compute"));
541 	de::MovePtr<deqp::TestCaseGroup> framebufferGroup(new deqp::TestCaseGroup(
542 		testCtx, "framebuffer", "Subgroup ballot other category tests: framebuffer"));
543 
544 	const ShaderStageFlags stages[] =
545 	{
546 		SHADER_STAGE_VERTEX_BIT,
547 		SHADER_STAGE_TESS_EVALUATION_BIT,
548 		SHADER_STAGE_TESS_CONTROL_BIT,
549 		SHADER_STAGE_GEOMETRY_BIT,
550 	};
551 
552 	for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
553 	{
554 		const string	op		= de::toLower(getOpTypeName(opTypeIndex));
555 		{
556 			const CaseDefinition caseDef = {opTypeIndex, SHADER_STAGE_COMPUTE_BIT};
557 			SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(computeGroup.get(), op, "", supportedCheck, initPrograms, test, caseDef);
558 		}
559 
560 		{
561 			const CaseDefinition caseDef = {opTypeIndex, SHADER_STAGE_ALL_GRAPHICS};
562 			SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(graphicGroup.get(), op, "", supportedCheck, initPrograms, test, caseDef);
563 		}
564 
565 		for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
566 		{
567 			const CaseDefinition caseDef = {opTypeIndex, stages[stageIndex]};
568 			SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(framebufferGroup.get(), op + "_" + getShaderStageName(caseDef.shaderStage), "", supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
569 		}
570 	}
571 
572 	de::MovePtr<deqp::TestCaseGroup> group(new deqp::TestCaseGroup(
573 		testCtx, "ballot_other", "Subgroup ballot other category tests"));
574 
575 	group->addChild(graphicGroup.release());
576 	group->addChild(computeGroup.release());
577 	group->addChild(framebufferGroup.release());
578 
579 	return group.release();
580 }
581 
582 } // subgroups
583 } // glc
584