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