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