1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2019 The Khronos Group Inc.
6 * Copyright (c) 2019 Google Inc.
7 * Copyright (c) 2017 Codeplay Software Ltd.
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 "vktSubgroupsBasicTests.hpp"
27 #include "vktSubgroupsTestsUtils.hpp"
28
29 #include "tcuStringTemplate.hpp"
30
31 #include <string>
32 #include <vector>
33
34 using namespace tcu;
35 using namespace std;
36 using namespace vk;
37 using namespace vkt;
38
39 namespace
40 {
41 enum OpType
42 {
43 OPTYPE_ELECT = 0,
44 OPTYPE_SUBGROUP_BARRIER,
45 OPTYPE_SUBGROUP_MEMORY_BARRIER,
46 OPTYPE_SUBGROUP_MEMORY_BARRIER_BUFFER,
47 OPTYPE_SUBGROUP_MEMORY_BARRIER_SHARED,
48 OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE,
49 OPTYPE_LAST
50 };
51
52 struct CaseDefinition
53 {
54 OpType opType;
55 VkShaderStageFlags shaderStage;
56 de::SharedPtr<bool> geometryPointSizeSupported;
57 deBool requiredSubgroupSize;
58 };
59
60 static const deUint32 ELECTED_VALUE = 42u;
61 static const deUint32 UNELECTED_VALUE = 13u;
62 static const VkDeviceSize SHADER_BUFFER_SIZE = 4096ull; // min(maxUniformBufferRange, maxImageDimension1D)
63
_checkFragmentSubgroupBarriersNoSSBO(vector<const void * > datas,deUint32 width,deUint32 height,bool withImage)64 static bool _checkFragmentSubgroupBarriersNoSSBO (vector<const void*> datas,
65 deUint32 width,
66 deUint32 height,
67 bool withImage)
68 {
69 const float* const resultData = reinterpret_cast<const float*>(datas[0]);
70
71 for (deUint32 x = 0u; x < width; ++x)
72 {
73 for (deUint32 y = 0u; y < height; ++y)
74 {
75 const deUint32 ndx = (x * height + y) * 4u;
76
77 if (!withImage && 0.0f == resultData[ndx])
78 {
79 return false;
80 }
81 else if (1.0f == resultData[ndx +2])
82 {
83 if(resultData[ndx] != resultData[ndx +1])
84 {
85 return false;
86 }
87 }
88 else if (resultData[ndx] != resultData[ndx +3])
89 {
90 return false;
91 }
92 }
93 }
94
95 return true;
96 }
97
checkFragmentSubgroupBarriersNoSSBO(const void * internalData,vector<const void * > datas,deUint32 width,deUint32 height,deUint32)98 static bool checkFragmentSubgroupBarriersNoSSBO (const void *internalData,
99 vector<const void*> datas,
100 deUint32 width,
101 deUint32 height,
102 deUint32)
103 {
104 DE_UNREF(internalData);
105
106 return _checkFragmentSubgroupBarriersNoSSBO(datas, width, height, false);
107 }
108
checkFragmentSubgroupBarriersWithImageNoSSBO(const void * internalData,vector<const void * > datas,deUint32 width,deUint32 height,deUint32)109 static bool checkFragmentSubgroupBarriersWithImageNoSSBO (const void* internalData,
110 vector<const void*> datas,
111 deUint32 width,
112 deUint32 height,
113 deUint32)
114 {
115 DE_UNREF(internalData);
116
117 return _checkFragmentSubgroupBarriersNoSSBO(datas, width, height, true);
118 }
119
checkVertexPipelineStagesSubgroupElectNoSSBO(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)120 static bool checkVertexPipelineStagesSubgroupElectNoSSBO (const void* internalData,
121 vector<const void*> datas,
122 deUint32 width,
123 deUint32)
124 {
125 DE_UNREF(internalData);
126
127 const float* const resultData = reinterpret_cast<const float*>(datas[0]);
128 float poisonValuesFound = 0.0f;
129 float numSubgroupsUsed = 0.0f;
130
131 for (deUint32 x = 0; x < width; ++x)
132 {
133 deUint32 val = static_cast<deUint32>(resultData[x * 2]);
134 numSubgroupsUsed += resultData[x * 2 + 1];
135
136 switch (val)
137 {
138 default:
139 // some garbage value was found!
140 return false;
141 case UNELECTED_VALUE:
142 break;
143 case ELECTED_VALUE:
144 poisonValuesFound += 1.0f;
145 break;
146 }
147 }
148
149 return numSubgroupsUsed == poisonValuesFound;
150 }
151
checkVertexPipelineStagesSubgroupElect(const void * internalData,vector<const void * > datas,deUint32 width,deUint32,bool multipleCallsPossible)152 static bool checkVertexPipelineStagesSubgroupElect (const void* internalData,
153 vector<const void*> datas,
154 deUint32 width,
155 deUint32,
156 bool multipleCallsPossible)
157 {
158 DE_UNREF(internalData);
159
160 const deUint32* const resultData = reinterpret_cast<const deUint32*>(datas[0]);
161 deUint32 poisonValuesFound = 0;
162
163 for (deUint32 x = 0; x < width; ++x)
164 {
165 deUint32 val = resultData[x];
166
167 switch (val)
168 {
169 default:
170 // some garbage value was found!
171 return false;
172 case UNELECTED_VALUE:
173 break;
174 case ELECTED_VALUE:
175 poisonValuesFound++;
176 break;
177 }
178 }
179
180 // we used an atomicly incremented counter to note how many subgroups we used for the vertex shader
181 const deUint32 numSubgroupsUsed = *reinterpret_cast<const deUint32*>(datas[1]);
182
183 return (multipleCallsPossible ? (numSubgroupsUsed >= poisonValuesFound) : (numSubgroupsUsed == poisonValuesFound));
184 }
185
checkVertexPipelineStagesSubgroupBarriers(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)186 static bool checkVertexPipelineStagesSubgroupBarriers (const void* internalData,
187 vector<const void*> datas,
188 deUint32 width,
189 deUint32)
190 {
191 DE_UNREF(internalData);
192
193 const deUint32* const resultData = reinterpret_cast<const deUint32*>(datas[0]);
194
195 // We used this SSBO to generate our unique value!
196 const deUint32 ref = *reinterpret_cast<const deUint32*>(datas[3]);
197
198 for (deUint32 x = 0; x < width; ++x)
199 {
200 deUint32 val = resultData[x];
201
202 if (val != ref)
203 return false;
204 }
205
206 return true;
207 }
208
_checkVertexPipelineStagesSubgroupBarriersNoSSBO(vector<const void * > datas,deUint32 width,bool withImage)209 static bool _checkVertexPipelineStagesSubgroupBarriersNoSSBO (vector<const void*> datas,
210 deUint32 width,
211 bool withImage)
212 {
213 const float* const resultData = reinterpret_cast<const float*>(datas[0]);
214
215 for (deUint32 x = 0u; x < width; ++x)
216 {
217 const deUint32 ndx = x*4u;
218 if (!withImage && 0.0f == resultData[ndx])
219 {
220 return false;
221 }
222 else if (1.0f == resultData[ndx +2])
223 {
224 if(resultData[ndx] != resultData[ndx +1])
225 return false;
226 }
227 else if (resultData[ndx] != resultData[ndx +3])
228 {
229 return false;
230 }
231 }
232
233 return true;
234 }
235
checkVertexPipelineStagesSubgroupBarriersNoSSBO(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)236 static bool checkVertexPipelineStagesSubgroupBarriersNoSSBO (const void* internalData,
237 vector<const void*> datas,
238 deUint32 width,
239 deUint32)
240 {
241 DE_UNREF(internalData);
242
243 return _checkVertexPipelineStagesSubgroupBarriersNoSSBO(datas, width, false);
244 }
245
checkVertexPipelineStagesSubgroupBarriersWithImageNoSSBO(const void * internalData,vector<const void * > datas,deUint32 width,deUint32)246 static bool checkVertexPipelineStagesSubgroupBarriersWithImageNoSSBO (const void* internalData,
247 vector<const void*> datas,
248 deUint32 width,
249 deUint32)
250 {
251 DE_UNREF(internalData);
252
253 return _checkVertexPipelineStagesSubgroupBarriersNoSSBO(datas, width, true);
254 }
255
_checkTessellationEvaluationSubgroupBarriersNoSSBO(vector<const void * > datas,deUint32 width,deUint32,bool withImage)256 static bool _checkTessellationEvaluationSubgroupBarriersNoSSBO (vector<const void*> datas,
257 deUint32 width,
258 deUint32,
259 bool withImage)
260 {
261 const float* const resultData = reinterpret_cast<const float*>(datas[0]);
262
263 for (deUint32 x = 0u; x < width; ++x)
264 {
265 const deUint32 ndx = x*4u;
266
267 if (!withImage && 0.0f == resultData[ndx])
268 {
269 return false;
270 }
271 else if (0.0f == resultData[ndx +2] && resultData[ndx] != resultData[ndx +3])
272 {
273 return false;
274 }
275 }
276
277 return true;
278 }
279
checkTessellationEvaluationSubgroupBarriersWithImageNoSSBO(const void * internalData,vector<const void * > datas,deUint32 width,deUint32 height)280 static bool checkTessellationEvaluationSubgroupBarriersWithImageNoSSBO (const void* internalData,
281 vector<const void*> datas,
282 deUint32 width,
283 deUint32 height)
284 {
285 DE_UNREF(internalData);
286
287 return _checkTessellationEvaluationSubgroupBarriersNoSSBO(datas, width, height, true);
288 }
289
checkTessellationEvaluationSubgroupBarriersNoSSBO(const void * internalData,vector<const void * > datas,deUint32 width,deUint32 height)290 static bool checkTessellationEvaluationSubgroupBarriersNoSSBO (const void* internalData,
291 vector<const void*> datas,
292 deUint32 width,
293 deUint32 height)
294 {
295 DE_UNREF(internalData);
296
297 return _checkTessellationEvaluationSubgroupBarriersNoSSBO (datas, width, height, false);
298 }
299
checkComputeOrMeshSubgroupElect(const void * internalData,vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)300 static bool checkComputeOrMeshSubgroupElect (const void* internalData,
301 vector<const void*> datas,
302 const deUint32 numWorkgroups[3],
303 const deUint32 localSize[3],
304 deUint32)
305 {
306 DE_UNREF(internalData);
307
308 return subgroups::checkComputeOrMesh(datas, numWorkgroups, localSize, 1);
309 }
310
checkComputeOrMeshSubgroupBarriers(const void * internalData,vector<const void * > datas,const deUint32 numWorkgroups[3],const deUint32 localSize[3],deUint32)311 static bool checkComputeOrMeshSubgroupBarriers (const void* internalData,
312 vector<const void*> datas,
313 const deUint32 numWorkgroups[3],
314 const deUint32 localSize[3],
315 deUint32)
316 {
317 DE_UNREF(internalData);
318
319 // We used this SSBO to generate our unique value!
320 const deUint32 ref = *reinterpret_cast<const deUint32*>(datas[2]);
321
322 return subgroups::checkComputeOrMesh(datas, numWorkgroups, localSize, ref);
323 }
324
getOpTypeName(OpType opType)325 string getOpTypeName (OpType opType)
326 {
327 switch (opType)
328 {
329 case OPTYPE_ELECT: return "subgroupElect";
330 case OPTYPE_SUBGROUP_BARRIER: return "subgroupBarrier";
331 case OPTYPE_SUBGROUP_MEMORY_BARRIER: return "subgroupMemoryBarrier";
332 case OPTYPE_SUBGROUP_MEMORY_BARRIER_BUFFER: return "subgroupMemoryBarrierBuffer";
333 case OPTYPE_SUBGROUP_MEMORY_BARRIER_SHARED: return "subgroupMemoryBarrierShared";
334 case OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE: return "subgroupMemoryBarrierImage";
335 default: TCU_THROW(InternalError, "Unsupported op type");
336 }
337 }
338
initFrameBufferPrograms(SourceCollections & programCollection,CaseDefinition caseDef)339 void initFrameBufferPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
340 {
341 const ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, SPIRV_VERSION_1_3, 0u);
342 const SpirVAsmBuildOptions buildOptionsSpr (programCollection.usedVulkanVersion, SPIRV_VERSION_1_3);
343
344 if (VK_SHADER_STAGE_FRAGMENT_BIT != caseDef.shaderStage)
345 {
346 /*
347 "layout(location = 0) in vec4 in_color;\n"
348 "layout(location = 0) out vec4 out_color;\n"
349 "void main()\n"
350 {\n"
351 " out_color = in_color;\n"
352 "}\n";
353 */
354 const string fragment =
355 "; SPIR-V\n"
356 "; Version: 1.3\n"
357 "; Generator: Khronos Glslang Reference Front End; 2\n"
358 "; Bound: 13\n"
359 "; Schema: 0\n"
360 "OpCapability Shader\n"
361 "%1 = OpExtInstImport \"GLSL.std.450\"\n"
362 "OpMemoryModel Logical GLSL450\n"
363 "OpEntryPoint Fragment %4 \"main\" %9 %11\n"
364 "OpExecutionMode %4 OriginUpperLeft\n"
365 "OpDecorate %9 Location 0\n"
366 "OpDecorate %11 Location 0\n"
367 "%2 = OpTypeVoid\n"
368 "%3 = OpTypeFunction %2\n"
369 "%6 = OpTypeFloat 32\n"
370 "%7 = OpTypeVector %6 4\n"
371 "%8 = OpTypePointer Output %7\n"
372 "%9 = OpVariable %8 Output\n"
373 "%10 = OpTypePointer Input %7\n"
374 "%11 = OpVariable %10 Input\n"
375 "%4 = OpFunction %2 None %3\n"
376 "%5 = OpLabel\n"
377 "%12 = OpLoad %7 %11\n"
378 "OpStore %9 %12\n"
379 "OpReturn\n"
380 "OpFunctionEnd\n";
381
382 programCollection.spirvAsmSources.add("fragment") << fragment;
383 }
384 if (VK_SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
385 {
386 /*
387 "#version 450\n"
388 "void main (void)\n"
389 "{\n"
390 " vec2 uv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);\n"
391 " gl_Position = vec4(uv * 2.0f + -1.0f, 0.0f, 1.0f);\n"
392 " gl_PointSize = 1.0f;\n"
393 "}\n";
394 */
395 const string vertex =
396 "; SPIR-V\n"
397 "; Version: 1.3\n"
398 "; Generator: Khronos Glslang Reference Front End; 2\n"
399 "; Bound: 44\n"
400 "; Schema: 0\n"
401 "OpCapability Shader\n"
402 "%1 = OpExtInstImport \"GLSL.std.450\"\n"
403 "OpMemoryModel Logical GLSL450\n"
404 "OpEntryPoint Vertex %4 \"main\" %12 %29\n"
405 "OpDecorate %12 BuiltIn VertexIndex\n"
406 "OpMemberDecorate %27 0 BuiltIn Position\n"
407 "OpMemberDecorate %27 1 BuiltIn PointSize\n"
408 "OpMemberDecorate %27 2 BuiltIn ClipDistance\n"
409 "OpMemberDecorate %27 3 BuiltIn CullDistance\n"
410 "OpDecorate %27 Block\n"
411 "%2 = OpTypeVoid\n"
412 "%3 = OpTypeFunction %2\n"
413 "%6 = OpTypeFloat 32\n"
414 "%7 = OpTypeVector %6 2\n"
415 "%8 = OpTypePointer Function %7\n"
416 "%10 = OpTypeInt 32 1\n"
417 "%11 = OpTypePointer Input %10\n"
418 "%12 = OpVariable %11 Input\n"
419 "%14 = OpConstant %10 1\n"
420 "%16 = OpConstant %10 2\n"
421 "%23 = OpTypeVector %6 4\n"
422 "%24 = OpTypeInt 32 0\n"
423 "%25 = OpConstant %24 1\n"
424 "%26 = OpTypeArray %6 %25\n"
425 "%27 = OpTypeStruct %23 %6 %26 %26\n"
426 "%28 = OpTypePointer Output %27\n"
427 "%29 = OpVariable %28 Output\n"
428 "%30 = OpConstant %10 0\n"
429 "%32 = OpConstant %6 2\n"
430 "%34 = OpConstant %6 -1\n"
431 "%37 = OpConstant %6 0\n"
432 "%38 = OpConstant %6 1\n"
433 "%42 = OpTypePointer Output %23\n"
434 "%44 = OpTypePointer Output %6\n"
435 "%4 = OpFunction %2 None %3\n"
436 "%5 = OpLabel\n"
437 "%9 = OpVariable %8 Function\n"
438 "%13 = OpLoad %10 %12\n"
439 "%15 = OpShiftLeftLogical %10 %13 %14\n"
440 "%17 = OpBitwiseAnd %10 %15 %16\n"
441 "%18 = OpConvertSToF %6 %17\n"
442 "%19 = OpLoad %10 %12\n"
443 "%20 = OpBitwiseAnd %10 %19 %16\n"
444 "%21 = OpConvertSToF %6 %20\n"
445 "%22 = OpCompositeConstruct %7 %18 %21\n"
446 "OpStore %9 %22\n"
447 "%31 = OpLoad %7 %9\n"
448 "%33 = OpVectorTimesScalar %7 %31 %32\n"
449 "%35 = OpCompositeConstruct %7 %34 %34\n"
450 "%36 = OpFAdd %7 %33 %35\n"
451 "%39 = OpCompositeExtract %6 %36 0\n"
452 "%40 = OpCompositeExtract %6 %36 1\n"
453 "%41 = OpCompositeConstruct %23 %39 %40 %37 %38\n"
454 "%43 = OpAccessChain %42 %29 %30\n"
455 "OpStore %43 %41\n"
456 "%45 = OpAccessChain %44 %29 %14\n"
457 "OpStore %45 %38\n"
458 "OpReturn\n"
459 "OpFunctionEnd\n";
460
461 programCollection.spirvAsmSources.add("vert") << vertex;
462 }
463 else if (VK_SHADER_STAGE_VERTEX_BIT != caseDef.shaderStage)
464 {
465 subgroups::setVertexShaderFrameBuffer(programCollection);
466 }
467
468 if (OPTYPE_ELECT == caseDef.opType)
469 {
470 ostringstream electedValue ;
471 ostringstream unelectedValue;
472
473 electedValue << ELECTED_VALUE;
474 unelectedValue << UNELECTED_VALUE;
475
476 if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
477 {
478 /*
479 "#extension GL_KHR_shader_subgroup_basic: enable\n"
480 "layout(location = 0) out vec4 out_color;\n"
481 "layout(location = 0) in highp vec4 in_position;\n"
482 "\n"
483 "void main (void)\n"
484 "{\n"
485 " if (subgroupElect())\n"
486 " {\n"
487 " out_color.r = " << ELECTED_VALUE << ";\n"
488 " out_color.g = 1.0f;\n"
489 " }\n"
490 " else\n"
491 " {\n"
492 " out_color.r = " << UNELECTED_VALUE << ";\n"
493 " out_color.g = 0.0f;\n"
494 " }\n"
495 " gl_Position = in_position;\n"
496 " gl_PointSize = 1.0f;\n"
497 "}\n";
498 */
499 const string vertex =
500 "; SPIR-V\n"
501 "; Version: 1.3\n"
502 "; Generator: Khronos Glslang Reference Front End; 2\n"
503 "; Bound: 38\n"
504 "; Schema: 0\n"
505 "OpCapability Shader\n"
506 "OpCapability GroupNonUniform\n"
507 "%1 = OpExtInstImport \"GLSL.std.450\"\n"
508 "OpMemoryModel Logical GLSL450\n"
509 "OpEntryPoint Vertex %4 \"main\" %15 %31 %35\n"
510 "OpDecorate %15 Location 0\n"
511 "OpMemberDecorate %29 0 BuiltIn Position\n"
512 "OpMemberDecorate %29 1 BuiltIn PointSize\n"
513 "OpMemberDecorate %29 2 BuiltIn ClipDistance\n"
514 "OpMemberDecorate %29 3 BuiltIn CullDistance\n"
515 "OpDecorate %29 Block\n"
516 "OpDecorate %35 Location 0\n"
517 "%2 = OpTypeVoid\n"
518 "%3 = OpTypeFunction %2\n"
519 "%6 = OpTypeBool\n"
520 "%7 = OpTypeInt 32 0\n"
521 "%8 = OpConstant %7 3\n"
522 "%12 = OpTypeFloat 32\n"
523 "%13 = OpTypeVector %12 4\n"
524 "%14 = OpTypePointer Output %13\n"
525 "%15 = OpVariable %14 Output\n"
526 "%16 = OpConstant %12 " + electedValue.str() + "\n"
527 "%17 = OpConstant %7 0\n"
528 "%18 = OpTypePointer Output %12\n"
529 "%20 = OpConstant %12 1\n"
530 "%21 = OpConstant %7 1\n"
531 "%24 = OpConstant %12 " + unelectedValue.str() + "\n"
532 "%26 = OpConstant %12 0\n"
533 "%28 = OpTypeArray %12 %21\n"
534 "%29 = OpTypeStruct %13 %12 %28 %28\n"
535 "%30 = OpTypePointer Output %29\n"
536 "%31 = OpVariable %30 Output\n"
537 "%32 = OpTypeInt 32 1\n"
538 "%33 = OpConstant %32 0\n"
539 "%34 = OpTypePointer Input %13\n"
540 "%35 = OpVariable %34 Input\n"
541 "%38 = OpConstant %32 1\n"
542 "%4 = OpFunction %2 None %3\n"
543 "%5 = OpLabel\n"
544 "%9 = OpGroupNonUniformElect %6 %8\n"
545 "OpSelectionMerge %11 None\n"
546 "OpBranchConditional %9 %10 %23\n"
547 "%10 = OpLabel\n"
548 "%19 = OpAccessChain %18 %15 %17\n"
549 "OpStore %19 %16\n"
550 "%22 = OpAccessChain %18 %15 %21\n"
551 "OpStore %22 %20\n"
552 "OpBranch %11\n"
553 "%23 = OpLabel\n"
554 "%25 = OpAccessChain %18 %15 %17\n"
555 "OpStore %25 %24\n"
556 "%27 = OpAccessChain %18 %15 %21\n"
557 "OpStore %27 %26\n"
558 "OpBranch %11\n"
559 "%11 = OpLabel\n"
560 "%36 = OpLoad %13 %35\n"
561 "%37 = OpAccessChain %14 %31 %33\n"
562 "OpStore %37 %36\n"
563 "%39 = OpAccessChain %18 %31 %38\n"
564 "OpStore %39 %20\n"
565 "OpReturn\n"
566 "OpFunctionEnd\n";
567
568 programCollection.spirvAsmSources.add("vert") << vertex << buildOptionsSpr;
569 }
570 else if (VK_SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
571 {
572 /*
573 "#version 450\n"
574 "#extension GL_KHR_shader_subgroup_basic: enable\n"
575 "layout(points) in;\n"
576 "layout(points, max_vertices = 1) out;\n"
577 "layout(location = 0) out vec4 out_color;\n"
578 "void main (void)\n"
579 "{\n"
580 " if (subgroupElect())\n"
581 " {\n"
582 " out_color.r = " << ELECTED_VALUE << ";\n"
583 " out_color.g = 1.0f;\n"
584 " }\n"
585 " else\n"
586 " {\n"
587 " out_color.r = " << UNELECTED_VALUE << ";\n"
588 " out_color.g = 0.0f;\n"
589 " }\n"
590 " gl_Position = gl_in[0].gl_Position;\n"
591 " gl_PointSize = gl_in[0].gl_PointSize;\n"
592 " EmitVertex();\n"
593 " EndPrimitive();\n"
594 "}\n";
595 */
596 ostringstream geometry;
597
598 geometry
599 << "; SPIR-V\n"
600 << "; Version: 1.3\n"
601 << "; Generator: Khronos Glslang Reference Front End; 2\n"
602 << "; Bound: 42\n"
603 << "; Schema: 0\n"
604 << "OpCapability Geometry\n"
605 << (*caseDef.geometryPointSizeSupported ?
606 "OpCapability GeometryPointSize\n" : "")
607 << "OpCapability GroupNonUniform\n"
608 << "%1 = OpExtInstImport \"GLSL.std.450\"\n"
609 << "OpMemoryModel Logical GLSL450\n"
610 << "OpEntryPoint Geometry %4 \"main\" %15 %31 %37\n"
611 << "OpExecutionMode %4 InputPoints\n"
612 << "OpExecutionMode %4 Invocations 1\n"
613 << "OpExecutionMode %4 OutputPoints\n"
614 << "OpExecutionMode %4 OutputVertices 1\n"
615 << "OpDecorate %15 Location 0\n"
616 << "OpMemberDecorate %29 0 BuiltIn Position\n"
617 << "OpMemberDecorate %29 1 BuiltIn PointSize\n"
618 << "OpMemberDecorate %29 2 BuiltIn ClipDistance\n"
619 << "OpMemberDecorate %29 3 BuiltIn CullDistance\n"
620 << "OpDecorate %29 Block\n"
621 << "OpMemberDecorate %34 0 BuiltIn Position\n"
622 << "OpMemberDecorate %34 1 BuiltIn PointSize\n"
623 << "OpMemberDecorate %34 2 BuiltIn ClipDistance\n"
624 << "OpMemberDecorate %34 3 BuiltIn CullDistance\n"
625 << "OpDecorate %34 Block\n"
626 << "%2 = OpTypeVoid\n"
627 << "%3 = OpTypeFunction %2\n"
628 << "%6 = OpTypeBool\n"
629 << "%7 = OpTypeInt 32 0\n"
630 << "%8 = OpConstant %7 3\n"
631 << "%12 = OpTypeFloat 32\n"
632 << "%13 = OpTypeVector %12 4\n"
633 << "%14 = OpTypePointer Output %13\n"
634 << "%15 = OpVariable %14 Output\n"
635 << "%16 = OpConstant %12 " << electedValue.str() << "\n"
636 << "%17 = OpConstant %7 0\n"
637 << "%18 = OpTypePointer Output %12\n"
638 << "%20 = OpConstant %12 1\n"
639 << "%21 = OpConstant %7 1\n"
640 << "%24 = OpConstant %12 " << unelectedValue.str() << "\n"
641 << "%26 = OpConstant %12 0\n"
642 << "%28 = OpTypeArray %12 %21\n"
643 << "%29 = OpTypeStruct %13 %12 %28 %28\n"
644 << "%30 = OpTypePointer Output %29\n"
645 << "%31 = OpVariable %30 Output\n"
646 << "%32 = OpTypeInt 32 1\n"
647 << "%33 = OpConstant %32 0\n"
648 << "%34 = OpTypeStruct %13 %12 %28 %28\n"
649 << "%35 = OpTypeArray %34 %21\n"
650 << "%36 = OpTypePointer Input %35\n"
651 << "%37 = OpVariable %36 Input\n"
652 << "%38 = OpTypePointer Input %13\n"
653 << (*caseDef.geometryPointSizeSupported ?
654 "%42 = OpConstant %32 1\n"
655 "%43 = OpTypePointer Input %12\n"
656 "%44 = OpTypePointer Output %12\n" : "")
657 << "%4 = OpFunction %2 None %3\n"
658 << "%5 = OpLabel\n"
659 << "%9 = OpGroupNonUniformElect %6 %8\n"
660 << "OpSelectionMerge %11 None\n"
661 << "OpBranchConditional %9 %10 %23\n"
662 << "%10 = OpLabel\n"
663 << "%19 = OpAccessChain %18 %15 %17\n"
664 << "OpStore %19 %16\n"
665 << "%22 = OpAccessChain %18 %15 %21\n"
666 << "OpStore %22 %20\n"
667 << "OpBranch %11\n"
668 << "%23 = OpLabel\n"
669 << "%25 = OpAccessChain %18 %15 %17\n"
670 << "OpStore %25 %24\n"
671 << "%27 = OpAccessChain %18 %15 %21\n"
672 << "OpStore %27 %26\n"
673 << "OpBranch %11\n"
674 << "%11 = OpLabel\n"
675 << "%39 = OpAccessChain %38 %37 %33 %33\n"
676 << "%40 = OpLoad %13 %39\n"
677 << "%41 = OpAccessChain %14 %31 %33\n"
678 << "OpStore %41 %40\n"
679 << (*caseDef.geometryPointSizeSupported ?
680 "%45 = OpAccessChain %43 %37 %33 %42\n"
681 "%46 = OpLoad %12 %45\n"
682 "%47 = OpAccessChain %44 %31 %42\n"
683 "OpStore %47 %46\n" : "" )
684 << "OpEmitVertex\n"
685 << "OpEndPrimitive\n"
686 << "OpReturn\n"
687 << "OpFunctionEnd\n";
688
689 programCollection.spirvAsmSources.add("geometry") << geometry.str() << buildOptionsSpr;
690 }
691 else if (VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT == caseDef.shaderStage)
692 {
693 /*
694 << "#extension GL_KHR_shader_subgroup_basic: enable\n"
695 << "#extension GL_EXT_tessellation_shader : require\n"
696 << "layout(vertices = 2) out;\n"
697 << "void main (void)\n"
698 << "{\n"
699 << " if (gl_InvocationID == 0)\n"
700 << " {\n"
701 << " gl_TessLevelOuter[0] = 1.0f;\n"
702 << " gl_TessLevelOuter[1] = 1.0f;\n"
703 << " }\n"
704 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
705 << "}\n";
706 */
707 const string controlSource =
708 "; SPIR-V\n"
709 "; Version: 1.3\n"
710 "; Generator: Khronos Glslang Reference Front End; 2\n"
711 "; Bound: 46\n"
712 "; Schema: 0\n"
713 "OpCapability Tessellation\n"
714 "%1 = OpExtInstImport \"GLSL.std.450\"\n"
715 "OpMemoryModel Logical GLSL450\n"
716 "OpEntryPoint TessellationControl %4 \"main\" %8 %20 %33 %39\n"
717 "OpExecutionMode %4 OutputVertices 2\n"
718 "OpDecorate %8 BuiltIn InvocationId\n"
719 "OpDecorate %20 Patch\n"
720 "OpDecorate %20 BuiltIn TessLevelOuter\n"
721 "OpMemberDecorate %29 0 BuiltIn Position\n"
722 "OpMemberDecorate %29 1 BuiltIn PointSize\n"
723 "OpMemberDecorate %29 2 BuiltIn ClipDistance\n"
724 "OpMemberDecorate %29 3 BuiltIn CullDistance\n"
725 "OpDecorate %29 Block\n"
726 "OpMemberDecorate %35 0 BuiltIn Position\n"
727 "OpMemberDecorate %35 1 BuiltIn PointSize\n"
728 "OpMemberDecorate %35 2 BuiltIn ClipDistance\n"
729 "OpMemberDecorate %35 3 BuiltIn CullDistance\n"
730 "OpDecorate %35 Block\n"
731 "%2 = OpTypeVoid\n"
732 "%3 = OpTypeFunction %2\n"
733 "%6 = OpTypeInt 32 1\n"
734 "%7 = OpTypePointer Input %6\n"
735 "%8 = OpVariable %7 Input\n"
736 "%10 = OpConstant %6 0\n"
737 "%11 = OpTypeBool\n"
738 "%15 = OpTypeFloat 32\n"
739 "%16 = OpTypeInt 32 0\n"
740 "%17 = OpConstant %16 4\n"
741 "%18 = OpTypeArray %15 %17\n"
742 "%19 = OpTypePointer Output %18\n"
743 "%20 = OpVariable %19 Output\n"
744 "%21 = OpConstant %15 1\n"
745 "%22 = OpTypePointer Output %15\n"
746 "%24 = OpConstant %6 1\n"
747 "%26 = OpTypeVector %15 4\n"
748 "%27 = OpConstant %16 1\n"
749 "%28 = OpTypeArray %15 %27\n"
750 "%29 = OpTypeStruct %26 %15 %28 %28\n"
751 "%30 = OpConstant %16 2\n"
752 "%31 = OpTypeArray %29 %30\n"
753 "%32 = OpTypePointer Output %31\n"
754 "%33 = OpVariable %32 Output\n"
755 "%35 = OpTypeStruct %26 %15 %28 %28\n"
756 "%36 = OpConstant %16 32\n"
757 "%37 = OpTypeArray %35 %36\n"
758 "%38 = OpTypePointer Input %37\n"
759 "%39 = OpVariable %38 Input\n"
760 "%41 = OpTypePointer Input %26\n"
761 "%44 = OpTypePointer Output %26\n"
762 "%4 = OpFunction %2 None %3\n"
763 "%5 = OpLabel\n"
764 "%9 = OpLoad %6 %8\n"
765 "%12 = OpIEqual %11 %9 %10\n"
766 "OpSelectionMerge %14 None\n"
767 "OpBranchConditional %12 %13 %14\n"
768 "%13 = OpLabel\n"
769 "%23 = OpAccessChain %22 %20 %10\n"
770 "OpStore %23 %21\n"
771 "%25 = OpAccessChain %22 %20 %24\n"
772 "OpStore %25 %21\n"
773 "OpBranch %14\n"
774 "%14 = OpLabel\n"
775 "%34 = OpLoad %6 %8\n"
776 "%40 = OpLoad %6 %8\n"
777 "%42 = OpAccessChain %41 %39 %40 %10\n"
778 "%43 = OpLoad %26 %42\n"
779 "%45 = OpAccessChain %44 %33 %34 %10\n"
780 "OpStore %45 %43\n"
781 "OpReturn\n"
782 "OpFunctionEnd\n";
783
784 programCollection.spirvAsmSources.add("tesc") << controlSource << buildOptionsSpr;
785
786 /*
787 "#extension GL_KHR_shader_subgroup_basic: enable\n"
788 "#extension GL_EXT_tessellation_shader : require\n"
789 "layout(isolines, equal_spacing, ccw ) in;\n"
790 "layout(location = 0) out vec4 out_color;\n"
791 "\n"
792 "void main (void)\n"
793 "{\n"
794 " if (subgroupElect())\n"
795 " {\n"
796 " out_color.r = " << 2 * ELECTED_VALUE - UNELECTED_VALUE << ";\n"
797 " out_color.g = 2.0f;\n"
798 " }\n"
799 " else\n"
800 " {\n"
801 " out_color.r = " << UNELECTED_VALUE << ";\n"
802 " out_color.g = 0.0f;\n"
803 " }\n"
804 " gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
805 "}\n";
806 */
807
808 const string evaluationSource =
809 "; SPIR-V\n"
810 "; Version: 1.3\n"
811 "; Generator: Khronos Glslang Reference Front End; 2\n"
812 "; Bound: 54\n"
813 "; Schema: 0\n"
814 "OpCapability Tessellation\n"
815 "OpCapability GroupNonUniform\n"
816 "%1 = OpExtInstImport \"GLSL.std.450\"\n"
817 "OpMemoryModel Logical GLSL450\n"
818 "OpEntryPoint TessellationEvaluation %4 \"main\" %15 %31 %38 %47\n"
819 "OpExecutionMode %4 Isolines\n"
820 "OpExecutionMode %4 SpacingEqual\n"
821 "OpExecutionMode %4 VertexOrderCcw\n"
822 "OpDecorate %15 Location 0\n"
823 "OpMemberDecorate %29 0 BuiltIn Position\n"
824 "OpMemberDecorate %29 1 BuiltIn PointSize\n"
825 "OpMemberDecorate %29 2 BuiltIn ClipDistance\n"
826 "OpMemberDecorate %29 3 BuiltIn CullDistance\n"
827 "OpDecorate %29 Block\n"
828 "OpMemberDecorate %34 0 BuiltIn Position\n"
829 "OpMemberDecorate %34 1 BuiltIn PointSize\n"
830 "OpMemberDecorate %34 2 BuiltIn ClipDistance\n"
831 "OpMemberDecorate %34 3 BuiltIn CullDistance\n"
832 "OpDecorate %34 Block\n"
833 "OpDecorate %47 BuiltIn TessCoord\n"
834 "%2 = OpTypeVoid\n"
835 "%3 = OpTypeFunction %2\n"
836 "%6 = OpTypeBool\n"
837 "%7 = OpTypeInt 32 0\n"
838 "%8 = OpConstant %7 3\n"
839 "%12 = OpTypeFloat 32\n"
840 "%13 = OpTypeVector %12 4\n"
841 "%14 = OpTypePointer Output %13\n"
842 "%15 = OpVariable %14 Output\n"
843 "%16 = OpConstant %12 71\n"//electedValue
844 "%17 = OpConstant %7 0\n"
845 "%18 = OpTypePointer Output %12\n"
846 "%20 = OpConstant %12 2\n"
847 "%21 = OpConstant %7 1\n"
848 "%24 = OpConstant %12 " + unelectedValue.str() + "\n"
849 "%26 = OpConstant %12 0\n"
850 "%28 = OpTypeArray %12 %21\n"
851 "%29 = OpTypeStruct %13 %12 %28 %28\n"
852 "%30 = OpTypePointer Output %29\n"
853 "%31 = OpVariable %30 Output\n"
854 "%32 = OpTypeInt 32 1\n"
855 "%33 = OpConstant %32 0\n"
856 "%34 = OpTypeStruct %13 %12 %28 %28\n"
857 "%35 = OpConstant %7 32\n"
858 "%36 = OpTypeArray %34 %35\n"
859 "%37 = OpTypePointer Input %36\n"
860 "%38 = OpVariable %37 Input\n"
861 "%39 = OpTypePointer Input %13\n"
862 "%42 = OpConstant %32 1\n"
863 "%45 = OpTypeVector %12 3\n"
864 "%46 = OpTypePointer Input %45\n"
865 "%47 = OpVariable %46 Input\n"
866 "%48 = OpTypePointer Input %12\n"
867 "%4 = OpFunction %2 None %3\n"
868 "%5 = OpLabel\n"
869 "%9 = OpGroupNonUniformElect %6 %8\n"
870 "OpSelectionMerge %11 None\n"
871 "OpBranchConditional %9 %10 %23\n"
872 "%10 = OpLabel\n"
873 "%19 = OpAccessChain %18 %15 %17\n"
874 "OpStore %19 %16\n"
875 "%22 = OpAccessChain %18 %15 %21\n"
876 "OpStore %22 %20\n"
877 "OpBranch %11\n"
878 "%23 = OpLabel\n"
879 "%25 = OpAccessChain %18 %15 %17\n"
880 "OpStore %25 %24\n"
881 "%27 = OpAccessChain %18 %15 %21\n"
882 "OpStore %27 %26\n"
883 "OpBranch %11\n"
884 "%11 = OpLabel\n"
885 "%40 = OpAccessChain %39 %38 %33 %33\n"
886 "%41 = OpLoad %13 %40\n"
887 "%43 = OpAccessChain %39 %38 %42 %33\n"
888 "%44 = OpLoad %13 %43\n"
889 "%49 = OpAccessChain %48 %47 %17\n"
890 "%50 = OpLoad %12 %49\n"
891 "%51 = OpCompositeConstruct %13 %50 %50 %50 %50\n"
892 "%52 = OpExtInst %13 %1 FMix %41 %44 %51\n"
893 "%53 = OpAccessChain %14 %31 %33\n"
894 "OpStore %53 %52\n"
895 "OpReturn\n"
896 "OpFunctionEnd\n";
897
898 programCollection.spirvAsmSources.add("tese") << evaluationSource << buildOptionsSpr;
899 }
900 else if (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage)
901 {
902 /*
903 "#extension GL_KHR_shader_subgroup_basic: enable\n"
904 "#extension GL_EXT_tessellation_shader : require\n"
905 "layout(vertices = 2) out;\n"
906 "layout(location = 0) out vec4 out_color[];\n"
907 "void main (void)\n"
908 "{\n"
909 " if (gl_InvocationID == 0)\n"
910 " {\n"
911 " gl_TessLevelOuter[0] = 1.0f;\n"
912 " gl_TessLevelOuter[1] = 1.0f;\n"
913 " }\n"
914 " if (subgroupElect())\n"
915 " {\n"
916 " out_color[gl_InvocationID].r = " << ELECTED_VALUE << ";\n"
917 " out_color[gl_InvocationID].g = 1.0f;\n"
918 " }\n"
919 " else\n"
920 " {\n"
921 " out_color[gl_InvocationID].r = " << UNELECTED_VALUE << ";\n"
922 " out_color[gl_InvocationID].g = 0.0f;\n"
923 " }\n"
924 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
925 "}\n";
926 */
927 const string controlSource =
928 "; SPIR-V\n"
929 "; Version: 1.3\n"
930 "; Generator: Khronos Glslang Reference Front End; 2\n"
931 "; Bound: 66\n"
932 "; Schema: 0\n"
933 "OpCapability Tessellation\n"
934 "OpCapability GroupNonUniform\n"
935 "%1 = OpExtInstImport \"GLSL.std.450\"\n"
936 "OpMemoryModel Logical GLSL450\n"
937 "OpEntryPoint TessellationControl %4 \"main\" %8 %20 %34 %53 %59\n"
938 "OpExecutionMode %4 OutputVertices 2\n"
939 "OpDecorate %8 BuiltIn InvocationId\n"
940 "OpDecorate %20 Patch\n"
941 "OpDecorate %20 BuiltIn TessLevelOuter\n"
942 "OpDecorate %34 Location 0\n"
943 "OpMemberDecorate %50 0 BuiltIn Position\n"
944 "OpMemberDecorate %50 1 BuiltIn PointSize\n"
945 "OpMemberDecorate %50 2 BuiltIn ClipDistance\n"
946 "OpMemberDecorate %50 3 BuiltIn CullDistance\n"
947 "OpDecorate %50 Block\n"
948 "OpMemberDecorate %55 0 BuiltIn Position\n"
949 "OpMemberDecorate %55 1 BuiltIn PointSize\n"
950 "OpMemberDecorate %55 2 BuiltIn ClipDistance\n"
951 "OpMemberDecorate %55 3 BuiltIn CullDistance\n"
952 "OpDecorate %55 Block\n"
953 "%2 = OpTypeVoid\n"
954 "%3 = OpTypeFunction %2\n"
955 "%6 = OpTypeInt 32 1\n"
956 "%7 = OpTypePointer Input %6\n"
957 "%8 = OpVariable %7 Input\n"
958 "%10 = OpConstant %6 0\n"
959 "%11 = OpTypeBool\n"
960 "%15 = OpTypeFloat 32\n"
961 "%16 = OpTypeInt 32 0\n"
962 "%17 = OpConstant %16 4\n"
963 "%18 = OpTypeArray %15 %17\n"
964 "%19 = OpTypePointer Output %18\n"
965 "%20 = OpVariable %19 Output\n"
966 "%21 = OpConstant %15 1\n"
967 "%22 = OpTypePointer Output %15\n"
968 "%24 = OpConstant %6 1\n"
969 "%26 = OpConstant %16 3\n"
970 "%30 = OpTypeVector %15 4\n"
971 "%31 = OpConstant %16 2\n"
972 "%32 = OpTypeArray %30 %31\n"
973 "%33 = OpTypePointer Output %32\n"
974 "%34 = OpVariable %33 Output\n"
975 "%36 = OpConstant %15 " + electedValue.str() + "\n"
976 "%37 = OpConstant %16 0\n"
977 "%40 = OpConstant %16 1\n"
978 "%44 = OpConstant %15 " + unelectedValue.str() + "\n"
979 "%47 = OpConstant %15 0\n"
980 "%49 = OpTypeArray %15 %40\n"
981 "%50 = OpTypeStruct %30 %15 %49 %49\n"
982 "%51 = OpTypeArray %50 %31\n"
983 "%52 = OpTypePointer Output %51\n"
984 "%53 = OpVariable %52 Output\n"
985 "%55 = OpTypeStruct %30 %15 %49 %49\n"
986 "%56 = OpConstant %16 32\n"
987 "%57 = OpTypeArray %55 %56\n"
988 "%58 = OpTypePointer Input %57\n"
989 "%59 = OpVariable %58 Input\n"
990 "%61 = OpTypePointer Input %30\n"
991 "%64 = OpTypePointer Output %30\n"
992 "%4 = OpFunction %2 None %3\n"
993 "%5 = OpLabel\n"
994 "%9 = OpLoad %6 %8\n"
995 "%12 = OpIEqual %11 %9 %10\n"
996 "OpSelectionMerge %14 None\n"
997 "OpBranchConditional %12 %13 %14\n"
998 "%13 = OpLabel\n"
999 "%23 = OpAccessChain %22 %20 %10\n"
1000 "OpStore %23 %21\n"
1001 "%25 = OpAccessChain %22 %20 %24\n"
1002 "OpStore %25 %21\n"
1003 "OpBranch %14\n"
1004 "%14 = OpLabel\n"
1005 "%27 = OpGroupNonUniformElect %11 %26\n"
1006 "OpSelectionMerge %29 None\n"
1007 "OpBranchConditional %27 %28 %42\n"
1008 "%28 = OpLabel\n"
1009 "%35 = OpLoad %6 %8\n"
1010 "%38 = OpAccessChain %22 %34 %35 %37\n"
1011 "OpStore %38 %36\n"
1012 "%39 = OpLoad %6 %8\n"
1013 "%41 = OpAccessChain %22 %34 %39 %40\n"
1014 "OpStore %41 %21\n"
1015 "OpBranch %29\n"
1016 "%42 = OpLabel\n"
1017 "%43 = OpLoad %6 %8\n"
1018 "%45 = OpAccessChain %22 %34 %43 %37\n"
1019 "OpStore %45 %44\n"
1020 "%46 = OpLoad %6 %8\n"
1021 "%48 = OpAccessChain %22 %34 %46 %40\n"
1022 "OpStore %48 %47\n"
1023 "OpBranch %29\n"
1024 "%29 = OpLabel\n"
1025 "%54 = OpLoad %6 %8\n"
1026 "%60 = OpLoad %6 %8\n"
1027 "%62 = OpAccessChain %61 %59 %60 %10\n"
1028 "%63 = OpLoad %30 %62\n"
1029 "%65 = OpAccessChain %64 %53 %54 %10\n"
1030 "OpStore %65 %63\n"
1031 "OpReturn\n"
1032 "OpFunctionEnd\n";
1033
1034 programCollection.spirvAsmSources.add("tesc") << controlSource << buildOptionsSpr;
1035
1036 /*
1037 "#extension GL_KHR_shader_subgroup_ballot: enable\n"
1038 "#extension GL_EXT_tessellation_shader : require\n"
1039 "layout(isolines, equal_spacing, ccw ) in;\n"
1040 "layout(location = 0) in vec4 in_color[];\n"
1041 "layout(location = 0) out vec4 out_color;\n"
1042 "\n"
1043 "void main (void)\n"
1044 "{\n"
1045 " gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
1046 " out_color = in_color[0];\n"
1047 "}\n";
1048 */
1049
1050 const string evaluationSource =
1051 "; SPIR-V\n"
1052 "; Version: 1.3\n"
1053 "; Generator: Khronos Glslang Reference Front End; 2\n"
1054 "; Bound: 44\n"
1055 "; Schema: 0\n"
1056 "OpCapability Tessellation\n"
1057 "%1 = OpExtInstImport \"GLSL.std.450\"\n"
1058 "OpMemoryModel Logical GLSL450\n"
1059 "OpEntryPoint TessellationEvaluation %4 \"main\" %13 %20 %29 %38 %41\n"
1060 "OpExecutionMode %4 Isolines\n"
1061 "OpExecutionMode %4 SpacingEqual\n"
1062 "OpExecutionMode %4 VertexOrderCcw\n"
1063 "OpMemberDecorate %11 0 BuiltIn Position\n"
1064 "OpMemberDecorate %11 1 BuiltIn PointSize\n"
1065 "OpMemberDecorate %11 2 BuiltIn ClipDistance\n"
1066 "OpMemberDecorate %11 3 BuiltIn CullDistance\n"
1067 "OpDecorate %11 Block\n"
1068 "OpMemberDecorate %16 0 BuiltIn Position\n"
1069 "OpMemberDecorate %16 1 BuiltIn PointSize\n"
1070 "OpMemberDecorate %16 2 BuiltIn ClipDistance\n"
1071 "OpMemberDecorate %16 3 BuiltIn CullDistance\n"
1072 "OpDecorate %16 Block\n"
1073 "OpDecorate %29 BuiltIn TessCoord\n"
1074 "OpDecorate %38 Location 0\n"
1075 "OpDecorate %41 Location 0\n"
1076 "%2 = OpTypeVoid\n"
1077 "%3 = OpTypeFunction %2\n"
1078 "%6 = OpTypeFloat 32\n"
1079 "%7 = OpTypeVector %6 4\n"
1080 "%8 = OpTypeInt 32 0\n"
1081 "%9 = OpConstant %8 1\n"
1082 "%10 = OpTypeArray %6 %9\n"
1083 "%11 = OpTypeStruct %7 %6 %10 %10\n"
1084 "%12 = OpTypePointer Output %11\n"
1085 "%13 = OpVariable %12 Output\n"
1086 "%14 = OpTypeInt 32 1\n"
1087 "%15 = OpConstant %14 0\n"
1088 "%16 = OpTypeStruct %7 %6 %10 %10\n"
1089 "%17 = OpConstant %8 32\n"
1090 "%18 = OpTypeArray %16 %17\n"
1091 "%19 = OpTypePointer Input %18\n"
1092 "%20 = OpVariable %19 Input\n"
1093 "%21 = OpTypePointer Input %7\n"
1094 "%24 = OpConstant %14 1\n"
1095 "%27 = OpTypeVector %6 3\n"
1096 "%28 = OpTypePointer Input %27\n"
1097 "%29 = OpVariable %28 Input\n"
1098 "%30 = OpConstant %8 0\n"
1099 "%31 = OpTypePointer Input %6\n"
1100 "%36 = OpTypePointer Output %7\n"
1101 "%38 = OpVariable %36 Output\n"
1102 "%39 = OpTypeArray %7 %17\n"
1103 "%40 = OpTypePointer Input %39\n"
1104 "%41 = OpVariable %40 Input\n"
1105 "%4 = OpFunction %2 None %3\n"
1106 "%5 = OpLabel\n"
1107 "%22 = OpAccessChain %21 %20 %15 %15\n"
1108 "%23 = OpLoad %7 %22\n"
1109 "%25 = OpAccessChain %21 %20 %24 %15\n"
1110 "%26 = OpLoad %7 %25\n"
1111 "%32 = OpAccessChain %31 %29 %30\n"
1112 "%33 = OpLoad %6 %32\n"
1113 "%34 = OpCompositeConstruct %7 %33 %33 %33 %33\n"
1114 "%35 = OpExtInst %7 %1 FMix %23 %26 %34\n"
1115 "%37 = OpAccessChain %36 %13 %15\n"
1116 "OpStore %37 %35\n"
1117 "%42 = OpAccessChain %21 %41 %15\n"
1118 "%43 = OpLoad %7 %42\n"
1119 "OpStore %38 %43\n"
1120 "OpReturn\n"
1121 "OpFunctionEnd\n";
1122
1123 programCollection.spirvAsmSources.add("tese") << evaluationSource << buildOptionsSpr;
1124 }
1125 else
1126 TCU_THROW(InternalError, "Unsupported shader stage");
1127 }
1128 else
1129 {
1130 const string color = (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage) ? "out_color[gl_InvocationID].b = 1.0f;\n" : "out_color.b = 1.0f;\n";
1131 ostringstream bdy;
1132
1133 switch (caseDef.opType)
1134 {
1135 case OPTYPE_SUBGROUP_BARRIER:
1136 case OPTYPE_SUBGROUP_MEMORY_BARRIER:
1137 case OPTYPE_SUBGROUP_MEMORY_BARRIER_BUFFER:
1138 {
1139 bdy << " tempResult2 = tempBuffer[id];\n"
1140 << " if (subgroupElect())\n"
1141 << " {\n"
1142 << " tempResult = value;\n"
1143 << " " << color
1144 << " }\n"
1145 << " else\n"
1146 << " {\n"
1147 << " tempResult = tempBuffer[id];\n"
1148 << " }\n"
1149 << " " << getOpTypeName(caseDef.opType) << "();\n";
1150 break;
1151 }
1152
1153 case OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE:
1154 bdy <<"tempResult2 = imageLoad(tempImage, ivec2(id, 0)).x;\n"
1155 << " if (subgroupElect())\n"
1156 << " {\n"
1157 << " tempResult = value;\n"
1158 << " " << color
1159 << " }\n"
1160 << " else\n"
1161 << " {\n"
1162 << " tempResult = imageLoad(tempImage, ivec2(id, 0)).x;\n"
1163 << " }\n"
1164 << " subgroupMemoryBarrierImage();\n";
1165 break;
1166
1167 default:
1168 TCU_THROW(InternalError, "Unhandled op type");
1169 }
1170
1171 if (VK_SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
1172 {
1173 ostringstream fragment;
1174
1175 fragment << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
1176 << "#extension GL_KHR_shader_subgroup_basic: enable\n"
1177 << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
1178 << "layout(location = 0) out vec4 out_color;\n"
1179 << "\n"
1180 << "layout(set = 0, binding = 0) uniform Buffer1\n"
1181 << "{\n"
1182 << " uint tempBuffer["<<SHADER_BUFFER_SIZE/4ull<<"];\n"
1183 << "};\n"
1184 << "\n"
1185 << "layout(set = 0, binding = 1) uniform Buffer2\n"
1186 << "{\n"
1187 << " uint value;\n"
1188 << "};\n"
1189 << (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? "layout(set = 0, binding = 2, r32ui) readonly uniform highp uimage2D tempImage;\n" : "\n")
1190 << "void main (void)\n"
1191 << "{\n"
1192 << " if (gl_HelperInvocation) return;\n"
1193 << " uint id = 0;\n"
1194 << " if (subgroupElect())\n"
1195 << " {\n"
1196 << " id = uint(gl_FragCoord.x);\n"
1197 << " }\n"
1198 << " id = subgroupBroadcastFirst(id);\n"
1199 << " uint localId = id;\n"
1200 << " uint tempResult = 0u;\n"
1201 << " uint tempResult2 = 0u;\n"
1202 << " out_color.b = 0.0f;\n"
1203 << bdy.str()
1204 << " out_color.r = float(tempResult);\n"
1205 << " out_color.g = float(value);\n"
1206 << " out_color.a = float(tempResult2);\n"
1207 << "}\n";
1208
1209 programCollection.glslSources.add("fragment") << glu::FragmentSource(fragment.str()) << buildOptions;
1210 }
1211 else if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
1212 {
1213 ostringstream vertex;
1214
1215 vertex << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
1216 << "#extension GL_KHR_shader_subgroup_basic: enable\n"
1217 << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
1218 <<"\n"
1219 << "layout(location = 0) out vec4 out_color;\n"
1220 << "layout(location = 0) in highp vec4 in_position;\n"
1221 << "\n"
1222 << "layout(set = 0, binding = 0) uniform Buffer1\n"
1223 << "{\n"
1224 << " uint tempBuffer["<<SHADER_BUFFER_SIZE/4ull<<"];\n"
1225 << "};\n"
1226 << "\n"
1227 << "layout(set = 0, binding = 1) uniform Buffer2\n"
1228 << "{\n"
1229 << " uint value;\n"
1230 << "};\n"
1231 << (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? "layout(set = 0, binding = 2, r32ui) readonly uniform highp uimage2D tempImage;\n" : "\n")
1232 << "void main (void)\n"
1233 << "{\n"
1234 << " uint id = 0;\n"
1235 << " if (subgroupElect())\n"
1236 << " {\n"
1237 << " id = gl_VertexIndex;\n"
1238 << " }\n"
1239 << " id = subgroupBroadcastFirst(id);\n"
1240 << " uint tempResult = 0u;\n"
1241 << " uint tempResult2 = 0u;\n"
1242 << " out_color.b = 0.0f;\n"
1243 << bdy.str()
1244 << " out_color.r = float(tempResult);\n"
1245 << " out_color.g = float(value);\n"
1246 << " out_color.a = float(tempResult2);\n"
1247 << " gl_Position = in_position;\n"
1248 << " gl_PointSize = 1.0f;\n"
1249 << "}\n";
1250
1251 programCollection.glslSources.add("vert") << glu::VertexSource(vertex.str()) << buildOptions;
1252 }
1253 else if (VK_SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
1254 {
1255 ostringstream geometry;
1256
1257 geometry << "#version 450\n"
1258 << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
1259 << "#extension GL_KHR_shader_subgroup_basic: enable\n"
1260 << "layout(points) in;\n"
1261 << "layout(points, max_vertices = 1) out;\n"
1262 << "layout(location = 0) out vec4 out_color;\n"
1263 << "layout(set = 0, binding = 0) uniform Buffer1\n"
1264 << "{\n"
1265 << " uint tempBuffer["<<SHADER_BUFFER_SIZE/4ull<<"];\n"
1266 << "};\n"
1267 << "\n"
1268 << "layout(set = 0, binding = 1) uniform Buffer2\n"
1269 << "{\n"
1270 << " uint value;\n"
1271 << "};\n"
1272 << (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? "layout(set = 0, binding = 2, r32ui) readonly uniform highp uimage2D tempImage;\n" : "\n")
1273 << "void main (void)\n"
1274 << "{\n"
1275 << " uint id = 0;\n"
1276 << " if (subgroupElect())\n"
1277 << " {\n"
1278 << " id = gl_InvocationID;\n"
1279 << " }\n"
1280 << " id = subgroupBroadcastFirst(id);\n"
1281 << " uint tempResult = 0u;\n"
1282 << " uint tempResult2 = 0u;\n"
1283 << " out_color.b = 0.0f;\n"
1284 << bdy.str()
1285 << " out_color.r = float(tempResult);\n"
1286 << " out_color.g = float(value);\n"
1287 << " out_color.a = float(tempResult2);\n"
1288 << " gl_Position = gl_in[0].gl_Position;\n"
1289 << (*caseDef.geometryPointSizeSupported ? " gl_PointSize = gl_in[0].gl_PointSize;\n" : "" )
1290 << " EmitVertex();\n"
1291 << " EndPrimitive();\n"
1292 << "}\n";
1293
1294 programCollection.glslSources.add("geometry") << glu::GeometrySource(geometry.str()) << buildOptions;
1295 }
1296 else if (VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT == caseDef.shaderStage)
1297 {
1298 ostringstream controlSource;
1299 ostringstream evaluationSource;
1300
1301 controlSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
1302 << "#extension GL_EXT_tessellation_shader : require\n"
1303 << "layout(vertices = 2) out;\n"
1304 << "void main (void)\n"
1305 << "{\n"
1306 << " if (gl_InvocationID == 0)\n"
1307 <<" {\n"
1308 << " gl_TessLevelOuter[0] = 1.0f;\n"
1309 << " gl_TessLevelOuter[1] = 1.0f;\n"
1310 << " }\n"
1311 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
1312 << (*caseDef.geometryPointSizeSupported ? " gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n" : "" )
1313 << "}\n";
1314
1315 evaluationSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
1316 << "#extension GL_KHR_shader_subgroup_basic: enable\n"
1317 << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
1318 << "#extension GL_EXT_tessellation_shader : require\n"
1319 << "layout(isolines, equal_spacing, ccw ) in;\n"
1320 << "layout(location = 0) out vec4 out_color;\n"
1321 << "layout(set = 0, binding = 0) uniform Buffer1\n"
1322 << "{\n"
1323 << " uint tempBuffer["<<SHADER_BUFFER_SIZE/4ull<<"];\n"
1324 << "};\n"
1325 << "\n"
1326 << "layout(set = 0, binding = 1) uniform Buffer2\n"
1327 << "{\n"
1328 << " uint value;\n"
1329 << "};\n"
1330 << (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? "layout(set = 0, binding = 2, r32ui) readonly uniform highp uimage2D tempImage;\n" : "\n")
1331 << "void main (void)\n"
1332 << "{\n"
1333 << " uint id = 0;\n"
1334 << " if (subgroupElect())\n"
1335 << " {\n"
1336 << " id = gl_PrimitiveID;\n"
1337 << " }\n"
1338 << " id = subgroupBroadcastFirst(id);\n"
1339 << " uint tempResult = 0u;\n"
1340 << " uint tempResult2 = 0u;\n"
1341 << " out_color.b = 0.0f;\n"
1342 << bdy.str()
1343 << " out_color.r = float(tempResult);\n"
1344 << " out_color.g = float(value);\n"
1345 << " out_color.a = float(tempResult2);\n"
1346 << " gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
1347 << (*caseDef.geometryPointSizeSupported ? " gl_PointSize = gl_in[0].gl_PointSize;\n" : "" )
1348 << "}\n";
1349
1350 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(controlSource.str()) << buildOptions;
1351 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(evaluationSource.str()) << buildOptions;
1352 }
1353 else if (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage)
1354 {
1355 ostringstream controlSource;
1356 ostringstream evaluationSource;
1357
1358 controlSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
1359 << "#extension GL_KHR_shader_subgroup_basic: enable\n"
1360 << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
1361 << "#extension GL_EXT_tessellation_shader : require\n"
1362 << "layout(vertices = 2) out;\n"
1363 << "layout(location = 0) out vec4 out_color[];\n"
1364 << "layout(set = 0, binding = 0) uniform Buffer1\n"
1365 << "{\n"
1366 << " uint tempBuffer["<<SHADER_BUFFER_SIZE/4ull<<"];\n"
1367 << "};\n"
1368 << "\n"
1369 << "layout(set = 0, binding = 1) uniform Buffer2\n"
1370 << "{\n"
1371 << " uint value;\n"
1372 << "};\n"
1373 << (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? "layout(set = 0, binding = 2, r32ui) readonly uniform highp uimage2D tempImage;\n" : "\n")
1374 << "void main (void)\n"
1375 << "{\n"
1376 << " uint id = 0;\n"
1377 << " if (gl_InvocationID == 0)\n"
1378 <<" {\n"
1379 << " gl_TessLevelOuter[0] = 1.0f;\n"
1380 << " gl_TessLevelOuter[1] = 1.0f;\n"
1381 << " }\n"
1382 << " if (subgroupElect())\n"
1383 << " {\n"
1384 << " id = gl_InvocationID;\n"
1385 << " }\n"
1386 << " id = subgroupBroadcastFirst(id);\n"
1387 << " uint tempResult = 0u;\n"
1388 << " uint tempResult2 = 0u;\n"
1389 << " out_color[gl_InvocationID].b = 0.0f;\n"
1390 << bdy.str()
1391 << " out_color[gl_InvocationID].r = float(tempResult);\n"
1392 << " out_color[gl_InvocationID].g = float(value);\n"
1393 << " out_color[gl_InvocationID].a = float(tempResult2);\n"
1394 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
1395 << (*caseDef.geometryPointSizeSupported ? " gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n" : "" )
1396 << "}\n";
1397
1398 evaluationSource << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450)<<"\n"
1399 << "#extension GL_KHR_shader_subgroup_ballot: enable\n"
1400 << "#extension GL_EXT_tessellation_shader : require\n"
1401 << "layout(isolines, equal_spacing, ccw ) in;\n"
1402 << "layout(location = 0) in vec4 in_color[];\n"
1403 << "layout(location = 0) out vec4 out_color;\n"
1404 << "\n"
1405 << "void main (void)\n"
1406 << "{\n"
1407 << " gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
1408 << (*caseDef.geometryPointSizeSupported ? " gl_PointSize = gl_in[0].gl_PointSize;\n" : "" )
1409 << " out_color = in_color[0];\n"
1410 << "}\n";
1411
1412 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(controlSource.str()) << buildOptions;
1413 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(evaluationSource.str()) << buildOptions;
1414 }
1415 else
1416 TCU_THROW(InternalError, "Unsupported shader stage");
1417 }
1418 }
1419
getPerStageHeadDeclarations(const CaseDefinition & caseDef)1420 vector<string> getPerStageHeadDeclarations (const CaseDefinition& caseDef)
1421 {
1422 const deUint32 stageCount = subgroups::getStagesCount(caseDef.shaderStage);
1423 const bool fragment = (caseDef.shaderStage & VK_SHADER_STAGE_FRAGMENT_BIT) != 0;
1424 vector<string> result (stageCount, string());
1425
1426 if (fragment)
1427 result.resize(result.size() + 1);
1428
1429 if (caseDef.opType == OPTYPE_ELECT)
1430 {
1431 for (size_t i = 0; i < result.size(); ++i)
1432 {
1433 const bool frag = (i == stageCount);
1434 const size_t binding1 = i;
1435 const size_t binding2 = stageCount + i;
1436
1437 if (frag)
1438 {
1439 result[i] += "layout(location = 0) out uint result;\n";
1440 }
1441 else
1442 {
1443 result[i] +=
1444 "layout(set = 0, binding = " + de::toString(binding1) + ", std430) buffer Buffer1\n"
1445 "{\n"
1446 " uint result[];\n"
1447 "};\n";
1448 }
1449
1450 result[i] +=
1451 "layout(set = 0, binding = " + de::toString(binding2) + ", std430) buffer Buffer2\n"
1452 "{\n"
1453 " uint numSubgroupsExecuted;\n"
1454 "};\n";
1455 }
1456 }
1457 else
1458 {
1459 for (size_t i = 0; i < result.size(); ++i)
1460 {
1461 const bool frag = (i == stageCount);
1462 const size_t binding1 = i;
1463 const size_t binding2 = stageCount + 4 * i;
1464 const size_t binding3 = stageCount + 4 * i + 1;
1465 const size_t binding4 = stageCount + 4 * i + 2;
1466 const size_t binding5 = stageCount + 4 * i + 3;
1467
1468 if (frag)
1469 {
1470 result[i] = "layout(location = 0) out uint result;\n";
1471 }
1472 else
1473 {
1474 result[i] +=
1475 "layout(set = 0, binding = " + de::toString(binding1) + ", std430) buffer Buffer1\n"
1476 "{\n"
1477 " uint result[];\n"
1478 "};\n";
1479 }
1480
1481 result[i] +=
1482 "layout(set = 0, binding = " + de::toString(binding2) + ", std430) buffer Buffer2\n"
1483 "{\n"
1484 " uint tempBuffer[];\n"
1485 "};\n"
1486 "layout(set = 0, binding = " + de::toString(binding3) + ", std430) buffer Buffer3\n"
1487 "{\n"
1488 " uint subgroupID;\n"
1489 "};\n"
1490 "layout(set = 0, binding = " + de::toString(binding4) + ", std430) buffer Buffer4\n"
1491 "{\n"
1492 " uint value;\n"
1493 "};\n"
1494 "layout(set = 0, binding = " + de::toString(binding5) + ", r32ui) uniform uimage2D tempImage;\n";
1495 }
1496 }
1497
1498 return result;
1499 }
1500
getTestString(const CaseDefinition & caseDef)1501 string getTestString (const CaseDefinition& caseDef)
1502 {
1503 stringstream body;
1504
1505 #ifndef CTS_USES_VULKANSC
1506 if (caseDef.opType != OPTYPE_ELECT && (isAllGraphicsStages(caseDef.shaderStage) || isAllRayTracingStages(caseDef.shaderStage)))
1507 #else
1508 if (caseDef.opType != OPTYPE_ELECT && (isAllGraphicsStages(caseDef.shaderStage)))
1509 #endif // CTS_USES_VULKANSC
1510 {
1511 body << " uint id = 0;\n"
1512 " if (subgroupElect())\n"
1513 " {\n"
1514 " id = atomicAdd(subgroupID, 1);\n"
1515 " }\n"
1516 " id = subgroupBroadcastFirst(id);\n"
1517 " uint localId = id;\n"
1518 " uint tempResult = 0;\n";
1519 }
1520
1521 switch (caseDef.opType)
1522 {
1523 case OPTYPE_ELECT:
1524 if (isAllComputeStages(caseDef.shaderStage))
1525 {
1526 body << " uint value = " << UNELECTED_VALUE << ";\n"
1527 " if (subgroupElect())\n"
1528 " {\n"
1529 " value = " << ELECTED_VALUE << ";\n"
1530 " }\n"
1531 " uvec4 bits = bitCount(sharedMemoryBallot(value == " << ELECTED_VALUE << "));\n"
1532 " tempRes = bits.x + bits.y + bits.z + bits.w;\n";
1533 }
1534 else
1535 {
1536 body << " if (subgroupElect())\n"
1537 " {\n"
1538 " tempRes = " << ELECTED_VALUE << ";\n"
1539 " atomicAdd(numSubgroupsExecuted, 1);\n"
1540 " }\n"
1541 " else\n"
1542 " {\n"
1543 " tempRes = " << UNELECTED_VALUE << ";\n"
1544 " }\n";
1545 }
1546 break;
1547
1548 case OPTYPE_SUBGROUP_BARRIER:
1549 case OPTYPE_SUBGROUP_MEMORY_BARRIER:
1550 case OPTYPE_SUBGROUP_MEMORY_BARRIER_BUFFER:
1551 body << " if (subgroupElect())\n"
1552 " {\n"
1553 " tempBuffer[id] = value;\n"
1554 " }\n"
1555 " " << getOpTypeName(caseDef.opType) << "();\n"
1556 " tempResult = tempBuffer[id];\n";
1557 break;
1558
1559 case OPTYPE_SUBGROUP_MEMORY_BARRIER_SHARED:
1560 body << " if (subgroupElect())\n"
1561 " {\n"
1562 " tempShared[localId] = value;\n"
1563 " }\n"
1564 " subgroupMemoryBarrierShared();\n"
1565 " tempResult = tempShared[localId];\n";
1566 break;
1567
1568 case OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE:
1569 body << " if (subgroupElect())\n"
1570 " {\n"
1571 " imageStore(tempImage, ivec2(id, 0), ivec4(value));\n"
1572 " }\n"
1573 " subgroupMemoryBarrierImage();\n"
1574 " tempResult = imageLoad(tempImage, ivec2(id, 0)).x;\n";
1575 break;
1576
1577 default:
1578 TCU_THROW(InternalError, "Unhandled op type!");
1579 }
1580
1581 #ifndef CTS_USES_VULKANSC
1582 if (caseDef.opType != OPTYPE_ELECT && (isAllGraphicsStages(caseDef.shaderStage) || isAllRayTracingStages(caseDef.shaderStage)))
1583 #else
1584 if (caseDef.opType != OPTYPE_ELECT && (isAllGraphicsStages(caseDef.shaderStage)))
1585 #endif // CTS_USES_VULKANSC
1586 {
1587 body << " tempRes = tempResult;\n";
1588 }
1589
1590 return body.str();
1591 }
1592
getExtHeader(const CaseDefinition & caseDef)1593 string getExtHeader (const CaseDefinition& caseDef)
1594 {
1595 const string extensions = (caseDef.opType == OPTYPE_ELECT)
1596 ? "#extension GL_KHR_shader_subgroup_basic: enable\n"
1597 : "#extension GL_KHR_shader_subgroup_basic: enable\n"
1598 "#extension GL_KHR_shader_subgroup_ballot: enable\n";
1599 return extensions;
1600 }
1601
initComputeOrMeshPrograms(SourceCollections & programCollection,CaseDefinition & caseDef,const string & extensions,const string & testSrc,const ShaderBuildOptions & buildOptions)1602 void initComputeOrMeshPrograms (SourceCollections& programCollection,
1603 CaseDefinition& caseDef,
1604 const string& extensions,
1605 const string& testSrc,
1606 const ShaderBuildOptions& buildOptions)
1607 {
1608 std::ostringstream electTemplateStream;
1609 electTemplateStream
1610 << "#version 450\n"
1611 << extensions
1612 << "${EXTENSIONS:opt}"
1613 << "layout (local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in;\n"
1614 << "${LAYOUTS:opt}"
1615 << "layout (set = 0, binding = 0, std430) buffer Buffer1\n"
1616 << "{\n"
1617 << " uint result[];\n"
1618 << "};\n"
1619 << "\n"
1620 << subgroups::getSharedMemoryBallotHelper()
1621 << "void main (void)\n"
1622 << "{\n"
1623 << " uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
1624 << " highp uint offset = globalSize.x * ((globalSize.y * gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + gl_GlobalInvocationID.x;\n"
1625 << " uint value = " << UNELECTED_VALUE << ";\n"
1626 << " if (subgroupElect())\n"
1627 << " {\n"
1628 << " value = " << ELECTED_VALUE << ";\n"
1629 << " }\n"
1630 << " uvec4 bits = bitCount(sharedMemoryBallot(value == " << ELECTED_VALUE << "));\n"
1631 << " result[offset] = bits.x + bits.y + bits.z + bits.w;\n"
1632 << "${BODY:opt}"
1633 << "}\n";
1634 ;
1635 const tcu::StringTemplate electTemplate(electTemplateStream.str());
1636
1637 std::ostringstream nonElectTemplateStream;
1638 nonElectTemplateStream
1639 << "#version 450\n"
1640 << "#extension GL_KHR_shader_subgroup_basic: enable\n"
1641 << "${EXTENSIONS:opt}"
1642 << "layout (local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in;\n"
1643 << "${LAYOUTS:opt}"
1644 << "layout (set = 0, binding = 0, std430) buffer Buffer1\n"
1645 << "{\n"
1646 << " uint result[];\n"
1647 << "};\n"
1648 << "layout (set = 0, binding = 1, std430) buffer Buffer2\n"
1649 << "{\n"
1650 << " uint tempBuffer[];\n"
1651 << "};\n"
1652 << "layout (set = 0, binding = 2, std430) buffer Buffer3\n"
1653 << "{\n"
1654 << " uint value;\n"
1655 << "};\n"
1656 << "layout (set = 0, binding = 3, r32ui) uniform uimage2D tempImage;\n"
1657 << "shared uint tempShared[gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z];\n"
1658 << "\n"
1659 << "void main (void)\n"
1660 << "{\n"
1661 << " uvec3 globalSize = gl_NumWorkGroups * gl_WorkGroupSize;\n"
1662 << " highp uint offset = globalSize.x * ((globalSize.y * gl_GlobalInvocationID.z) + gl_GlobalInvocationID.y) + gl_GlobalInvocationID.x;\n"
1663 << " uint localId = gl_SubgroupID;\n"
1664 << " uint id = globalSize.x * ((globalSize.y * gl_WorkGroupID.z) + gl_WorkGroupID.y) + gl_WorkGroupID.x + localId;\n"
1665 << " uint tempResult = 0;\n"
1666 << testSrc
1667 << " result[offset] = tempResult;\n"
1668 << "${BODY:opt}"
1669 << "}\n";
1670 ;
1671 const tcu::StringTemplate nonElectTemplate(nonElectTemplateStream.str());
1672
1673 if (isAllComputeStages(caseDef.shaderStage))
1674 {
1675 const std::map<std::string, std::string> emptyMap;
1676
1677 if (OPTYPE_ELECT == caseDef.opType)
1678 {
1679 const auto programSource = electTemplate.specialize(emptyMap);
1680 programCollection.glslSources.add("comp") << glu::ComputeSource(programSource) << buildOptions;
1681 }
1682 else
1683 {
1684 const auto programSource = nonElectTemplate.specialize(emptyMap);
1685 programCollection.glslSources.add("comp") << glu::ComputeSource(programSource) << buildOptions;
1686 }
1687 }
1688 #ifndef CTS_USES_VULKANSC
1689 else if (isAllMeshShadingStages(caseDef.shaderStage))
1690 {
1691 const bool testMesh = ((caseDef.shaderStage & VK_SHADER_STAGE_MESH_BIT_EXT) != 0u);
1692 const bool testTask = ((caseDef.shaderStage & VK_SHADER_STAGE_TASK_BIT_EXT) != 0u);
1693 const tcu::UVec3 emitSize = (testMesh ? tcu::UVec3(1u, 1u, 1u) : tcu::UVec3(0u, 0u, 0u));
1694
1695 const std::map<std::string, std::string> meshMap
1696 {
1697 std::make_pair("EXTENSIONS", "#extension GL_EXT_mesh_shader : enable\n"),
1698 std::make_pair("LAYOUTS", "layout (points) out;\nlayout (max_vertices=1, max_primitives=1) out;\n"),
1699 std::make_pair("BODY", " SetMeshOutputsEXT(0u, 0u);\n")
1700 };
1701
1702 const std::map<std::string, std::string> taskMap
1703 {
1704 std::make_pair("EXTENSIONS", "#extension GL_EXT_mesh_shader : enable\n"),
1705 std::make_pair("BODY", " EmitMeshTasksEXT(" + std::to_string(emitSize.x()) + ", " + std::to_string(emitSize.y()) + ", " + std::to_string(emitSize.z()) + ");\n")
1706 };
1707
1708 if (testMesh)
1709 {
1710 if (OPTYPE_ELECT == caseDef.opType)
1711 {
1712 const auto programSource = electTemplate.specialize(meshMap);
1713 programCollection.glslSources.add("mesh") << glu::MeshSource(programSource) << buildOptions;
1714 }
1715 else
1716 {
1717 const auto programSource = nonElectTemplate.specialize(meshMap);
1718 programCollection.glslSources.add("mesh") << glu::MeshSource(programSource) << buildOptions;
1719 }
1720 }
1721 else
1722 {
1723 const std::string meshShaderNoSubgroups =
1724 "#version 450\n"
1725 "#extension GL_EXT_mesh_shader : enable\n"
1726 "\n"
1727 "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
1728 "layout (points) out;\n"
1729 "layout (max_vertices = 1, max_primitives = 1) out;\n"
1730 "\n"
1731 "void main (void)\n"
1732 "{\n"
1733 " SetMeshOutputsEXT(0u, 0u);\n"
1734 "}\n"
1735 ;
1736 programCollection.glslSources.add("mesh") << glu::MeshSource(meshShaderNoSubgroups) << buildOptions;
1737 }
1738
1739 if (testTask)
1740 {
1741 if (OPTYPE_ELECT == caseDef.opType)
1742 {
1743 const auto programSource = electTemplate.specialize(taskMap);
1744 programCollection.glslSources.add("task") << glu::TaskSource(programSource) << buildOptions;
1745 }
1746 else
1747 {
1748 const auto programSource = nonElectTemplate.specialize(taskMap);
1749 programCollection.glslSources.add("task") << glu::TaskSource(programSource) << buildOptions;
1750 }
1751 }
1752 }
1753 #endif // CTS_USES_VULKANSC
1754 else
1755 {
1756 DE_ASSERT(false);
1757 }
1758 }
1759
initPrograms(SourceCollections & programCollection,CaseDefinition caseDef)1760 void initPrograms (SourceCollections& programCollection, CaseDefinition caseDef)
1761 {
1762 #ifndef CTS_USES_VULKANSC
1763 const bool spirv14required = (isAllRayTracingStages(caseDef.shaderStage) || isAllMeshShadingStages(caseDef.shaderStage));
1764 #else
1765 const bool spirv14required = false;
1766 #endif // CTS_USES_VULKANSC
1767 const SpirvVersion spirvVersion = (spirv14required ? SPIRV_VERSION_1_4 : SPIRV_VERSION_1_3);
1768 const ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, spirvVersion, 0u, spirv14required);
1769 const string extHeader = getExtHeader(caseDef);
1770 const string testSrc = getTestString(caseDef);
1771 const vector<string> headDeclarations = getPerStageHeadDeclarations(caseDef);
1772 const bool pointSizeSupport = *caseDef.geometryPointSizeSupported;
1773 const bool isComp = isAllComputeStages(caseDef.shaderStage);
1774 #ifndef CTS_USES_VULKANSC
1775 const bool isMesh = isAllMeshShadingStages(caseDef.shaderStage);
1776 #else
1777 const bool isMesh = false;
1778 #endif // CTS_USES_VULKANSC
1779
1780 if (isComp || isMesh)
1781 initComputeOrMeshPrograms(programCollection, caseDef, extHeader, testSrc, buildOptions);
1782 else
1783 subgroups::initStdPrograms(programCollection, buildOptions, caseDef.shaderStage, VK_FORMAT_R32_UINT, pointSizeSupport, extHeader, testSrc, "", headDeclarations, true);
1784 }
1785
supportedCheck(Context & context,CaseDefinition caseDef)1786 void supportedCheck (Context& context, CaseDefinition caseDef)
1787 {
1788 if (!subgroups::isSubgroupSupported(context))
1789 TCU_THROW(NotSupportedError, "Subgroup operations are not supported");
1790
1791 if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_BASIC_BIT))
1792 TCU_FAIL("supportedOperations will have the VK_SUBGROUP_FEATURE_BASIC_BIT bit set if any of the physical device's queues support VK_QUEUE_GRAPHICS_BIT or VK_QUEUE_COMPUTE_BIT.");
1793
1794 if (caseDef.requiredSubgroupSize)
1795 {
1796 context.requireDeviceFunctionality("VK_EXT_subgroup_size_control");
1797
1798 #ifndef CTS_USES_VULKANSC
1799 const VkPhysicalDeviceSubgroupSizeControlFeatures& subgroupSizeControlFeatures = context.getSubgroupSizeControlFeatures();
1800 const VkPhysicalDeviceSubgroupSizeControlProperties& subgroupSizeControlProperties = context.getSubgroupSizeControlProperties();
1801 #else
1802 const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT& subgroupSizeControlFeatures = context.getSubgroupSizeControlFeaturesEXT();
1803 const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT& subgroupSizeControlProperties = context.getSubgroupSizeControlPropertiesEXT();
1804 #endif // CTS_USES_VULKANSC
1805
1806 if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
1807 TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes nor required subgroup size");
1808
1809 if (subgroupSizeControlFeatures.computeFullSubgroups == DE_FALSE)
1810 TCU_THROW(NotSupportedError, "Device does not support full subgroups in compute shaders");
1811
1812 if ((subgroupSizeControlProperties.requiredSubgroupSizeStages & caseDef.shaderStage) != caseDef.shaderStage)
1813 TCU_THROW(NotSupportedError, "Required subgroup size is not supported for shader stage");
1814 }
1815
1816 *caseDef.geometryPointSizeSupported = subgroups::isTessellationAndGeometryPointSizeSupported(context);
1817
1818 subgroups::supportedCheckShader(context, caseDef.shaderStage);
1819
1820 if (OPTYPE_ELECT != caseDef.opType && VK_SHADER_STAGE_COMPUTE_BIT != caseDef.shaderStage)
1821 {
1822 if (!subgroups::isSubgroupFeatureSupportedForDevice(context, VK_SUBGROUP_FEATURE_BALLOT_BIT))
1823 {
1824 TCU_THROW(NotSupportedError, "Subgroup basic operation non-compute stage test required that ballot operations are supported!");
1825 }
1826 }
1827
1828 #ifndef CTS_USES_VULKANSC
1829 if (isAllRayTracingStages(caseDef.shaderStage))
1830 {
1831 context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline");
1832 }
1833 else if (isAllMeshShadingStages(caseDef.shaderStage))
1834 {
1835 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
1836 context.requireDeviceFunctionality("VK_EXT_mesh_shader");
1837
1838 if ((caseDef.shaderStage & VK_SHADER_STAGE_TASK_BIT_EXT) != 0u)
1839 {
1840 const auto& features = context.getMeshShaderFeaturesEXT();
1841 if (!features.taskShader)
1842 TCU_THROW(NotSupportedError, "Task shaders not supported");
1843 }
1844 }
1845 #endif // CTS_USES_VULKANSC
1846 }
1847
noSSBOtest(Context & context,const CaseDefinition caseDef)1848 TestStatus noSSBOtest (Context& context, const CaseDefinition caseDef)
1849 {
1850 const deUint32 inputDatasCount = OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType ? 3u : 2u;
1851 vector<subgroups::SSBOData> inputDatas (inputDatasCount);
1852
1853 inputDatas[0].format = VK_FORMAT_R32_UINT;
1854 inputDatas[0].layout = subgroups::SSBOData::LayoutStd140;
1855 inputDatas[0].numElements = SHADER_BUFFER_SIZE/4ull;
1856 inputDatas[0].initializeType = subgroups::SSBOData::InitializeNonZero;
1857 inputDatas[0].bindingType = subgroups::SSBOData::BindingUBO;
1858
1859 inputDatas[1].format = VK_FORMAT_R32_UINT;
1860 inputDatas[1].layout = subgroups::SSBOData::LayoutStd140;
1861 inputDatas[1].numElements = 1ull;
1862 inputDatas[1].initializeType = subgroups::SSBOData::InitializeNonZero;
1863 inputDatas[1].bindingType = subgroups::SSBOData::BindingUBO;
1864
1865 if(OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType )
1866 {
1867 inputDatas[2].format = VK_FORMAT_R32_UINT;
1868 inputDatas[2].layout = subgroups::SSBOData::LayoutPacked;
1869 inputDatas[2].numElements = SHADER_BUFFER_SIZE;
1870 inputDatas[2].initializeType = subgroups::SSBOData::InitializeNone;
1871 inputDatas[2].bindingType = subgroups::SSBOData::BindingImage;
1872 }
1873
1874 if (VK_SHADER_STAGE_VERTEX_BIT == caseDef.shaderStage)
1875 {
1876 if (OPTYPE_ELECT == caseDef.opType)
1877 return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32G32_SFLOAT, DE_NULL, 0u, DE_NULL, checkVertexPipelineStagesSubgroupElectNoSSBO);
1878 else
1879 return subgroups::makeVertexFrameBufferTest(context, VK_FORMAT_R32G32B32A32_SFLOAT, &inputDatas[0], inputDatasCount, DE_NULL,
1880 (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType) ?
1881 checkVertexPipelineStagesSubgroupBarriersWithImageNoSSBO :
1882 checkVertexPipelineStagesSubgroupBarriersNoSSBO
1883 );
1884 }
1885 else if (VK_SHADER_STAGE_FRAGMENT_BIT == caseDef.shaderStage)
1886 {
1887 return subgroups::makeFragmentFrameBufferTest(context, VK_FORMAT_R32G32B32A32_SFLOAT, &inputDatas[0], inputDatasCount, DE_NULL,
1888 (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType) ?
1889 checkFragmentSubgroupBarriersWithImageNoSSBO :
1890 checkFragmentSubgroupBarriersNoSSBO
1891 );
1892 }
1893 else if (VK_SHADER_STAGE_GEOMETRY_BIT == caseDef.shaderStage)
1894 {
1895 if (OPTYPE_ELECT == caseDef.opType)
1896 return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32G32_SFLOAT, DE_NULL, 0u, DE_NULL, checkVertexPipelineStagesSubgroupElectNoSSBO);
1897 else
1898 return subgroups::makeGeometryFrameBufferTest(context, VK_FORMAT_R32G32B32A32_SFLOAT, &inputDatas[0], inputDatasCount, DE_NULL,
1899 (OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType) ?
1900 checkVertexPipelineStagesSubgroupBarriersWithImageNoSSBO :
1901 checkVertexPipelineStagesSubgroupBarriersNoSSBO
1902 );
1903 }
1904
1905 if (OPTYPE_ELECT == caseDef.opType)
1906 return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32G32_SFLOAT, DE_NULL, 0u, DE_NULL, checkVertexPipelineStagesSubgroupElectNoSSBO, caseDef.shaderStage);
1907
1908 return subgroups::makeTessellationEvaluationFrameBufferTest(context, VK_FORMAT_R32G32B32A32_SFLOAT, &inputDatas[0], inputDatasCount, DE_NULL,
1909 (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT == caseDef.shaderStage) ?
1910 ((OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType) ?
1911 checkVertexPipelineStagesSubgroupBarriersWithImageNoSSBO :
1912 checkVertexPipelineStagesSubgroupBarriersNoSSBO) :
1913 ((OPTYPE_SUBGROUP_MEMORY_BARRIER_IMAGE == caseDef.opType) ?
1914 checkTessellationEvaluationSubgroupBarriersWithImageNoSSBO :
1915 checkTessellationEvaluationSubgroupBarriersNoSSBO),
1916 caseDef.shaderStage);
1917 }
1918
test(Context & context,const CaseDefinition caseDef)1919 TestStatus test (Context& context, const CaseDefinition caseDef)
1920 {
1921 const bool isCompute = isAllComputeStages(caseDef.shaderStage);
1922 #ifndef CTS_USES_VULKANSC
1923 const bool isMesh = isAllMeshShadingStages(caseDef.shaderStage);
1924 #else
1925 const bool isMesh = false;
1926 #endif // CTS_USES_VULKANSC
1927 DE_ASSERT(!(isCompute && isMesh));
1928
1929 if (isCompute || isMesh)
1930 {
1931 #ifndef CTS_USES_VULKANSC
1932 const VkPhysicalDeviceSubgroupSizeControlProperties& subgroupSizeControlProperties = context.getSubgroupSizeControlProperties();
1933 #else
1934 const VkPhysicalDeviceSubgroupSizeControlPropertiesEXT& subgroupSizeControlProperties = context.getSubgroupSizeControlPropertiesEXT();
1935 #endif // CTS_USES_VULKANSC
1936 TestLog& log = context.getTestContext().getLog();
1937
1938 if (OPTYPE_ELECT == caseDef.opType)
1939 {
1940 if (caseDef.requiredSubgroupSize == DE_FALSE)
1941 {
1942 if (isCompute)
1943 return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0, DE_NULL, checkComputeOrMeshSubgroupElect);
1944 else
1945 return subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, nullptr, 0, nullptr, checkComputeOrMeshSubgroupElect);
1946 }
1947
1948 log << TestLog::Message << "Testing required subgroup size range [" << subgroupSizeControlProperties.minSubgroupSize << ", "
1949 << subgroupSizeControlProperties.maxSubgroupSize << "]" << TestLog::EndMessage;
1950
1951 // According to the spec, requiredSubgroupSize must be a power-of-two integer.
1952 for (deUint32 size = subgroupSizeControlProperties.minSubgroupSize; size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
1953 {
1954 TestStatus result (QP_TEST_RESULT_INTERNAL_ERROR, "Internal Error");
1955
1956 if (isCompute)
1957 result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, DE_NULL, 0u, DE_NULL, checkComputeOrMeshSubgroupElect, size);
1958 else
1959 result = subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, nullptr, 0u, nullptr, checkComputeOrMeshSubgroupElect, size);
1960
1961 if (result.getCode() != QP_TEST_RESULT_PASS)
1962 {
1963 log << TestLog::Message << "subgroupSize " << size << " failed" << TestLog::EndMessage;
1964 return result;
1965 }
1966 }
1967
1968 return TestStatus::pass("OK");
1969 }
1970 else
1971 {
1972 const deUint32 inputDatasCount = 3;
1973 const subgroups::SSBOData inputDatas[inputDatasCount] =
1974 {
1975 {
1976 subgroups::SSBOData::InitializeNone, // InputDataInitializeType initializeType;
1977 subgroups::SSBOData::LayoutStd430, // InputDataLayoutType layout;
1978 VK_FORMAT_R32_UINT, // vk::VkFormat format;
1979 SHADER_BUFFER_SIZE, // vk::VkDeviceSize numElements;
1980 },
1981 {
1982 subgroups::SSBOData::InitializeNonZero, // InputDataInitializeType initializeType;
1983 subgroups::SSBOData::LayoutStd430, // InputDataLayoutType layout;
1984 VK_FORMAT_R32_UINT, // vk::VkFormat format;
1985 1, // vk::VkDeviceSize numElements;
1986 },
1987 {
1988 subgroups::SSBOData::InitializeNone, // InputDataInitializeType initializeType;
1989 subgroups::SSBOData::LayoutPacked, // InputDataLayoutType layout;
1990 VK_FORMAT_R32_UINT, // vk::VkFormat format;
1991 SHADER_BUFFER_SIZE, // vk::VkDeviceSize numElements;
1992 subgroups::SSBOData::BindingImage, // bool isImage;
1993 },
1994 };
1995
1996 if (caseDef.requiredSubgroupSize == DE_FALSE)
1997 {
1998 if (isCompute)
1999 return subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, inputDatas, inputDatasCount, DE_NULL, checkComputeOrMeshSubgroupBarriers);
2000 else
2001 return subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, inputDatas, inputDatasCount, nullptr, checkComputeOrMeshSubgroupBarriers);
2002 }
2003
2004 log << TestLog::Message << "Testing required subgroup size range [" << subgroupSizeControlProperties.minSubgroupSize << ", "
2005 << subgroupSizeControlProperties.maxSubgroupSize << "]" << TestLog::EndMessage;
2006
2007 // According to the spec, requiredSubgroupSize must be a power-of-two integer.
2008 for (deUint32 size = subgroupSizeControlProperties.minSubgroupSize; size <= subgroupSizeControlProperties.maxSubgroupSize; size *= 2)
2009 {
2010 TestStatus result (QP_TEST_RESULT_INTERNAL_ERROR, "Internal Error");
2011
2012 if (isCompute)
2013 result = subgroups::makeComputeTest(context, VK_FORMAT_R32_UINT, inputDatas, inputDatasCount, DE_NULL, checkComputeOrMeshSubgroupBarriers, size);
2014 else
2015 result = subgroups::makeMeshTest(context, VK_FORMAT_R32_UINT, inputDatas, inputDatasCount, nullptr, checkComputeOrMeshSubgroupBarriers, size);
2016
2017 if (result.getCode() != QP_TEST_RESULT_PASS)
2018 {
2019 log << TestLog::Message << "subgroupSize " << size << " failed" << TestLog::EndMessage;
2020 return result;
2021 }
2022 }
2023
2024 return TestStatus::pass("OK");
2025 }
2026 }
2027 else if (isAllGraphicsStages(caseDef.shaderStage))
2028 {
2029 if (!subgroups::isFragmentSSBOSupportedForDevice(context))
2030 {
2031 TCU_THROW(NotSupportedError, "Subgroup basic operation require that the fragment stage be able to write to SSBOs!");
2032 }
2033
2034 const VkShaderStageFlags stages = subgroups::getPossibleGraphicsSubgroupStages(context, caseDef.shaderStage);
2035 const VkShaderStageFlags stagesBits[] =
2036 {
2037 VK_SHADER_STAGE_VERTEX_BIT,
2038 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
2039 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
2040 VK_SHADER_STAGE_GEOMETRY_BIT,
2041 VK_SHADER_STAGE_FRAGMENT_BIT,
2042 };
2043
2044 if (OPTYPE_ELECT == caseDef.opType)
2045 {
2046 const deUint32 inputCount = DE_LENGTH_OF_ARRAY(stagesBits);
2047 subgroups::SSBOData inputData[inputCount];
2048
2049 for (deUint32 ndx = 0; ndx < DE_LENGTH_OF_ARRAY(stagesBits); ++ndx)
2050 {
2051 inputData[ndx] =
2052 {
2053 subgroups::SSBOData::InitializeZero, // InputDataInitializeType initializeType;
2054 subgroups::SSBOData::LayoutStd430, // InputDataLayoutType layout;
2055 VK_FORMAT_R32_UINT, // vk::VkFormat format;
2056 1, // vk::VkDeviceSize numElements;
2057 subgroups::SSBOData::BindingSSBO, // bool isImage;
2058 4 + ndx, // deUint32 binding;
2059 stagesBits[ndx], // vk::VkShaderStageFlags stages;
2060 };
2061 }
2062
2063 return subgroups::allStages(context, VK_FORMAT_R32_UINT, inputData, inputCount, DE_NULL, checkVertexPipelineStagesSubgroupElect, stages);
2064 }
2065 else
2066 {
2067 const deUint32 inputDatasCount = DE_LENGTH_OF_ARRAY(stagesBits) * 4u;
2068 subgroups::SSBOData inputDatas[inputDatasCount];
2069
2070 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(stagesBits); ++ndx)
2071 {
2072 const deUint32 index = ndx*4;
2073
2074 inputDatas[index].format = VK_FORMAT_R32_UINT;
2075 inputDatas[index].layout = subgroups::SSBOData::LayoutStd430;
2076 inputDatas[index].numElements = SHADER_BUFFER_SIZE;
2077 inputDatas[index].initializeType = subgroups::SSBOData::InitializeNonZero;
2078 inputDatas[index].binding = index + 4u;
2079 inputDatas[index].stages = stagesBits[ndx];
2080
2081 inputDatas[index + 1].format = VK_FORMAT_R32_UINT;
2082 inputDatas[index + 1].layout = subgroups::SSBOData::LayoutStd430;
2083 inputDatas[index + 1].numElements = 1;
2084 inputDatas[index + 1].initializeType = subgroups::SSBOData::InitializeZero;
2085 inputDatas[index + 1].binding = index + 5u;
2086 inputDatas[index + 1].stages = stagesBits[ndx];
2087
2088 inputDatas[index + 2].format = VK_FORMAT_R32_UINT;
2089 inputDatas[index + 2].layout = subgroups::SSBOData::LayoutStd430;
2090 inputDatas[index + 2].numElements = 1;
2091 inputDatas[index + 2].initializeType = subgroups::SSBOData::InitializeNonZero;
2092 inputDatas[index + 2].binding = index + 6u;
2093 inputDatas[index + 2].stages = stagesBits[ndx];
2094
2095 inputDatas[index + 3].format = VK_FORMAT_R32_UINT;
2096 inputDatas[index + 3].layout = subgroups::SSBOData::LayoutStd430;
2097 inputDatas[index + 3].numElements = SHADER_BUFFER_SIZE;
2098 inputDatas[index + 3].initializeType = subgroups::SSBOData::InitializeNone;
2099 inputDatas[index + 3].bindingType = subgroups::SSBOData::BindingImage;
2100 inputDatas[index + 3].binding = index + 7u;
2101 inputDatas[index + 3].stages = stagesBits[ndx];
2102 }
2103
2104 return subgroups::allStages(context, VK_FORMAT_R32_UINT, inputDatas, inputDatasCount, DE_NULL, checkVertexPipelineStagesSubgroupBarriers, stages);
2105 }
2106 }
2107 #ifndef CTS_USES_VULKANSC
2108 else if (isAllRayTracingStages(caseDef.shaderStage))
2109 {
2110 const VkShaderStageFlags stages = subgroups::getPossibleRayTracingSubgroupStages(context, caseDef.shaderStage);
2111 const VkShaderStageFlags stagesBits[] =
2112 {
2113 VK_SHADER_STAGE_RAYGEN_BIT_KHR,
2114 VK_SHADER_STAGE_ANY_HIT_BIT_KHR,
2115 VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR,
2116 VK_SHADER_STAGE_MISS_BIT_KHR,
2117 VK_SHADER_STAGE_INTERSECTION_BIT_KHR,
2118 VK_SHADER_STAGE_CALLABLE_BIT_KHR,
2119 };
2120 const deUint32 stagesCount = DE_LENGTH_OF_ARRAY(stagesBits);
2121
2122 if (OPTYPE_ELECT == caseDef.opType)
2123 {
2124 const deUint32 inputDataCount = stagesCount;
2125 subgroups::SSBOData inputData[inputDataCount];
2126
2127 for (deUint32 ndx = 0; ndx < inputDataCount; ++ndx)
2128 {
2129 inputData[ndx].format = VK_FORMAT_R32_UINT;
2130 inputData[ndx].layout = subgroups::SSBOData::LayoutStd430;
2131 inputData[ndx].numElements = 1;
2132 inputData[ndx].initializeType = subgroups::SSBOData::InitializeZero;
2133 inputData[ndx].binding = stagesCount + ndx;
2134 inputData[ndx].stages = stagesBits[ndx];
2135 }
2136
2137 return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, inputData, inputDataCount, DE_NULL, checkVertexPipelineStagesSubgroupElect, stages);
2138 }
2139 else
2140 {
2141 const deUint32 datasPerStage = 4u;
2142 const deUint32 inputDatasCount = datasPerStage * stagesCount;
2143 subgroups::SSBOData inputDatas[inputDatasCount];
2144
2145 for (deUint32 ndx = 0; ndx < stagesCount; ++ndx)
2146 {
2147 const deUint32 index = datasPerStage * ndx;
2148
2149 for (deUint32 perStageNdx = 0; perStageNdx < datasPerStage; ++perStageNdx)
2150 {
2151 inputDatas[index + perStageNdx].format = VK_FORMAT_R32_UINT;
2152 inputDatas[index + perStageNdx].layout = subgroups::SSBOData::LayoutStd430;
2153 inputDatas[index + perStageNdx].stages = stagesBits[ndx];
2154 inputDatas[index + perStageNdx].bindingType = subgroups::SSBOData::BindingSSBO;
2155 }
2156
2157 inputDatas[index + 0].numElements = SHADER_BUFFER_SIZE;
2158 inputDatas[index + 0].initializeType = subgroups::SSBOData::InitializeNonZero;
2159 inputDatas[index + 0].binding = index + stagesCount;
2160
2161 inputDatas[index + 1].numElements = 1;
2162 inputDatas[index + 1].initializeType = subgroups::SSBOData::InitializeZero;
2163 inputDatas[index + 1].binding = index + stagesCount + 1u;
2164
2165 inputDatas[index + 2].numElements = 1;
2166 inputDatas[index + 2].initializeType = subgroups::SSBOData::InitializeNonZero;
2167 inputDatas[index + 2].binding = index + stagesCount + 2u;
2168
2169 inputDatas[index + 3].numElements = SHADER_BUFFER_SIZE;
2170 inputDatas[index + 3].initializeType = subgroups::SSBOData::InitializeNone;
2171 inputDatas[index + 3].bindingType = subgroups::SSBOData::BindingImage;
2172 inputDatas[index + 3].binding = index + stagesCount + 3u;
2173 }
2174
2175 return subgroups::allRayTracingStages(context, VK_FORMAT_R32_UINT, inputDatas, inputDatasCount, DE_NULL, checkVertexPipelineStagesSubgroupBarriers, stages);
2176 }
2177 }
2178 #endif // CTS_USES_VULKANSC
2179 else
2180 TCU_THROW(InternalError, "Unknown stage or invalid stage set");
2181 }
2182 }
2183
2184 namespace vkt
2185 {
2186 namespace subgroups
2187 {
createSubgroupsBasicTests(TestContext & testCtx)2188 TestCaseGroup* createSubgroupsBasicTests (TestContext& testCtx)
2189 {
2190 de::MovePtr<TestCaseGroup> group (new TestCaseGroup(testCtx, "basic", "Subgroup basic category tests"));
2191 de::MovePtr<TestCaseGroup> graphicGroup (new TestCaseGroup(testCtx, "graphics", "Subgroup basic category tests: graphics"));
2192 de::MovePtr<TestCaseGroup> computeGroup (new TestCaseGroup(testCtx, "compute", "Subgroup basic category tests: compute"));
2193 de::MovePtr<TestCaseGroup> meshGroup (new TestCaseGroup(testCtx, "mesh", "Subgroup basic category tests: mesh shading"));
2194 de::MovePtr<TestCaseGroup> framebufferGroup (new TestCaseGroup(testCtx, "framebuffer", "Subgroup basic category tests: framebuffer"));
2195 de::MovePtr<TestCaseGroup> raytracingGroup (new TestCaseGroup(testCtx, "ray_tracing", "Subgroup basic category tests: ray tracing"));
2196 const VkShaderStageFlags fbStages[] =
2197 {
2198 VK_SHADER_STAGE_FRAGMENT_BIT,
2199 VK_SHADER_STAGE_VERTEX_BIT,
2200 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
2201 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
2202 VK_SHADER_STAGE_GEOMETRY_BIT,
2203 };
2204 #ifndef CTS_USES_VULKANSC
2205 const VkShaderStageFlags meshStages[] =
2206 {
2207 VK_SHADER_STAGE_MESH_BIT_EXT,
2208 VK_SHADER_STAGE_TASK_BIT_EXT,
2209 };
2210 #endif // CTS_USES_VULKANSC
2211 const deBool boolValues[] =
2212 {
2213 DE_FALSE,
2214 DE_TRUE
2215 };
2216
2217 for (int opTypeIndex = 0; opTypeIndex < OPTYPE_LAST; ++opTypeIndex)
2218 {
2219 const OpType opType = static_cast<OpType>(opTypeIndex);
2220 const string op = de::toLower(getOpTypeName(opType));
2221
2222 for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
2223 {
2224 const deBool requiredSubgroupSize = boolValues[groupSizeNdx];
2225 const string testNameSuffix = requiredSubgroupSize ? "_requiredsubgroupsize" : "";
2226 const CaseDefinition caseDef =
2227 {
2228 opType, // OpType opType;
2229 VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlags shaderStage;
2230 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
2231 requiredSubgroupSize // deBool requiredSubgroupSize;
2232 };
2233 const string testName = op + testNameSuffix;
2234
2235 addFunctionCaseWithPrograms(computeGroup.get(), testName, "", supportedCheck, initPrograms, test, caseDef);
2236 }
2237
2238 #ifndef CTS_USES_VULKANSC
2239 for (size_t groupSizeNdx = 0; groupSizeNdx < DE_LENGTH_OF_ARRAY(boolValues); ++groupSizeNdx)
2240 {
2241 for (const auto& stage : meshStages)
2242 {
2243 const deBool requiredSubgroupSize = boolValues[groupSizeNdx];
2244 const string testNameSuffix = requiredSubgroupSize ? "_requiredsubgroupsize" : "";
2245 const CaseDefinition caseDef =
2246 {
2247 opType, // OpType opType;
2248 stage, // VkShaderStageFlags shaderStage;
2249 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
2250 requiredSubgroupSize // deBool requiredSubgroupSize;
2251 };
2252 const string testName = op + testNameSuffix + "_" + getShaderStageName(stage);
2253
2254 addFunctionCaseWithPrograms(meshGroup.get(), testName, "", supportedCheck, initPrograms, test, caseDef);
2255 }
2256 }
2257 #endif // CTS_USES_VULKANSC
2258
2259 if (OPTYPE_SUBGROUP_MEMORY_BARRIER_SHARED == opType)
2260 {
2261 // Shared isn't available in non compute shaders.
2262 continue;
2263 }
2264
2265 {
2266 const CaseDefinition caseDef =
2267 {
2268 opType, // OpType opType;
2269 VK_SHADER_STAGE_ALL_GRAPHICS, // VkShaderStageFlags shaderStage;
2270 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
2271 DE_FALSE // deBool requiredSubgroupSize;
2272 };
2273
2274 addFunctionCaseWithPrograms(graphicGroup.get(), op, "", supportedCheck, initPrograms, test, caseDef);
2275 }
2276
2277 #ifndef CTS_USES_VULKANSC
2278 {
2279 const CaseDefinition caseDef =
2280 {
2281 opType, // OpType opType;
2282 SHADER_STAGE_ALL_RAY_TRACING, // VkShaderStageFlags shaderStage;
2283 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
2284 DE_FALSE // deBool requiredSubgroupSize;
2285 };
2286
2287 addFunctionCaseWithPrograms(raytracingGroup.get(), op, "", supportedCheck, initPrograms, test, caseDef);
2288 }
2289 #endif // CTS_USES_VULKANSC
2290
2291 for (int stageIndex = 0; stageIndex < DE_LENGTH_OF_ARRAY(fbStages); ++stageIndex)
2292 {
2293 if (OPTYPE_ELECT == opType && fbStages[stageIndex] == VK_SHADER_STAGE_FRAGMENT_BIT)
2294 continue; // This is not tested. I don't know why.
2295
2296 const CaseDefinition caseDef =
2297 {
2298 opType, // OpType opType;
2299 fbStages[stageIndex], // VkShaderStageFlags shaderStage;
2300 de::SharedPtr<bool>(new bool), // de::SharedPtr<bool> geometryPointSizeSupported;
2301 DE_FALSE // deBool requiredSubgroupSize;
2302 };
2303 const string testName = op + "_" + getShaderStageName(caseDef.shaderStage);
2304
2305 addFunctionCaseWithPrograms(framebufferGroup.get(), testName, "", supportedCheck, initFrameBufferPrograms, noSSBOtest, caseDef);
2306 }
2307 }
2308
2309 group->addChild(graphicGroup.release());
2310 group->addChild(computeGroup.release());
2311 group->addChild(framebufferGroup.release());
2312 group->addChild(raytracingGroup.release());
2313 group->addChild(meshGroup.release());
2314
2315 return group.release();
2316 }
2317
2318 } // subgroups
2319 } // vkt
2320