• 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 "glcSubgroupsVoteTests.hpp"
27 #include "glcSubgroupsTestsUtils.hpp"
28 
29 #include <string>
30 #include <vector>
31 #include "tcuStringTemplate.hpp"
32 
33 using namespace tcu;
34 using namespace std;
35 
36 namespace glc
37 {
38 namespace subgroups
39 {
40 
41 namespace
42 {
43 
44 enum OpType
45 {
46 	OPTYPE_ALL = 0,
47 	OPTYPE_ANY,
48 	OPTYPE_ALLEQUAL,
49 	OPTYPE_LAST
50 };
51 
checkVertexPipelineStages(std::vector<const void * > datas,deUint32 width,deUint32)52 static bool checkVertexPipelineStages(std::vector<const void*> datas,
53 									  deUint32 width, deUint32)
54 {
55 	return glc::subgroups::check(datas, width, 0x1F);
56 }
57 
checkFragmentPipelineStages(std::vector<const void * > datas,deUint32 width,deUint32 height,deUint32)58 static 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 
checkComputeStage(std::vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)85 static 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 
getOpTypeName(int opType)92 std::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 
108 struct CaseDefinition
109 {
110 	int					opType;
111 	ShaderStageFlags	shaderStage;
112 	Format				format;
113 };
114 
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)115 void 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 			<< "#extension GL_EXT_tessellation_shader : require\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 
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)333 void 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 
supportedCheck(Context & context,CaseDefinition caseDef)602 void 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 
noSSBOtest(Context & context,const CaseDefinition caseDef)619 tcu::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 
test(Context & context,const CaseDefinition caseDef)659 tcu::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 
createSubgroupsVoteTests(deqp::Context & testCtx)712 deqp::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