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