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
32using namespace tcu;
33using namespace std;
34
35namespace glc
36{
37namespace subgroups
38{
39namespace
40{
41enum 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
53static bool checkVertexPipelineStages(std::vector<const void*> datas,
54									  deUint32 width, deUint32)
55{
56	return glc::subgroups::check(datas, width, 0xf);
57}
58
59static 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
66std::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
90struct CaseDefinition
91{
92	int					opType;
93	ShaderStageFlags	shaderStage;
94};
95
96std::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		<< "i == 128u ? 0u : (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
240void 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
333void 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
459void 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
471tcu::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
499tcu::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
535deqp::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