• 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 "glcSubgroupsBuiltinMaskVarTests.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 
checkVertexPipelineStages(std::vector<const void * > datas,deUint32 width,deUint32)40 static bool checkVertexPipelineStages(std::vector<const void*> datas,
41 									  deUint32 width, deUint32)
42 {
43 	return check(datas, width, 1);
44 }
45 
checkComputeStage(std::vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)46 static bool checkComputeStage(std::vector<const void*> datas,
47 						 const deUint32 numWorkgroups[3], const deUint32 localSize[3],
48 						 deUint32)
49 {
50 	return checkCompute(datas, numWorkgroups, localSize, 1);
51 }
52 
53 namespace
54 {
55 struct CaseDefinition
56 {
57 	std::string			varName;
58 	ShaderStageFlags	shaderStage;
59 };
60 }
61 
subgroupMask(const CaseDefinition & caseDef)62 std::string subgroupMask (const CaseDefinition& caseDef)
63 {
64 	std::ostringstream bdy;
65 
66 	bdy << "  uint tempResult = 0x1u;\n"
67 		<< "  uint bit        = 0x1u;\n"
68 		<< "  uint bitCount   = 0x0u;\n"
69 		<< "  uvec4 mask = subgroupBallot(true);\n"
70 		<< "  uvec4 var = " << caseDef.varName << ";\n"
71 		<< "  for (uint i = 0u; i < gl_SubgroupSize; i++)\n"
72 		<< "  {\n";
73 
74 	if ("gl_SubgroupEqMask" == caseDef.varName)
75 	{
76 		bdy << "    if ((i == gl_SubgroupInvocationID) ^^ subgroupBallotBitExtract(var, i))\n"
77 			<< "    {\n"
78 			<< "      tempResult = 0u;\n"
79 			<< "    }\n";
80 	}
81 	else if ("gl_SubgroupGeMask" == caseDef.varName)
82 	{
83 		bdy << "    if ((i >= gl_SubgroupInvocationID) ^^ subgroupBallotBitExtract(var, i))\n"
84 			<< "    {\n"
85 			<< "      tempResult = 0u;\n"
86 			<< "    }\n";
87 	}
88 	else if ("gl_SubgroupGtMask" == caseDef.varName)
89 	{
90 		bdy << "    if ((i > gl_SubgroupInvocationID) ^^ subgroupBallotBitExtract(var, i))\n"
91 			<< "    {\n"
92 			<< "      tempResult = 0u;\n"
93 			<< "    }\n";
94 	}
95 	else if ("gl_SubgroupLeMask" == caseDef.varName)
96 	{
97 		bdy << "    if ((i <= gl_SubgroupInvocationID) ^^ subgroupBallotBitExtract(var, i))\n"
98 			<< "    {\n"
99 			<< "      tempResult = 0u;\n"
100 			<< "    }\n";
101 	}
102 	else if ("gl_SubgroupLtMask" == caseDef.varName)
103 	{
104 		bdy << "    if ((i < gl_SubgroupInvocationID) ^^ subgroupBallotBitExtract(var, i))\n"
105 			<< "    {\n"
106 			<< "      tempResult = 0u;\n"
107 			<< "    }\n";
108 	}
109 
110 	bdy << "  }\n"
111 		<< "  for (uint i = 0u; i < 32u; i++)\n"
112 		<< "  {\n"
113 		<< "    if ((var.x & bit) > 0u)\n"
114 		<< "    {\n"
115 		<< "      bitCount++;\n"
116 		<< "    }\n"
117 		<< "    if ((var.y & bit) > 0u)\n"
118 		<< "    {\n"
119 		<< "      bitCount++;\n"
120 		<< "    }\n"
121 		<< "    if ((var.z & bit) > 0u)\n"
122 		<< "    {\n"
123 		<< "      bitCount++;\n"
124 		<< "    }\n"
125 		<< "    if ((var.w & bit) > 0u)\n"
126 		<< "    {\n"
127 		<< "      bitCount++;\n"
128 		<< "    }\n"
129 		<< "    bit = bit << 1u;\n"
130 		<< "  }\n"
131 		<< "  if (subgroupBallotBitCount(var) != bitCount)\n"
132 		<< "  {\n"
133 		<< "    tempResult = 0u;\n"
134 		<< "  }\n";
135 	return bdy.str();
136 }
137 
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)138 void initFrameBufferPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
139 {
140 	subgroups::setFragmentShaderFrameBuffer(programCollection);
141 
142 	if (SHADER_STAGE_VERTEX_BIT != caseDef.shaderStage)
143 		subgroups::setVertexShaderFrameBuffer(programCollection);
144 
145 	if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
146 	{
147 		const string bdy = subgroupMask(caseDef);
148 		const string vertexGLSL =
149 			"${VERSION_DECL}\n"
150 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
151 			"layout(location = 0) out float out_color;\n"
152 			"layout(location = 0) in highp vec4 in_position;\n"
153 			"\n"
154 			"void main (void)\n"
155 			"{\n"
156 			+ bdy +
157 			"  out_color = float(tempResult);\n"
158 			"  gl_Position = in_position;\n"
159 			"  gl_PointSize = 1.0f;\n"
160 			"}\n";
161 		programCollection.add("vert") << glu::VertexSource(vertexGLSL);
162 	}
163 	else if (SHADER_STAGE_TESS_EVALUATION_BIT == caseDef.shaderStage)
164 	{
165 		const string bdy = subgroupMask(caseDef);
166 		const string  evaluationSourceGLSL =
167 			"${VERSION_DECL}\n"
168 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
169 			"#extension GL_EXT_tessellation_shader : require\n"
170 			"layout(isolines, equal_spacing, ccw ) in;\n"
171 			"layout(location = 0) out float out_color;\n"
172 			"\n"
173 			"void main (void)\n"
174 			"{\n"
175 			+ bdy +
176 			"  out_color = float(tempResult);\n"
177 			"  gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
178 			"}\n";
179 		programCollection.add("tese") << glu::TessellationEvaluationSource(evaluationSourceGLSL);
180 		subgroups::setTesCtrlShaderFrameBuffer(programCollection);
181 	}
182 	else if (SHADER_STAGE_TESS_CONTROL_BIT == caseDef.shaderStage)
183 	{
184 		const string bdy = subgroupMask(caseDef);
185 		const string  controlSourceGLSL =
186 			"${VERSION_DECL}\n"
187 			"#extension GL_EXT_tessellation_shader : require\n"
188 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
189 			"layout(vertices = 2) out;\n"
190 			"layout(location = 0) out float out_color[];\n"
191 			"void main (void)\n"
192 			"{\n"
193 			"  if (gl_InvocationID == 0)\n"
194 			"  {\n"
195 			"    gl_TessLevelOuter[0] = 1.0f;\n"
196 			"    gl_TessLevelOuter[1] = 1.0f;\n"
197 			"  }\n"
198 			+ bdy +
199 			"  out_color[gl_InvocationID] = float(tempResult);\n"
200 			"  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
201 			"}\n";
202 		programCollection.add("tesc") << glu::TessellationControlSource(controlSourceGLSL);
203 		subgroups::setTesEvalShaderFrameBuffer(programCollection);
204 	}
205 	else if (SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
206 	{
207 		const string bdy = subgroupMask(caseDef);
208 		const string geometryGLSL =
209 			"${VERSION_DECL}\n"
210 			"#extension GL_KHR_shader_subgroup_ballot: enable\n"
211 			"layout(points) in;\n"
212 			"layout(points, max_vertices = 1) out;\n"
213 			"layout(location = 0) out float out_color;\n"
214 			"\n"
215 			"void main (void)\n"
216 			"{\n"
217 			+ bdy +
218 			"  out_color = float(tempResult);\n"
219 			"  gl_Position = gl_in[0].gl_Position;\n"
220 			"  EmitVertex();\n"
221 			"  EndPrimitive();\n"
222 			"}\n";
223 		programCollection.add("geometry") << glu::GeometrySource(geometryGLSL);
224 	}
225 	else
226 	{
227 		DE_FATAL("Unsupported shader stage");
228 	}
229 }
230 
231 
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)232 void initPrograms(SourceCollections& programCollection, CaseDefinition caseDef)
233 {
234 	const string bdy = subgroupMask(caseDef);
235 
236 	if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
237 	{
238 		std::ostringstream src;
239 
240 		src << "${VERSION_DECL}\n"
241 			<< "#extension GL_KHR_shader_subgroup_ballot: enable\n"
242 			<< "layout (${LOCAL_SIZE_X}, ${LOCAL_SIZE_Y}, ${LOCAL_SIZE_Z}) in;\n"
243 			<< "layout(binding = 0, std430) buffer Output\n"
244 			<< "{\n"
245 			<< "  uint result[];\n"
246 			<< "};\n"
247 			<< "\n"
248 			<< "void main (void)\n"
249 			<< "{\n"
250 			<< "  uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
251 			<< "  highp uint offset = globalSize.x * ((globalSize.y * "
252 			"gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + "
253 			"gl_GlobalInvocationID.x;\n"
254 			<< bdy
255 			<< "  result[offset] = tempResult;\n"
256 			<< "}\n";
257 
258 		programCollection.add("comp") << glu::ComputeSource(src.str());
259 	}
260 	else
261 	{
262 		{
263 			const string vertex =
264 				"${VERSION_DECL}\n"
265 				"#extension GL_KHR_shader_subgroup_ballot: enable\n"
266 				"layout(binding = 0, std430) buffer Output0\n"
267 				"{\n"
268 				"  uint result[];\n"
269 				"} b0;\n"
270 				"\n"
271 				"void main (void)\n"
272 				"{\n"
273 				+ bdy +
274 				"  b0.result[gl_VertexID] = tempResult;\n"
275 				"  float pixelSize = 2.0f/1024.0f;\n"
276 				"  float pixelPosition = pixelSize/2.0f - 1.0f;\n"
277 				"  gl_Position = vec4(float(gl_VertexID) * pixelSize + pixelPosition, 0.0f, 0.0f, 1.0f);\n"
278 				"  gl_PointSize = 1.0f;\n"
279 				"}\n";
280 			programCollection.add("vert") << glu::VertexSource(vertex);
281 		}
282 
283 		{
284 			const string tesc =
285 				"${VERSION_DECL}\n"
286 				"#extension GL_KHR_shader_subgroup_ballot: enable\n"
287 				"layout(vertices=1) out;\n"
288 				"layout(binding = 1, std430) buffer Output1\n"
289 				"{\n"
290 				"  uint result[];\n"
291 				"} b1;\n"
292 				"\n"
293 				"void main (void)\n"
294 				"{\n"
295 				+ bdy +
296 				"  b1.result[gl_PrimitiveID] = tempResult;\n"
297 				"  if (gl_InvocationID == 0)\n"
298 				"  {\n"
299 				"    gl_TessLevelOuter[0] = 1.0f;\n"
300 				"    gl_TessLevelOuter[1] = 1.0f;\n"
301 				"  }\n"
302 				"  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
303 				"}\n";
304 			programCollection.add("tesc") << glu::TessellationControlSource(tesc);
305 		}
306 
307 		{
308 			const string tese =
309 				"${VERSION_DECL}\n"
310 				"#extension GL_KHR_shader_subgroup_ballot: enable\n"
311 				"layout(isolines) in;\n"
312 				"layout(binding = 2, std430) buffer Output2\n"
313 				"{\n"
314 				"  uint result[];\n"
315 				"} b2;\n"
316 				"\n"
317 				"void main (void)\n"
318 				"{\n"
319 				+ bdy +
320 				"  b2.result[gl_PrimitiveID * 2 + int(gl_TessCoord.x + 0.5)] = tempResult;\n"
321 				"  float pixelSize = 2.0f/1024.0f;\n"
322 				"  gl_Position = gl_in[0].gl_Position + gl_TessCoord.x * pixelSize / 2.0f;\n"
323 				"}\n";
324 
325 			programCollection.add("tese") << glu::TessellationEvaluationSource(tese);
326 		}
327 
328 		{
329 			const string geometry =
330 				"#extension GL_KHR_shader_subgroup_ballot: enable\n"
331 				"layout(${TOPOLOGY}) in;\n"
332 				"layout(points, max_vertices = 1) out;\n"
333 				"layout(binding = 3, std430) buffer Output3\n"
334 				"{\n"
335 				"  uint result[];\n"
336 				"} b3;\n"
337 				"\n"
338 				"void main (void)\n"
339 				"{\n"
340 				+ bdy +
341 				"  b3.result[gl_PrimitiveIDIn] = tempResult;\n"
342 				"  gl_Position = gl_in[0].gl_Position;\n"
343 				"  EmitVertex();\n"
344 				"  EndPrimitive();\n"
345 				"}\n";
346 
347 			subgroups::addGeometryShadersFromTemplate(geometry, programCollection);
348 		}
349 
350 		{
351 			const string fragment =
352 				"${VERSION_DECL}\n"
353 				"#extension GL_KHR_shader_subgroup_ballot: enable\n"
354 				"precision highp int;\n"
355 				"layout(location = 0) out uint result;\n"
356 				"void main (void)\n"
357 				"{\n"
358 				+ bdy +
359 				"  result = tempResult;\n"
360 				"}\n";
361 
362 			programCollection.add("fragment") << glu::FragmentSource(fragment);
363 		}
364 
365 		subgroups::addNoSubgroupShader(programCollection);
366 	}
367 }
368 
supportedCheck(Context & context,CaseDefinition caseDef)369 void supportedCheck (Context& context, CaseDefinition caseDef)
370 {
371 	DE_UNREF(caseDef);
372 	if (!subgroups::isSubgroupSupported(context))
373 		TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
374 }
375 
noSSBOtest(Context & context,const CaseDefinition caseDef)376 tcu::TestStatus noSSBOtest(Context& context, const CaseDefinition caseDef)
377 {
378 	if (!areSubgroupOperationsSupportedForStage(
379 				context, caseDef.shaderStage))
380 	{
381 		if (areSubgroupOperationsRequiredForStage(caseDef.shaderStage))
382 		{
383 			return tcu::TestStatus::fail(
384 					   "Shader stage " + getShaderStageName(caseDef.shaderStage) +
385 					   " is required to support subgroup operations!");
386 		}
387 		else
388 		{
389 			TCU_THROW(NotSupportedError, "Device does not support subgroup operations for this stage");
390 		}
391 	}
392 
393 	if (!subgroups::isSubgroupFeatureSupportedForDevice(context, SUBGROUP_FEATURE_BALLOT_BIT))
394 	{
395 		TCU_THROW(NotSupportedError, "Device does not support subgroup ballot operations");
396 	}
397 
398 	if (SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
399 		return makeVertexFrameBufferTest(context, FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages);
400 	else if ((SHADER_STAGE_TESS_EVALUATION_BIT | SHADER_STAGE_TESS_CONTROL_BIT) & caseDef.shaderStage )
401 		return makeTessellationEvaluationFrameBufferTest(context, FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages);
402 
403 	return makeGeometryFrameBufferTest(context, FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages);
404 }
405 
406 
test(Context & context,const CaseDefinition caseDef)407 tcu::TestStatus test(Context& context, const CaseDefinition caseDef)
408 {
409 	if (!subgroups::isSubgroupFeatureSupportedForDevice(context, SUBGROUP_FEATURE_BALLOT_BIT))
410 	{
411 		TCU_THROW(NotSupportedError, "Device does not support subgroup ballot operations");
412 	}
413 
414 	if (SHADER_STAGE_COMPUTE_BIT == caseDef.shaderStage)
415 	{
416 		if (!areSubgroupOperationsSupportedForStage(context, caseDef.shaderStage))
417 		{
418 				return tcu::TestStatus::fail(
419 						   "Shader stage " + getShaderStageName(caseDef.shaderStage) +
420 						   " is required to support subgroup operations!");
421 		}
422 		return makeComputeTest(context, FORMAT_R32_UINT, DE_NULL, 0, checkComputeStage);
423 	}
424 	else
425 	{
426 		int supportedStages = context.getDeqpContext().getContextInfo().getInt(GL_SUBGROUP_SUPPORTED_STAGES_KHR);
427 
428 		subgroups::ShaderStageFlags stages = (subgroups::ShaderStageFlags)(caseDef.shaderStage & supportedStages);
429 
430 		if ( SHADER_STAGE_FRAGMENT_BIT != stages && !subgroups::isVertexSSBOSupportedForDevice(context))
431 		{
432 			if ( (stages & SHADER_STAGE_FRAGMENT_BIT) == 0)
433 				TCU_THROW(NotSupportedError, "Device does not support vertex stage SSBO writes");
434 			else
435 				stages = SHADER_STAGE_FRAGMENT_BIT;
436 		}
437 
438 		if ((ShaderStageFlags)0u == stages)
439 			TCU_THROW(NotSupportedError, "Subgroup operations are not supported for any graphic shader");
440 
441 		return subgroups::allStages(context, FORMAT_R32_UINT, DE_NULL, 0, checkVertexPipelineStages, stages);
442 	}
443 }
444 
createSubgroupsBuiltinMaskVarTests(deqp::Context & testCtx)445 deqp::TestCaseGroup* createSubgroupsBuiltinMaskVarTests(deqp::Context& testCtx)
446 {
447 	de::MovePtr<deqp::TestCaseGroup> graphicGroup(new deqp::TestCaseGroup(
448 		testCtx, "graphics", "Subgroup builtin mask category	tests: graphics"));
449 	de::MovePtr<deqp::TestCaseGroup> computeGroup(new deqp::TestCaseGroup(
450 		testCtx, "compute", "Subgroup builtin mask category tests: compute"));
451 	de::MovePtr<deqp::TestCaseGroup> framebufferGroup(new deqp::TestCaseGroup(
452 		testCtx, "framebuffer", "Subgroup builtin mask category tests: framebuffer"));
453 
454 	const char* const all_stages_vars[] =
455 	{
456 		"SubgroupEqMask",
457 		"SubgroupGeMask",
458 		"SubgroupGtMask",
459 		"SubgroupLeMask",
460 		"SubgroupLtMask",
461 	};
462 
463 	const subgroups::ShaderStageFlags stages[] =
464 	{
465 		SHADER_STAGE_VERTEX_BIT,
466 		SHADER_STAGE_TESS_EVALUATION_BIT,
467 		SHADER_STAGE_TESS_CONTROL_BIT,
468 		SHADER_STAGE_GEOMETRY_BIT,
469 	};
470 
471 
472 	for (int a = 0; a < DE_LENGTH_OF_ARRAY(all_stages_vars); ++a)
473 	{
474 		const std::string var = all_stages_vars[a];
475 		const std::string varLower = de::toLower(var);
476 
477 		{
478 			const CaseDefinition caseDef = {"gl_" + var, SHADER_STAGE_ALL_GRAPHICS};
479 			SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(graphicGroup.get(),
480 										varLower, "",
481 										supportedCheck, initPrograms, test, caseDef);
482 		}
483 
484 		{
485 			const CaseDefinition caseDef = {"gl_" + var, SHADER_STAGE_COMPUTE_BIT};
486 			SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(computeGroup.get(),
487 										varLower, "",
488 										supportedCheck, initPrograms, test, caseDef);
489 		}
490 
491 		for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(stages); ++stageIndex)
492 		{
493 			const CaseDefinition caseDef = {"gl_" + var, stages[stageIndex]};
494 			SubgroupFactory<CaseDefinition>::addFunctionCaseWithPrograms(framebufferGroup.get(),
495 						varLower + "_" +
496 						getShaderStageName(caseDef.shaderStage), "",
497 						supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
498 		}
499 	}
500 
501 	de::MovePtr<deqp::TestCaseGroup> group(new deqp::TestCaseGroup(
502 		testCtx, "builtin_mask_var", "Subgroup builtin mask variable tests"));
503 
504 	group->addChild(graphicGroup.release());
505 	group->addChild(computeGroup.release());
506 	group->addChild(framebufferGroup.release());
507 
508 	return group.release();
509 }
510 } // subgroups
511 } // glc
512