• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2024 The Khronos Group Inc.
6  * Copyright (c) 2024 Valve Corporation.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Device Generated Commands EXT Graphics Draw Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktDGCGraphicsDrawTestsExt.hpp"
26 #include "vkCmdUtil.hpp"
27 #include "vktTestCase.hpp"
28 #include "vktDGCUtilCommon.hpp"
29 #include "vktDGCUtilExt.hpp"
30 
31 #include "vkImageUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkBarrierUtil.hpp"
34 
35 #include "tcuImageCompare.hpp"
36 
37 #include "deUniquePtr.hpp"
38 #include "deRandom.hpp"
39 #include "vktTestCaseUtil.hpp"
40 
41 #include <sstream>
42 #include <map>
43 #include <memory>
44 #include <algorithm>
45 #include <iterator>
46 #include <bitset>
47 #include <utility>
48 
49 namespace vkt
50 {
51 namespace DGC
52 {
53 
54 namespace
55 {
56 
57 using namespace vk;
58 
59 /*
60 TEST MECHANISM FOR VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT
61 
62 2x2 pixel framebuffer, with 3 sequences: lets call them 0, 1, 2
63 
64 Each sequence will draw triangles over the following pixels:
65 
66 0 1
67 1 2
68 
69 The indirect commands layout will contain:
70 
71 1. VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT (optional)
72 2. VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_EXT
73 3. VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_EXT
74 4. VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT
75 
76 The order of the two intermediate elements will be chosen pseudorandomly.
77 
78 The structure in the indirect commands buffer needs to be:
79 
80 typedef struct VkDrawIndirectCommand {
81     uint32_t  vertexCount;
82     uint32_t  instanceCount;
83     uint32_t  firstVertex;
84     uint32_t  firstInstance;
85 } VkDrawIndirectCommand;
86 
87 And we want to check if each of those 4 parameters is properly taken into account.
88 
89 We'll create vertex coordinates for 4 triangles (12 vertices in total) each covering one of the framebuffer pixels.
90 
91 Lets call these triangles A, B, C and D, by default drawn as:
92 
93 A B
94 C D
95 
96 Over the 4 pixels of the framebuffer.
97 
98 To make things more interesting and use a different vertex buffer in each sequence, we'll create a vertex buffer for each of the 3
99 sequences with different configurations, so that the stride and size also varies a bit. ZZ represents Zeros.
100 
101 Buffer 0: A0 A1 A2                              # Smaller buffer.
102 Buffer 1: B0 ZZ B1 ZZ B2 ZZ C0 ZZ C1 ZZ C2 ZZ   # Wider stride.
103 Buffer 2: ZZ ZZ ZZ ZZ ZZ ZZ ZZ ZZ ZZ D0 D1 D2   # Non-zero first vertex.
104 
105 The vertex count for each sequence varies: 3, 6, 3.
106 
107 The instance count could change also for each sequence: 1, 1, 2.
108   - And we could pass the instance index to the fragment shader and use it as the green channel.
109 
110 The first vertex will vary in each call: 0, 0, 9
111 
112 The first instance can also vary per call: 0 1 0
113 
114 The push constants will determine the red channel, and will vary in each sequence.
115 
116 The test setup is good for cases where VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT is not used. If it is, how can we make a
117 difference there?
118 
119 We can provide 2 fragment shaders: one stores 0 in the blue channel and another one stores 1. We can make the
120 sequences use pipelines 0 0 1, for example. What about the vertex shader? One could mirror coordinates in the X dimension for the
121 *first* triangle *only* and another one would not. With this, we can determine the expected color for each of the 4 pixels.
122 
123 We can add variations that use tessellation or geometry, and in that case the tessellation or geometry shaders would be the ones
124 flipping coordinates in the X dimension for the first triangle. As VertexIndex can only be used in the vertex shader, the
125 determination of which triangle to flip will be done in the vertex shader, which will pass a flag to the tessellation or geometry
126 shader indicating which triangle needs flipping.
127 
128 */
129 
130 /*
131 TEST MECHANISM FOR VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_EXT
132 
133 Note: very similar to a non-indexed draw as explained above.
134 
135 2x2 pixel framebuffer, with 3 sequences: lets call them 0, 1, 2
136 
137 Each sequence will draw triangles over the following pixels:
138 
139 0 1
140 1 2
141 
142 The indirect commands layout will contain:
143 
144 1. VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT (optional)
145 2. VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_EXT
146 3. VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_EXT
147 4. VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT
148 
149 The order of the two intermediate elements will be chosen pseudorandomly.
150 
151 The structure in the indirect commands buffer needs to be:
152 
153 typedef struct VkDrawIndexedIndirectCommand {
154     uint32_t    indexCount;
155     uint32_t    instanceCount;
156     uint32_t    firstIndex;
157     int32_t     vertexOffset;
158     uint32_t    firstInstance;
159 } VkDrawIndexedIndirectCommand;
160 
161 And we want to check if each of those 5 parameters is properly taken into account.
162 
163 We'll create vertex coordinates for 4 triangles (12 vertices in total) each covering one of the framebuffer pixels.
164 
165 Lets call these triangles A, B, C and D, by default drawn as:
166 
167 A B
168 C D
169 
170 Over the 4 pixels of the framebuffer.
171 
172 We'll use a single vertex buffer with all vertices stored consecutively for triangles A, B, C and D.
173 
174 To make things more interesting and use a different index buffer in each sequence, we'll create an index buffer for each of the 3
175 sequences with different configurations, so that the size and index type also varies. ZZ represents an invalid large index value.
176 
177 Buffer 0:  0  1  2                              # Different sizes.
178 Buffer 1:  3  4  5  6  7  8                     #
179 Buffer 2: ZZ ZZ ZZ ZZ ZZ ZZ ZZ ZZ ZZ 29 30 31   # Non-zero first vertex, plus indices will be stored as 16-bit instead of 32-bit.
180 
181 Parameters for each sequence:
182 
183 indexCount: 3 6 3
184 instanceCount: 1 1 2
185 firstIndex: 0 0 9
186 vertexOffset: 0 0 -20
187 firstInstance: 0 1 0
188 
189 The push constants will determine the red channel, and will vary in each sequence.
190 
191 The test setup is good for cases where VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT is not used. If it is, wow can we make a
192 difference there?
193 
194 We can provide 2 fragment shaders: one stores 0 in the blue channel and another one stores 1. We can make the
195 sequences use pipelines 0 0 1, for example. What about the vertex shader? One could mirror coordinates in the X dimension for the
196 *first* and *second* triangles and another one would not. With this, we can determine the expected color for each of the 4 pixels.
197 
198 We can add variations that use tessellation or geometry, and in that case the tessellation or geometry shaders would be the ones
199 flipping coordinates in the X dimension for the first triangle. As VertexIndex can only be used in the vertex shader, the
200 determination of which triangle to flip will be done in the vertex shader, which will pass a flag to the tessellation or geometry
201 shader indicating which triangle needs flipping.
202 
203 */
204 
205 using DGCShaderExtPtr = std::unique_ptr<DGCShaderExt>;
206 
207 constexpr int kPerTriangleVertices   = 3;
208 constexpr float kVertNormalRedOffset = 0.125f;
209 constexpr float kVertFlipRedOffset   = 0.25f;
210 
211 enum class TestType
212 {
213     DRAW = 0,
214     DRAW_SIMPLE, // No vertex or index buffer tokens.
215     DRAW_INDEXED,
216     DRAW_INDEXED_DX, // Using VK_INDIRECT_COMMANDS_INPUT_MODE_DXGI_INDEX_BUFFER_EXT.
217 };
218 
isIndexed(TestType testType)219 bool isIndexed(TestType testType)
220 {
221     return (testType == TestType::DRAW_INDEXED || testType == TestType::DRAW_INDEXED_DX);
222 }
223 
224 enum class ExtraStages
225 {
226     NONE = 0,
227     TESSELLATION,
228     GEOMETRY,
229 };
230 
231 enum class PipelineType
232 {
233     MONOLITHIC = 0,
234     SHADER_OBJECTS,
235     GPL_FAST,
236     GPL_OPTIMIZED,
237     GPL_MIX_BASE_FAST,
238     GPL_MIX_BASE_OPT,
239 };
240 
241 enum class PreprocessType
242 {
243     NONE = 0,
244     SAME_STATE_CMD_BUFFER,
245     OTHER_STATE_CMD_BUFFER,
246 };
247 
isGPL(PipelineType pipelineType)248 bool isGPL(PipelineType pipelineType)
249 {
250     return (pipelineType == PipelineType::GPL_FAST || pipelineType == PipelineType::GPL_OPTIMIZED ||
251             pipelineType == PipelineType::GPL_MIX_BASE_FAST || pipelineType == PipelineType::GPL_MIX_BASE_OPT);
252 }
253 
getGeneralConstructionType(PipelineType pipelineType)254 PipelineConstructionType getGeneralConstructionType(PipelineType pipelineType)
255 {
256     PipelineConstructionType constructionType =
257         PIPELINE_CONSTRUCTION_TYPE_SHADER_OBJECT_LINKED_BINARY; // Actually invalid.
258     switch (pipelineType)
259     {
260     case PipelineType::MONOLITHIC:
261         constructionType = PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC;
262         break;
263     case PipelineType::SHADER_OBJECTS:
264         constructionType = PIPELINE_CONSTRUCTION_TYPE_SHADER_OBJECT_UNLINKED_SPIRV;
265         break;
266     case PipelineType::GPL_FAST:
267     case PipelineType::GPL_MIX_BASE_FAST:
268         constructionType = PIPELINE_CONSTRUCTION_TYPE_FAST_LINKED_LIBRARY;
269         break;
270     case PipelineType::GPL_OPTIMIZED:
271     case PipelineType::GPL_MIX_BASE_OPT:
272         constructionType = PIPELINE_CONSTRUCTION_TYPE_LINK_TIME_OPTIMIZED_LIBRARY;
273         break;
274     default:
275         break;
276     }
277     return constructionType;
278 }
279 
280 struct DrawTestParams
281 {
282     TestType testType;
283     ExtraStages extraStages;
284     PipelineType pipelineType;
285     PreprocessType preprocessType;
286     bool checkDrawParams;
287     bool useExecutionSet;
288     bool unorderedSequences;
289 
hasExtraStagesvkt::DGC::__anon47167f390111::DrawTestParams290     bool hasExtraStages(void) const
291     {
292         return (extraStages != ExtraStages::NONE);
293     }
294 
isShaderObjectsvkt::DGC::__anon47167f390111::DrawTestParams295     bool isShaderObjects(void) const
296     {
297         return (pipelineType == PipelineType::SHADER_OBJECTS);
298     }
299 
getStageFlagsvkt::DGC::__anon47167f390111::DrawTestParams300     VkShaderStageFlags getStageFlags(void) const
301     {
302         VkShaderStageFlags stages = (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
303 
304         if (extraStages == ExtraStages::TESSELLATION)
305             stages |= (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
306         else if (extraStages == ExtraStages::GEOMETRY)
307             stages |= (VK_SHADER_STAGE_GEOMETRY_BIT);
308         else if (extraStages == ExtraStages::NONE)
309             ;
310         else
311             DE_ASSERT(false);
312 
313         return stages;
314     }
315 
getInputModeFlagsvkt::DGC::__anon47167f390111::DrawTestParams316     VkIndirectCommandsInputModeFlagsEXT getInputModeFlags(void) const
317     {
318         VkIndirectCommandsInputModeFlagsEXT flags = 0u;
319 
320         if (isIndexed(testType))
321         {
322             flags |= (testType == TestType::DRAW_INDEXED ? VK_INDIRECT_COMMANDS_INPUT_MODE_VULKAN_INDEX_BUFFER_EXT :
323                                                            VK_INDIRECT_COMMANDS_INPUT_MODE_DXGI_INDEX_BUFFER_EXT);
324         }
325 
326         return flags;
327     }
328 
doPreprocessvkt::DGC::__anon47167f390111::DrawTestParams329     bool doPreprocess(void) const
330     {
331         return (preprocessType != PreprocessType::NONE);
332     }
333 };
334 
335 class DGCDrawInstance : public vkt::TestInstance
336 {
337 public:
DGCDrawInstance(Context & context,DrawTestParams params)338     DGCDrawInstance(Context &context, DrawTestParams params) : TestInstance(context), m_params(params)
339     {
340     }
~DGCDrawInstance(void)341     virtual ~DGCDrawInstance(void)
342     {
343     }
344 
345     tcu::TestStatus iterate(void) override;
346 
347 protected:
348     DrawTestParams m_params;
349 };
350 
351 class DGCDrawCase : public vkt::TestCase
352 {
353 public:
DGCDrawCase(tcu::TestContext & testCtx,const std::string & name,const DrawTestParams & params)354     DGCDrawCase(tcu::TestContext &testCtx, const std::string &name, const DrawTestParams &params)
355         : vkt::TestCase(testCtx, name)
356         , m_params(params)
357     {
358     }
~DGCDrawCase(void)359     virtual ~DGCDrawCase(void)
360     {
361     }
362 
363     void initPrograms(vk::SourceCollections &programCollection) const override;
364     TestInstance *createInstance(Context &context) const override;
365     void checkSupport(Context &context) const override;
366 
367 protected:
368     DrawTestParams m_params;
369 };
370 
createInstance(Context & context) const371 TestInstance *DGCDrawCase::createInstance(Context &context) const
372 {
373     return new DGCDrawInstance(context, m_params);
374 }
375 
checkSupport(Context & context) const376 void DGCDrawCase::checkSupport(Context &context) const
377 {
378     const auto stages                 = m_params.getStageFlags();
379     const auto bindStages             = (m_params.useExecutionSet ? stages : 0u);
380     const bool useESO                 = m_params.isShaderObjects();
381     const auto bindStagesPipeline     = (useESO ? 0u : bindStages);
382     const auto bindStagesShaderObject = (useESO ? bindStages : 0u);
383     const auto modeFlags              = m_params.getInputModeFlags();
384 
385     checkDGCExtSupport(context, stages, bindStagesPipeline, bindStagesShaderObject, modeFlags);
386 
387     if (m_params.extraStages == ExtraStages::TESSELLATION)
388         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
389 
390     if (m_params.extraStages == ExtraStages::GEOMETRY)
391         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
392 
393     if (m_params.checkDrawParams)
394         context.requireDeviceFunctionality("VK_KHR_shader_draw_parameters");
395 
396     if (isGPL(m_params.pipelineType))
397     {
398         DE_ASSERT(m_params.useExecutionSet); // The code is not prepared otherwise.
399         context.requireDeviceFunctionality("VK_EXT_graphics_pipeline_library");
400     }
401 
402     const auto &dgcProperties = context.getDeviceGeneratedCommandsPropertiesEXT();
403 
404     if (useESO)
405     {
406         context.requireDeviceFunctionality("VK_EXT_shader_object");
407 
408         if (m_params.useExecutionSet && dgcProperties.maxIndirectShaderObjectCount == 0u)
409             TCU_THROW(NotSupportedError, "maxIndirectShaderObjectCount is zero");
410     }
411 }
412 
initPrograms(vk::SourceCollections & programCollection) const413 void DGCDrawCase::initPrograms(vk::SourceCollections &programCollection) const
414 {
415     const bool flipFirstTriangleHoriz = m_params.useExecutionSet;
416     const bool passFlipFactorDown     = (flipFirstTriangleHoriz && m_params.hasExtraStages());
417     const bool checkDrawParams        = m_params.checkDrawParams; // Start at location=2 for simplicity.
418 
419     // Normal vertex shader, always used.
420     {
421         std::ostringstream vert;
422         vert << "#version 460\n"
423              << "out gl_PerVertex\n"
424              << "{\n"
425              << "    vec4 gl_Position;\n"
426              << "};\n"
427              << "layout (location=0) in vec4 inPos;\n"
428              << "layout (location=0) out flat int instanceIndex;\n"
429              << "layout (location=1) out flat float redOffset;\n"
430              << (checkDrawParams ? "layout (location=3) out flat int drawIndex;\n" : "")
431              << (checkDrawParams ? "layout (location=4) out flat int baseVertex;\n" : "")
432              << (checkDrawParams ? "layout (location=5) out flat int baseInstance;\n" : "") << "void main (void) {\n"
433              << "    gl_Position = inPos;\n"
434              << "    instanceIndex = gl_InstanceIndex;\n"
435              << "    redOffset = " << kVertNormalRedOffset << ";\n"
436              << (checkDrawParams ? "    drawIndex = gl_DrawID;\n" : "")
437              << (checkDrawParams ? "    baseVertex = gl_BaseVertex;\n" : "")
438              << (checkDrawParams ? "    baseInstance = gl_BaseInstance;\n" : "") << "}\n";
439         programCollection.glslSources.add("vert_normal") << glu::VertexSource(vert.str());
440     }
441 
442     // Vertex shader that flips the X coordinates of the first triangle in each draw.
443     // Used for the first two sequences when using execution sets.
444     if (flipFirstTriangleHoriz)
445     {
446         // For indexed draws, the vertex index matches the index value, so we have to flip the first 2 triangles in the list.
447         // For non-indexed draws, the vertex index is per-draw, so we have to flip the first 1 triangle in the first 2 draws.
448         const auto flippedTriangles     = ((m_params.testType == TestType::DRAW) ? 1u : 2u);
449         const auto flippedVertexIndices = flippedTriangles * kPerTriangleVertices;
450 
451         std::ostringstream vert;
452         vert << "#version 460\n"
453              << "out gl_PerVertex\n"
454              << "{\n"
455              << "    vec4 gl_Position;\n"
456              << "};\n"
457              << "layout (location=0) in vec4 inPos;\n"
458              << "layout (location=0) out flat int instanceIndex;\n"
459              << "layout (location=1) out flat float redOffset;\n"
460              << (passFlipFactorDown ? "layout (location=2) out flat float xCoordFactor;\n" : "")
461              << (checkDrawParams ? "layout (location=3) out flat int drawIndex;\n" : "")
462              << (checkDrawParams ? "layout (location=4) out flat int baseVertex;\n" : "")
463              << (checkDrawParams ? "layout (location=5) out flat int baseInstance;\n" : "") << "void main (void) {\n"
464              << "    const bool passFlipFactorDown = " << (passFlipFactorDown ? "true" : "false") << ";\n"
465              << "    const bool flippedTriangle = (gl_VertexIndex < " << flippedVertexIndices << ");\n"
466              << (passFlipFactorDown ? "    xCoordFactor = (flippedTriangle ? -1.0 : 1.0);\n" : "")
467              << (checkDrawParams ? "    drawIndex = gl_DrawID;\n" : "")
468              << (checkDrawParams ? "    baseVertex = gl_BaseVertex;\n" : "")
469              << (checkDrawParams ? "    baseInstance = gl_BaseInstance;\n" : "")
470              << "    const float xCoord = ((flippedTriangle && !passFlipFactorDown) ? (inPos.x * -1.0) : inPos.x);\n"
471              << "    gl_Position = vec4(xCoord, inPos.yzw);\n"
472              << "    instanceIndex = gl_InstanceIndex;\n"
473              << "    redOffset = " << kVertFlipRedOffset << ";\n"
474              << "}\n";
475         programCollection.glslSources.add("vert_flip") << glu::VertexSource(vert.str());
476     }
477 
478     // The normal fragment shader uses 0 for the blue channel and an alternative one uses 1 in the blue channel, if needed.
479     std::map<std::string, float> shaderNameBlueMap;
480     shaderNameBlueMap["frag_normal"] = 0.0f;
481     if (m_params.useExecutionSet)
482         shaderNameBlueMap["frag_alt"] = 1.0f;
483 
484     for (const auto &kvPair : shaderNameBlueMap)
485     {
486         std::ostringstream frag;
487         frag << "#version 460\n"
488              << "layout (push_constant, std430) uniform PushConstantBlock {\n"
489              << "    float redValue;\n"
490              << (checkDrawParams ? "    int drawIndex;\n" : "") << (checkDrawParams ? "    int baseVertex;\n" : "")
491              << (checkDrawParams ? "    int baseInstance;\n" : "") << "} pc;\n"
492              << "layout (location=0) in flat int instanceIndex;\n"
493              << "layout (location=1) in flat float redOffset;\n"
494              << (checkDrawParams ? "layout (location=3) in flat int drawIndex;\n" : "")
495              << (checkDrawParams ? "layout (location=4) in flat int baseVertex;\n" : "")
496              << (checkDrawParams ? "layout (location=5) in flat int baseInstance;\n" : "")
497              << "layout (location=0) out vec4 outColor;\n"
498              << "void main (void) {\n"
499              << "    bool drawParamsOK = true;\n"
500              << (checkDrawParams ? "    drawParamsOK = (drawParamsOK && (drawIndex == pc.drawIndex));\n" : "")
501              << (checkDrawParams ? "    drawParamsOK = (drawParamsOK && (baseVertex == pc.baseVertex));\n" : "")
502              << (checkDrawParams ? "    drawParamsOK = (drawParamsOK && (baseInstance == pc.baseInstance));\n" : "")
503              << "    const float alphaValue = (drawParamsOK ? 1.0 : 0.0);\n"
504              << "    outColor = vec4(pc.redValue + redOffset, float(instanceIndex), " << kvPair.second
505              << ", alphaValue);\n"
506              << "}\n";
507         programCollection.glslSources.add(kvPair.first) << glu::FragmentSource(frag.str());
508     }
509 
510     if (m_params.extraStages == ExtraStages::GEOMETRY)
511     {
512         // We have to create one or two geometry shaders, depending on if we need to flip the first triangle.
513         std::map<std::string, bool> shaderNameFlipMap;
514         shaderNameFlipMap["geom_normal"] = false;
515         if (flipFirstTriangleHoriz)
516             shaderNameFlipMap["geom_flip"] = true;
517 
518         for (const auto &kvPair : shaderNameFlipMap)
519         {
520             const auto &shaderName = kvPair.first;
521             const auto flip        = kvPair.second;
522 
523             std::ostringstream geom;
524             geom << "#version 460\n"
525                  << "layout (triangles) in;\n"
526                  << "layout (triangle_strip, max_vertices=3) out;\n"
527                  << "in gl_PerVertex\n"
528                  << "{\n"
529                  << "    vec4 gl_Position;\n"
530                  << "} gl_in[3];\n"
531                  << "out gl_PerVertex\n"
532                  << "{\n"
533                  << "    vec4 gl_Position;\n"
534                  << "};\n"
535                  << "layout (location=0) in int inInstanceIndex[3];\n"
536                  << "layout (location=1) in float inRedOffset[3];\n"
537                  << (checkDrawParams ? "layout (location=3) in int inDrawIndex[3];\n" : "")
538                  << (checkDrawParams ? "layout (location=4) in int inBaseVertex[3];\n" : "")
539                  << (checkDrawParams ? "layout (location=5) in int inBaseInstance[3];\n" : "")
540                  << "layout (location=0) out flat int outInstanceIndex;\n"
541                  << "layout (location=1) out flat float outRedOffset;\n"
542                  << (checkDrawParams ? "layout (location=3) out flat int outDrawIndex;\n" : "")
543                  << (checkDrawParams ? "layout (location=4) out flat int outBaseVertex;\n" : "")
544                  << (checkDrawParams ? "layout (location=5) out flat int outBaseInstance;\n" : "")
545                  << (flip ? "layout (location=2) in float inXCoordFactor[3];\n" : "") << "void main() {\n"
546                  << "    for (int i = 0; i < 3; ++i) {\n"
547                  << "        const float xCoordFactor = " << (flip ? "inXCoordFactor[i]" : "1.0") << ";\n"
548                  << "        gl_Position = vec4(gl_in[i].gl_Position.x * xCoordFactor, gl_in[i].gl_Position.yzw);\n"
549                  << "        outInstanceIndex = inInstanceIndex[i];\n"
550                  << "        outRedOffset = inRedOffset[i];\n"
551                  << (checkDrawParams ? "        outDrawIndex = inDrawIndex[i];\n" : "")
552                  << (checkDrawParams ? "        outBaseVertex = inBaseVertex[i];\n" : "")
553                  << (checkDrawParams ? "        outBaseInstance = inBaseInstance[i];\n" : "")
554                  << "        EmitVertex();\n"
555                  << "    }\n"
556                  << "}\n";
557             programCollection.glslSources.add(shaderName) << glu::GeometrySource(geom.str());
558         }
559     }
560 
561     if (m_params.extraStages == ExtraStages::TESSELLATION)
562     {
563         // Same as in the geometry shader case.
564         std::map<std::string, bool> shaderNameFlipMap;
565         shaderNameFlipMap["tesc_normal"] = false;
566         if (flipFirstTriangleHoriz)
567             shaderNameFlipMap["tesc_flip"] = true;
568 
569         for (const auto &kvPair : shaderNameFlipMap)
570         {
571             const auto &shaderName = kvPair.first;
572             const auto flip        = kvPair.second;
573 
574             std::ostringstream tesc;
575             tesc << "#version 460\n"
576                  << "layout (vertices=3) out;\n"
577                  << "in gl_PerVertex\n"
578                  << "{\n"
579                  << "    vec4  gl_Position;\n"
580                  << "} gl_in[gl_MaxPatchVertices];\n"
581                  << "out gl_PerVertex\n"
582                  << "{\n"
583                  << "    vec4  gl_Position;\n"
584                  << "} gl_out[];\n"
585                  << "layout (location=0) in int inInstanceIndex[gl_MaxPatchVertices];\n"
586                  << "layout (location=1) in float inRedOffset[gl_MaxPatchVertices];\n"
587                  << (checkDrawParams ? "layout (location=3) in int inDrawIndex[gl_MaxPatchVertices];\n" : "")
588                  << (checkDrawParams ? "layout (location=4) in int inBaseVertex[gl_MaxPatchVertices];\n" : "")
589                  << (checkDrawParams ? "layout (location=5) in int inBaseInstance[gl_MaxPatchVertices];\n" : "")
590                  << "layout (location=0) out int outInstanceIndex[];\n"
591                  << "layout (location=1) out float outRedOffset[];\n"
592                  << (checkDrawParams ? "layout (location=3) out int outDrawIndex[];\n" : "")
593                  << (checkDrawParams ? "layout (location=4) out int outBaseVertex[];\n" : "")
594                  << (checkDrawParams ? "layout (location=5) out int outBaseInstance[];\n" : "")
595                  << (flip ? "layout (location=2) in float inXCoordFactor[gl_MaxPatchVertices];\n" : "")
596                  << "void main (void)\n"
597                  << "{\n"
598                  << "    const float xCoordFactor = " << (flip ? "inXCoordFactor[gl_InvocationID]" : "1.0") << ";\n"
599                  << "    gl_TessLevelInner[0] = 1.0;\n"
600                  << "    gl_TessLevelInner[1] = 1.0;\n"
601                  << "    gl_TessLevelOuter[0] = 1.0;\n"
602                  << "    gl_TessLevelOuter[1] = 1.0;\n"
603                  << "    gl_TessLevelOuter[2] = 1.0;\n"
604                  << "    gl_TessLevelOuter[3] = 1.0;\n"
605                  << "    gl_out[gl_InvocationID].gl_Position = vec4(gl_in[gl_InvocationID].gl_Position.x * "
606                     "xCoordFactor, gl_in[gl_InvocationID].gl_Position.yzw);\n"
607                  << "    outInstanceIndex[gl_InvocationID] = inInstanceIndex[gl_InvocationID];\n"
608                  << "    outRedOffset[gl_InvocationID] = inRedOffset[gl_InvocationID];\n"
609                  << (checkDrawParams ? "    outDrawIndex[gl_InvocationID] = inDrawIndex[gl_InvocationID];\n" : "")
610                  << (checkDrawParams ? "    outBaseVertex[gl_InvocationID] = inBaseVertex[gl_InvocationID];\n" : "")
611                  << (checkDrawParams ? "    outBaseInstance[gl_InvocationID] = inBaseInstance[gl_InvocationID];\n" : "")
612                  << "}\n";
613 
614             programCollection.glslSources.add(shaderName) << glu::TessellationControlSource(tesc.str());
615         }
616 
617         // Tessellation evaluation is always the same.
618         std::ostringstream tese;
619         tese << "#version 460\n"
620              << "layout (triangles, fractional_odd_spacing, cw) in;\n"
621              << "in gl_PerVertex\n"
622              << "{\n"
623              << "  vec4 gl_Position;\n"
624              << "} gl_in[gl_MaxPatchVertices];\n"
625              << "out gl_PerVertex\n"
626              << "{\n"
627              << "  vec4 gl_Position;\n"
628              << "};\n"
629              << "layout (location=0) in int inInstanceIndex[];\n"
630              << "layout (location=1) in float inRedOffset[];\n"
631              << (checkDrawParams ? "layout (location=3) in int inDrawIndex[];\n" : "")
632              << (checkDrawParams ? "layout (location=4) in int inBaseVertex[];\n" : "")
633              << (checkDrawParams ? "layout (location=5) in int inBaseInstance[];\n" : "")
634              << "layout (location=0) out flat int outInstanceIndex;\n"
635              << "layout (location=1) out flat float outRedOffset;\n"
636              << (checkDrawParams ? "layout (location=3) out flat int outDrawIndex;\n" : "")
637              << (checkDrawParams ? "layout (location=4) out flat int outBaseVertex;\n" : "")
638              << (checkDrawParams ? "layout (location=5) out flat int outBaseInstance;\n" : "") << "void main (void)\n"
639              << "{\n"
640              << "    gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) +\n"
641              << "                  (gl_TessCoord.y * gl_in[1].gl_Position) +\n"
642              << "                  (gl_TessCoord.z * gl_in[2].gl_Position);\n"
643              << "    outInstanceIndex = inInstanceIndex[0];\n"
644              << "    outRedOffset = inRedOffset[0];\n"
645              << (checkDrawParams ? "    outDrawIndex = inDrawIndex[0];\n" : "")
646              << (checkDrawParams ? "    outBaseVertex = inBaseVertex[0];\n" : "")
647              << (checkDrawParams ? "    outBaseInstance = inBaseInstance[0];\n" : "") << "}\n";
648 
649         programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(tese.str());
650     }
651 }
652 
653 // Generates float values for a color, given a starting point, a maximum value and a step.
654 // E.g. SequentialColorGenerator (start=128, max=255, step=2) generates 128/255, 130/255, 132/255, etc.
655 class SequentialColorGenerator
656 {
657 protected:
658     float m_current;
659     float m_max;
660     float m_step;
661 
662 public:
SequentialColorGenerator(uint32_t start,uint32_t max,uint32_t step)663     SequentialColorGenerator(uint32_t start, uint32_t max, uint32_t step)
664         : m_current(static_cast<float>(start))
665         , m_max(static_cast<float>(max))
666         , m_step(static_cast<float>(step))
667     {
668     }
669 
operator ()(void)670     float operator()(void)
671     {
672         const float gen = m_current / m_max;
673         m_current += m_step;
674         return gen;
675     }
676 };
677 
678 // Creates a shader module if the shader exists.
679 using ShaderWrapperPtr = std::unique_ptr<ShaderWrapper>;
680 
maybeCreateModule(const DeviceInterface & vkd,VkDevice device,const BinaryCollection & binaries,const std::string & name)681 ShaderWrapperPtr maybeCreateModule(const DeviceInterface &vkd, VkDevice device, const BinaryCollection &binaries,
682                                    const std::string &name)
683 {
684     ShaderWrapperPtr shaderPtr;
685 
686     if (binaries.contains(name))
687         shaderPtr.reset(new ShaderWrapper(vkd, device, binaries.get(name)));
688     else
689         shaderPtr.reset(new ShaderWrapper());
690 
691     return shaderPtr;
692 }
693 
maybeCreateShader(const DeviceInterface & vkd,VkDevice device,const BinaryCollection & binaries,const std::string & name,VkShaderStageFlagBits stage,const VkPushConstantRange * pcRange,bool tessFeature,bool geomFeature)694 DGCShaderExtPtr maybeCreateShader(const DeviceInterface &vkd, VkDevice device, const BinaryCollection &binaries,
695                                   const std::string &name, VkShaderStageFlagBits stage,
696                                   const VkPushConstantRange *pcRange, bool tessFeature, bool geomFeature)
697 {
698     DGCShaderExtPtr shaderPtr;
699     if (binaries.contains(name))
700     {
701         const std::vector<VkDescriptorSetLayout> setLayouts;
702 
703         std::vector<VkPushConstantRange> pcRanges;
704         if (pcRange)
705             pcRanges.push_back(*pcRange);
706 
707         shaderPtr.reset(new DGCShaderExt(vkd, device, stage, 0u, binaries.get(name), setLayouts, pcRanges, tessFeature,
708                                          geomFeature, nullptr, nullptr));
709     }
710     return shaderPtr;
711 }
712 
713 using BufferWithMemoryPtr = std::unique_ptr<BufferWithMemory>;
714 
715 struct VertexBufferInfo
716 {
717     BufferWithMemoryPtr buffer;
718     VkDeviceAddress address;
719     uint32_t size;
720     uint32_t stride;
721 
VertexBufferInfovkt::DGC::__anon47167f390111::VertexBufferInfo722     VertexBufferInfo() : buffer(), address(0ull), size(0u), stride(0u)
723     {
724     }
725 };
726 
makeVertexBuffers(const DeviceInterface & vkd,const VkDevice device,Allocator & allocator,const std::vector<tcu::Vec4> & vertices,uint32_t sequenceCount,uint32_t pixelCount)727 std::vector<VertexBufferInfo> makeVertexBuffers(const DeviceInterface &vkd, const VkDevice device, Allocator &allocator,
728                                                 const std::vector<tcu::Vec4> &vertices, uint32_t sequenceCount,
729                                                 uint32_t pixelCount)
730 {
731     // Return vector.
732     std::vector<VertexBufferInfo> ret;
733 
734     DE_ASSERT(sequenceCount == 1u || sequenceCount == 3u); // We don't know how to do more cases yet.
735 
736     const auto vertexBufferUsage   = (VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
737     const auto vertexBufferMemReqs = (MemoryRequirement::HostVisible | MemoryRequirement::DeviceAddress);
738     const auto vertexSize = static_cast<uint32_t>(sizeof(std::remove_reference<decltype(vertices)>::type::value_type));
739 
740     if (sequenceCount == 1u)
741     {
742         // Flat buffer containing all vertices.
743         const auto vertexBufferSize = static_cast<VkDeviceSize>(de::dataSize(vertices));
744         const auto vertexBufferInfo = makeBufferCreateInfo(vertexBufferSize, vertexBufferUsage);
745         BufferWithMemoryPtr vertexBuffer(
746             new BufferWithMemory(vkd, device, allocator, vertexBufferInfo, vertexBufferMemReqs));
747 
748         auto &vertexBufferAlloc = vertexBuffer->getAllocation();
749         void *vertexBufferData  = vertexBufferAlloc.getHostPtr();
750 
751         deMemcpy(vertexBufferData, de::dataOrNull(vertices), de::dataSize(vertices));
752 
753         ret.resize(1u);
754         auto &bufferInfo = ret.at(0u);
755 
756         bufferInfo.buffer.reset(vertexBuffer.release());
757         bufferInfo.address = getBufferDeviceAddress(vkd, device, bufferInfo.buffer->get());
758         bufferInfo.size    = static_cast<uint32_t>(vertexBufferSize);
759         bufferInfo.stride  = vertexSize;
760     }
761     else
762     {
763         // Vertex buffers: one per sequence, with the first one containing the
764         // first triangle and the last one containg the last triangle.
765         std::vector<BufferWithMemoryPtr> vertexBuffers(sequenceCount);
766 
767         const auto vtxBufferStrideNormal = vertexSize;
768         const auto vtxBufferStrideWide   = vtxBufferStrideNormal * 2u;
769 
770         const std::vector<uint32_t> vertexBufferSizes{
771             vtxBufferStrideNormal * kPerTriangleVertices,
772             vtxBufferStrideWide * kPerTriangleVertices * (pixelCount - 2u), // Wider stride and 2 triangles.
773             vtxBufferStrideNormal * kPerTriangleVertices * pixelCount,      // Large vertex offset.
774         };
775 
776         const std::vector<uint32_t> vertexBufferStrides{
777             vtxBufferStrideNormal,
778             vtxBufferStrideWide, // The second vertex buffer has a wider stride. See long comment above.
779             vtxBufferStrideNormal,
780         };
781 
782         for (uint32_t i = 0u; i < sequenceCount; ++i)
783         {
784             const auto vertexBufferCreateInfo = makeBufferCreateInfo(vertexBufferSizes.at(i), vertexBufferUsage);
785             vertexBuffers.at(i).reset(
786                 new BufferWithMemory(vkd, device, allocator, vertexBufferCreateInfo, vertexBufferMemReqs));
787         }
788 
789         // Device addresses for the vertex buffers.
790         std::vector<VkDeviceAddress> vertexBufferAddresses;
791         vertexBufferAddresses.reserve(vertexBuffers.size());
792         std::transform(begin(vertexBuffers), end(vertexBuffers), std::back_inserter(vertexBufferAddresses),
793                        [&vkd, &device](const BufferWithMemoryPtr &vtxBuffer)
794                        { return getBufferDeviceAddress(vkd, device, vtxBuffer->get()); });
795 
796         std::vector<tcu::Vec4 *> vertexBufferDataPtrs;
797         vertexBufferDataPtrs.reserve(vertexBuffers.size());
798         std::transform(begin(vertexBuffers), end(vertexBuffers), std::back_inserter(vertexBufferDataPtrs),
799                        [](const BufferWithMemoryPtr &bufferPtr)
800                        { return reinterpret_cast<tcu::Vec4 *>(bufferPtr->getAllocation().getHostPtr()); });
801 
802         const tcu::Vec4 zeroedVertex(0.0f, 0.0f, 0.0f, 0.0f);
803 
804         // First vertex buffer.
805         uint32_t nextVertex = 0u;
806         for (uint32_t i = 0u; i < kPerTriangleVertices; ++i)
807             vertexBufferDataPtrs.at(0u)[i] = vertices.at(nextVertex++);
808 
809         // Second vertex buffer.
810         {
811             uint32_t nextPos = 0u;
812             for (uint32_t i = 0u; i < pixelCount - 2u /*remove the first and last triangles*/; ++i)
813                 for (uint32_t j = 0u; j < kPerTriangleVertices; ++j)
814                 {
815                     vertexBufferDataPtrs.at(1u)[nextPos++] = vertices.at(nextVertex++);
816                     vertexBufferDataPtrs.at(1u)[nextPos++] =
817                         zeroedVertex; // Padding between vertices for the wider stride.
818                 }
819         }
820 
821         // Third vertex buffer.
822         {
823             uint32_t nextPos = 0u;
824 
825             // Padding at the beginning.
826             for (uint32_t i = 0u; i < nextVertex; ++i)
827                 vertexBufferDataPtrs.at(2u)[nextPos++] = zeroedVertex;
828 
829             // Vertices for triangle D.
830             for (uint32_t i = 0u; i < kPerTriangleVertices; ++i)
831                 vertexBufferDataPtrs.at(2u)[nextPos++] = vertices.at(nextVertex++);
832         }
833 
834         // Prepare return vector.
835         ret.resize(sequenceCount);
836 
837         for (uint32_t i = 0u; i < sequenceCount; ++i)
838         {
839             auto &bufferInfo = ret.at(i);
840 
841             bufferInfo.buffer.reset(vertexBuffers.at(i).release());
842             bufferInfo.address = vertexBufferAddresses.at(i);
843             bufferInfo.size    = vertexBufferSizes.at(i);
844             bufferInfo.stride  = vertexBufferStrides.at(i);
845         }
846     }
847 
848     return ret;
849 }
850 
851 struct IndexBufferInfo
852 {
853     BufferWithMemoryPtr buffer;
854     VkDeviceAddress address;
855     uint32_t size;
856     VkIndexType indexType;
857     int32_t vertexOffset;
858 };
859 
makeIndexBuffers(const DeviceInterface & vkd,const VkDevice device,Allocator & allocator,uint32_t sequenceCount,uint32_t pixelCount)860 std::vector<IndexBufferInfo> makeIndexBuffers(const DeviceInterface &vkd, const VkDevice device, Allocator &allocator,
861                                               uint32_t sequenceCount, uint32_t pixelCount)
862 {
863     DE_ASSERT(sequenceCount == 0u || sequenceCount == 3u);
864 
865     std::vector<IndexBufferInfo> ret;
866     if (sequenceCount == 0u)
867         return ret;
868 
869     const auto indexBufferUsage   = (VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT);
870     const auto indexBufferMemReqs = (MemoryRequirement::HostVisible | MemoryRequirement::DeviceAddress);
871 
872     // Buffer contents.
873     constexpr uint16_t kInvalidIndex16 = std::numeric_limits<uint16_t>::max() / uint16_t{2};
874     const uint32_t indexCountMiddle    = (pixelCount - 2u) * kPerTriangleVertices;
875 
876     std::vector<uint32_t> firstBuffer;
877     firstBuffer.reserve(kPerTriangleVertices);
878     for (uint32_t i = 0u; i < kPerTriangleVertices; ++i)
879         firstBuffer.push_back(i);
880 
881     std::vector<uint32_t> secondBuffer;
882     secondBuffer.reserve(indexCountMiddle);
883     for (uint32_t i = 0u; i < indexCountMiddle; ++i)
884         secondBuffer.push_back(i + kPerTriangleVertices);
885 
886     std::vector<uint16_t> thirdBuffer;
887     thirdBuffer.reserve(pixelCount * kPerTriangleVertices);
888 
889     const uint32_t prevVertexCount = (pixelCount - 1u) * kPerTriangleVertices;
890     const uint16_t vertexOffset    = 20;
891 
892     for (uint32_t i = 0u; i < prevVertexCount; ++i)
893         thirdBuffer.push_back(kInvalidIndex16);
894     for (uint32_t i = 0u; i < kPerTriangleVertices; ++i)
895         thirdBuffer.push_back(static_cast<uint16_t>(i + prevVertexCount + vertexOffset));
896 
897     // Data pointers.
898     const std::vector<void *> bufferDataPtrs{
899         de::dataOrNull(firstBuffer),
900         de::dataOrNull(secondBuffer),
901         de::dataOrNull(thirdBuffer),
902     };
903 
904     // Buffer sizes.
905     const std::vector<uint32_t> bufferSizes{
906         static_cast<uint32_t>(de::dataSize(firstBuffer)),
907         static_cast<uint32_t>(de::dataSize(secondBuffer)),
908         static_cast<uint32_t>(de::dataSize(thirdBuffer)),
909     };
910 
911     // Index types.
912     const std::vector<VkIndexType> indexTypes{
913         VK_INDEX_TYPE_UINT32,
914         VK_INDEX_TYPE_UINT32,
915         VK_INDEX_TYPE_UINT16,
916     };
917 
918     // Actual buffers.
919     std::vector<BufferWithMemoryPtr> indexBuffers;
920     indexBuffers.reserve(sequenceCount);
921     for (uint32_t i = 0u; i < sequenceCount; ++i)
922     {
923         const auto createInfo = makeBufferCreateInfo(static_cast<VkDeviceSize>(bufferSizes.at(i)), indexBufferUsage);
924         indexBuffers.emplace_back(new BufferWithMemory(vkd, device, allocator, createInfo, indexBufferMemReqs));
925 
926         auto &alloc   = indexBuffers.back()->getAllocation();
927         void *dataPtr = alloc.getHostPtr();
928         deMemcpy(dataPtr, bufferDataPtrs.at(i), static_cast<size_t>(bufferSizes.at(i)));
929         flushAlloc(vkd, device, alloc);
930     }
931 
932     // Device addresses.
933     std::vector<VkDeviceAddress> addresses;
934     addresses.reserve(sequenceCount);
935 
936     for (uint32_t i = 0u; i < sequenceCount; ++i)
937         addresses.push_back(getBufferDeviceAddress(vkd, device, indexBuffers.at(i)->get()));
938 
939     // Vertex offsets.
940     const std::vector<int32_t> vertexOffsets{0, 0, -vertexOffset};
941 
942     ret.resize(sequenceCount);
943 
944     for (uint32_t i = 0u; i < sequenceCount; ++i)
945     {
946         auto &bufferInfo = ret.at(i);
947 
948         bufferInfo.buffer.reset(indexBuffers.at(i).release());
949         bufferInfo.address      = addresses.at(i);
950         bufferInfo.size         = bufferSizes.at(i);
951         bufferInfo.indexType    = indexTypes.at(i);
952         bufferInfo.vertexOffset = vertexOffsets.at(i);
953     }
954 
955     return ret;
956 }
957 
iterate(void)958 tcu::TestStatus DGCDrawInstance::iterate(void)
959 {
960     const auto ctx = m_context.getContextCommonData();
961     const tcu::IVec3 fbExtent(2, 2, 1);
962     const tcu::Vec3 floatExtent = fbExtent.asFloat();
963     const auto pixelCountI      = fbExtent.x() * fbExtent.y() * fbExtent.z();
964     const auto vkExtent         = makeExtent3D(fbExtent);
965     const auto pixelCountU      = vkExtent.width * vkExtent.height * vkExtent.depth;
966     const auto colorFormat      = VK_FORMAT_R8G8B8A8_UNORM;
967     const auto colorUsage =
968         (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
969     const auto sequenceCount = 3u;
970     const auto stageFlags    = m_params.getStageFlags();
971     const auto bindPoint     = VK_PIPELINE_BIND_POINT_GRAPHICS;
972 
973     // Color buffer.
974     ImageWithBuffer colorBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage,
975                                 VK_IMAGE_TYPE_2D);
976 
977     // Vertex data: 1 triangle per pixel.
978     std::vector<tcu::Vec4> vertices;
979     vertices.reserve(pixelCountI * kPerTriangleVertices);
980 
981     const float pixWidth  = 2.0f / floatExtent.x();
982     const float pixHeight = 2.0f / floatExtent.y();
983     const float horMargin = pixWidth / 4.0f;
984     const float verMargin = pixHeight / 4.0f;
985 
986     for (int y = 0; y < fbExtent.y(); ++y)
987         for (int x = 0; x < fbExtent.x(); ++x)
988         {
989             const float xCenter = ((static_cast<float>(x) + 0.5f) / floatExtent.x() * 2.0f) - 1.0f;
990             const float yCenter = ((static_cast<float>(y) + 0.5f) / floatExtent.y() * 2.0f) - 1.0f;
991 
992             vertices.emplace_back(xCenter - horMargin, yCenter + verMargin, 0.0f, 1.0f);
993             vertices.emplace_back(xCenter + horMargin, yCenter + verMargin, 0.0f, 1.0f);
994             vertices.emplace_back(xCenter, yCenter - verMargin, 0.0f, 1.0f);
995         }
996 
997     // Create vertex and index buffers.
998     const auto vertSeqCount  = (m_params.testType == TestType::DRAW ? sequenceCount : 1u);
999     const auto indexSeqCount = (isIndexed(m_params.testType) ? sequenceCount : 0u);
1000 
1001     const auto vertexBuffers =
1002         makeVertexBuffers(ctx.vkd, ctx.device, ctx.allocator, vertices, vertSeqCount, pixelCountU);
1003     const auto indexBuffers = makeIndexBuffers(ctx.vkd, ctx.device, ctx.allocator, indexSeqCount, pixelCountU);
1004 
1005     // Push constants.
1006     const auto drawParamsCount = (m_params.checkDrawParams ? 3u /*DrawIndex, BaseVertex, BaseInstance*/ : 0u);
1007     const auto pcStages        = (VK_SHADER_STAGE_FRAGMENT_BIT);
1008     const auto pcSize          = DE_SIZEOF32(float) + // Must match fragment shader.
1009                         drawParamsCount * DE_SIZEOF32(int32_t);
1010     const auto pcRange = makePushConstantRange(pcStages, 0u, pcSize);
1011 
1012     // Pipeline layout. Note the wrapper only needs to know if it uses shader objects or not. The specific type is not
1013     // important as long as the category is correct.
1014     PipelineLayoutWrapper pipelineLayout((m_params.isShaderObjects() ?
1015                                               PIPELINE_CONSTRUCTION_TYPE_SHADER_OBJECT_UNLINKED_SPIRV :
1016                                               PIPELINE_CONSTRUCTION_TYPE_MONOLITHIC),
1017                                          ctx.vkd, ctx.device, VK_NULL_HANDLE, &pcRange);
1018 
1019     const uint32_t randomSeed =
1020         ((static_cast<uint32_t>(m_params.extraStages) << 24) | (static_cast<uint32_t>(m_params.checkDrawParams) << 16) |
1021          (static_cast<uint32_t>(m_params.useExecutionSet) << 15));
1022     de::Random rnd(randomSeed);
1023 
1024     // Indirect commands layout.
1025     VkIndirectCommandsLayoutUsageFlagsEXT layoutFlags = 0u;
1026     if (m_params.doPreprocess())
1027         layoutFlags |= VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_EXT;
1028     if (m_params.unorderedSequences)
1029         layoutFlags |= VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_EXT;
1030 
1031     IndirectCommandsLayoutBuilderExt cmdsLayoutBuilder(layoutFlags, stageFlags, *pipelineLayout);
1032     if (m_params.useExecutionSet)
1033     {
1034         const auto infoType = (m_params.isShaderObjects() ? VK_INDIRECT_EXECUTION_SET_INFO_TYPE_SHADER_OBJECTS_EXT :
1035                                                             VK_INDIRECT_EXECUTION_SET_INFO_TYPE_PIPELINES_EXT);
1036         cmdsLayoutBuilder.addExecutionSetToken(0u, infoType, stageFlags);
1037     }
1038 
1039     const bool pcFirst = rnd.getBool();
1040 
1041     if (pcFirst)
1042         cmdsLayoutBuilder.addPushConstantToken(cmdsLayoutBuilder.getStreamRange(), pcRange);
1043 
1044     if (m_params.testType == TestType::DRAW)
1045     {
1046         cmdsLayoutBuilder.addVertexBufferToken(cmdsLayoutBuilder.getStreamRange(), 0u);
1047     }
1048     else if (isIndexed(m_params.testType))
1049     {
1050         const auto mode = m_params.getInputModeFlags();
1051         {
1052             constexpr auto kBitCount = sizeof(VkIndirectCommandsInputModeFlagsEXT) * 8u;
1053             const std::bitset<kBitCount> bitMask(mode);
1054             DE_UNREF(bitMask); // For release mode.
1055             DE_ASSERT(bitMask.count() == 1u);
1056         }
1057         const auto modeBits = static_cast<VkIndirectCommandsInputModeFlagBitsEXT>(mode);
1058         cmdsLayoutBuilder.addIndexBufferToken(cmdsLayoutBuilder.getStreamRange(), modeBits);
1059     }
1060     else if (m_params.testType == TestType::DRAW_SIMPLE)
1061         ; // No vertex or index buffer tokens.
1062     else
1063         DE_ASSERT(false);
1064 
1065     if (!pcFirst)
1066         cmdsLayoutBuilder.addPushConstantToken(cmdsLayoutBuilder.getStreamRange(), pcRange);
1067 
1068     if (m_params.testType == TestType::DRAW || m_params.testType == TestType::DRAW_SIMPLE)
1069         cmdsLayoutBuilder.addDrawToken(cmdsLayoutBuilder.getStreamRange());
1070     else if (isIndexed(m_params.testType))
1071         cmdsLayoutBuilder.addDrawIndexedToken(cmdsLayoutBuilder.getStreamRange());
1072     else
1073         DE_ASSERT(false);
1074 
1075     const auto cmdsLayout = cmdsLayoutBuilder.build(ctx.vkd, ctx.device);
1076 
1077     // Device-generated commands data.
1078     std::vector<uint32_t> dgcData;
1079     dgcData.reserve((sequenceCount * cmdsLayoutBuilder.getStreamStride()) / sizeof(uint32_t));
1080 
1081     // Red color values.
1082     SequentialColorGenerator colorGenerator(128u, 255u, 5u);
1083     std::vector<float> redValues(sequenceCount, -1.0f);
1084     std::generate(begin(redValues), end(redValues), colorGenerator);
1085 
1086     // Draw commands.
1087     const auto middleVertexCount = (pixelCountU - 2u) * kPerTriangleVertices;    // For the second sequence.
1088     const auto firstVertexAtEnd  = de::sizeU32(vertices) - kPerTriangleVertices; // First vertex for the final sequence.
1089 
1090     std::vector<VkDrawIndirectCommand> drawCmds;
1091     std::vector<VkDrawIndexedIndirectCommand> drawIndexedCmds;
1092 
1093     if (m_params.testType == TestType::DRAW)
1094     {
1095         drawCmds.reserve(sequenceCount);
1096 
1097         // For the rationale behind these numbers, see the explanation above. The idea is to vary every number.
1098         drawCmds.push_back(VkDrawIndirectCommand{kPerTriangleVertices, 1u, 0u, 0u});
1099         drawCmds.push_back(VkDrawIndirectCommand{middleVertexCount, 1u, 0u, 1u});
1100         drawCmds.push_back(VkDrawIndirectCommand{kPerTriangleVertices, 2u, firstVertexAtEnd, 0u});
1101     }
1102     else if (m_params.testType == TestType::DRAW_SIMPLE)
1103     {
1104         drawCmds.reserve(sequenceCount);
1105 
1106         // Alternative to the one above with a single vertex buffer, so the middle draw uses a different firstVertex.
1107         drawCmds.push_back(VkDrawIndirectCommand{kPerTriangleVertices, 1u, 0u, 0u});
1108         drawCmds.push_back(VkDrawIndirectCommand{middleVertexCount, 1u, kPerTriangleVertices, 1u});
1109         drawCmds.push_back(VkDrawIndirectCommand{kPerTriangleVertices, 2u, firstVertexAtEnd, 0u});
1110     }
1111     else if (isIndexed(m_params.testType))
1112     {
1113         drawIndexedCmds.reserve(sequenceCount);
1114 
1115         const std::vector<int32_t> offsets{
1116             indexBuffers.at(0).vertexOffset,
1117             indexBuffers.at(1).vertexOffset,
1118             indexBuffers.at(2).vertexOffset,
1119         };
1120 
1121         // For the rationale behind these numbers, see the explanation above. The idea is to vary every number.
1122         drawIndexedCmds.push_back(VkDrawIndexedIndirectCommand{kPerTriangleVertices, 1u, 0u, offsets.at(0), 0u});
1123         drawIndexedCmds.push_back(VkDrawIndexedIndirectCommand{middleVertexCount, 1u, 0u, offsets.at(1), 1u});
1124         drawIndexedCmds.push_back(
1125             VkDrawIndexedIndirectCommand{kPerTriangleVertices, 2u, firstVertexAtEnd, offsets.at(2), 0u});
1126     }
1127     else
1128         DE_ASSERT(false);
1129 
1130     std::vector<VkBindVertexBufferIndirectCommandEXT> bindVertexBufferCmds;
1131     std::vector<VkBindIndexBufferIndirectCommandEXT> bindIndexBufferCmds;
1132 
1133     if (m_params.testType == TestType::DRAW)
1134     {
1135         bindVertexBufferCmds.reserve(sequenceCount);
1136 
1137         for (uint32_t i = 0u; i < sequenceCount; ++i)
1138         {
1139             bindVertexBufferCmds.emplace_back(VkBindVertexBufferIndirectCommandEXT{
1140                 vertexBuffers.at(i).address,
1141                 vertexBuffers.at(i).size,
1142                 vertexBuffers.at(i).stride,
1143             });
1144         }
1145     }
1146     else if (isIndexed(m_params.testType))
1147     {
1148         bindIndexBufferCmds.reserve(sequenceCount);
1149 
1150         for (uint32_t i = 0u; i < sequenceCount; ++i)
1151         {
1152             if (m_params.testType == TestType::DRAW_INDEXED)
1153             {
1154                 bindIndexBufferCmds.emplace_back(VkBindIndexBufferIndirectCommandEXT{
1155                     indexBuffers.at(i).address,
1156                     indexBuffers.at(i).size,
1157                     indexBuffers.at(i).indexType,
1158                 });
1159             }
1160             else
1161             {
1162                 IndexBufferViewD3D12 cmd(indexBuffers.at(i).address, indexBuffers.at(i).size,
1163                                          indexBuffers.at(i).indexType);
1164                 pushBackElement(bindIndexBufferCmds, cmd);
1165             }
1166         }
1167     }
1168     else if (m_params.testType == TestType::DRAW_SIMPLE)
1169         ; // No vertex or index buffer bind tokens.
1170     else
1171         DE_ASSERT(false);
1172 
1173     // Closure to avoid code duplication.
1174     const auto pushPushConstants = [&dgcData, &redValues, &drawCmds, &drawIndexedCmds, this](uint32_t i)
1175     {
1176         pushBackElement(dgcData, redValues.at(i));
1177         if (this->m_params.checkDrawParams)
1178         {
1179             pushBackElement(dgcData, static_cast<int32_t>(0)); // For non-count commands, DrawIndex stays at 0.
1180 
1181             const auto &testType = this->m_params.testType;
1182 
1183             if (testType == TestType::DRAW || testType == TestType::DRAW_SIMPLE)
1184             {
1185                 pushBackElement(dgcData, drawCmds.at(i).firstVertex);
1186                 pushBackElement(dgcData, drawCmds.at(i).firstInstance);
1187             }
1188             else if (isIndexed(this->m_params.testType))
1189             {
1190                 pushBackElement(dgcData, drawIndexedCmds.at(i).vertexOffset);
1191                 pushBackElement(dgcData, drawIndexedCmds.at(i).firstInstance);
1192             }
1193             else
1194                 DE_ASSERT(false);
1195         }
1196     };
1197 
1198     // Rationale behind execution sets
1199     //
1200     // For pipelines, we'll create a different pipeline per sequence with the
1201     // right shaders, and store them in order in the execution set. This means
1202     // sequence i will use element i in the execution set.
1203     //
1204     // For shader objects, the execution set will contain 2 vertex shaders and 2
1205     // fragment shaders (plus optionally 2 tessellation control shaders and 1
1206     // tessellation evaluation shader, or 2 geometry shaders). For stages with 2
1207     // shaders, the first one will be the "normal" one and the second one will
1208     // be the "alternative" one, so in each sequence we need a different set of
1209     // numbers that will match what we'll be using for pipelines, which means,
1210     // per stage:
1211     //
1212     // vert: 1 1 0 (flip, flip, normal)
1213     // tesc: 1 1 0 (flip, flip, normal)
1214     // tese: 0 0 0 (we only have 1)
1215     // geom: 1 1 0 (flip, flip, normal)
1216     // frag: 0 1 1 (normal, alt, alt)
1217     //
1218     // However, as each shader needs to have a unique index, we'll offset those
1219     // values by a base value calculated according to the stages we will be
1220     // using.
1221     //
1222     // Also, in the indirect commands buffer, the indices for a sequence need to
1223     // appear in the order of the stages in the pipeline.
1224     //
1225 
1226     // Base unique indices for each stage.
1227     const auto invalidIndex  = std::numeric_limits<uint32_t>::max() / 2u; // Divided by 2 to avoid overflows.
1228     const auto vertBaseIndex = 0u;
1229     const auto fragBaseIndex = 2u;
1230     auto tescBaseIndex       = invalidIndex;
1231     auto teseBaseIndex       = invalidIndex;
1232     auto geomBaseIndex       = invalidIndex;
1233 
1234     if (m_params.extraStages == ExtraStages::TESSELLATION)
1235     {
1236         tescBaseIndex = 4u;
1237         teseBaseIndex = 6u;
1238     }
1239     if (m_params.extraStages == ExtraStages::GEOMETRY)
1240         geomBaseIndex = 4u;
1241 
1242     const std::vector<uint32_t> vertIndicesESO{vertBaseIndex + 1u, vertBaseIndex + 1u, vertBaseIndex + 0u};
1243     const std::vector<uint32_t> tescIndicesESO{tescBaseIndex + 1u, tescBaseIndex + 1u, tescBaseIndex + 0u};
1244     const std::vector<uint32_t> teseIndicesESO{teseBaseIndex + 0u, teseBaseIndex + 0u, teseBaseIndex + 0u};
1245     const std::vector<uint32_t> geomIndicesESO{geomBaseIndex + 1u, geomBaseIndex + 1u, geomBaseIndex + 0u};
1246     const std::vector<uint32_t> fragIndicesESO{fragBaseIndex + 0u, fragBaseIndex + 1u, fragBaseIndex + 1u};
1247 
1248     for (uint32_t i = 0u; i < sequenceCount; ++i)
1249     {
1250         if (m_params.useExecutionSet)
1251         {
1252             if (m_params.isShaderObjects())
1253             {
1254                 pushBackElement(dgcData, vertIndicesESO.at(i));
1255                 if (m_params.extraStages == ExtraStages::TESSELLATION)
1256                 {
1257                     pushBackElement(dgcData, tescIndicesESO.at(i));
1258                     pushBackElement(dgcData, teseIndicesESO.at(i));
1259                 }
1260                 if (m_params.extraStages == ExtraStages::GEOMETRY)
1261                     pushBackElement(dgcData, geomIndicesESO.at(i));
1262                 pushBackElement(dgcData, fragIndicesESO.at(i));
1263             }
1264             else
1265                 pushBackElement(dgcData, i);
1266         }
1267 
1268         if (pcFirst)
1269             pushPushConstants(i);
1270 
1271         if (m_params.testType == TestType::DRAW)
1272             pushBackElement(dgcData, bindVertexBufferCmds.at(i));
1273         else if (isIndexed(m_params.testType))
1274             pushBackElement(dgcData, bindIndexBufferCmds.at(i));
1275         else if (m_params.testType == TestType::DRAW_SIMPLE)
1276             ; // No vertex or index buffer bind tokens.
1277         else
1278             DE_ASSERT(false);
1279 
1280         if (!pcFirst)
1281             pushPushConstants(i);
1282 
1283         if (m_params.testType == TestType::DRAW || m_params.testType == TestType::DRAW_SIMPLE)
1284             pushBackElement(dgcData, drawCmds.at(i));
1285         else if (isIndexed(m_params.testType))
1286             pushBackElement(dgcData, drawIndexedCmds.at(i));
1287         else
1288             DE_ASSERT(false);
1289     }
1290 
1291     // Buffer holding the device-generated commands.
1292     const auto dgcBufferSize = static_cast<VkDeviceSize>(de::dataSize(dgcData));
1293     DGCBuffer dgcBuffer(ctx.vkd, ctx.device, ctx.allocator, dgcBufferSize);
1294 
1295     auto &dgcBufferAlloc   = dgcBuffer.getAllocation();
1296     void *dgcBufferDataPtr = dgcBufferAlloc.getHostPtr();
1297 
1298     deMemcpy(dgcBufferDataPtr, de::dataOrNull(dgcData), de::dataSize(dgcData));
1299     flushAlloc(ctx.vkd, ctx.device, dgcBufferAlloc);
1300 
1301     // Prepare single pipeline, shaders or indirect execution set.
1302     const auto &binaries = m_context.getBinaryCollection();
1303 
1304     ShaderWrapperPtr vertNormal;
1305     ShaderWrapperPtr vertFlip;
1306     ShaderWrapperPtr tescNormal;
1307     ShaderWrapperPtr tescFlip;
1308     ShaderWrapperPtr tese;
1309     ShaderWrapperPtr geomNormal;
1310     ShaderWrapperPtr geomFlip;
1311     ShaderWrapperPtr fragNormal;
1312     ShaderWrapperPtr fragAlt;
1313 
1314     DGCShaderExtPtr vertNormalShader;
1315     DGCShaderExtPtr vertFlipShader;
1316     DGCShaderExtPtr tescNormalShader;
1317     DGCShaderExtPtr tescFlipShader;
1318     DGCShaderExtPtr teseShader;
1319     DGCShaderExtPtr geomNormalShader;
1320     DGCShaderExtPtr geomFlipShader;
1321     DGCShaderExtPtr fragNormalShader;
1322     DGCShaderExtPtr fragAltShader;
1323 
1324     const auto &meshFeatures = m_context.getMeshShaderFeaturesEXT();
1325     const auto &features     = m_context.getDeviceFeatures();
1326 
1327     const auto tessFeature = (features.tessellationShader == VK_TRUE);
1328     const auto geomFeature = (features.geometryShader == VK_TRUE);
1329 
1330     if (m_params.isShaderObjects())
1331     {
1332         vertNormalShader = maybeCreateShader(ctx.vkd, ctx.device, binaries, "vert_normal", VK_SHADER_STAGE_VERTEX_BIT,
1333                                              nullptr, tessFeature, geomFeature);
1334         vertFlipShader   = maybeCreateShader(ctx.vkd, ctx.device, binaries, "vert_flip", VK_SHADER_STAGE_VERTEX_BIT,
1335                                              nullptr, tessFeature, geomFeature);
1336         tescNormalShader =
1337             maybeCreateShader(ctx.vkd, ctx.device, binaries, "tesc_normal", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
1338                               nullptr, tessFeature, geomFeature);
1339         tescFlipShader   = maybeCreateShader(ctx.vkd, ctx.device, binaries, "tesc_flip",
1340                                              VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, nullptr, tessFeature, geomFeature);
1341         teseShader       = maybeCreateShader(ctx.vkd, ctx.device, binaries, "tese",
1342                                              VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, nullptr, tessFeature, geomFeature);
1343         geomNormalShader = maybeCreateShader(ctx.vkd, ctx.device, binaries, "geom_normal", VK_SHADER_STAGE_GEOMETRY_BIT,
1344                                              nullptr, tessFeature, geomFeature);
1345         geomFlipShader   = maybeCreateShader(ctx.vkd, ctx.device, binaries, "geom_flip", VK_SHADER_STAGE_GEOMETRY_BIT,
1346                                              nullptr, tessFeature, geomFeature);
1347         fragNormalShader = maybeCreateShader(ctx.vkd, ctx.device, binaries, "frag_normal", VK_SHADER_STAGE_FRAGMENT_BIT,
1348                                              &pcRange, tessFeature, geomFeature);
1349         fragAltShader    = maybeCreateShader(ctx.vkd, ctx.device, binaries, "frag_alt", VK_SHADER_STAGE_FRAGMENT_BIT,
1350                                              &pcRange, tessFeature, geomFeature);
1351     }
1352     else
1353     {
1354         vertNormal = maybeCreateModule(ctx.vkd, ctx.device, binaries, "vert_normal");
1355         vertFlip   = maybeCreateModule(ctx.vkd, ctx.device, binaries, "vert_flip");
1356         tescNormal = maybeCreateModule(ctx.vkd, ctx.device, binaries, "tesc_normal");
1357         tescFlip   = maybeCreateModule(ctx.vkd, ctx.device, binaries, "tesc_flip");
1358         tese       = maybeCreateModule(ctx.vkd, ctx.device, binaries, "tese");
1359         geomNormal = maybeCreateModule(ctx.vkd, ctx.device, binaries, "geom_normal");
1360         geomFlip   = maybeCreateModule(ctx.vkd, ctx.device, binaries, "geom_flip");
1361         fragNormal = maybeCreateModule(ctx.vkd, ctx.device, binaries, "frag_normal");
1362         fragAlt    = maybeCreateModule(ctx.vkd, ctx.device, binaries, "frag_alt");
1363     }
1364 
1365     Move<VkRenderPass> renderPass;
1366     Move<VkFramebuffer> framebuffer;
1367 
1368     if (!m_params.isShaderObjects())
1369     {
1370         renderPass  = makeRenderPass(ctx.vkd, ctx.device, colorFormat);
1371         framebuffer = makeFramebuffer(ctx.vkd, ctx.device, *renderPass, colorBuffer.getImageView(), vkExtent.width,
1372                                       vkExtent.height);
1373     }
1374 
1375     const std::vector<VkViewport> viewports(1u, makeViewport(vkExtent));
1376     const std::vector<VkRect2D> scissors(1u, makeRect2D(vkExtent));
1377 
1378     const bool hasTessellation = (m_params.extraStages == ExtraStages::TESSELLATION);
1379     const auto primitiveTopology =
1380         (hasTessellation ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
1381     const auto patchControlPoints = (hasTessellation ? 3u : 0u);
1382 
1383     Move<VkPipeline> normalPipeline;
1384 
1385     using GraphicsPipelineWrapperPtr = std::unique_ptr<GraphicsPipelineWrapper>;
1386     std::vector<GraphicsPipelineWrapperPtr> dgcPipelines;
1387 
1388     const auto vertexBinding =
1389         makeVertexInputBindingDescription(0u, 0u /*stride will come from DGC*/, VK_VERTEX_INPUT_RATE_VERTEX);
1390     const auto vertexAttrib = makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u);
1391 
1392     const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
1393         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
1394         nullptr,                                                   // const void* pNext;
1395         0u,                                                        // VkPipelineVertexInputStateCreateFlags flags;
1396         1u,                                                        // uint32_t vertexBindingDescriptionCount;
1397         &vertexBinding, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
1398         1u,             // uint32_t vertexAttributeDescriptionCount;
1399         &vertexAttrib,  // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
1400     };
1401 
1402     const std::vector<VkDynamicState> dynamicStates{VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE};
1403 
1404     const VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo = {
1405         VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
1406         nullptr,                                              // const void* pNext;
1407         0u,                                                   // VkPipelineDynamicStateCreateFlags flags;
1408         de::sizeU32(dynamicStates),                           // uint32_t dynamicStateCount;
1409         de::dataOrNull(dynamicStates),                        // const VkDynamicState* pDynamicStates;
1410     };
1411 
1412     // Prepare indirect execution set at the same time as the pipelines.
1413     ExecutionSetManagerPtr executionSetManager;
1414 
1415     if (m_params.useExecutionSet)
1416     {
1417         if (m_params.isShaderObjects())
1418         {
1419             const std::vector<VkDescriptorSetLayout> noSetLayouts; // No set layouts being used in these tests.
1420             std::vector<IESStageInfo> stageInfos;
1421             uint32_t maxShaderCount = 0u;
1422 
1423             stageInfos.reserve(5u); // Potentially vert, tesc, tese, geom, frag.
1424 
1425             const auto addStage = [&maxShaderCount, &stageInfos, &noSetLayouts](VkShaderEXT shader, uint32_t maxShaders)
1426             {
1427                 stageInfos.emplace_back(IESStageInfo{shader, noSetLayouts});
1428                 maxShaderCount += maxShaders;
1429             };
1430 
1431             addStage(vertNormalShader->get(), 2u);
1432             addStage(fragNormalShader->get(), 2u);
1433 
1434             if (m_params.extraStages == ExtraStages::TESSELLATION)
1435             {
1436                 addStage(tescNormalShader->get(), 2u);
1437                 addStage(teseShader->get(), 1u);
1438             }
1439 
1440             if (m_params.extraStages == ExtraStages::GEOMETRY)
1441                 addStage(geomNormalShader->get(), 2u);
1442 
1443             const std::vector<vk::VkPushConstantRange> pcRanges(1u, pcRange);
1444 
1445             // Execution set for shader objects. Note we store the normal shader
1446             // with index 0 and the alternative with index 1. This matches the
1447             // rationale we're following for shader objects described before,
1448             // and the expected contents of the indirect commands buffer.
1449             {
1450                 executionSetManager =
1451                     makeExecutionSetManagerShader(ctx.vkd, ctx.device, stageInfos, pcRanges, maxShaderCount);
1452 
1453                 executionSetManager->addShader(vertBaseIndex + 0u, vertNormalShader->get());
1454                 executionSetManager->addShader(vertBaseIndex + 1u, vertFlipShader->get());
1455 
1456                 executionSetManager->addShader(fragBaseIndex + 0u, fragNormalShader->get());
1457                 executionSetManager->addShader(fragBaseIndex + 1u, fragAltShader->get());
1458 
1459                 if (m_params.extraStages == ExtraStages::TESSELLATION)
1460                 {
1461                     executionSetManager->addShader(tescBaseIndex + 0u, tescNormalShader->get());
1462                     executionSetManager->addShader(tescBaseIndex + 1u, tescFlipShader->get());
1463 
1464                     executionSetManager->addShader(teseBaseIndex + 0u, teseShader->get());
1465                 }
1466 
1467                 if (m_params.extraStages == ExtraStages::GEOMETRY)
1468                 {
1469                     executionSetManager->addShader(geomBaseIndex + 0u, geomNormalShader->get());
1470                     executionSetManager->addShader(geomBaseIndex + 1u, geomFlipShader->get());
1471                 }
1472 
1473                 executionSetManager->update();
1474             }
1475         }
1476         else
1477         {
1478             dgcPipelines.resize(sequenceCount);
1479 
1480             const auto initialValue = getGeneralConstructionType(m_params.pipelineType);
1481             std::vector<PipelineConstructionType> constructionTypes(sequenceCount, initialValue);
1482 
1483             if (m_params.pipelineType == PipelineType::GPL_MIX_BASE_OPT)
1484                 constructionTypes.at(1u) = PIPELINE_CONSTRUCTION_TYPE_FAST_LINKED_LIBRARY;
1485             else if (m_params.pipelineType == PipelineType::GPL_MIX_BASE_FAST)
1486                 constructionTypes.at(1u) = PIPELINE_CONSTRUCTION_TYPE_LINK_TIME_OPTIMIZED_LIBRARY;
1487 
1488             const VkPipelineCreateFlags2KHR creationFlags = VK_PIPELINE_CREATE_2_INDIRECT_BINDABLE_BIT_EXT;
1489 
1490             {
1491                 auto &pipeline = dgcPipelines.at(0u);
1492                 pipeline.reset(new GraphicsPipelineWrapper(ctx.vki, ctx.vkd, ctx.physicalDevice, ctx.device,
1493                                                            m_context.getDeviceExtensions(), constructionTypes.at(0u)));
1494 
1495                 pipeline->setDefaultTopology(primitiveTopology)
1496                     .setPipelineCreateFlags2(creationFlags)
1497                     .setDefaultRasterizationState()
1498                     .setDefaultColorBlendState()
1499                     .setDefaultMultisampleState()
1500                     .setDefaultPatchControlPoints(patchControlPoints)
1501                     .setDynamicState(&dynamicStateCreateInfo)
1502                     .setupVertexInputState(&vertexInputStateCreateInfo)
1503                     .setupPreRasterizationShaderState2(viewports, scissors, pipelineLayout, *renderPass, 0u, *vertFlip,
1504                                                        nullptr, *tescFlip, *tese, *geomFlip)
1505                     .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, *fragNormal)
1506                     .setupFragmentOutputState(*renderPass, 0u)
1507                     .setMonolithicPipelineLayout(pipelineLayout)
1508                     .buildPipeline();
1509             }
1510 
1511             {
1512                 auto &pipeline = dgcPipelines.at(1u);
1513                 pipeline.reset(new GraphicsPipelineWrapper(ctx.vki, ctx.vkd, ctx.physicalDevice, ctx.device,
1514                                                            m_context.getDeviceExtensions(), constructionTypes.at(1u)));
1515 
1516                 pipeline->setDefaultTopology(primitiveTopology)
1517                     .setPipelineCreateFlags2(creationFlags)
1518                     .setDefaultRasterizationState()
1519                     .setDefaultColorBlendState()
1520                     .setDefaultMultisampleState()
1521                     .setDefaultPatchControlPoints(patchControlPoints)
1522                     .setDynamicState(&dynamicStateCreateInfo)
1523                     .setupVertexInputState(&vertexInputStateCreateInfo)
1524                     .setupPreRasterizationShaderState2(viewports, scissors, pipelineLayout, *renderPass, 0u, *vertFlip,
1525                                                        nullptr, *tescFlip, *tese, *geomFlip)
1526                     .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, *fragAlt)
1527                     .setupFragmentOutputState(*renderPass, 0u)
1528                     .setMonolithicPipelineLayout(pipelineLayout)
1529                     .buildPipeline();
1530             }
1531 
1532             {
1533                 auto &pipeline = dgcPipelines.at(2u);
1534                 pipeline.reset(new GraphicsPipelineWrapper(ctx.vki, ctx.vkd, ctx.physicalDevice, ctx.device,
1535                                                            m_context.getDeviceExtensions(), constructionTypes.at(2u)));
1536 
1537                 pipeline->setDefaultTopology(primitiveTopology)
1538                     .setPipelineCreateFlags2(creationFlags)
1539                     .setDefaultRasterizationState()
1540                     .setDefaultColorBlendState()
1541                     .setDefaultMultisampleState()
1542                     .setDefaultPatchControlPoints(patchControlPoints)
1543                     .setDynamicState(&dynamicStateCreateInfo)
1544                     .setupVertexInputState(&vertexInputStateCreateInfo)
1545                     .setupPreRasterizationShaderState2(viewports, scissors, pipelineLayout, *renderPass, 0u,
1546                                                        *vertNormal, nullptr, *tescNormal, *tese, *geomNormal)
1547                     .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, *fragAlt)
1548                     .setupFragmentOutputState(*renderPass, 0u)
1549                     .setMonolithicPipelineLayout(pipelineLayout)
1550                     .buildPipeline();
1551             }
1552 
1553             executionSetManager =
1554                 makeExecutionSetManagerPipeline(ctx.vkd, ctx.device, dgcPipelines.at(0u)->getPipeline(), sequenceCount);
1555             for (uint32_t i = 0u; i < sequenceCount; ++i)
1556                 executionSetManager->addPipeline(i, dgcPipelines.at(i)->getPipeline());
1557             executionSetManager->update();
1558         }
1559     }
1560     else
1561     {
1562         if (!m_params.isShaderObjects())
1563         {
1564             normalPipeline = makeGraphicsPipeline(
1565                 ctx.vkd, ctx.device, *pipelineLayout, vertNormal->getModule(), tescNormal->getModule(),
1566                 tese->getModule(), geomNormal->getModule(), fragNormal->getModule(), *renderPass, viewports, scissors,
1567                 primitiveTopology, 0u, patchControlPoints, &vertexInputStateCreateInfo, nullptr, nullptr, nullptr,
1568                 nullptr, &dynamicStateCreateInfo);
1569         }
1570     }
1571 
1572     const auto indirectExecutionSet = (executionSetManager ? executionSetManager->get() : VK_NULL_HANDLE);
1573 
1574     // Preprocess buffer.
1575     std::vector<VkShaderEXT> shadersVec;
1576     if (m_params.isShaderObjects() && !m_params.useExecutionSet)
1577     {
1578         shadersVec.reserve(5u); // At most: vert, tesc, tese, geom, frag.
1579         if (vertNormalShader)
1580             shadersVec.push_back(vertNormalShader->get());
1581         if (tescNormalShader)
1582             shadersVec.push_back(tescNormalShader->get());
1583         if (teseShader)
1584             shadersVec.push_back(teseShader->get());
1585         if (geomNormalShader)
1586             shadersVec.push_back(geomNormalShader->get());
1587         if (fragNormalShader)
1588             shadersVec.push_back(fragNormalShader->get());
1589     }
1590     const std::vector<VkShaderEXT> *shadersVecPtr = (shadersVec.empty() ? nullptr : &shadersVec);
1591     PreprocessBufferExt preprocessBuffer(ctx.vkd, ctx.device, ctx.allocator, indirectExecutionSet, *cmdsLayout,
1592                                          sequenceCount, 0u, *normalPipeline, shadersVecPtr);
1593 
1594     // Record commands.
1595     CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
1596     const auto cmdBuffer = *cmd.cmdBuffer;
1597 
1598     const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 0.0f);
1599     const auto clearValueColor = makeClearValueColor(clearColor);
1600     const auto colorSRR        = makeDefaultImageSubresourceRange();
1601 
1602     // Will be used for both preprocessing and execution.
1603     const DGCGenCmdsInfo generatedCommandsInfo(
1604         stageFlags,                          // VkShaderStageFlags shaderStages;
1605         indirectExecutionSet,                // VkIndirectExecutionSetEXT indirectExecutionSet;
1606         *cmdsLayout,                         // VkIndirectCommandsLayoutEXT indirectCommandsLayout;
1607         dgcBuffer.getDeviceAddress(),        // VkDeviceAddress indirectAddress;
1608         dgcBufferSize,                       // VkDeviceSize indirectAddressSize;
1609         preprocessBuffer.getDeviceAddress(), // VkDeviceAddress preprocessAddress;
1610         preprocessBuffer.getSize(),          // VkDeviceSize preprocessSize;
1611         sequenceCount,                       // uint32_t maxSequenceCount;
1612         0ull,                                // VkDeviceAddress sequenceCountAddress;
1613         0u,                                  // uint32_t maxDrawCount;
1614         *normalPipeline, shadersVecPtr);
1615 
1616     // When preprocessing, we need to use a separate command buffer to record state.
1617     // The preprocessing step needs to happen outside the render pass.
1618     Move<VkCommandBuffer> separateStateCmdBuffer;
1619 
1620     // A command buffer we want to record state into.
1621     // .first is the command buffer itself.
1622     // .second, if not NULL, means we'll record a preprocess command with it as the state command buffer.
1623     using StateCmdBuffer                 = std::pair<VkCommandBuffer, VkCommandBuffer>;
1624     const VkCommandBuffer kNullCmdBuffer = VK_NULL_HANDLE; // Workaround for emplace_back below.
1625     std::vector<StateCmdBuffer> stateCmdBuffers;
1626 
1627     // Sequences and iterations for the different cases:
1628     //     - PreprocessType::NONE
1629     //         - Only one loop iteration.
1630     //         - Iteration 0: .first = main cmd buffer, .second = NULL
1631     //             - No preprocess, bind state
1632     //         - Execute.
1633     //     - PreprocessType::OTHER_STATE_CMD_BUFFER
1634     //         - Iteration 0: .first = state cmd buffer, .second = NULL
1635     //             - No preprocess, bind state
1636     //         - Iteration 1: .first = main cmd buffer, .second = state cmd buffer
1637     //             - Preprocess with state cmd buffer, bind state on main
1638     //         - Execute.
1639     //     - PreprocessType::SAME_STATE_CMD_BUFFER
1640     //         - Iteration 0: .first = main cmd buffer, .second = NULL
1641     //             - No preprocess, bind state
1642     //         - Iteration 1: .first = main cmd buffer, .second = main cmd buffer
1643     //             - Preprocess with main cmd buffer, break
1644     //         - Execute.
1645     switch (m_params.preprocessType)
1646     {
1647     case PreprocessType::NONE:
1648         stateCmdBuffers.emplace_back(cmdBuffer, kNullCmdBuffer);
1649         break;
1650     case PreprocessType::SAME_STATE_CMD_BUFFER:
1651         stateCmdBuffers.emplace_back(cmdBuffer, kNullCmdBuffer);
1652         stateCmdBuffers.emplace_back(cmdBuffer, cmdBuffer);
1653         break;
1654     case PreprocessType::OTHER_STATE_CMD_BUFFER:
1655         separateStateCmdBuffer =
1656             allocateCommandBuffer(ctx.vkd, ctx.device, *cmd.cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1657         stateCmdBuffers.emplace_back(*separateStateCmdBuffer, kNullCmdBuffer);
1658         stateCmdBuffers.emplace_back(cmdBuffer, *separateStateCmdBuffer);
1659         break;
1660     default:
1661         DE_ASSERT(false);
1662     }
1663 
1664     // Record pre-execution state to all needed command buffers.
1665     VkCommandBuffer prevCmdBuffer = VK_NULL_HANDLE;
1666     for (const auto &stateCmdBufferPair : stateCmdBuffers)
1667     {
1668         const auto &recCmdBuffer = stateCmdBufferPair.first;
1669 
1670         // Only begin each command buffer once.
1671         if (recCmdBuffer != prevCmdBuffer)
1672         {
1673             beginCommandBuffer(ctx.vkd, recCmdBuffer);
1674             prevCmdBuffer = recCmdBuffer;
1675         }
1676 
1677         if (stateCmdBufferPair.second != VK_NULL_HANDLE)
1678         {
1679             ctx.vkd.cmdPreprocessGeneratedCommandsEXT(recCmdBuffer, &generatedCommandsInfo.get(),
1680                                                       stateCmdBufferPair.second);
1681             separateStateCmdBuffer =
1682                 Move<VkCommandBuffer>(); // Delete state command buffer right away as allowed by the spec.
1683 
1684             preprocessToExecuteBarrierExt(ctx.vkd, recCmdBuffer);
1685 
1686             // Break for iteration 1 of PreprocessType::SAME_STATE_CMD_BUFFER. See above.
1687             if (stateCmdBufferPair.first == stateCmdBufferPair.second)
1688                 break;
1689         }
1690 
1691         if (m_params.isShaderObjects())
1692         {
1693             // Bind shaders.
1694             std::map<VkShaderStageFlagBits, VkShaderEXT> shadersToBind{
1695                 std::make_pair(VK_SHADER_STAGE_VERTEX_BIT, vertNormalShader->get()),
1696                 std::make_pair(VK_SHADER_STAGE_FRAGMENT_BIT, fragNormalShader->get()),
1697             };
1698 
1699             if (m_params.extraStages == ExtraStages::TESSELLATION)
1700             {
1701                 shadersToBind[VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT]    = tescNormalShader->get();
1702                 shadersToBind[VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT] = teseShader->get();
1703             }
1704             else if (features.tessellationShader)
1705             {
1706                 shadersToBind[VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT]    = VK_NULL_HANDLE;
1707                 shadersToBind[VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT] = VK_NULL_HANDLE;
1708             }
1709 
1710             if (m_params.extraStages == ExtraStages::GEOMETRY)
1711                 shadersToBind[VK_SHADER_STAGE_GEOMETRY_BIT] = geomNormalShader->get();
1712             else if (features.geometryShader)
1713                 shadersToBind[VK_SHADER_STAGE_GEOMETRY_BIT] = VK_NULL_HANDLE;
1714 
1715             if (meshFeatures.meshShader)
1716                 shadersToBind[VK_SHADER_STAGE_MESH_BIT_EXT] = VK_NULL_HANDLE;
1717             if (meshFeatures.taskShader)
1718                 shadersToBind[VK_SHADER_STAGE_TASK_BIT_EXT] = VK_NULL_HANDLE;
1719 
1720             for (const auto &stageAndShader : shadersToBind)
1721                 ctx.vkd.cmdBindShadersEXT(recCmdBuffer, 1u, &stageAndShader.first, &stageAndShader.second);
1722         }
1723         else
1724         {
1725             if (m_params.useExecutionSet)
1726             {
1727                 DE_ASSERT(!dgcPipelines.empty());
1728                 ctx.vkd.cmdBindPipeline(recCmdBuffer, bindPoint, dgcPipelines.at(0u)->getPipeline());
1729             }
1730             else
1731             {
1732                 // Bind shaders and state.
1733                 DE_ASSERT(*normalPipeline != VK_NULL_HANDLE);
1734                 ctx.vkd.cmdBindPipeline(recCmdBuffer, bindPoint, *normalPipeline);
1735             }
1736         }
1737 
1738         if (m_params.isShaderObjects())
1739         {
1740             // Bind state for shader objects. This is needed with and without execution sets.
1741             bindShaderObjectState(ctx.vkd, getDeviceCreationExtensions(m_context), recCmdBuffer, viewports, scissors,
1742                                   primitiveTopology, patchControlPoints, &vertexInputStateCreateInfo, nullptr, nullptr,
1743                                   nullptr, nullptr);
1744         }
1745 
1746         if (isIndexed(m_params.testType) || m_params.testType == TestType::DRAW_SIMPLE)
1747         {
1748             const VkBuffer vertexBuffer           = vertexBuffers.at(0u).buffer->get();
1749             const VkDeviceSize vertexBufferOffset = 0ull;
1750             const VkDeviceSize vertexBufferSize   = static_cast<VkDeviceSize>(vertexBuffers.at(0u).size);
1751             const VkDeviceSize vertexBufferStride = static_cast<VkDeviceSize>(vertexBuffers.at(0u).stride);
1752 
1753             ctx.vkd.cmdBindVertexBuffers2(recCmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset, &vertexBufferSize,
1754                                           &vertexBufferStride);
1755         }
1756     }
1757 
1758     if (m_params.isShaderObjects())
1759     {
1760         const auto clearLayout     = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1761         const auto renderingLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1762 
1763         const auto preClearBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
1764                                                             clearLayout, colorBuffer.getImage(), colorSRR);
1765 
1766         const auto postClearBarrier = makeImageMemoryBarrier(
1767             VK_ACCESS_TRANSFER_WRITE_BIT, (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
1768             clearLayout, renderingLayout, colorBuffer.getImage(), colorSRR);
1769 
1770         cmdPipelineImageMemoryBarrier(ctx.vkd, cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1771                                       VK_PIPELINE_STAGE_TRANSFER_BIT, &preClearBarrier);
1772         ctx.vkd.cmdClearColorImage(cmdBuffer, colorBuffer.getImage(), clearLayout, &clearValueColor.color, 1u,
1773                                    &colorSRR);
1774         cmdPipelineImageMemoryBarrier(ctx.vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
1775                                       VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, &postClearBarrier);
1776 
1777         beginRendering(ctx.vkd, cmdBuffer, colorBuffer.getImageView(), scissors.at(0u), clearValueColor /*unused*/,
1778                        VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
1779     }
1780     else
1781         beginRenderPass(ctx.vkd, cmdBuffer, *renderPass, *framebuffer, scissors.at(0u), clearColor);
1782 
1783     ctx.vkd.cmdExecuteGeneratedCommandsEXT(cmdBuffer, makeVkBool(m_params.doPreprocess()),
1784                                            &generatedCommandsInfo.get());
1785 
1786     if (m_params.isShaderObjects())
1787         endRendering(ctx.vkd, cmdBuffer);
1788     else
1789         endRenderPass(ctx.vkd, cmdBuffer);
1790 
1791     copyImageToBuffer(ctx.vkd, cmdBuffer, colorBuffer.getImage(), colorBuffer.getBuffer(), fbExtent.swizzle(0, 1));
1792     endCommandBuffer(ctx.vkd, cmdBuffer);
1793     submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
1794 
1795     // Verify results.
1796     auto &resultsBufferAlloc = colorBuffer.getBufferAllocation();
1797     invalidateAlloc(ctx.vkd, ctx.device, resultsBufferAlloc);
1798 
1799     const auto tcuFormat = mapVkFormat(colorFormat);
1800     tcu::ConstPixelBufferAccess result(tcuFormat, fbExtent, resultsBufferAlloc.getHostPtr());
1801 
1802     tcu::TextureLevel referenceLevel(tcuFormat, fbExtent.x(), fbExtent.y(), fbExtent.z());
1803     auto reference = referenceLevel.getAccess();
1804 
1805     // The first and second triangles will have their pixels swapped when using execution sets, because of the X coordinate flip.
1806     // The last two sequences should have blue 1 when using execution sets.
1807     // Except for the first pixel, all others have green 1, either because of the instance count or because of the first instance value.
1808     const auto firstX       = (m_params.useExecutionSet ? 1 : 0);
1809     const auto secondX      = (m_params.useExecutionSet ? 0 : 1);
1810     const auto blueAlt      = (m_params.useExecutionSet ? 1.0f : 0.0f);
1811     const auto redOffsetAlt = (m_params.useExecutionSet ? kVertFlipRedOffset : kVertNormalRedOffset);
1812 
1813     reference.setPixel(tcu::Vec4(redValues.at(0u) + redOffsetAlt, 0.0f, 0.0f, 1.0f), firstX, 0);
1814     reference.setPixel(tcu::Vec4(redValues.at(1u) + redOffsetAlt, 1.0f, blueAlt, 1.0f), secondX, 0);
1815     reference.setPixel(tcu::Vec4(redValues.at(1u) + redOffsetAlt, 1.0f, blueAlt, 1.0f), 0, 1);
1816     reference.setPixel(tcu::Vec4(redValues.at(2u) + kVertNormalRedOffset, 1.0f, blueAlt, 1.0f), 1, 1);
1817 
1818     auto &log                  = m_context.getTestContext().getLog();
1819     const float thresholdValue = 0.005f; // 1/255 < 0.005 < 2/255
1820     const tcu::Vec4 threshold(thresholdValue, 0.0f, 0.0f, 0.0f);
1821     if (!tcu::floatThresholdCompare(log, "Result", "", reference, result, threshold, tcu::COMPARE_LOG_EVERYTHING))
1822         TCU_FAIL("Unexpected results in color buffer; check log for details");
1823 
1824     return tcu::TestStatus::pass("Pass");
1825 }
1826 
checkBasicDGCGraphicsSupport(Context & context,bool)1827 void checkBasicDGCGraphicsSupport(Context &context, bool)
1828 {
1829     const VkShaderStageFlags stages = (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
1830     checkDGCExtSupport(context, stages);
1831 }
1832 
1833 // The fragment shader uses a push constant for the geometry color but, in addition to that, if pushConstantToken is
1834 // true we're also going to use a push constant for the point size.
basicGraphicsPrograms(SourceCollections & dst,bool pcToken)1835 void basicGraphicsPrograms(SourceCollections &dst, bool pcToken)
1836 {
1837     std::ostringstream vert;
1838     vert << "#version 460\n"
1839          << "layout (location=0) in vec4 inPos;\n"
1840          << (pcToken ? "layout (push_constant, std430) uniform PCBlock { layout(offset=16) float ptSize; } pc;\n" : "")
1841          << "void main (void) {\n"
1842          << "    gl_Position = inPos;\n"
1843          << "    const float pointSize = " << (pcToken ? "pc.ptSize" : "1.0") << ";\n"
1844          << "    gl_PointSize = pointSize;\n"
1845          << "}\n";
1846     dst.glslSources.add("vert") << glu::VertexSource(vert.str());
1847 
1848     std::ostringstream frag;
1849     frag << "#version 460\n"
1850          << "layout (push_constant, std430) uniform PCBlock { vec4 color; } pc;\n"
1851          << "layout (location=0) out vec4 outColor;\n"
1852          << "void main (void) {\n"
1853          << "    outColor = pc.color;\n"
1854          << "}\n";
1855     dst.glslSources.add("frag") << glu::FragmentSource(frag.str());
1856 }
1857 
1858 // indexedDrawWithoutIndexTokenRun tests indexed draws without an index buffer token.
indexedDrawWithoutIndexTokenRun(Context & context,bool pcToken)1859 tcu::TestStatus indexedDrawWithoutIndexTokenRun(Context &context, bool pcToken)
1860 {
1861     const auto &ctx = context.getContextCommonData();
1862     const tcu::IVec3 fbExtent(4, 4, 1);
1863     const auto floatExtent = fbExtent.asFloat();
1864     const auto pixelCount  = static_cast<uint32_t>(fbExtent.x() * fbExtent.y() * fbExtent.z());
1865     const auto pixelCountF = static_cast<float>(pixelCount);
1866     const auto vkExtent    = makeExtent3D(fbExtent);
1867     const auto fbFormat    = VK_FORMAT_R8G8B8A8_UNORM;
1868     const auto tcuFormat   = mapVkFormat(fbFormat);
1869     const auto fbUsage     = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1870     const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1871     const tcu::Vec4 geomColor(0.0f, 0.0f, 1.0f, 1.0f);
1872     const tcu::Vec4 solidThreshold(0.0f, 0.0f, 0.0f, 0.0f);      // When using 0 and 1 only, we expect exact results.
1873     const tcu::Vec4 gradientThreshold(0.0f, 0.0f, 0.005f, 0.0f); // Allow a small mistake in the blue component.
1874     const auto bindPoint  = VK_PIPELINE_BIND_POINT_GRAPHICS;
1875     const auto stageFlags = (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
1876 
1877     // Color buffer with verification buffer.
1878     ImageWithBuffer colorBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, fbFormat, fbUsage, VK_IMAGE_TYPE_2D);
1879 
1880     // Vertices.
1881     std::vector<tcu::Vec4> vertices;
1882     vertices.reserve(pixelCount);
1883 
1884     for (int y = 0; y < fbExtent.y(); ++y)
1885         for (int x = 0; x < fbExtent.x(); ++x)
1886         {
1887             const float xCenter = (static_cast<float>(x) + 0.5f) / floatExtent.x() * 2.0f - 1.0f;
1888             const float yCenter = (static_cast<float>(y) + 0.5f) / floatExtent.y() * 2.0f - 1.0f;
1889             vertices.emplace_back(xCenter, yCenter, 0.0f, 1.0f);
1890         }
1891 
1892     // Vertex buffer
1893     const auto vbSize = static_cast<VkDeviceSize>(de::dataSize(vertices));
1894     const auto vbInfo = makeBufferCreateInfo(vbSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1895     BufferWithMemory vertexBuffer(ctx.vkd, ctx.device, ctx.allocator, vbInfo, MemoryRequirement::HostVisible);
1896     const auto &vbAlloc = vertexBuffer.getAllocation();
1897     void *vbData        = vbAlloc.getHostPtr();
1898     const auto vbOffset = static_cast<VkDeviceSize>(0);
1899 
1900     deMemcpy(vbData, de::dataOrNull(vertices), de::dataSize(vertices));
1901 
1902     // Indices. To make sure these are used we're going duplicate every even index and skip odd indices. And, on top
1903     // of that, we're going to apply an offset to each point.
1904     std::vector<int32_t> offsets;
1905     offsets.reserve(pixelCount);
1906     for (uint32_t i = 0u; i < pixelCount; ++i)
1907         offsets.push_back(100 + i);
1908 
1909     std::vector<uint32_t> indices;
1910     indices.reserve(pixelCount);
1911     for (uint32_t i = 0u; i < pixelCount; ++i)
1912         indices.push_back((i / 2u) * 2u + offsets.at(i));
1913 
1914     const auto ibSize = static_cast<VkDeviceSize>(de::dataSize(indices));
1915     const auto ibInfo = makeBufferCreateInfo(ibSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
1916     BufferWithMemory indexBuffer(ctx.vkd, ctx.device, ctx.allocator, ibInfo, MemoryRequirement::HostVisible);
1917     const auto &ibAlloc = indexBuffer.getAllocation();
1918     void *ibData        = ibAlloc.getHostPtr();
1919 
1920     deMemcpy(ibData, de::dataOrNull(indices), de::dataSize(indices));
1921 
1922     // Pipeline, render pass, framebuffer...
1923     std::vector<VkPushConstantRange> pcRanges;
1924     if (pcToken)
1925         pcRanges.push_back(
1926             makePushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, DE_SIZEOF32(geomColor), DE_SIZEOF32(float)));
1927     pcRanges.push_back(makePushConstantRange(VK_SHADER_STAGE_FRAGMENT_BIT, 0u, DE_SIZEOF32(geomColor)));
1928 
1929     const auto pipelineLayout =
1930         makePipelineLayout(ctx.vkd, ctx.device, 0u, nullptr, de::sizeU32(pcRanges), de::dataOrNull(pcRanges));
1931     const auto renderPass = makeRenderPass(ctx.vkd, ctx.device, fbFormat);
1932     const auto framebuffer =
1933         makeFramebuffer(ctx.vkd, ctx.device, *renderPass, colorBuffer.getImageView(), vkExtent.width, vkExtent.height);
1934 
1935     // Modules.
1936     const auto &binaries  = context.getBinaryCollection();
1937     const auto vertModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("vert"));
1938     const auto fragModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("frag"));
1939 
1940     const std::vector<VkViewport> viewports(1u, makeViewport(vkExtent));
1941     const std::vector<VkRect2D> scissors(1u, makeRect2D(vkExtent));
1942 
1943     // The default values works for the current setup, including the vertex input data format.
1944     const auto pipeline = makeGraphicsPipeline(ctx.vkd, ctx.device, *pipelineLayout, *vertModule, VK_NULL_HANDLE,
1945                                                VK_NULL_HANDLE, VK_NULL_HANDLE, *fragModule, *renderPass, viewports,
1946                                                scissors, VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
1947 
1948     // Indirect commands layout.
1949     IndirectCommandsLayoutBuilderExt cmdsLayoutBuilder(0u, stageFlags, *pipelineLayout);
1950     if (pcToken)
1951     {
1952         // The color will be provided with a push constant token.
1953         cmdsLayoutBuilder.addPushConstantToken(cmdsLayoutBuilder.getStreamRange(), pcRanges.back());
1954     }
1955     cmdsLayoutBuilder.addDrawIndexedToken(cmdsLayoutBuilder.getStreamRange());
1956     const auto cmdsLayout = cmdsLayoutBuilder.build(ctx.vkd, ctx.device);
1957 
1958     // DGC Buffer.
1959     std::vector<VkDrawIndexedIndirectCommand> drawCmds;
1960     drawCmds.reserve(pixelCount);
1961     for (size_t i = 0u; i < vertices.size(); ++i)
1962         drawCmds.push_back(VkDrawIndexedIndirectCommand{1u, 1u, static_cast<uint32_t>(i), -offsets.at(i), 0u});
1963 
1964     std::vector<uint32_t> dgcData;
1965     dgcData.reserve(pixelCount * (cmdsLayoutBuilder.getStreamStride() / DE_SIZEOF32(uint32_t)));
1966     for (size_t i = 0u; i < drawCmds.size(); ++i)
1967     {
1968         if (pcToken)
1969         {
1970             // Color pc token, making a gradient.
1971             const float blueComp = static_cast<float>(i) / pixelCountF;
1972             const tcu::Vec4 color(0.0f, 0.0f, blueComp, 1.0f);
1973             pushBackElement(dgcData, color);
1974         }
1975         pushBackElement(dgcData, drawCmds.at(i));
1976     }
1977 
1978     const auto dgcBufferSize = static_cast<VkDeviceSize>(de::dataSize(dgcData));
1979     DGCBuffer dgcBuffer(ctx.vkd, ctx.device, ctx.allocator, dgcBufferSize);
1980     auto &dgcBufferAlloc = dgcBuffer.getAllocation();
1981     void *dgcBufferData  = dgcBufferAlloc.getHostPtr();
1982     deMemcpy(dgcBufferData, de::dataOrNull(dgcData), de::dataSize(dgcData));
1983 
1984     // Preprocess buffer.
1985     PreprocessBufferExt preprocessBuffer(ctx.vkd, ctx.device, ctx.allocator, VK_NULL_HANDLE, *cmdsLayout,
1986                                          de::sizeU32(drawCmds), 0u, *pipeline);
1987 
1988     CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
1989     const auto cmdBuffer = *cmd.cmdBuffer;
1990 
1991     beginCommandBuffer(ctx.vkd, cmdBuffer);
1992     ctx.vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vbOffset);
1993     ctx.vkd.cmdBindIndexBuffer(cmdBuffer, indexBuffer.get(), 0ull, vk::VK_INDEX_TYPE_UINT32);
1994     ctx.vkd.cmdBindPipeline(cmdBuffer, bindPoint, *pipeline);
1995     if (pcToken)
1996     {
1997         // The fixed push constant will contain the point size for the vertex shader.
1998         const auto &pcRange = pcRanges.front();
1999         const float ptSz    = 1.0f;
2000         ctx.vkd.cmdPushConstants(cmdBuffer, *pipelineLayout, pcRange.stageFlags, pcRange.offset, pcRange.size, &ptSz);
2001     }
2002     else
2003     {
2004         // A fixed geometry color in this case, for the fragment shader.
2005         const auto &pcRange = pcRanges.back();
2006         ctx.vkd.cmdPushConstants(cmdBuffer, *pipelineLayout, pcRange.stageFlags, pcRange.offset, pcRange.size,
2007                                  &geomColor);
2008     }
2009     beginRenderPass(ctx.vkd, cmdBuffer, *renderPass, *framebuffer, scissors.at(0u), clearColor);
2010     {
2011         DGCGenCmdsInfo cmdsInfo(stageFlags, VK_NULL_HANDLE, *cmdsLayout, dgcBuffer.getDeviceAddress(),
2012                                 dgcBuffer.getSize(), preprocessBuffer.getDeviceAddress(), preprocessBuffer.getSize(),
2013                                 de::sizeU32(drawCmds), 0ull, 0u, *pipeline);
2014         ctx.vkd.cmdExecuteGeneratedCommandsEXT(cmdBuffer, VK_FALSE, &cmdsInfo.get());
2015     }
2016     endRenderPass(ctx.vkd, cmdBuffer);
2017     copyImageToBuffer(ctx.vkd, cmdBuffer, colorBuffer.getImage(), colorBuffer.getBuffer(), fbExtent.swizzle(0, 1),
2018                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u,
2019                       VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT,
2020                       VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
2021     endCommandBuffer(ctx.vkd, cmdBuffer);
2022     submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
2023 
2024     // Verify color output.
2025     invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation());
2026     tcu::PixelBufferAccess resultAccess(tcuFormat, fbExtent, colorBuffer.getBufferAllocation().getHostPtr());
2027 
2028     tcu::TextureLevel referenceLevel(tcuFormat, fbExtent.x(), fbExtent.y());
2029     auto referenceAccess = referenceLevel.getAccess();
2030     for (int y = 0; y < fbExtent.y(); ++y)
2031         for (int x = 0; x < fbExtent.x(); ++x)
2032         {
2033             const int pixelIdx   = y * fbExtent.x() + x;
2034             const bool drawnOver = (pixelIdx % 2 == 0); // Only even pixels are drawn into.
2035 
2036             tcu::Vec4 color(0.0f, 0.0f, 0.0f, 0.0f);
2037 
2038             if (pcToken)
2039             {
2040                 // The passed color will be in the pc token and will change with each draw, forming a gradient. See above.
2041                 if (drawnOver)
2042                 {
2043                     // The +1 in the pixelIdx is because even points are drawn twice and the second color prevails.
2044                     const float blueComp = static_cast<float>(pixelIdx + 1) / pixelCountF;
2045                     color                = tcu::Vec4(0.0f, 0.0f, blueComp, 1.0f);
2046                 }
2047                 else
2048                     color = clearColor;
2049             }
2050             else
2051             {
2052                 // Fixed color in this case.
2053                 color = (drawnOver ? geomColor : clearColor);
2054             }
2055             referenceAccess.setPixel(color, x, y);
2056         }
2057 
2058     auto &log             = context.getTestContext().getLog();
2059     const auto &threshold = (pcToken ? gradientThreshold : solidThreshold);
2060     if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, threshold,
2061                                     tcu::COMPARE_LOG_ON_ERROR))
2062         return tcu::TestStatus::fail("Unexpected color in result buffer; check log for details");
2063 
2064     return tcu::TestStatus::pass("Pass");
2065 }
2066 
2067 } // namespace
2068 
createDGCGraphicsDrawTestsExt(tcu::TestContext & testCtx)2069 tcu::TestCaseGroup *createDGCGraphicsDrawTestsExt(tcu::TestContext &testCtx)
2070 {
2071     using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
2072     GroupPtr mainGroup(new tcu::TestCaseGroup(testCtx, "draw"));
2073 
2074     GroupPtr drawTokenGroup(new tcu::TestCaseGroup(testCtx, "token_draw"));
2075     GroupPtr drawIndexedTokenGroup(new tcu::TestCaseGroup(testCtx, "token_draw_indexed"));
2076 
2077     const struct
2078     {
2079         ExtraStages extraStages;
2080         const char *name;
2081     } extraStageCases[] = {
2082         {ExtraStages::NONE, ""},
2083         {ExtraStages::TESSELLATION, "_with_tess"},
2084         {ExtraStages::GEOMETRY, "_with_geom"},
2085     };
2086 
2087     const struct
2088     {
2089         PipelineType pipelineType;
2090         const std::string name;
2091     } pipelineTypeCases[] = {
2092         {PipelineType::MONOLITHIC, "monolithic"},
2093         {PipelineType::SHADER_OBJECTS, "shader_objects"},
2094         {PipelineType::GPL_FAST, "gpl_fast"},
2095         {PipelineType::GPL_OPTIMIZED, "gpl_optimized"},
2096         {PipelineType::GPL_MIX_BASE_FAST, "gpl_mix_base_fast"},
2097         {PipelineType::GPL_MIX_BASE_OPT, "gpl_mix_base_opt"},
2098     };
2099 
2100     const struct
2101     {
2102         PreprocessType preprocessType;
2103         const char *suffix;
2104     } preprocessCases[] = {
2105         {PreprocessType::NONE, ""},
2106         {PreprocessType::SAME_STATE_CMD_BUFFER, "_preprocess_same_state_cmd_buffer"},
2107         {PreprocessType::OTHER_STATE_CMD_BUFFER, "_preprocess_separate_state_cmd_buffer"},
2108     };
2109 
2110     for (const auto testType :
2111          {TestType::DRAW_SIMPLE, TestType::DRAW, TestType::DRAW_INDEXED, TestType::DRAW_INDEXED_DX})
2112         for (const auto &pipelineTypeCase : pipelineTypeCases)
2113             for (const auto useExecutionSet : {false, true})
2114             {
2115                 if (isGPL(pipelineTypeCase.pipelineType) && !useExecutionSet)
2116                     continue;
2117 
2118                 for (const auto &extraStageCase : extraStageCases)
2119                     for (const bool checkDrawParams : {false, true})
2120                         for (const auto &preprocessCase : preprocessCases)
2121                             for (const auto unordered : {false, true})
2122                             {
2123                                 const DrawTestParams params{testType,
2124                                                             extraStageCase.extraStages,
2125                                                             pipelineTypeCase.pipelineType,
2126                                                             preprocessCase.preprocessType,
2127                                                             checkDrawParams,
2128                                                             useExecutionSet,
2129                                                             unordered};
2130                                 const std::string testName = pipelineTypeCase.name + extraStageCase.name +
2131                                                              (useExecutionSet ? "_with_execution_set" : "") +
2132                                                              (checkDrawParams ? "_check_draw_params" : "") +
2133                                                              preprocessCase.suffix + (unordered ? "_unordered" : "") +
2134                                                              (testType == TestType::DRAW_SIMPLE ? "_simple" : "") +
2135                                                              (testType == TestType::DRAW_INDEXED_DX ? "_dx_index" : "");
2136 
2137                                 const auto group =
2138                                     (isIndexed(testType) ? drawIndexedTokenGroup.get() : drawTokenGroup.get());
2139 
2140                                 group->addChild(new DGCDrawCase(testCtx, testName, params));
2141                             }
2142             }
2143 
2144     for (const auto pcToken : {false, true})
2145     {
2146         const std::string testName =
2147             std::string("indexed_draw_without_index_buffer_token") + (pcToken ? "_with_pc_token" : "");
2148         addFunctionCaseWithPrograms(drawIndexedTokenGroup.get(), testName, checkBasicDGCGraphicsSupport,
2149                                     basicGraphicsPrograms, indexedDrawWithoutIndexTokenRun, pcToken);
2150     }
2151 
2152     mainGroup->addChild(drawTokenGroup.release());
2153     mainGroup->addChild(drawIndexedTokenGroup.release());
2154 
2155     return mainGroup.release();
2156 }
2157 
2158 } // namespace DGC
2159 } // namespace vkt
2160