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