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 "glcSubgroupsVoteTests.hpp"
27#include "glcSubgroupsTestsUtils.hpp"
28
29#include <string>
30#include <vector>
31#include "tcuStringTemplate.hpp"
32
33using namespace tcu;
34using namespace std;
35
36namespace glc
37{
38namespace subgroups
39{
40
41namespace
42{
43
44enum OpType
45{
46	OPTYPE_ALL = 0,
47	OPTYPE_ANY,
48	OPTYPE_ALLEQUAL,
49	OPTYPE_LAST
50};
51
52static bool checkVertexPipelineStages(std::vector<const void*> datas,
53									  deUint32 width, deUint32)
54{
55	return glc::subgroups::check(datas, width, 0x1F);
56}
57
58static bool checkFragmentPipelineStages(std::vector<const void*> datas,
59									  deUint32 width, deUint32 height, deUint32)
60{
61	const deUint32* data =
62		reinterpret_cast<const deUint32*>(datas[0]);
63	for (deUint32 x = 0u; x < width; ++x)
64	{
65		for (deUint32 y = 0u; y < height; ++y)
66		{
67			const deUint32 ndx = (x * height + y);
68			deUint32 val = data[ndx] & 0x1F;
69
70			if (data[ndx] & 0x40) //Helper fragment shader invocation was executed
71			{
72				if(val != 0x1F)
73					return false;
74			}
75			else //Helper fragment shader invocation was not executed yet
76			{
77				if (val != 0x1E)
78					return false;
79			}
80		}
81	}
82	return true;
83}
84
85static bool checkComputeStage(std::vector<const void*> datas,
86						 const deUint32 numWorkgroups[3], const deUint32 localSize[3],
87						 deUint32)
88{
89	return glc::subgroups::checkCompute(datas, numWorkgroups, localSize, 0x1F);
90}
91
92std::string getOpTypeName(int opType)
93{
94	switch (opType)
95	{
96		default:
97			DE_FATAL("Unsupported op type");
98			return "";
99		case OPTYPE_ALL:
100			return "subgroupAll";
101		case OPTYPE_ANY:
102			return "subgroupAny";
103		case OPTYPE_ALLEQUAL:
104			return "subgroupAllEqual";
105	}
106}
107
108struct CaseDefinition
109{
110	int					opType;
111	ShaderStageFlags	shaderStage;
112	Format				format;
113};
114
115void initFrameBufferPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
116{
117	const bool formatIsBoolean =
118		FORMAT_R32_BOOL == caseDef.format || FORMAT_R32G32_BOOL == caseDef.format || FORMAT_R32G32B32_BOOL == caseDef.format || FORMAT_R32G32B32A32_BOOL == caseDef.format;
119
120	if (SHADER_STAGE_FRAGMENT_BIT != caseDef.shaderStage)
121		subgroups::setFragmentShaderFrameBuffer(programCollection);
122
123	if (SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
124	{
125		const string vertex	= "${VERSION_DECL}\n"
126			"void main (void)\n"
127			"{\n"
128			"  vec2 uv = vec2(float(gl_VertexID & 1), float((gl_VertexID >> 1) & 1));\n"
129			"  gl_Position = vec4(uv * 4.0f -2.0f, 0.0f, 1.0f);\n"
130			"  gl_PointSize = 1.0f;\n"
131			"}\n";
132		programCollection.add("vert") << glu::VertexSource(vertex);
133	}
134	else if (SHADER_STAGE_VERTEX_BIT != caseDef.shaderStage)
135		subgroups::setVertexShaderFrameBuffer(programCollection);
136
137	const string source =
138		(OPTYPE_ALL == caseDef.opType) ?
139			"  result = " + getOpTypeName(caseDef.opType) +
140			"(true) ? 0x1u : 0u;\n"
141			"  result |= " + getOpTypeName(caseDef.opType) +
142			"(false) ? 0u : 0x1Au;\n"
143			"  result |= 0x4u;\n"
144		: (OPTYPE_ANY == caseDef.opType) ?
145				"  result = " + getOpTypeName(caseDef.opType) +
146				"(true) ? 0x1u : 0u;\n"
147				"  result |= " + getOpTypeName(caseDef.opType) +
148				"(false) ? 0u : 0x1Au;\n"
149				"  result |= 0x4u;\n"
150		: (OPTYPE_ALLEQUAL == caseDef.opType) ?
151				"  " + subgroups::getFormatNameForGLSL(caseDef.format) + " valueEqual = " + subgroups::getFormatNameForGLSL(caseDef.format) + "(1.25 * float(data[gl_SubgroupInvocationID]) + 5.0);\n" +
152				"  " + subgroups::getFormatNameForGLSL(caseDef.format) + " valueNoEqual = " + subgroups::getFormatNameForGLSL(caseDef.format) + (formatIsBoolean ? "(subgroupElect())\n;" : "(12.0 * float(data[gl_SubgroupInvocationID]) + float(gl_SubgroupInvocationID));\n") +
153				"  result = " + getOpTypeName(caseDef.opType) + "("
154				+ subgroups::getFormatNameForGLSL(caseDef.format) + "(1)) ? 0x1u : 0u;\n"
155				"  result |= " + getOpTypeName(caseDef.opType) +
156				"(gl_SubgroupInvocationID) ? 0u : 0x2u;\n"
157				"  result |= " + getOpTypeName(caseDef.opType) +
158				"(data[0]) ? 0x4u : 0u;\n"
159				"  result |= " + getOpTypeName(caseDef.opType) +
160				"(valueEqual) ? 0x8u : 0x0u;\n"
161				"  result |= " + getOpTypeName(caseDef.opType) +
162				"(valueNoEqual) ? 0x0u : 0x10u;\n"
163				"  if (subgroupElect()) result |= 0x2u | 0x10u;\n"
164		: "";
165
166	if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
167	{
168		std::ostringstream vertexSrc;
169		vertexSrc << "${VERSION_DECL}\n"
170			<< "#extension GL_KHR_shader_subgroup_vote: enable\n"
171			<< "layout(location = 0) out float out_color;\n"
172			<< "layout(location = 0) in highp vec4 in_position;\n"
173			<< "layout(binding = 0, std140) uniform Buffer1\n"
174			<< "{\n"
175			<< "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data[" << subgroups::maxSupportedSubgroupSize() << "];\n"
176			<< "};\n"
177			<< "\n"
178			<< "void main (void)\n"
179			<< "{\n"
180			<< "  uint result;\n"
181			<< source
182			<< "  out_color = float(result);\n"
183			<< "  gl_Position = in_position;\n"
184			<< "  gl_PointSize = 1.0f;\n"
185			<< "}\n";
186
187		programCollection.add("vert") << glu::VertexSource(vertexSrc.str());
188	}
189	else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
190	{
191		std::ostringstream geometry;
192
193		geometry << "${VERSION_DECL}\n"
194			<< "#extension GL_KHR_shader_subgroup_vote: enable\n"
195			<< "layout(points) in;\n"
196			<< "layout(points, max_vertices = 1) out;\n"
197			<< "layout(location = 0) out float out_color;\n"
198			<< "layout(binding = 0, std140) uniform Buffer1\n"
199			<< "{\n"
200			<< "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data[" << subgroups::maxSupportedSubgroupSize() << "];\n"
201			<< "};\n"
202			<< "\n"
203			<< "void main (void)\n"
204			<< "{\n"
205			<< "  uint result;\n"
206			<< source
207			<< "  out_color = float(result);\n"
208			<< "  gl_Position = gl_in[0].gl_Position;\n"
209			<< "  EmitVertex();\n"
210			<< "  EndPrimitive();\n"
211			<< "}\n";
212
213		programCollection.add("geometry") << glu::GeometrySource(geometry.str());
214	}
215	else if (SHADER_STAGE_TESS_CONTROL_BIT == caseDef.shaderStage)
216	{
217		std::ostringstream controlSource;
218		controlSource << "${VERSION_DECL}\n"
219			<< "#extension GL_KHR_shader_subgroup_vote: enable\n"
220			<< "layout(vertices = 2) out;\n"
221			<< "layout(location = 0) out float out_color[];\n"
222			<< "layout(binding = 0, std140) uniform Buffer1\n"
223			<< "{\n"
224			<< "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data[" << subgroups::maxSupportedSubgroupSize() << "];\n"
225			<< "};\n"
226			<< "\n"
227			<< "void main (void)\n"
228			<< "{\n"
229			<< "  uint result;\n"
230			<< "  if (gl_InvocationID == 0)\n"
231			<<"  {\n"
232			<< "    gl_TessLevelOuter[0] = 1.0f;\n"
233			<< "    gl_TessLevelOuter[1] = 1.0f;\n"
234			<< "  }\n"
235			<< source
236			<< "  out_color[gl_InvocationID] = float(result);"
237			<< "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
238			<< "}\n";
239
240		programCollection.add("tesc") << glu::TessellationControlSource(controlSource.str());
241		subgroups::setTesEvalShaderFrameBuffer(programCollection);
242	}
243	else if (SHADER_STAGE_TESS_EVALUATION_BIT == caseDef.shaderStage)
244	{
245		std::ostringstream evaluationSource;
246		evaluationSource << "${VERSION_DECL}\n"
247			<< "#extension GL_KHR_shader_subgroup_vote: enable\n"
248			<< "${TESS_EXTENSION}\n"
249			<< "layout(isolines, equal_spacing, ccw ) in;\n"
250			<< "layout(location = 0) out float out_color;\n"
251			<< "layout(binding = 0, std140) uniform Buffer1\n"
252			<< "{\n"
253			<< "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data[" << subgroups::maxSupportedSubgroupSize() << "];\n"
254			<< "};\n"
255			<< "\n"
256			<< "void main (void)\n"
257			<< "{\n"
258			<< "  uint result;\n"
259			<< "  highp uint offset = uint(gl_PrimitiveID) * 2u + uint(gl_TessCoord.x + 0.5);\n"
260			<< source
261			<< "  out_color = float(result);\n"
262			<< "  gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
263			<< "}\n";
264
265		subgroups::setTesCtrlShaderFrameBuffer(programCollection);
266		programCollection.add("tese") << glu::TessellationEvaluationSource(evaluationSource.str());
267	}
268	else if (SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
269	{
270		const string sourceFragment =
271		(OPTYPE_ALL == caseDef.opType) ?
272			"  result |= " + getOpTypeName(caseDef.opType) +
273			"(!gl_HelperInvocation) ? 0x0u : 0x1u;\n"
274			"  result |= " + getOpTypeName(caseDef.opType) +
275			"(false) ? 0u : 0x1Au;\n"
276			"  result |= 0x4u;\n"
277		: (OPTYPE_ANY == caseDef.opType) ?
278				"  result |= " + getOpTypeName(caseDef.opType) +
279				"(gl_HelperInvocation) ? 0x1u : 0x0u;\n"
280				"  result |= " + getOpTypeName(caseDef.opType) +
281				"(false) ? 0u : 0x1Au;\n"
282				"  result |= 0x4u;\n"
283		: (OPTYPE_ALLEQUAL == caseDef.opType) ?
284				"  " + subgroups::getFormatNameForGLSL(caseDef.format) + " valueEqual = " + subgroups::getFormatNameForGLSL(caseDef.format) + "(1.25 * float(data[gl_SubgroupInvocationID]) + 5.0);\n" +
285				"  " + subgroups::getFormatNameForGLSL(caseDef.format) + " valueNoEqual = " + subgroups::getFormatNameForGLSL(caseDef.format) + (formatIsBoolean ? "(subgroupElect());\n" : "(12.0 * float(data[gl_SubgroupInvocationID]) + gl_FragCoord.x * float(gl_SubgroupInvocationID));\n") +
286				"  result |= " + getOpTypeName(caseDef.opType) + "("
287				+ subgroups::getFormatNameForGLSL(caseDef.format) + "(1)) ? 0x10u : 0u;\n"
288				"  result |= " + getOpTypeName(caseDef.opType) +
289				"(gl_SubgroupInvocationID) ? 0u : 0x2u;\n"
290				"  result |= " + getOpTypeName(caseDef.opType) +
291				"(data[0]) ? 0x4u : 0u;\n"
292				"  result |= " + getOpTypeName(caseDef.opType) +
293				"(valueEqual) ? 0x8u : 0x0u;\n"
294				"  result |= " + getOpTypeName(caseDef.opType) +
295				"(gl_HelperInvocation) ? 0x0u : 0x1u;\n"
296				"  if (subgroupElect()) result |= 0x2u | 0x10u;\n"
297		: "";
298
299		std::ostringstream fragmentSource;
300		fragmentSource << "${VERSION_DECL}\n"
301		<< "#extension GL_KHR_shader_subgroup_vote: enable\n"
302		<< "precision highp float;\n"
303		<< "layout(location = 0) out uint out_color;\n"
304		<< "layout(binding = 0, std140) uniform Buffer1\n"
305		<< "{\n"
306		<< "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data[" << subgroups::maxSupportedSubgroupSize() << "];\n"
307		<< "};\n"
308		<< ""
309		<< "void main()\n"
310		<< "{\n"
311		<< "  uint result = 0u;\n"
312		<< "  if (dFdx(float(gl_SubgroupInvocationID) * gl_FragCoord.x * gl_FragCoord.y) - dFdy(float(gl_SubgroupInvocationID) * gl_FragCoord.x * gl_FragCoord.y) > 0.0f)\n"
313		<< "  {\n"
314		<< "    result |= 0x20u;\n" // to be sure that compiler doesn't remove dFdx and dFdy executions
315		<< "  }\n"
316		<< "  bool helper = subgroupAny(gl_HelperInvocation);\n"
317		<< "  if (helper)\n"
318		<< "  {\n"
319		<< "    result |= 0x40u;\n"
320		<< "  }\n"
321		<< sourceFragment
322		<< "  out_color = result;\n"
323		<< "}\n";
324
325		programCollection.add("fragment") << glu::FragmentSource(fragmentSource.str());
326	}
327	else
328	{
329		DE_FATAL("Unsupported shader stage");
330	}
331}
332
333void initPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
334{
335	const bool formatIsBoolean =
336		FORMAT_R32_BOOL == caseDef.format || FORMAT_R32G32_BOOL == caseDef.format || FORMAT_R32G32B32_BOOL == caseDef.format || FORMAT_R32G32B32A32_BOOL == caseDef.format;
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_vote: enable\n"
343			<< "layout (${LOCAL_SIZE_X}, ${LOCAL_SIZE_Y}, ${LOCAL_SIZE_Z}) in;\n"
344			<< "layout(binding = 0, std430) buffer Buffer1\n"
345			<< "{\n"
346			<< "  uint result[];\n"
347			<< "};\n"
348			<< "layout(binding = 1, std430) buffer Buffer2\n"
349			<< "{\n"
350			<< "  " << subgroups::getFormatNameForGLSL(caseDef.format) << " data[];\n"
351			<< "};\n"
352			<< "\n"
353			<< "void main (void)\n"
354			<< "{\n"
355			<< "  uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
356			<< "  highp uint offset = globalSize.x * ((globalSize.y * "
357			"gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + "
358			"gl_GlobalInvocationID.x;\n";
359		if (OPTYPE_ALL == caseDef.opType)
360		{
361			src << "  result[offset] = " << getOpTypeName(caseDef.opType)
362				<< "(true) ? 0x1u : 0u;\n"
363				<< "  result[offset] |= " << getOpTypeName(caseDef.opType)
364				<< "(false) ? 0u : 0x1Au;\n"
365				<< "  result[offset] |= " << getOpTypeName(caseDef.opType)
366				<< "(data[gl_SubgroupInvocationID] > 0u) ? 0x4u : 0u;\n";
367		}
368		else if (OPTYPE_ANY == caseDef.opType)
369		{
370			src << "  result[offset] = " << getOpTypeName(caseDef.opType)
371				<< "(true) ? 0x1u : 0u;\n"
372				<< "  result[offset] |= " << getOpTypeName(caseDef.opType)
373				<< "(false) ? 0u : 0x1Au;\n"
374				<< "  result[offset] |= " << getOpTypeName(caseDef.opType)
375				<< "(data[gl_SubgroupInvocationID] == data[0]) ? 0x4u : 0u;\n";
376		}
377
378		else if (OPTYPE_ALLEQUAL == caseDef.opType)
379		{
380			src << "  " << subgroups::getFormatNameForGLSL(caseDef.format) <<" valueEqual = " << subgroups::getFormatNameForGLSL(caseDef.format) << "(1.25 * float(data[gl_SubgroupInvocationID]) + 5.0);\n"
381				<< "  " << subgroups::getFormatNameForGLSL(caseDef.format) <<" valueNoEqual = " << subgroups::getFormatNameForGLSL(caseDef.format) << (formatIsBoolean ? "(subgroupElect());\n" : "(12.0 * float(data[gl_SubgroupInvocationID]) + float(offset));\n")
382				<<"  result[offset] = " << getOpTypeName(caseDef.opType) << "("
383				<< subgroups::getFormatNameForGLSL(caseDef.format) << "(1)) ? 0x1u : 0x0u;\n"
384				<< "  result[offset] |= " << getOpTypeName(caseDef.opType)
385				<< "(gl_SubgroupInvocationID) ? 0x0u : 0x2u;\n"
386				<< "  result[offset] |= " << getOpTypeName(caseDef.opType)
387				<< "(data[0]) ? 0x4u : 0x0u;\n"
388				<< "  result[offset] |= "<< getOpTypeName(caseDef.opType)
389				<< "(valueEqual) ? 0x8u : 0x0u;\n"
390				<< "  result[offset] |= "<< getOpTypeName(caseDef.opType)
391				<< "(valueNoEqual) ? 0x0u : 0x10u;\n"
392				<< "  if (subgroupElect()) result[offset] |= 0x2u | 0x10u;\n";
393		}
394
395		src << "}\n";
396
397		programCollection.add("comp") << glu::ComputeSource(src.str());
398	}
399	else
400	{
401		const string source =
402		(OPTYPE_ALL == caseDef.opType) ?
403			"  b${SSBO1}.result[offset] = " + getOpTypeName(caseDef.opType) +
404			"(true) ? 0x1u : 0u;\n"
405			"  b${SSBO1}.result[offset] |= " + getOpTypeName(caseDef.opType) +
406			"(false) ? 0u : 0x1Au;\n"
407			"  b${SSBO1}.result[offset] |= 0x4u;\n"
408		: (OPTYPE_ANY == caseDef.opType) ?
409				"  b${SSBO1}.result[offset] = " + getOpTypeName(caseDef.opType) +
410				"(true) ? 0x1u : 0u;\n"
411				"  b${SSBO1}.result[offset] |= " + getOpTypeName(caseDef.opType) +
412				"(false) ? 0u : 0x1Au;\n"
413				"  b${SSBO1}.result[offset] |= 0x4u;\n"
414		: (OPTYPE_ALLEQUAL == caseDef.opType) ?
415				"  " + subgroups::getFormatNameForGLSL(caseDef.format) + " valueEqual = " + subgroups::getFormatNameForGLSL(caseDef.format) + "(1.25 * float(data[gl_SubgroupInvocationID]) + 5.0);\n" +
416				"  " + subgroups::getFormatNameForGLSL(caseDef.format) + " valueNoEqual = " + subgroups::getFormatNameForGLSL(caseDef.format) + (formatIsBoolean ? "(subgroupElect());\n" : "(12.0 * float(data[gl_SubgroupInvocationID]) + float(gl_SubgroupInvocationID));\n") +
417				"  b${SSBO1}.result[offset] = " + getOpTypeName(caseDef.opType) + "("
418				+ subgroups::getFormatNameForGLSL(caseDef.format) + "(1)) ? 0x1u : 0u;\n"
419				"  b${SSBO1}.result[offset] |= " + getOpTypeName(caseDef.opType) +
420				"(gl_SubgroupInvocationID) ? 0u : 0x2u;\n"
421				"  b${SSBO1}.result[offset] |= " + getOpTypeName(caseDef.opType) +
422				"(data[0]) ? 0x4u : 0u;\n"
423				"  b${SSBO1}.result[offset] |= " + getOpTypeName(caseDef.opType) +
424				"(valueEqual) ? 0x8u : 0x0u;\n"
425				"  b${SSBO1}.result[offset] |= " + getOpTypeName(caseDef.opType) +
426				"(valueNoEqual) ? 0x0u : 0x10u;\n"
427				"  if (subgroupElect()) b${SSBO1}.result[offset] |= 0x2u | 0x10u;\n"
428		: "";
429
430		tcu::StringTemplate sourceTemplate(source);
431
432		const string formatString = subgroups::getFormatNameForGLSL(caseDef.format);
433
434		{
435			map<string, string> bufferNameMapping;
436			bufferNameMapping.insert(pair<string, string>("SSBO1", "0"));
437
438			const string vertex =
439				"${VERSION_DECL}\n"
440				"#extension GL_KHR_shader_subgroup_vote: enable\n"
441				"layout(binding = 0, std430) buffer Buffer0\n"
442				"{\n"
443				"  uint result[];\n"
444				"} b0;\n"
445				"layout(binding = 4, std430) readonly buffer Buffer4\n"
446				"{\n"
447				"  " + formatString + " data[];\n"
448				"};\n"
449				"\n"
450				"void main (void)\n"
451				"{\n"
452				"  highp int offset = gl_VertexID;\n"
453				+ sourceTemplate.specialize(bufferNameMapping) +
454				"  float pixelSize = 2.0f/1024.0f;\n"
455				"  float pixelPosition = pixelSize/2.0f - 1.0f;\n"
456				"  gl_Position = vec4(float(gl_VertexID) * pixelSize + pixelPosition, 0.0f, 0.0f, 1.0f);\n"
457				"  gl_PointSize = 1.0f;\n"
458				"}\n";
459			programCollection.add("vert") << glu::VertexSource(vertex);
460		}
461
462		{
463			map<string, string> bufferNameMapping;
464			bufferNameMapping.insert(pair<string, string>("SSBO1", "1"));
465
466			const string tesc =
467				"${VERSION_DECL}\n"
468				"#extension GL_KHR_shader_subgroup_vote: enable\n"
469				"layout(vertices=1) out;\n"
470				"layout(binding = 1, std430) buffer Buffer1\n"
471				"{\n"
472				"  uint result[];\n"
473				"} b1;\n"
474				"layout(binding = 4, std430) readonly buffer Buffer4\n"
475				"{\n"
476				"  " + formatString + " data[];\n"
477				"};\n"
478				"\n"
479				"void main (void)\n"
480				"{\n"
481				"  highp int offset = gl_PrimitiveID;\n"
482				+ sourceTemplate.specialize(bufferNameMapping) +
483				"  if (gl_InvocationID == 0)\n"
484				"  {\n"
485				"    gl_TessLevelOuter[0] = 1.0f;\n"
486				"    gl_TessLevelOuter[1] = 1.0f;\n"
487				"  }\n"
488				"  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
489				"}\n";
490
491			programCollection.add("tesc") << glu::TessellationControlSource(tesc);
492		}
493
494		{
495			map<string, string> bufferNameMapping;
496			bufferNameMapping.insert(pair<string, string>("SSBO1", "2"));
497
498			const string tese =
499				"${VERSION_DECL}\n"
500				"#extension GL_KHR_shader_subgroup_vote: enable\n"
501				"layout(isolines) in;\n"
502				"layout(binding = 2, std430) buffer Buffer2\n"
503				"{\n"
504				"  uint result[];\n"
505				"} b2;\n"
506				"layout(binding = 4, std430) readonly buffer Buffer4\n"
507				"{\n"
508				"  " + formatString + " data[];\n"
509				"};\n"
510				"\n"
511				"void main (void)\n"
512				"{\n"
513				"  highp uint offset = uint(gl_PrimitiveID * 2) + uint(gl_TessCoord.x + 0.5);\n"
514				+ sourceTemplate.specialize(bufferNameMapping) +
515				"  float pixelSize = 2.0f/1024.0f;\n"
516				"  gl_Position = gl_in[0].gl_Position + gl_TessCoord.x * pixelSize / 2.0f;\n"
517				"}\n";
518
519			programCollection.add("tese") << glu::TessellationEvaluationSource(tese);
520		}
521
522		{
523			map<string, string> bufferNameMapping;
524			bufferNameMapping.insert(pair<string, string>("SSBO1", "3"));
525
526			const string geometry =
527				// version string added by addGeometryShadersFromTemplate
528				"#extension GL_KHR_shader_subgroup_vote: enable\n"
529				"layout(${TOPOLOGY}) in;\n"
530				"layout(points, max_vertices = 1) out;\n"
531				"layout(binding = 3, std430) buffer Buffer3\n"
532				"{\n"
533				"  uint result[];\n"
534				"} b3;\n"
535				"layout(binding = 4, std430) readonly buffer Buffer4\n"
536				"{\n"
537				"  " + formatString + " data[];\n"
538				"};\n"
539				"\n"
540				"void main (void)\n"
541				"{\n"
542				"  highp int offset = gl_PrimitiveIDIn;\n"
543				+ sourceTemplate.specialize(bufferNameMapping) +
544				"  gl_Position = gl_in[0].gl_Position;\n"
545				"  EmitVertex();\n"
546				"  EndPrimitive();\n"
547				"}\n";
548
549			subgroups::addGeometryShadersFromTemplate(geometry, programCollection);
550		}
551
552		{
553			const string sourceFragment =
554			(OPTYPE_ALL == caseDef.opType) ?
555				"  result = " + getOpTypeName(caseDef.opType) +
556				"(true) ? 0x1u : 0u;\n"
557				"  result |= " + getOpTypeName(caseDef.opType) +
558				"(false) ? 0u : 0x1Au;\n"
559				"  result |= 0x4u;\n"
560			: (OPTYPE_ANY == caseDef.opType) ?
561					"  result = " + getOpTypeName(caseDef.opType) +
562					"(true) ? 0x1u : 0u;\n"
563					"  result |= " + getOpTypeName(caseDef.opType) +
564					"(false) ? 0u : 0x1Au;\n"
565					"  result |= 0x4u;\n"
566			: (OPTYPE_ALLEQUAL == caseDef.opType) ?
567					"  " + subgroups::getFormatNameForGLSL(caseDef.format) + " valueEqual = " + subgroups::getFormatNameForGLSL(caseDef.format) + "(1.25 * float(data[gl_SubgroupInvocationID]) + 5.0);\n" +
568					"  " + subgroups::getFormatNameForGLSL(caseDef.format) + " valueNoEqual = " + subgroups::getFormatNameForGLSL(caseDef.format) + (formatIsBoolean ? "(subgroupElect());\n" : "(12.0 * float(data[gl_SubgroupInvocationID]) + gl_FragCoord.x * float(gl_SubgroupInvocationID));\n") +
569					"  result = " + getOpTypeName(caseDef.opType) + "("
570					+ subgroups::getFormatNameForGLSL(caseDef.format) + "(1)) ? 0x1u : 0u;\n"
571					"  result |= " + getOpTypeName(caseDef.opType) +
572					"(gl_SubgroupInvocationID) ? 0u : 0x2u;\n"
573					"  result |= " + getOpTypeName(caseDef.opType) +
574					"(data[0]) ? 0x4u : 0u;\n"
575					"  result |= " + getOpTypeName(caseDef.opType) +
576					"(valueEqual) ? 0x8u : 0x0u;\n"
577					"  result |= " + getOpTypeName(caseDef.opType) +
578					"(valueNoEqual) ? 0x0u : 0x10u;\n"
579					"  if (subgroupElect()) result |= 0x2u | 0x10u;\n"
580			: "";
581			const string fragment =
582				"${VERSION_DECL}\n"
583				"#extension GL_KHR_shader_subgroup_vote: enable\n"
584				"precision highp float;\n"
585				"layout(location = 0) out uint result;\n"
586				"layout(binding = 4, std430) readonly buffer Buffer4\n"
587				"{\n"
588				"  " + formatString + " data[];\n"
589				"};\n"
590				"void main (void)\n"
591				"{\n"
592				+ sourceFragment +
593				"}\n";
594
595			programCollection.add("fragment") << glu::FragmentSource(fragment);
596		}
597
598		subgroups::addNoSubgroupShader(programCollection);
599	}
600}
601
602void supportedCheck (Context& context, CaseDefinition caseDef)
603{
604	if (!subgroups::isSubgroupSupported(context))
605		TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
606
607	if (!subgroups::isSubgroupFeatureSupportedForDevice(context, subgroups::SUBGROUP_FEATURE_VOTE_BIT))
608	{
609		TCU_THROW(NotSupportedError, "Device does not support subgroup vote operations");
610	}
611
612	if (subgroups::isDoubleFormat(caseDef.format) &&
613			!subgroups::isDoubleSupportedForDevice(context))
614	{
615		TCU_THROW(NotSupportedError, "Device does not support subgroup double operations");
616	}
617}
618
619tcu::TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
620{
621	if (!subgroups::areSubgroupOperationsSupportedForStage(
622				context, caseDef.shaderStage))
623	{
624		if (subgroups::areSubgroupOperationsRequiredForStage(
625					caseDef.shaderStage))
626		{
627			return tcu::TestStatus::fail(
628					   "Shader stage " +
629					   subgroups::getShaderStageName(caseDef.shaderStage) +
630					   " is required to support subgroup operations!");
631		}
632		else
633		{
634			TCU_THROW(NotSupportedError, "Device does not support subgroup operations for this stage");
635		}
636	}
637
638	subgroups::SSBOData inputData;
639	inputData.format = caseDef.format;
640	inputData.layout = subgroups::SSBOData::LayoutStd140;
641	inputData.numElements = subgroups::maxSupportedSubgroupSize();
642	inputData.initializeType = OPTYPE_ALLEQUAL == caseDef.opType ? subgroups::SSBOData::InitializeZero : subgroups::SSBOData::InitializeNonZero;
643
644	if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
645		return subgroups::makeVertexFrameBufferTest(context, FORMAT_R32_UINT, &inputData, 1, checkVertexPipelineStages);
646	else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
647		return subgroups::makeGeometryFrameBufferTest(context, FORMAT_R32_UINT, &inputData, 1, checkVertexPipelineStages);
648	else if (SHADER_STAGE_TESS_CONTROL_BIT == caseDef.shaderStage)
649		return subgroups::makeTessellationEvaluationFrameBufferTest(context, FORMAT_R32_UINT, &inputData, 1, checkVertexPipelineStages, SHADER_STAGE_TESS_CONTROL_BIT);
650	else if (SHADER_STAGE_TESS_EVALUATION_BIT == caseDef.shaderStage)
651		return subgroups::makeTessellationEvaluationFrameBufferTest(context, FORMAT_R32_UINT, &inputData, 1, checkVertexPipelineStages, SHADER_STAGE_TESS_EVALUATION_BIT);
652	else if (SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
653		return subgroups::makeFragmentFrameBufferTest(context, FORMAT_R32_UINT, &inputData, 1, checkFragmentPipelineStages);
654	else
655		TCU_THROW(InternalError, "Unhandled shader stage");
656}
657
658
659tcu::TestStatus test(Context& context, const CaseDefinition caseDef)
660{
661	if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
662	{
663		if (!subgroups::areSubgroupOperationsSupportedForStage(context, caseDef.shaderStage))
664		{
665			return tcu::TestStatus::fail(
666					   "Shader stage " +
667					   subgroups::getShaderStageName(caseDef.shaderStage) +
668					   " is required to support subgroup operations!");
669		}
670
671		subgroups::SSBOData inputData;
672		inputData.format = caseDef.format;
673		inputData.layout = subgroups::SSBOData::LayoutStd430;
674		inputData.numElements = subgroups::maxSupportedSubgroupSize();
675		inputData.initializeType = OPTYPE_ALLEQUAL == caseDef.opType ? subgroups::SSBOData::InitializeZero : subgroups::SSBOData::InitializeNonZero;
676		inputData.binding = 1u;
677
678		return subgroups::makeComputeTest(context, FORMAT_R32_UINT, &inputData,
679										  1, checkComputeStage);
680	}
681	else
682	{
683		int supportedStages = context.getDeqpContext().getContextInfo().getInt(GL_SUBGROUP_SUPPORTED_STAGES_KHR);
684
685		ShaderStageFlags stages = (ShaderStageFlags)(caseDef.shaderStage & supportedStages);
686
687		if (SHADER_STAGE_FRAGMENT_BIT != stages && !subgroups::isVertexSSBOSupportedForDevice(context))
688		{
689			if ( (stages & SHADER_STAGE_FRAGMENT_BIT) == 0)
690				TCU_THROW(NotSupportedError, "Device does not support vertex stage SSBO writes");
691			else
692				stages = SHADER_STAGE_FRAGMENT_BIT;
693		}
694
695		if ((ShaderStageFlags)0u == stages)
696			TCU_THROW(NotSupportedError, "Subgroup operations are not supported for any graphic shader");
697
698		subgroups::SSBOData inputData;
699		inputData.format			= caseDef.format;
700		inputData.layout			= subgroups::SSBOData::LayoutStd430;
701		inputData.numElements		= subgroups::maxSupportedSubgroupSize();
702		inputData.initializeType	= OPTYPE_ALLEQUAL == caseDef.opType ? subgroups::SSBOData::InitializeZero : subgroups::SSBOData::InitializeNonZero;
703		inputData.binding			= 4u;
704		inputData.stages			= stages;
705
706		return subgroups::allStages(context, FORMAT_R32_UINT, &inputData, 1, checkVertexPipelineStages, stages);
707	}
708}
709
710} // namespace
711
712deqp::TestCaseGroup* createSubgroupsVoteTests(deqp::Context& testCtx)
713{
714	de::MovePtr<deqp::TestCaseGroup> graphicGroup(new deqp::TestCaseGroup(
715		testCtx, "graphics", "Subgroup arithmetic category tests: graphics"));
716	de::MovePtr<deqp::TestCaseGroup> computeGroup(new deqp::TestCaseGroup(
717		testCtx, "compute", "Subgroup arithmetic category tests: compute"));
718	de::MovePtr<deqp::TestCaseGroup> framebufferGroup(new deqp::TestCaseGroup(
719		testCtx, "framebuffer", "Subgroup arithmetic category tests: framebuffer"));
720
721	de::MovePtr<deqp::TestCaseGroup> fragHelperGroup(new deqp::TestCaseGroup(
722		testCtx, "frag_helper", "Subgroup arithmetic category tests: fragment helper invocation"));
723
724	const ShaderStageFlags stages[] =
725	{
726		SHADER_STAGE_VERTEX_BIT,
727		SHADER_STAGE_TESS_EVALUATION_BIT,
728		SHADER_STAGE_TESS_CONTROL_BIT,
729		SHADER_STAGE_GEOMETRY_BIT,
730	};
731
732	const Format formats[] =
733	{
734		FORMAT_R32_SINT, FORMAT_R32G32_SINT, FORMAT_R32G32B32_SINT,
735		FORMAT_R32G32B32A32_SINT, FORMAT_R32_UINT, FORMAT_R32G32_UINT,
736		FORMAT_R32G32B32_UINT, FORMAT_R32G32B32A32_UINT,
737		FORMAT_R32_SFLOAT, FORMAT_R32G32_SFLOAT,
738		FORMAT_R32G32B32_SFLOAT, FORMAT_R32G32B32A32_SFLOAT,
739		FORMAT_R64_SFLOAT, FORMAT_R64G64_SFLOAT,
740		FORMAT_R64G64B64_SFLOAT, FORMAT_R64G64B64A64_SFLOAT,
741		FORMAT_R32_BOOL, FORMAT_R32G32_BOOL,
742		FORMAT_R32G32B32_BOOL, FORMAT_R32G32B32A32_BOOL,
743	};
744
745	for (int formatIndex = 0; formatIndex < DE_LENGTH_OF_ARRAY(formats); ++formatIndex)
746	{
747		const Format format = formats[formatIndex];
748
749		for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
750		{
751			// Skip the typed tests for all but subgroupAllEqual()
752			if ((FORMAT_R32_UINT != format) && (OPTYPE_ALLEQUAL != opTypeIndex))
753			{
754				continue;
755			}
756
757			const std::string op = de::toLower(getOpTypeName(opTypeIndex));
758
759			{
760				const CaseDefinition caseDef = {opTypeIndex, SHADER_STAGE_COMPUTE_BIT, format};
761				SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(computeGroup.get(),
762											op + "_" + subgroups::getFormatNameForGLSL(format),
763											"", supportedCheck, initPrograms, test, caseDef);
764			}
765
766			{
767				const CaseDefinition caseDef = {opTypeIndex, SHADER_STAGE_ALL_GRAPHICS, format};
768				SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(graphicGroup.get(),
769											op + "_" + subgroups::getFormatNameForGLSL(format),
770											"", supportedCheck, initPrograms, test, caseDef);
771			}
772
773			for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
774			{
775				const CaseDefinition caseDef = {opTypeIndex, stages[stageIndex], format};
776				SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(framebufferGroup.get(),
777							op + "_" +
778							subgroups::getFormatNameForGLSL(format)
779							+ "_" + getShaderStageName(caseDef.shaderStage), "",
780							supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
781			}
782
783			const CaseDefinition caseDef = {opTypeIndex, SHADER_STAGE_FRAGMENT_BIT, format};
784			SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(fragHelperGroup.get(),
785						op + "_" +
786						subgroups::getFormatNameForGLSL(format)
787						+ "_" + getShaderStageName(caseDef.shaderStage), "",
788						supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
789		}
790	}
791
792	de::MovePtr<deqp::TestCaseGroup> group(new deqp::TestCaseGroup(
793		testCtx, "vote", "Subgroup vote category tests"));
794
795	group->addChild(graphicGroup.release());
796	group->addChild(computeGroup.release());
797	group->addChild(framebufferGroup.release());
798	group->addChild(fragHelperGroup.release());
799
800	return group.release();
801}
802
803} // subgroups
804} // glc
805