xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/draw/vktBasicDrawTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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 Simple Draw Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktBasicDrawTests.hpp"
26 
27 #include "vktDrawBaseClass.hpp"
28 #include "vkQueryUtil.hpp"
29 #include "vkCmdUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vktTestGroupUtil.hpp"
32 
33 #include "deDefs.h"
34 #include "deRandom.hpp"
35 #include "deString.h"
36 
37 #include "tcuTestCase.hpp"
38 #include "tcuRGBA.hpp"
39 #include "tcuTextureUtil.hpp"
40 #include "tcuImageCompare.hpp"
41 #include "tcuVectorUtil.hpp"
42 
43 #include "rrRenderer.hpp"
44 
45 #include <string>
46 #include <sstream>
47 
48 namespace vkt
49 {
50 namespace Draw
51 {
52 namespace
53 {
54 static const uint32_t SEED        = 0xc2a39fu;
55 static const uint32_t INDEX_LIMIT = 10000;
56 // To avoid too big and mostly empty structures
57 static const uint32_t OFFSET_LIMIT = 1000;
58 // Number of primitives to draw
59 static const uint32_t PRIMITIVE_COUNT[] = {1, 3, 17, 45};
60 
61 enum DrawCommandType
62 {
63     DRAW_COMMAND_TYPE_DRAW,
64     DRAW_COMMAND_TYPE_DRAW_INDEXED,
65     DRAW_COMMAND_TYPE_DRAW_INDIRECT,
66     DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT,
67 
68     DRAW_COMMAND_TYPE_DRAW_LAST
69 };
70 
getDrawCommandTypeName(DrawCommandType command)71 const char *getDrawCommandTypeName(DrawCommandType command)
72 {
73     switch (command)
74     {
75     case DRAW_COMMAND_TYPE_DRAW:
76         return "draw";
77     case DRAW_COMMAND_TYPE_DRAW_INDEXED:
78         return "draw_indexed";
79     case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
80         return "draw_indirect";
81     case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
82         return "draw_indexed_indirect";
83     default:
84         DE_ASSERT(false);
85     }
86     return "";
87 }
88 
mapVkPrimitiveTopology(vk::VkPrimitiveTopology primitiveTopology)89 rr::PrimitiveType mapVkPrimitiveTopology(vk::VkPrimitiveTopology primitiveTopology)
90 {
91     switch (primitiveTopology)
92     {
93     case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
94         return rr::PRIMITIVETYPE_POINTS;
95     case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
96         return rr::PRIMITIVETYPE_LINES;
97     case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
98         return rr::PRIMITIVETYPE_LINE_STRIP;
99     case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
100         return rr::PRIMITIVETYPE_TRIANGLES;
101     case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
102         return rr::PRIMITIVETYPE_TRIANGLE_FAN;
103     case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
104         return rr::PRIMITIVETYPE_TRIANGLE_STRIP;
105     case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
106         return rr::PRIMITIVETYPE_LINES_ADJACENCY;
107     case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
108         return rr::PRIMITIVETYPE_LINE_STRIP_ADJACENCY;
109     case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
110         return rr::PRIMITIVETYPE_TRIANGLES_ADJACENCY;
111     case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
112         return rr::PRIMITIVETYPE_TRIANGLE_STRIP_ADJACENCY;
113     default:
114         DE_ASSERT(false);
115     }
116     return rr::PRIMITIVETYPE_LAST;
117 }
118 
119 struct DrawParamsBase
120 {
121     std::vector<PositionColorVertex> vertices;
122     vk::VkPrimitiveTopology topology;
123     bool useMaintenance5;
124     GroupParams groupParams; // we can't use SharedGroupParams here
125 
DrawParamsBasevkt::Draw::__anon91bcb92a0111::DrawParamsBase126     DrawParamsBase()
127     {
128     }
129 
~DrawParamsBasevkt::Draw::__anon91bcb92a0111::DrawParamsBase130     virtual ~DrawParamsBase()
131     {
132     }
133 
DrawParamsBasevkt::Draw::__anon91bcb92a0111::DrawParamsBase134     DrawParamsBase(const vk::VkPrimitiveTopology top, const SharedGroupParams gParams)
135         : topology(top)
136         , useMaintenance5(false)
137         , groupParams{gParams->useDynamicRendering, gParams->useSecondaryCmdBuffer,
138                       gParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass, gParams->nestedSecondaryCmdBuffer}
139     {
140     }
141 };
142 
143 struct IndexedParamsBase
144 {
145     std::vector<uint32_t> indexes;
146     const vk::VkIndexType indexType;
147 
IndexedParamsBasevkt::Draw::__anon91bcb92a0111::IndexedParamsBase148     IndexedParamsBase(const vk::VkIndexType indexT) : indexType(indexT)
149     {
150     }
151 };
152 
153 // Structs to store draw parameters
154 struct DrawParams : DrawParamsBase
155 {
156     // vkCmdDraw parameters is like a single VkDrawIndirectCommand
157     vk::VkDrawIndirectCommand params;
158 
DrawParamsvkt::Draw::__anon91bcb92a0111::DrawParams159     DrawParams(const vk::VkPrimitiveTopology top, const SharedGroupParams gParams, const uint32_t vertexC,
160                const uint32_t instanceC, const uint32_t firstV, const uint32_t firstI)
161         : DrawParamsBase(top, gParams)
162     {
163         params.vertexCount   = vertexC;
164         params.instanceCount = instanceC;
165         params.firstVertex   = firstV;
166         params.firstInstance = firstI;
167     }
168 };
169 
170 struct DrawIndexedParams : DrawParamsBase, IndexedParamsBase
171 {
172     // vkCmdDrawIndexed parameters is like a single VkDrawIndexedIndirectCommand
173     vk::VkDrawIndexedIndirectCommand params;
174 
DrawIndexedParamsvkt::Draw::__anon91bcb92a0111::DrawIndexedParams175     DrawIndexedParams(const vk::VkPrimitiveTopology top, const SharedGroupParams gParams, const vk::VkIndexType indexT,
176                       const uint32_t indexC, const uint32_t instanceC, const uint32_t firstIdx, const int32_t vertexO,
177                       const uint32_t firstIns)
178         : DrawParamsBase(top, gParams)
179         , IndexedParamsBase(indexT)
180     {
181         params.indexCount    = indexC;
182         params.instanceCount = instanceC;
183         params.firstIndex    = firstIdx;
184         params.vertexOffset  = vertexO;
185         params.firstInstance = firstIns;
186     }
187 };
188 
189 struct DrawIndirectParams : DrawParamsBase
190 {
191     std::vector<vk::VkDrawIndirectCommand> commands;
192 
DrawIndirectParamsvkt::Draw::__anon91bcb92a0111::DrawIndirectParams193     DrawIndirectParams(const vk::VkPrimitiveTopology top, const SharedGroupParams gParams)
194         : DrawParamsBase(top, gParams)
195     {
196     }
197 
addCommandvkt::Draw::__anon91bcb92a0111::DrawIndirectParams198     void addCommand(const uint32_t vertexC, const uint32_t instanceC, const uint32_t firstV, const uint32_t firstI)
199     {
200         vk::VkDrawIndirectCommand cmd;
201         cmd.vertexCount   = vertexC;
202         cmd.instanceCount = instanceC;
203         cmd.firstVertex   = firstV;
204         cmd.firstInstance = firstI;
205 
206         commands.push_back(cmd);
207     }
208 };
209 
210 struct DrawIndexedIndirectParams : DrawParamsBase, IndexedParamsBase
211 {
212     std::vector<vk::VkDrawIndexedIndirectCommand> commands;
213 
DrawIndexedIndirectParamsvkt::Draw::__anon91bcb92a0111::DrawIndexedIndirectParams214     DrawIndexedIndirectParams(const vk::VkPrimitiveTopology top, const SharedGroupParams gParams,
215                               const vk::VkIndexType indexT)
216         : DrawParamsBase(top, gParams)
217         , IndexedParamsBase(indexT)
218     {
219     }
220 
addCommandvkt::Draw::__anon91bcb92a0111::DrawIndexedIndirectParams221     void addCommand(const uint32_t indexC, const uint32_t instanceC, const uint32_t firstIdx, const int32_t vertexO,
222                     const uint32_t firstIns)
223     {
224         vk::VkDrawIndexedIndirectCommand cmd;
225         cmd.indexCount    = indexC;
226         cmd.instanceCount = instanceC;
227         cmd.firstIndex    = firstIdx;
228         cmd.vertexOffset  = vertexO;
229         cmd.firstInstance = firstIns;
230 
231         commands.push_back(cmd);
232     }
233 };
234 
235 // Reference renderer shaders
236 class PassthruVertShader : public rr::VertexShader
237 {
238 public:
PassthruVertShader(void)239     PassthruVertShader(void) : rr::VertexShader(2, 1)
240     {
241         m_inputs[0].type  = rr::GENERICVECTYPE_FLOAT;
242         m_inputs[1].type  = rr::GENERICVECTYPE_FLOAT;
243         m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
244     }
245 
~PassthruVertShader()246     virtual ~PassthruVertShader()
247     {
248     }
249 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const250     void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const
251     {
252         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
253         {
254             packets[packetNdx]->position =
255                 rr::readVertexAttribFloat(inputs[0], packets[packetNdx]->instanceNdx, packets[packetNdx]->vertexNdx);
256 
257             tcu::Vec4 color =
258                 rr::readVertexAttribFloat(inputs[1], packets[packetNdx]->instanceNdx, packets[packetNdx]->vertexNdx);
259 
260             packets[packetNdx]->outputs[0] = color;
261         }
262     }
263 };
264 
265 class PassthruFragShader : public rr::FragmentShader
266 {
267 public:
PassthruFragShader(void)268     PassthruFragShader(void) : rr::FragmentShader(1, 1)
269     {
270         m_inputs[0].type  = rr::GENERICVECTYPE_FLOAT;
271         m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
272     }
273 
~PassthruFragShader()274     virtual ~PassthruFragShader()
275     {
276     }
277 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const278     void shadeFragments(rr::FragmentPacket *packets, const int numPackets,
279                         const rr::FragmentShadingContext &context) const
280     {
281         for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
282         {
283             rr::FragmentPacket &packet = packets[packetNdx];
284             for (uint32_t fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; ++fragNdx)
285             {
286                 tcu::Vec4 color = rr::readVarying<float>(packet, context, 0, fragNdx);
287                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
288             }
289         }
290     }
291 };
292 
imageCompare(tcu::TestLog & log,const tcu::ConstPixelBufferAccess & reference,const tcu::ConstPixelBufferAccess & result,const vk::VkPrimitiveTopology topology)293 inline bool imageCompare(tcu::TestLog &log, const tcu::ConstPixelBufferAccess &reference,
294                          const tcu::ConstPixelBufferAccess &result, const vk::VkPrimitiveTopology topology)
295 {
296     if (topology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
297     {
298         return tcu::intThresholdPositionDeviationCompare(log, "Result", "Image comparison result", reference, result,
299                                                          tcu::UVec4(4u),      // color threshold
300                                                          tcu::IVec3(1, 1, 0), // position deviation tolerance
301                                                          true,                // don't check the pixels at the boundary
302                                                          tcu::COMPARE_LOG_RESULT);
303     }
304     else
305         return tcu::fuzzyCompare(log, "Result", "Image comparison result", reference, result, 0.053f,
306                                  tcu::COMPARE_LOG_RESULT);
307 }
308 
309 class DrawTestInstanceBase : public TestInstance
310 {
311 public:
312     DrawTestInstanceBase(Context &context);
313     virtual ~DrawTestInstanceBase(void) = 0;
314     void initialize(const DrawParamsBase &data);
315     void initPipeline(const vk::VkDevice device);
316     void preRenderBarriers(void);
317     void beginRenderPass(vk::VkCommandBuffer cmdBuffer);
318     void endRenderPass(vk::VkCommandBuffer cmdBuffer);
319 
320 #ifndef CTS_USES_VULKANSC
321     void beginSecondaryCmdBuffer(const vk::DeviceInterface &vk, vk::VkRenderingFlagsKHR renderingFlags = 0u);
322     void beginNestedCmdBuffer(const vk::DeviceInterface &vk, vk::VkRenderingFlagsKHR renderingFlags = 0u);
323     void beginDynamicRender(vk::VkCommandBuffer cmdBuffer, vk::VkRenderingFlagsKHR renderingFlags = 0u);
324     void beginNestedDynamicRender(vk::VkCommandBuffer cmdBuffer, bool nested,
325                                   vk::VkRenderingFlagsKHR renderingFlags = 0u);
326     void endDynamicRender(vk::VkCommandBuffer cmdBuffer);
327 #endif // CTS_USES_VULKANSC
328 
329     // Specialize this function for each type
330     virtual tcu::TestStatus iterate(void) = 0;
331 
332 protected:
333     // Specialize this function for each type
334     virtual void generateDrawData(void) = 0;
335     void generateRefImage(const tcu::PixelBufferAccess &access, const std::vector<tcu::Vec4> &vertices,
336                           const std::vector<tcu::Vec4> &colors) const;
337 
338     DrawParamsBase m_data;
339     const vk::DeviceInterface &m_vk;
340     vk::Move<vk::VkPipeline> m_pipeline;
341     vk::Move<vk::VkPipelineLayout> m_pipelineLayout;
342     vk::VkFormat m_colorAttachmentFormat;
343     de::SharedPtr<Image> m_colorTargetImage;
344     vk::Move<vk::VkImageView> m_colorTargetView;
345     vk::Move<vk::VkRenderPass> m_renderPass;
346     vk::Move<vk::VkFramebuffer> m_framebuffer;
347     PipelineCreateInfo::VertexInputState m_vertexInputState;
348     de::SharedPtr<Buffer> m_vertexBuffer;
349     vk::Move<vk::VkCommandPool> m_cmdPool;
350     vk::Move<vk::VkCommandBuffer> m_cmdBuffer;
351     vk::Move<vk::VkCommandBuffer> m_secCmdBuffer;
352     vk::Move<vk::VkCommandBuffer> m_nestedCmdBuffer;
353 
354     enum
355     {
356         WIDTH  = 256,
357         HEIGHT = 256
358     };
359 };
360 
DrawTestInstanceBase(Context & context)361 DrawTestInstanceBase::DrawTestInstanceBase(Context &context)
362     : vkt::TestInstance(context)
363     , m_vk(context.getDeviceInterface())
364     , m_colorAttachmentFormat(vk::VK_FORMAT_R8G8B8A8_UNORM)
365 {
366 }
367 
~DrawTestInstanceBase(void)368 DrawTestInstanceBase::~DrawTestInstanceBase(void)
369 {
370 }
371 
initialize(const DrawParamsBase & data)372 void DrawTestInstanceBase::initialize(const DrawParamsBase &data)
373 {
374     m_data = data;
375 
376     const vk::VkDevice device       = m_context.getDevice();
377     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
378 
379     const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
380     m_pipelineLayout = vk::createPipelineLayout(m_vk, device, &pipelineLayoutCreateInfo);
381 
382     const vk::VkExtent3D targetImageExtent = {WIDTH, HEIGHT, 1};
383     const ImageCreateInfo targetImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, targetImageExtent, 1, 1,
384                                                 vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL,
385                                                 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
386                                                     vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
387                                                     vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT);
388 
389     m_colorTargetImage = Image::createAndAlloc(m_vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(),
390                                                m_context.getUniversalQueueFamilyIndex());
391 
392     const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D,
393                                                   m_colorAttachmentFormat);
394     m_colorTargetView = vk::createImageView(m_vk, device, &colorTargetViewInfo);
395 
396     // create render pass only when we are not using dynamic rendering
397     if (!m_data.groupParams.useDynamicRendering)
398     {
399         RenderPassCreateInfo renderPassCreateInfo;
400         renderPassCreateInfo.addAttachment(AttachmentDescription(
401             m_colorAttachmentFormat, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_ATTACHMENT_LOAD_OP_LOAD,
402             vk::VK_ATTACHMENT_STORE_OP_STORE, vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, vk::VK_ATTACHMENT_STORE_OP_STORE,
403             vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_IMAGE_LAYOUT_GENERAL));
404 
405         const vk::VkAttachmentReference colorAttachmentReference{0, vk::VK_IMAGE_LAYOUT_GENERAL};
406 
407         renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS, 0, 0, DE_NULL, 1,
408                                                            &colorAttachmentReference, DE_NULL, AttachmentReference(), 0,
409                                                            DE_NULL));
410 
411         m_renderPass = vk::createRenderPass(m_vk, device, &renderPassCreateInfo);
412 
413         // create framebuffer
414         std::vector<vk::VkImageView> colorAttachments{*m_colorTargetView};
415         const FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, colorAttachments, WIDTH, HEIGHT, 1);
416         m_framebuffer = vk::createFramebuffer(m_vk, device, &framebufferCreateInfo);
417     }
418 
419     const vk::VkVertexInputBindingDescription vertexInputBindingDescription = {
420         0,
421         (uint32_t)sizeof(tcu::Vec4) * 2,
422         vk::VK_VERTEX_INPUT_RATE_VERTEX,
423     };
424 
425     const vk::VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] = {
426         {0u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u},
427         {
428             1u,
429             0u,
430             vk::VK_FORMAT_R32G32B32A32_SFLOAT,
431             (uint32_t)(sizeof(float) * 4),
432         }};
433 
434     m_vertexInputState =
435         PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription, 2, vertexInputAttributeDescriptions);
436 
437     const vk::VkDeviceSize dataSize = m_data.vertices.size() * sizeof(PositionColorVertex);
438     BufferCreateInfo createInfo(dataSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
439 
440 #ifndef CTS_USES_VULKANSC
441     vk::VkBufferUsageFlags2CreateInfoKHR bufferUsageFlags2 = vk::initVulkanStructure();
442     if (m_data.useMaintenance5)
443     {
444         bufferUsageFlags2.usage = vk::VK_BUFFER_USAGE_2_VERTEX_BUFFER_BIT_KHR;
445         createInfo.pNext        = &bufferUsageFlags2;
446         createInfo.usage        = 0xBAD00000;
447     }
448 #endif // CTS_USES_VULKANSC
449 
450     m_vertexBuffer = Buffer::createAndAlloc(m_vk, device, createInfo, m_context.getDefaultAllocator(),
451                                             vk::MemoryRequirement::HostVisible);
452 
453     uint8_t *ptr = reinterpret_cast<uint8_t *>(m_vertexBuffer->getBoundMemory().getHostPtr());
454     deMemcpy(ptr, &(m_data.vertices[0]), static_cast<size_t>(dataSize));
455 
456     vk::flushAlloc(m_vk, device, m_vertexBuffer->getBoundMemory());
457 
458     const CmdPoolCreateInfo cmdPoolCreateInfo(queueFamilyIndex);
459     m_cmdPool   = vk::createCommandPool(m_vk, device, &cmdPoolCreateInfo);
460     m_cmdBuffer = vk::allocateCommandBuffer(m_vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
461 
462     if (m_data.groupParams.useSecondaryCmdBuffer)
463         m_secCmdBuffer = vk::allocateCommandBuffer(m_vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY);
464 
465     if (m_data.groupParams.nestedSecondaryCmdBuffer)
466         m_nestedCmdBuffer = vk::allocateCommandBuffer(m_vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY);
467 
468     initPipeline(device);
469 }
470 
initPipeline(const vk::VkDevice device)471 void DrawTestInstanceBase::initPipeline(const vk::VkDevice device)
472 {
473     const vk::Unique<vk::VkShaderModule> vs(
474         createShaderModule(m_vk, device, m_context.getBinaryCollection().get("vert"), 0));
475     const vk::Unique<vk::VkShaderModule> fs(
476         createShaderModule(m_vk, device, m_context.getBinaryCollection().get("frag"), 0));
477 
478     const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState;
479 
480     vk::VkViewport viewport = vk::makeViewport(WIDTH, HEIGHT);
481     vk::VkRect2D scissor    = vk::makeRect2D(WIDTH, HEIGHT);
482 
483     // when dynamic_rendering is tested then renderPass won't be created and VK_NULL_HANDLE will be used here
484     PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
485     pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
486     pipelineCreateInfo.addShader(
487         PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
488     pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(m_vertexInputState));
489     pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(m_data.topology));
490     pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
491     pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport),
492                                                                   std::vector<vk::VkRect2D>(1, scissor)));
493     pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
494     pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
495     pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
496 
497 #ifndef CTS_USES_VULKANSC
498     vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo{vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
499                                                              DE_NULL,
500                                                              0u,
501                                                              1u,
502                                                              &m_colorAttachmentFormat,
503                                                              vk::VK_FORMAT_UNDEFINED,
504                                                              vk::VK_FORMAT_UNDEFINED};
505 
506     if (m_data.groupParams.useDynamicRendering)
507         pipelineCreateInfo.pNext = &renderingCreateInfo;
508 
509     vk::VkPipelineCreateFlags2CreateInfoKHR pipelineFlags2CreateInfo{
510         vk::VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO_KHR, pipelineCreateInfo.pNext,
511         vk::VK_PIPELINE_CREATE_2_ALLOW_DERIVATIVES_BIT_KHR};
512     if (m_data.useMaintenance5)
513     {
514         pipelineCreateInfo.flags = 0xBAD00000;
515         pipelineCreateInfo.pNext = &pipelineFlags2CreateInfo;
516     }
517 #endif // CTS_USES_VULKANSC
518 
519     m_pipeline = vk::createGraphicsPipeline(m_vk, device, DE_NULL, &pipelineCreateInfo);
520 }
521 
preRenderBarriers(void)522 void DrawTestInstanceBase::preRenderBarriers(void)
523 {
524     const vk::VkClearValue clearColor{{{0.0f, 0.0f, 0.0f, 1.0f}}};
525 
526     initialTransitionColor2DImage(m_vk, *m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
527                                   vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
528 
529     const ImageSubresourceRange subresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT);
530     m_vk.cmdClearColorImage(*m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL, &clearColor.color,
531                             1, &subresourceRange);
532 
533     const vk::VkMemoryBarrier memBarrier{
534         vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER, DE_NULL, vk::VK_ACCESS_TRANSFER_WRITE_BIT,
535         vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT};
536 
537     m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
538                             vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0,
539                             DE_NULL);
540 }
541 
beginRenderPass(vk::VkCommandBuffer cmdBuffer)542 void DrawTestInstanceBase::beginRenderPass(vk::VkCommandBuffer cmdBuffer)
543 {
544     const vk::VkClearValue clearColor{{{0.0f, 0.0f, 0.0f, 1.0f}}};
545     const vk::VkRect2D renderArea = vk::makeRect2D(WIDTH, HEIGHT);
546 
547     vk::beginRenderPass(m_vk, cmdBuffer, *m_renderPass, *m_framebuffer, renderArea, 1u, &clearColor);
548 }
549 
endRenderPass(vk::VkCommandBuffer cmdBuffer)550 void DrawTestInstanceBase::endRenderPass(vk::VkCommandBuffer cmdBuffer)
551 {
552     vk::endRenderPass(m_vk, cmdBuffer);
553 }
554 
555 #ifndef CTS_USES_VULKANSC
beginSecondaryCmdBuffer(const vk::DeviceInterface & vk,vk::VkRenderingFlagsKHR renderingFlags)556 void DrawTestInstanceBase::beginSecondaryCmdBuffer(const vk::DeviceInterface &vk,
557                                                    vk::VkRenderingFlagsKHR renderingFlags)
558 {
559     const vk::VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo{
560         vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
561         DE_NULL,                                                             // const void* pNext;
562         renderingFlags,                                                      // VkRenderingFlagsKHR flags;
563         0u,                                                                  // uint32_t viewMask;
564         1u,                                                                  // uint32_t colorAttachmentCount;
565         &m_colorAttachmentFormat,                                            // const VkFormat* pColorAttachmentFormats;
566         vk::VK_FORMAT_UNDEFINED,                                             // VkFormat depthAttachmentFormat;
567         vk::VK_FORMAT_UNDEFINED,                                             // VkFormat stencilAttachmentFormat;
568         vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
569     };
570 
571     const vk::VkCommandBufferInheritanceInfo bufferInheritanceInfo{
572         vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, // VkStructureType sType;
573         &inheritanceRenderingInfo,                             // const void* pNext;
574         DE_NULL,                                               // VkRenderPass renderPass;
575         0u,                                                    // uint32_t subpass;
576         DE_NULL,                                               // VkFramebuffer framebuffer;
577         VK_FALSE,                                              // VkBool32 occlusionQueryEnable;
578         (vk::VkQueryControlFlags)0u,                           // VkQueryControlFlags queryFlags;
579         (vk::VkQueryPipelineStatisticFlags)0u                  // VkQueryPipelineStatisticFlags pipelineStatistics;
580     };
581 
582     vk::VkCommandBufferUsageFlags usageFlags = vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
583     if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
584         usageFlags |= vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
585 
586     const vk::VkCommandBufferBeginInfo commandBufBeginParams{
587         vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
588         DE_NULL,                                         // const void* pNext;
589         usageFlags,                                      // VkCommandBufferUsageFlags flags;
590         &bufferInheritanceInfo};
591 
592     VK_CHECK(vk.beginCommandBuffer(*m_secCmdBuffer, &commandBufBeginParams));
593 }
594 
beginNestedCmdBuffer(const vk::DeviceInterface & vk,vk::VkRenderingFlagsKHR renderingFlags)595 void DrawTestInstanceBase::beginNestedCmdBuffer(const vk::DeviceInterface &vk, vk::VkRenderingFlagsKHR renderingFlags)
596 {
597     const vk::VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo{
598         vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
599         DE_NULL,                                                             // const void* pNext;
600         renderingFlags,                                                      // VkRenderingFlagsKHR flags;
601         0u,                                                                  // uint32_t viewMask;
602         1u,                                                                  // uint32_t colorAttachmentCount;
603         &m_colorAttachmentFormat,                                            // const VkFormat* pColorAttachmentFormats;
604         vk::VK_FORMAT_UNDEFINED,                                             // VkFormat depthAttachmentFormat;
605         vk::VK_FORMAT_UNDEFINED,                                             // VkFormat stencilAttachmentFormat;
606         vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
607     };
608 
609     const vk::VkCommandBufferInheritanceInfo bufferInheritanceInfo{
610         vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, // VkStructureType sType;
611         &inheritanceRenderingInfo,                             // const void* pNext;
612         DE_NULL,                                               // VkRenderPass renderPass;
613         0u,                                                    // uint32_t subpass;
614         DE_NULL,                                               // VkFramebuffer framebuffer;
615         VK_FALSE,                                              // VkBool32 occlusionQueryEnable;
616         (vk::VkQueryControlFlags)0u,                           // VkQueryControlFlags queryFlags;
617         (vk::VkQueryPipelineStatisticFlags)0u                  // VkQueryPipelineStatisticFlags pipelineStatistics;
618     };
619 
620     vk::VkCommandBufferUsageFlags usageFlags = vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
621     if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
622         usageFlags |= vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
623 
624     const vk::VkCommandBufferBeginInfo commandBufBeginParams{
625         vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
626         DE_NULL,                                         // const void* pNext;
627         usageFlags,                                      // VkCommandBufferUsageFlags flags;
628         &bufferInheritanceInfo};
629 
630     VK_CHECK(vk.beginCommandBuffer(*m_nestedCmdBuffer, &commandBufBeginParams));
631 }
632 
beginDynamicRender(vk::VkCommandBuffer cmdBuffer,vk::VkRenderingFlagsKHR renderingFlags)633 void DrawTestInstanceBase::beginDynamicRender(vk::VkCommandBuffer cmdBuffer, vk::VkRenderingFlagsKHR renderingFlags)
634 {
635     const vk::VkClearValue clearColor{{{0.0f, 0.0f, 0.0f, 1.0f}}};
636     const vk::VkRect2D renderArea = vk::makeRect2D(WIDTH, HEIGHT);
637 
638     vk::beginRendering(m_vk, cmdBuffer, *m_colorTargetView, renderArea, clearColor, vk::VK_IMAGE_LAYOUT_GENERAL,
639                        vk::VK_ATTACHMENT_LOAD_OP_LOAD, renderingFlags);
640 }
641 
endDynamicRender(vk::VkCommandBuffer cmdBuffer)642 void DrawTestInstanceBase::endDynamicRender(vk::VkCommandBuffer cmdBuffer)
643 {
644     vk::endRendering(m_vk, cmdBuffer);
645 }
646 #endif // CTS_USES_VULKANSC
647 
generateRefImage(const tcu::PixelBufferAccess & access,const std::vector<tcu::Vec4> & vertices,const std::vector<tcu::Vec4> & colors) const648 void DrawTestInstanceBase::generateRefImage(const tcu::PixelBufferAccess &access,
649                                             const std::vector<tcu::Vec4> &vertices,
650                                             const std::vector<tcu::Vec4> &colors) const
651 {
652     const PassthruVertShader vertShader;
653     const PassthruFragShader fragShader;
654     const rr::Program program(&vertShader, &fragShader);
655     const rr::MultisamplePixelBufferAccess colorBuffer =
656         rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(access);
657     const rr::RenderTarget renderTarget(colorBuffer);
658     const rr::RenderState renderState((rr::ViewportState(colorBuffer)),
659                                       m_context.getDeviceProperties().limits.subPixelPrecisionBits);
660     const rr::Renderer renderer;
661 
662     const rr::VertexAttrib vertexAttribs[] = {
663         rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &vertices[0]),
664         rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &colors[0])};
665 
666     renderer.draw(
667         rr::DrawCommand(renderState, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs), &vertexAttribs[0],
668                         rr::PrimitiveList(mapVkPrimitiveTopology(m_data.topology), (uint32_t)vertices.size(), 0)));
669 }
670 
671 template <typename T>
672 class DrawTestInstance : public DrawTestInstanceBase
673 {
674 public:
675     DrawTestInstance(Context &context, const T &data);
676     virtual ~DrawTestInstance(void);
677     virtual void generateDrawData(void);
678     virtual void draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer indirectBuffer = DE_NULL,
679                       vk::VkDeviceSize indirectOffset = 0ul);
680     virtual tcu::TestStatus iterate(void);
681 
682 private:
683     T m_data;
684 };
685 
686 template <typename T>
DrawTestInstance(Context & context,const T & data)687 DrawTestInstance<T>::DrawTestInstance(Context &context, const T &data) : DrawTestInstanceBase(context)
688                                                                        , m_data(data)
689 {
690     generateDrawData();
691     initialize(m_data);
692 }
693 
694 template <typename T>
~DrawTestInstance(void)695 DrawTestInstance<T>::~DrawTestInstance(void)
696 {
697 }
698 
699 template <typename T>
generateDrawData(void)700 void DrawTestInstance<T>::generateDrawData(void)
701 {
702     DE_FATAL("Using the general case of this function is forbidden!");
703 }
704 
705 template <typename T>
draw(vk::VkCommandBuffer,vk::VkBuffer,vk::VkDeviceSize)706 void DrawTestInstance<T>::draw(vk::VkCommandBuffer, vk::VkBuffer, vk::VkDeviceSize)
707 {
708     DE_FATAL("Using the general case of this function is forbidden!");
709 }
710 
711 template <typename T>
iterate(void)712 tcu::TestStatus DrawTestInstance<T>::iterate(void)
713 {
714     DE_FATAL("Using the general case of this function is forbidden!");
715     return tcu::TestStatus::fail("");
716 }
717 
718 template <typename T>
719 class DrawTestCase : public TestCase
720 {
721 public:
722     DrawTestCase(tcu::TestContext &context, const char *name, const T data);
723     ~DrawTestCase(void);
724     virtual void initPrograms(vk::SourceCollections &programCollection) const;
725     virtual void initShaderSources(void);
726     virtual void checkSupport(Context &context) const;
727     virtual TestInstance *createInstance(Context &context) const;
728 
729 private:
730     T m_data;
731     std::string m_vertShaderSource;
732     std::string m_fragShaderSource;
733 };
734 
735 template <typename T>
DrawTestCase(tcu::TestContext & context,const char * name,const T data)736 DrawTestCase<T>::DrawTestCase(tcu::TestContext &context, const char *name, const T data)
737     : vkt::TestCase(context, name)
738     , m_data(data)
739 {
740     initShaderSources();
741 }
742 
743 template <typename T>
~DrawTestCase(void)744 DrawTestCase<T>::~DrawTestCase(void)
745 {
746 }
747 
748 template <typename T>
initPrograms(vk::SourceCollections & programCollection) const749 void DrawTestCase<T>::initPrograms(vk::SourceCollections &programCollection) const
750 {
751     programCollection.glslSources.add("vert") << glu::VertexSource(m_vertShaderSource);
752     programCollection.glslSources.add("frag") << glu::FragmentSource(m_fragShaderSource);
753 }
754 
755 template <typename T>
checkSupport(Context & context) const756 void DrawTestCase<T>::checkSupport(Context &context) const
757 {
758     if (m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY ||
759         m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY ||
760         m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY ||
761         m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY)
762     {
763         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
764     }
765 
766 #ifndef CTS_USES_VULKANSC
767     if (m_data.useMaintenance5)
768         context.requireDeviceFunctionality("VK_KHR_maintenance5");
769 
770     if (m_data.groupParams.useDynamicRendering)
771         context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
772 
773     if (m_data.groupParams.nestedSecondaryCmdBuffer)
774     {
775         context.requireDeviceFunctionality("VK_EXT_nested_command_buffer");
776         const auto &features =
777             *vk::findStructure<vk::VkPhysicalDeviceNestedCommandBufferFeaturesEXT>(&context.getDeviceFeatures2());
778         if (!features.nestedCommandBuffer)
779             TCU_THROW(NotSupportedError, "nestedCommandBuffer is not supported");
780         if (!features.nestedCommandBufferRendering)
781             TCU_THROW(NotSupportedError, "nestedCommandBufferRendering is not supported, so "
782                                          "VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT cannot be used");
783     }
784 
785     if (m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
786         context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
787         !context.getPortabilitySubsetFeatures().triangleFans)
788     {
789         TCU_THROW(NotSupportedError,
790                   "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
791     }
792 #endif // CTS_USES_VULKANSC
793 }
794 
795 template <typename T>
initShaderSources(void)796 void DrawTestCase<T>::initShaderSources(void)
797 {
798     std::stringstream vertShader;
799     vertShader << "#version 430\n"
800                << "layout(location = 0) in vec4 in_position;\n"
801                << "layout(location = 1) in vec4 in_color;\n"
802                << "layout(location = 0) out vec4 out_color;\n"
803 
804                << "out gl_PerVertex {\n"
805                << "    vec4  gl_Position;\n"
806                << "    float gl_PointSize;\n"
807                << "};\n"
808                << "void main() {\n"
809                << "    gl_PointSize = 1.0;\n"
810                << "    gl_Position  = in_position;\n"
811                << "    out_color    = in_color;\n"
812                << "}\n";
813 
814     m_vertShaderSource = vertShader.str();
815 
816     std::stringstream fragShader;
817     fragShader << "#version 430\n"
818                << "layout(location = 0) in vec4 in_color;\n"
819                << "layout(location = 0) out vec4 out_color;\n"
820                << "void main()\n"
821                << "{\n"
822                << "    out_color = in_color;\n"
823                << "}\n";
824 
825     m_fragShaderSource = fragShader.str();
826 }
827 
828 template <typename T>
createInstance(Context & context) const829 TestInstance *DrawTestCase<T>::createInstance(Context &context) const
830 {
831     return new DrawTestInstance<T>(context, m_data);
832 }
833 
834 // Specialized cases
835 template <>
generateDrawData(void)836 void DrawTestInstance<DrawParams>::generateDrawData(void)
837 {
838     de::Random rnd(SEED ^ m_data.params.firstVertex ^ m_data.params.vertexCount);
839 
840     const uint32_t vectorSize = m_data.params.firstVertex + m_data.params.vertexCount;
841 
842     // Initialize the vector
843     m_data.vertices = std::vector<PositionColorVertex>(
844         vectorSize, PositionColorVertex(tcu::Vec4(0.0, 0.0, 0.0, 0.0), tcu::Vec4(0.0, 0.0, 0.0, 0.0)));
845 
846     // Fill only the used indexes
847     for (uint32_t vertexIdx = m_data.params.firstVertex; vertexIdx < vectorSize; ++vertexIdx)
848     {
849         const float f0 = rnd.getFloat(-1.0f, 1.0f);
850         const float f1 = rnd.getFloat(-1.0f, 1.0f);
851 
852         m_data.vertices[vertexIdx] = PositionColorVertex(tcu::Vec4(f0, f1, 1.0f, 1.0f), // Coord
853                                                          tcu::randomVec4(rnd));         // Color
854     }
855 }
856 
857 template <>
draw(vk::VkCommandBuffer cmdBuffer,vk::VkBuffer,vk::VkDeviceSize)858 void DrawTestInstance<DrawParams>::draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer, vk::VkDeviceSize)
859 {
860     m_vk.cmdDraw(cmdBuffer, m_data.params.vertexCount, m_data.params.instanceCount, m_data.params.firstVertex,
861                  m_data.params.firstInstance);
862 }
863 
864 template <>
iterate(void)865 tcu::TestStatus DrawTestInstance<DrawParams>::iterate(void)
866 {
867     tcu::TestLog &log                         = m_context.getTestContext().getLog();
868     const vk::VkQueue queue                   = m_context.getUniversalQueue();
869     const vk::VkDevice device                 = m_context.getDevice();
870     const vk::VkDeviceSize vertexBufferOffset = 0;
871     const vk::VkBuffer vertexBuffer           = m_vertexBuffer->object();
872 
873 #ifndef CTS_USES_VULKANSC
874     if (m_data.groupParams.useSecondaryCmdBuffer)
875     {
876         // record secondary command buffer
877         if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
878         {
879             beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
880             beginDynamicRender(*m_secCmdBuffer);
881         }
882         else
883             beginSecondaryCmdBuffer(m_vk);
884 
885         m_vk.cmdBindVertexBuffers(*m_secCmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
886         m_vk.cmdBindPipeline(*m_secCmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
887         draw(*m_secCmdBuffer);
888 
889         if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
890             endDynamicRender(*m_secCmdBuffer);
891 
892         endCommandBuffer(m_vk, *m_secCmdBuffer);
893 
894         if (m_data.groupParams.nestedSecondaryCmdBuffer)
895         {
896             // record buffer to nest secondary buffer in
897             beginNestedCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT |
898                                            vk::VK_RENDERING_CONTENTS_INLINE_BIT_EXT);
899             m_vk.cmdExecuteCommands(*m_nestedCmdBuffer, 1u, &*m_secCmdBuffer);
900             endCommandBuffer(m_vk, *m_nestedCmdBuffer);
901         }
902 
903         // record primary command buffer
904         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
905 
906         preRenderBarriers();
907 
908         if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
909             beginDynamicRender(*m_cmdBuffer, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
910 
911         if (m_data.groupParams.nestedSecondaryCmdBuffer)
912         {
913             m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_nestedCmdBuffer);
914         }
915         else
916         {
917             m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
918         }
919 
920         if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
921             endDynamicRender(*m_cmdBuffer);
922 
923         endCommandBuffer(m_vk, *m_cmdBuffer);
924     }
925     else if (m_data.groupParams.useDynamicRendering)
926     {
927         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
928         preRenderBarriers();
929         beginDynamicRender(*m_cmdBuffer);
930 
931         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
932         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
933         draw(*m_cmdBuffer);
934 
935         endDynamicRender(*m_cmdBuffer);
936         endCommandBuffer(m_vk, *m_cmdBuffer);
937     }
938 #endif // CTS_USES_VULKANSC
939 
940     if (!m_data.groupParams.useDynamicRendering)
941     {
942         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
943         preRenderBarriers();
944         beginRenderPass(*m_cmdBuffer);
945 
946         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
947         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
948         draw(*m_cmdBuffer);
949 
950         endRenderPass(*m_cmdBuffer);
951         endCommandBuffer(m_vk, *m_cmdBuffer);
952     }
953 
954     submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
955 
956     // Validation
957     tcu::TextureLevel refImage(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)),
958                                (int)(0.5f + static_cast<float>(HEIGHT)));
959     tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
960 
961     std::vector<tcu::Vec4> vertices;
962     std::vector<tcu::Vec4> colors;
963 
964     for (std::vector<PositionColorVertex>::const_iterator vertex = m_data.vertices.begin() + m_data.params.firstVertex;
965          vertex != m_data.vertices.end(); ++vertex)
966     {
967         vertices.push_back(vertex->position);
968         colors.push_back(vertex->color);
969     }
970     generateRefImage(refImage.getAccess(), vertices, colors);
971 
972     const vk::VkOffset3D zeroOffset = {0, 0, 0};
973     const tcu::ConstPixelBufferAccess renderedFrame =
974         m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset,
975                                         WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
976 
977     qpTestResult res = QP_TEST_RESULT_PASS;
978 
979     if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
980         res = QP_TEST_RESULT_FAIL;
981 
982     return tcu::TestStatus(res, qpGetTestResultName(res));
983 }
984 
985 template <>
generateDrawData(void)986 void DrawTestInstance<DrawIndexedParams>::generateDrawData(void)
987 {
988     de::Random rnd(SEED ^ m_data.params.firstIndex ^ m_data.params.indexCount);
989     const uint32_t indexSize = m_data.params.firstIndex + m_data.params.indexCount;
990 
991     // Initialize the vector with zeros
992     m_data.indexes = std::vector<uint32_t>(indexSize, 0);
993 
994     uint32_t highestIndex = 0; // Store to highest index to calculate the vertices size
995     // Fill the indexes from firstIndex
996     for (uint32_t idx = 0; idx < m_data.params.indexCount; ++idx)
997     {
998         uint32_t vertexIdx = rnd.getInt(m_data.params.vertexOffset, INDEX_LIMIT);
999         highestIndex       = (vertexIdx > highestIndex) ? vertexIdx : highestIndex;
1000 
1001         m_data.indexes[m_data.params.firstIndex + idx] = vertexIdx;
1002     }
1003 
1004     // Fill up the vertex coordinates with zeros until the highestIndex including the vertexOffset
1005     m_data.vertices = std::vector<PositionColorVertex>(
1006         m_data.params.vertexOffset + highestIndex + 1,
1007         PositionColorVertex(tcu::Vec4(0.0, 0.0, 0.0, 0.0), tcu::Vec4(0.0, 0.0, 0.0, 0.0)));
1008 
1009     // Generate random vertex only where you have index pointing at
1010     for (std::vector<uint32_t>::const_iterator indexIt = m_data.indexes.begin() + m_data.params.firstIndex;
1011          indexIt != m_data.indexes.end(); ++indexIt)
1012     {
1013         // Get iterator to the vertex position  with the vertexOffset
1014         std::vector<PositionColorVertex>::iterator vertexIt =
1015             m_data.vertices.begin() + m_data.params.vertexOffset + *indexIt;
1016 
1017         tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
1018         const float f0                             = rnd.getFloat(-1.0f, 1.0f);
1019         const float f1                             = rnd.getFloat(-1.0f, 1.0f);
1020         positionAccess                             = tcu::Vec4(f0, f1, 1.0f, 1.0f);
1021 
1022         tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
1023         colorAccess                             = tcu::randomVec4(rnd);
1024     }
1025 }
1026 
1027 template <>
draw(vk::VkCommandBuffer cmdBuffer,vk::VkBuffer,vk::VkDeviceSize)1028 void DrawTestInstance<DrawIndexedParams>::draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer, vk::VkDeviceSize)
1029 {
1030     m_vk.cmdDrawIndexed(cmdBuffer, m_data.params.indexCount, m_data.params.instanceCount, m_data.params.firstIndex,
1031                         m_data.params.vertexOffset, m_data.params.firstInstance);
1032 }
1033 
1034 template <>
iterate(void)1035 tcu::TestStatus DrawTestInstance<DrawIndexedParams>::iterate(void)
1036 {
1037     tcu::TestLog &log                         = m_context.getTestContext().getLog();
1038     const vk::DeviceInterface &vk             = m_context.getDeviceInterface();
1039     const vk::VkDevice vkDevice               = m_context.getDevice();
1040     const uint32_t queueFamilyIndex           = m_context.getUniversalQueueFamilyIndex();
1041     const vk::VkQueue queue                   = m_context.getUniversalQueue();
1042     vk::Allocator &allocator                  = m_context.getDefaultAllocator();
1043     const vk::VkDeviceSize vertexBufferOffset = 0;
1044     const vk::VkBuffer vertexBuffer           = m_vertexBuffer->object();
1045     const uint32_t bufferSize                 = (uint32_t)(m_data.indexes.size() * sizeof(uint32_t));
1046 
1047     const vk::VkBufferCreateInfo bufferCreateInfo = {
1048         vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1049         DE_NULL,                                  // const void* pNext;
1050         0u,                                       // VkBufferCreateFlags flags;
1051         bufferSize,                               // VkDeviceSize size;
1052         vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT,     // VkBufferUsageFlags usage;
1053         vk::VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
1054         1u,                                       // uint32_t queueFamilyIndexCount;
1055         &queueFamilyIndex,                        // const uint32_t* pQueueFamilyIndices;
1056     };
1057 
1058     vk::Move<vk::VkBuffer> indexBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
1059     de::MovePtr<vk::Allocation> indexAlloc;
1060 
1061     indexAlloc =
1062         allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indexBuffer), vk::MemoryRequirement::HostVisible);
1063     VK_CHECK(vk.bindBufferMemory(vkDevice, *indexBuffer, indexAlloc->getMemory(), indexAlloc->getOffset()));
1064 
1065     deMemcpy(indexAlloc->getHostPtr(), &(m_data.indexes[0]), bufferSize);
1066 
1067     vk::flushAlloc(m_vk, vkDevice, *indexAlloc);
1068 
1069 #ifndef CTS_USES_VULKANSC
1070     if (m_data.groupParams.useSecondaryCmdBuffer)
1071     {
1072         // record secondary command buffer
1073         if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1074         {
1075             beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1076             beginDynamicRender(*m_secCmdBuffer);
1077         }
1078         else
1079             beginSecondaryCmdBuffer(m_vk);
1080 
1081         m_vk.cmdBindPipeline(*m_secCmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1082         m_vk.cmdBindVertexBuffers(*m_secCmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1083         m_vk.cmdBindIndexBuffer(*m_secCmdBuffer, *indexBuffer, 0u, m_data.indexType);
1084         draw(*m_secCmdBuffer);
1085 
1086         if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1087             endDynamicRender(*m_secCmdBuffer);
1088 
1089         endCommandBuffer(m_vk, *m_secCmdBuffer);
1090 
1091         // record primary command buffer
1092         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1093 
1094         preRenderBarriers();
1095 
1096         if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1097             beginDynamicRender(*m_cmdBuffer, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1098 
1099         m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
1100 
1101         if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1102             endDynamicRender(*m_cmdBuffer);
1103 
1104         endCommandBuffer(m_vk, *m_cmdBuffer);
1105     }
1106     else if (m_data.groupParams.useDynamicRendering)
1107     {
1108         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1109         preRenderBarriers();
1110         beginDynamicRender(*m_cmdBuffer);
1111 
1112         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1113         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1114         m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
1115         draw(*m_cmdBuffer);
1116 
1117         endDynamicRender(*m_cmdBuffer);
1118         endCommandBuffer(m_vk, *m_cmdBuffer);
1119     }
1120 #endif // CTS_USES_VULKANSC
1121 
1122     if (!m_data.groupParams.useDynamicRendering)
1123     {
1124         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1125         preRenderBarriers();
1126         beginRenderPass(*m_cmdBuffer);
1127 
1128         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1129         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1130         m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
1131         draw(*m_cmdBuffer);
1132 
1133         endRenderPass(*m_cmdBuffer);
1134         endCommandBuffer(m_vk, *m_cmdBuffer);
1135     }
1136 
1137     submitCommandsAndWait(m_vk, vkDevice, queue, m_cmdBuffer.get());
1138 
1139     // Validation
1140     tcu::TextureLevel refImage(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)),
1141                                (int)(0.5f + static_cast<float>(HEIGHT)));
1142     tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1143 
1144     std::vector<tcu::Vec4> vertices;
1145     std::vector<tcu::Vec4> colors;
1146 
1147     for (std::vector<uint32_t>::const_iterator it = m_data.indexes.begin() + m_data.params.firstIndex;
1148          it != m_data.indexes.end(); ++it)
1149     {
1150         uint32_t idx = m_data.params.vertexOffset + *it;
1151         vertices.push_back(m_data.vertices[idx].position);
1152         colors.push_back(m_data.vertices[idx].color);
1153     }
1154     generateRefImage(refImage.getAccess(), vertices, colors);
1155 
1156     const vk::VkOffset3D zeroOffset = {0, 0, 0};
1157     const tcu::ConstPixelBufferAccess renderedFrame =
1158         m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset,
1159                                         WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1160 
1161     qpTestResult res = QP_TEST_RESULT_PASS;
1162 
1163     if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
1164         res = QP_TEST_RESULT_FAIL;
1165 
1166     return tcu::TestStatus(res, qpGetTestResultName(res));
1167 }
1168 
1169 template <>
generateDrawData(void)1170 void DrawTestInstance<DrawIndirectParams>::generateDrawData(void)
1171 {
1172     de::Random rnd(SEED ^ m_data.commands[0].vertexCount ^ m_data.commands[0].firstVertex);
1173 
1174     uint32_t lastIndex = 0;
1175 
1176     // Find the interval which will be used
1177     for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin();
1178          it != m_data.commands.end(); ++it)
1179     {
1180         const uint32_t index = it->firstVertex + it->vertexCount;
1181         lastIndex            = (index > lastIndex) ? index : lastIndex;
1182     }
1183 
1184     // Initialize with zeros
1185     m_data.vertices = std::vector<PositionColorVertex>(
1186         lastIndex, PositionColorVertex(tcu::Vec4(0.0, 0.0, 0.0, 0.0), tcu::Vec4(0.0, 0.0, 0.0, 0.0)));
1187 
1188     // Generate random vertices only where necessary
1189     for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin();
1190          it != m_data.commands.end(); ++it)
1191     {
1192         std::vector<PositionColorVertex>::iterator vertexStart = m_data.vertices.begin() + it->firstVertex;
1193 
1194         for (uint32_t idx = 0; idx < it->vertexCount; ++idx)
1195         {
1196             std::vector<PositionColorVertex>::iterator vertexIt = vertexStart + idx;
1197 
1198             tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
1199             const float f0                             = rnd.getFloat(-1.0f, 1.0f);
1200             const float f1                             = rnd.getFloat(-1.0f, 1.0f);
1201             positionAccess                             = tcu::Vec4(f0, f1, 1.0f, 1.0f);
1202 
1203             tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
1204             colorAccess                             = tcu::randomVec4(rnd);
1205         }
1206     }
1207 }
1208 
1209 template <>
draw(vk::VkCommandBuffer cmdBuffer,vk::VkBuffer indirectBuffer,vk::VkDeviceSize indirectOffset)1210 void DrawTestInstance<DrawIndirectParams>::draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer indirectBuffer,
1211                                                 vk::VkDeviceSize indirectOffset)
1212 {
1213     const vk::VkPhysicalDeviceFeatures features = m_context.getDeviceFeatures();
1214 
1215     // If multiDrawIndirect not supported execute single calls
1216     if (m_data.commands.size() > 1 && !(features.multiDrawIndirect))
1217     {
1218         for (uint32_t cmdIdx = 0; cmdIdx < m_data.commands.size(); ++cmdIdx)
1219         {
1220             const uint32_t offset = (uint32_t)(indirectOffset + cmdIdx * sizeof(vk::VkDrawIndirectCommand));
1221             m_vk.cmdDrawIndirect(cmdBuffer, indirectBuffer, offset, 1, sizeof(vk::VkDrawIndirectCommand));
1222         }
1223     }
1224     else
1225     {
1226         m_vk.cmdDrawIndirect(cmdBuffer, indirectBuffer, indirectOffset, (uint32_t)m_data.commands.size(),
1227                              sizeof(vk::VkDrawIndirectCommand));
1228     }
1229 }
1230 
1231 template <>
iterate(void)1232 tcu::TestStatus DrawTestInstance<DrawIndirectParams>::iterate(void)
1233 {
1234     tcu::TestLog &log                         = m_context.getTestContext().getLog();
1235     const vk::DeviceInterface &vk             = m_context.getDeviceInterface();
1236     const vk::VkDevice vkDevice               = m_context.getDevice();
1237     vk::Allocator &allocator                  = m_context.getDefaultAllocator();
1238     const vk::VkQueue queue                   = m_context.getUniversalQueue();
1239     const uint32_t queueFamilyIndex           = m_context.getUniversalQueueFamilyIndex();
1240     const vk::VkDeviceSize vertexBufferOffset = 0;
1241     const vk::VkBuffer vertexBuffer           = m_vertexBuffer->object();
1242     vk::Move<vk::VkBuffer> indirectBuffer;
1243     de::MovePtr<vk::Allocation> indirectAlloc;
1244 
1245     {
1246         const vk::VkDeviceSize indirectInfoSize = m_data.commands.size() * sizeof(vk::VkDrawIndirectCommand);
1247 
1248         const vk::VkBufferCreateInfo indirectCreateInfo = {
1249             vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1250             DE_NULL,                                  // const void* pNext;
1251             0u,                                       // VkBufferCreateFlags flags;
1252             indirectInfoSize,                         // VkDeviceSize size;
1253             vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,  // VkBufferUsageFlags usage;
1254             vk::VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
1255             1u,                                       // uint32_t queueFamilyIndexCount;
1256             &queueFamilyIndex,                        // const uint32_t* pQueueFamilyIndices;
1257         };
1258 
1259         indirectBuffer = createBuffer(vk, vkDevice, &indirectCreateInfo);
1260         indirectAlloc  = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indirectBuffer),
1261                                             vk::MemoryRequirement::HostVisible);
1262         VK_CHECK(
1263             vk.bindBufferMemory(vkDevice, *indirectBuffer, indirectAlloc->getMemory(), indirectAlloc->getOffset()));
1264 
1265         deMemcpy(indirectAlloc->getHostPtr(), &(m_data.commands[0]), (size_t)indirectInfoSize);
1266 
1267         vk::flushAlloc(m_vk, vkDevice, *indirectAlloc);
1268     }
1269 
1270 #ifndef CTS_USES_VULKANSC
1271     if (m_data.groupParams.useSecondaryCmdBuffer)
1272     {
1273         // record secondary command buffer
1274         if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1275         {
1276             beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1277             beginDynamicRender(*m_secCmdBuffer);
1278         }
1279         else
1280             beginSecondaryCmdBuffer(m_vk);
1281 
1282         m_vk.cmdBindVertexBuffers(*m_secCmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1283         m_vk.cmdBindPipeline(*m_secCmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1284         draw(*m_secCmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1285 
1286         if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1287             endDynamicRender(*m_secCmdBuffer);
1288 
1289         endCommandBuffer(m_vk, *m_secCmdBuffer);
1290 
1291         // record primary command buffer
1292         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1293 
1294         preRenderBarriers();
1295 
1296         if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1297             beginDynamicRender(*m_cmdBuffer, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1298 
1299         m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
1300 
1301         if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1302             endDynamicRender(*m_cmdBuffer);
1303 
1304         endCommandBuffer(m_vk, *m_cmdBuffer);
1305     }
1306     else if (m_data.groupParams.useDynamicRendering)
1307     {
1308         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1309         preRenderBarriers();
1310         beginDynamicRender(*m_cmdBuffer);
1311 
1312         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1313         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1314         draw(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1315 
1316         endDynamicRender(*m_cmdBuffer);
1317         endCommandBuffer(m_vk, *m_cmdBuffer);
1318     }
1319 #endif // CTS_USES_VULKANSC
1320 
1321     if (!m_data.groupParams.useDynamicRendering)
1322     {
1323         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1324         preRenderBarriers();
1325         beginRenderPass(*m_cmdBuffer);
1326 
1327         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1328         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1329         draw(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1330 
1331         endRenderPass(*m_cmdBuffer);
1332         endCommandBuffer(m_vk, *m_cmdBuffer);
1333     }
1334 
1335     submitCommandsAndWait(m_vk, vkDevice, queue, m_cmdBuffer.get());
1336 
1337     // Validation
1338     tcu::TextureLevel refImage(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)),
1339                                (int)(0.5f + static_cast<float>(HEIGHT)));
1340     tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1341 
1342     for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin();
1343          it != m_data.commands.end(); ++it)
1344     {
1345         std::vector<tcu::Vec4> vertices;
1346         std::vector<tcu::Vec4> colors;
1347 
1348         std::vector<PositionColorVertex>::const_iterator firstIt = m_data.vertices.begin() + it->firstVertex;
1349         std::vector<PositionColorVertex>::const_iterator lastIt  = firstIt + it->vertexCount;
1350 
1351         for (std::vector<PositionColorVertex>::const_iterator vertex = firstIt; vertex != lastIt; ++vertex)
1352         {
1353             vertices.push_back(vertex->position);
1354             colors.push_back(vertex->color);
1355         }
1356         generateRefImage(refImage.getAccess(), vertices, colors);
1357     }
1358 
1359     const vk::VkOffset3D zeroOffset = {0, 0, 0};
1360     const tcu::ConstPixelBufferAccess renderedFrame =
1361         m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset,
1362                                         WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1363 
1364     qpTestResult res = QP_TEST_RESULT_PASS;
1365 
1366     if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
1367         res = QP_TEST_RESULT_FAIL;
1368 
1369     return tcu::TestStatus(res, qpGetTestResultName(res));
1370 }
1371 
1372 template <>
generateDrawData(void)1373 void DrawTestInstance<DrawIndexedIndirectParams>::generateDrawData(void)
1374 {
1375     de::Random rnd(SEED ^ m_data.commands[0].firstIndex ^ m_data.commands[0].indexCount);
1376 
1377     uint32_t lastIndex = 0;
1378 
1379     // Get the maximum range of indexes
1380     for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator it = m_data.commands.begin();
1381          it != m_data.commands.end(); ++it)
1382     {
1383         const uint32_t index = it->firstIndex + it->indexCount;
1384         lastIndex            = (index > lastIndex) ? index : lastIndex;
1385     }
1386 
1387     // Initialize the vector with zeros
1388     m_data.indexes = std::vector<uint32_t>(lastIndex, 0);
1389 
1390     uint32_t highestIndex = 0;
1391 
1392     // Generate random indexes for the ranges
1393     for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator it = m_data.commands.begin();
1394          it != m_data.commands.end(); ++it)
1395     {
1396         for (uint32_t idx = 0; idx < it->indexCount; ++idx)
1397         {
1398             const uint32_t vertexIdx = rnd.getInt(it->vertexOffset, INDEX_LIMIT);
1399             const uint32_t maxIndex  = vertexIdx + it->vertexOffset;
1400 
1401             highestIndex                         = (maxIndex > highestIndex) ? maxIndex : highestIndex;
1402             m_data.indexes[it->firstIndex + idx] = vertexIdx;
1403         }
1404     }
1405 
1406     // Initialize the vertex vector
1407     m_data.vertices = std::vector<PositionColorVertex>(
1408         highestIndex + 1, PositionColorVertex(tcu::Vec4(0.0, 0.0, 0.0, 0.0), tcu::Vec4(0.0, 0.0, 0.0, 0.0)));
1409 
1410     // Generate random vertices in the used locations
1411     for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator cmdIt = m_data.commands.begin();
1412          cmdIt != m_data.commands.end(); ++cmdIt)
1413     {
1414         uint32_t firstIdx = cmdIt->firstIndex;
1415         uint32_t lastIdx  = firstIdx + cmdIt->indexCount;
1416 
1417         for (uint32_t idx = firstIdx; idx < lastIdx; ++idx)
1418         {
1419             std::vector<PositionColorVertex>::iterator vertexIt =
1420                 m_data.vertices.begin() + cmdIt->vertexOffset + m_data.indexes[idx];
1421 
1422             tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
1423             const float f0                             = rnd.getFloat(-1.0f, 1.0f);
1424             const float f1                             = rnd.getFloat(-1.0f, 1.0f);
1425             positionAccess                             = tcu::Vec4(f0, f1, 1.0f, 1.0f);
1426 
1427             tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
1428             colorAccess                             = tcu::randomVec4(rnd);
1429         }
1430     }
1431 }
1432 
1433 template <>
draw(vk::VkCommandBuffer cmdBuffer,vk::VkBuffer indirectBuffer,vk::VkDeviceSize indirectOffset)1434 void DrawTestInstance<DrawIndexedIndirectParams>::draw(vk::VkCommandBuffer cmdBuffer, vk::VkBuffer indirectBuffer,
1435                                                        vk::VkDeviceSize indirectOffset)
1436 {
1437     const vk::VkPhysicalDeviceFeatures features = m_context.getDeviceFeatures();
1438 
1439     // If multiDrawIndirect not supported execute single calls
1440     if (m_data.commands.size() > 1 && !(features.multiDrawIndirect))
1441     {
1442         for (uint32_t cmdIdx = 0; cmdIdx < m_data.commands.size(); ++cmdIdx)
1443         {
1444             const uint32_t offset = (uint32_t)(indirectOffset + cmdIdx * sizeof(vk::VkDrawIndexedIndirectCommand));
1445             m_vk.cmdDrawIndexedIndirect(cmdBuffer, indirectBuffer, offset, 1, sizeof(vk::VkDrawIndexedIndirectCommand));
1446         }
1447     }
1448     else
1449     {
1450         m_vk.cmdDrawIndexedIndirect(cmdBuffer, indirectBuffer, indirectOffset, (uint32_t)m_data.commands.size(),
1451                                     sizeof(vk::VkDrawIndexedIndirectCommand));
1452     }
1453 }
1454 
1455 template <>
iterate(void)1456 tcu::TestStatus DrawTestInstance<DrawIndexedIndirectParams>::iterate(void)
1457 {
1458     tcu::TestLog &log                         = m_context.getTestContext().getLog();
1459     const vk::DeviceInterface &vk             = m_context.getDeviceInterface();
1460     const vk::VkDevice vkDevice               = m_context.getDevice();
1461     const uint32_t queueFamilyIndex           = m_context.getUniversalQueueFamilyIndex();
1462     const vk::VkQueue queue                   = m_context.getUniversalQueue();
1463     vk::Allocator &allocator                  = m_context.getDefaultAllocator();
1464     const vk::VkDeviceSize vertexBufferOffset = 0;
1465     const vk::VkBuffer vertexBuffer           = m_vertexBuffer->object();
1466     vk::Move<vk::VkBuffer> indirectBuffer;
1467     de::MovePtr<vk::Allocation> indirectAlloc;
1468 
1469     {
1470         const vk::VkDeviceSize indirectInfoSize = m_data.commands.size() * sizeof(vk::VkDrawIndexedIndirectCommand);
1471 
1472         vk::VkBufferCreateInfo indirectCreateInfo{
1473             vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1474             DE_NULL,                                  // const void* pNext;
1475             0u,                                       // VkBufferCreateFlags flags;
1476             indirectInfoSize,                         // VkDeviceSize size;
1477             vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,  // VkBufferUsageFlags usage;
1478             vk::VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
1479             1u,                                       // uint32_t queueFamilyIndexCount;
1480             &queueFamilyIndex,                        // const uint32_t* pQueueFamilyIndices;
1481         };
1482 
1483 #ifndef CTS_USES_VULKANSC
1484         vk::VkBufferUsageFlags2CreateInfoKHR bufferUsageFlags2 = vk::initVulkanStructure();
1485         if (m_data.useMaintenance5)
1486         {
1487             bufferUsageFlags2.usage  = vk::VK_BUFFER_USAGE_2_INDIRECT_BUFFER_BIT_KHR;
1488             indirectCreateInfo.pNext = &bufferUsageFlags2;
1489             indirectCreateInfo.usage = 0xBAD00000;
1490         }
1491 #endif // CTS_USES_VULKANSC
1492 
1493         indirectBuffer = createBuffer(vk, vkDevice, &indirectCreateInfo);
1494         indirectAlloc  = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indirectBuffer),
1495                                             vk::MemoryRequirement::HostVisible);
1496         VK_CHECK(
1497             vk.bindBufferMemory(vkDevice, *indirectBuffer, indirectAlloc->getMemory(), indirectAlloc->getOffset()));
1498 
1499         deMemcpy(indirectAlloc->getHostPtr(), &(m_data.commands[0]), (size_t)indirectInfoSize);
1500 
1501         vk::flushAlloc(m_vk, vkDevice, *indirectAlloc);
1502     }
1503 
1504     const uint32_t bufferSize = (uint32_t)(m_data.indexes.size() * sizeof(uint32_t));
1505 
1506     vk::Move<vk::VkBuffer> indexBuffer;
1507 
1508     vk::VkBufferCreateInfo bufferCreateInfo{
1509         vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1510         DE_NULL,                                  // const void* pNext;
1511         0u,                                       // VkBufferCreateFlags flags;
1512         bufferSize,                               // VkDeviceSize size;
1513         vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT,     // VkBufferUsageFlags usage;
1514         vk::VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
1515         1u,                                       // uint32_t queueFamilyIndexCount;
1516         &queueFamilyIndex,                        // const uint32_t* pQueueFamilyIndices;
1517     };
1518 
1519 #ifndef CTS_USES_VULKANSC
1520     vk::VkBufferUsageFlags2CreateInfoKHR bufferUsageFlags2 = vk::initVulkanStructure();
1521     if (m_data.useMaintenance5)
1522     {
1523         bufferUsageFlags2.usage = vk::VK_BUFFER_USAGE_2_INDEX_BUFFER_BIT_KHR;
1524         bufferCreateInfo.pNext  = &bufferUsageFlags2;
1525         bufferCreateInfo.usage  = 0xBAD00000;
1526     }
1527 #endif // CTS_USES_VULKANSC
1528 
1529     indexBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
1530 
1531     de::MovePtr<vk::Allocation> indexAlloc;
1532 
1533     indexAlloc =
1534         allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indexBuffer), vk::MemoryRequirement::HostVisible);
1535     VK_CHECK(vk.bindBufferMemory(vkDevice, *indexBuffer, indexAlloc->getMemory(), indexAlloc->getOffset()));
1536 
1537     deMemcpy(indexAlloc->getHostPtr(), &(m_data.indexes[0]), bufferSize);
1538 
1539     vk::flushAlloc(m_vk, vkDevice, *indexAlloc);
1540 
1541 #ifndef CTS_USES_VULKANSC
1542     if (m_data.groupParams.useSecondaryCmdBuffer)
1543     {
1544         // record secondary command buffer
1545         if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1546         {
1547             beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1548             beginDynamicRender(*m_secCmdBuffer);
1549         }
1550         else
1551             beginSecondaryCmdBuffer(m_vk);
1552 
1553         m_vk.cmdBindPipeline(*m_secCmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1554         m_vk.cmdBindVertexBuffers(*m_secCmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1555         m_vk.cmdBindIndexBuffer(*m_secCmdBuffer, *indexBuffer, 0u, m_data.indexType);
1556         draw(*m_secCmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1557 
1558         if (m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1559             endDynamicRender(*m_secCmdBuffer);
1560 
1561         endCommandBuffer(m_vk, *m_secCmdBuffer);
1562 
1563         // record primary command buffer
1564         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1565 
1566         preRenderBarriers();
1567 
1568         if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1569             beginDynamicRender(*m_cmdBuffer, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1570 
1571         m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
1572 
1573         if (!m_data.groupParams.secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1574             endDynamicRender(*m_cmdBuffer);
1575 
1576         endCommandBuffer(m_vk, *m_cmdBuffer);
1577     }
1578     else if (m_data.groupParams.useDynamicRendering)
1579     {
1580         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1581         preRenderBarriers();
1582         beginDynamicRender(*m_cmdBuffer);
1583 
1584         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1585         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1586         m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
1587         draw(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1588 
1589         endDynamicRender(*m_cmdBuffer);
1590         endCommandBuffer(m_vk, *m_cmdBuffer);
1591     }
1592 #endif // CTS_USES_VULKANSC
1593 
1594     if (!m_data.groupParams.useDynamicRendering)
1595     {
1596         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1597         preRenderBarriers();
1598         beginRenderPass(*m_cmdBuffer);
1599 
1600         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1601         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1602         m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
1603         draw(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset());
1604 
1605         endRenderPass(*m_cmdBuffer);
1606         endCommandBuffer(m_vk, *m_cmdBuffer);
1607     }
1608 
1609     submitCommandsAndWait(m_vk, vkDevice, queue, m_cmdBuffer.get());
1610 
1611     // Validation
1612     tcu::TextureLevel refImage(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)),
1613                                (int)(0.5f + static_cast<float>(HEIGHT)));
1614     tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1615 
1616     for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator cmd = m_data.commands.begin();
1617          cmd != m_data.commands.end(); ++cmd)
1618     {
1619         std::vector<tcu::Vec4> vertices;
1620         std::vector<tcu::Vec4> colors;
1621 
1622         for (uint32_t idx = 0; idx < cmd->indexCount; ++idx)
1623         {
1624             const uint32_t vertexIndex = cmd->vertexOffset + m_data.indexes[cmd->firstIndex + idx];
1625             vertices.push_back(m_data.vertices[vertexIndex].position);
1626             colors.push_back(m_data.vertices[vertexIndex].color);
1627         }
1628         generateRefImage(refImage.getAccess(), vertices, colors);
1629     }
1630 
1631     const vk::VkOffset3D zeroOffset = {0, 0, 0};
1632     const tcu::ConstPixelBufferAccess renderedFrame =
1633         m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset,
1634                                         WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1635 
1636     qpTestResult res = QP_TEST_RESULT_PASS;
1637 
1638     if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
1639         res = QP_TEST_RESULT_FAIL;
1640 
1641     return tcu::TestStatus(res, qpGetTestResultName(res));
1642 }
1643 
1644 typedef DrawTestCase<DrawParams> DrawCase;
1645 typedef DrawTestCase<DrawIndexedParams> IndexedCase;
1646 typedef DrawTestCase<DrawIndirectParams> IndirectCase;
1647 typedef DrawTestCase<DrawIndexedIndirectParams> IndexedIndirectCase;
1648 
1649 struct TestCaseParams
1650 {
1651     const DrawCommandType command;
1652     const vk::VkPrimitiveTopology topology;
1653     const SharedGroupParams groupParams;
1654 
TestCaseParamsvkt::Draw::__anon91bcb92a0111::TestCaseParams1655     TestCaseParams(const DrawCommandType cmd, const vk::VkPrimitiveTopology top, const SharedGroupParams gParams)
1656         : command(cmd)
1657         , topology(top)
1658         , groupParams(gParams)
1659     {
1660     }
1661 };
1662 
1663 } // namespace
1664 
populateSubGroup(tcu::TestCaseGroup * testGroup,const TestCaseParams caseParams)1665 void populateSubGroup(tcu::TestCaseGroup *testGroup, const TestCaseParams caseParams)
1666 {
1667     de::Random rnd(SEED ^ deStringHash(testGroup->getName()));
1668     tcu::TestContext &testCtx              = testGroup->getTestContext();
1669     const DrawCommandType command          = caseParams.command;
1670     const vk::VkPrimitiveTopology topology = caseParams.topology;
1671     const SharedGroupParams groupParams    = caseParams.groupParams;
1672     const uint32_t primitiveCountArrLength = DE_LENGTH_OF_ARRAY(PRIMITIVE_COUNT);
1673 
1674     for (uint32_t primitiveCountIdx = 0; primitiveCountIdx < primitiveCountArrLength; ++primitiveCountIdx)
1675     {
1676         const uint32_t primitives = PRIMITIVE_COUNT[primitiveCountIdx];
1677 
1678         // when testing VK_KHR_dynamic_rendering there is no need to duplicate tests for all primitive counts; use just 1 and 45
1679         if (groupParams->useDynamicRendering && (primitiveCountIdx != 0) &&
1680             (primitiveCountIdx != primitiveCountArrLength - 1))
1681             continue;
1682 
1683         uint32_t multiplier = 1;
1684         uint32_t offset     = 0;
1685         // Calculated by Vulkan 23.1
1686         switch (topology)
1687         {
1688         case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
1689             break;
1690         case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
1691             multiplier = 2;
1692             break;
1693         case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
1694             break;
1695         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
1696             multiplier = 3;
1697             break;
1698         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
1699             break;
1700         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
1701             offset = 1;
1702             break;
1703         case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
1704             multiplier = 4;
1705             offset     = 1;
1706             break;
1707         case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
1708             offset = 1;
1709             break;
1710         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
1711             multiplier = 6;
1712             break;
1713         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
1714             multiplier = 2;
1715             break;
1716         default:
1717             DE_FATAL("Unsupported topology.");
1718         }
1719 
1720         const uint32_t vertexCount = multiplier * primitives + offset;
1721         std::string name           = de::toString(primitives);
1722 
1723         switch (command)
1724         {
1725         case DRAW_COMMAND_TYPE_DRAW:
1726         {
1727             uint32_t firstPrimitive = rnd.getInt(0, primitives);
1728             uint32_t firstVertex    = multiplier * firstPrimitive;
1729             testGroup->addChild(
1730                 new DrawCase(testCtx, name.c_str(), DrawParams(topology, groupParams, vertexCount, 1, firstVertex, 0)));
1731             break;
1732         }
1733         case DRAW_COMMAND_TYPE_DRAW_INDEXED:
1734         {
1735             uint32_t firstIndex   = rnd.getInt(0, OFFSET_LIMIT);
1736             uint32_t vertexOffset = rnd.getInt(0, OFFSET_LIMIT);
1737             testGroup->addChild(new IndexedCase(testCtx, name.c_str(),
1738                                                 DrawIndexedParams(topology, groupParams, vk::VK_INDEX_TYPE_UINT32,
1739                                                                   vertexCount, 1, firstIndex, vertexOffset, 0)));
1740             break;
1741         }
1742         case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
1743         {
1744             uint32_t firstVertex = rnd.getInt(0, OFFSET_LIMIT);
1745 
1746             DrawIndirectParams params = DrawIndirectParams(topology, groupParams);
1747 
1748             params.addCommand(vertexCount, 1, 0, 0);
1749             testGroup->addChild(new IndirectCase(testCtx, (name + "_single_command").c_str(), params));
1750 
1751             params.addCommand(vertexCount, 1, firstVertex, 0);
1752             testGroup->addChild(new IndirectCase(testCtx, (name + "_multi_command").c_str(), params));
1753             break;
1754         }
1755         case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
1756         {
1757             uint32_t firstIndex   = rnd.getInt(vertexCount, OFFSET_LIMIT);
1758             uint32_t vertexOffset = rnd.getInt(vertexCount, OFFSET_LIMIT);
1759 
1760             DrawIndexedIndirectParams params =
1761                 DrawIndexedIndirectParams(topology, groupParams, vk::VK_INDEX_TYPE_UINT32);
1762             params.addCommand(vertexCount, 1, 0, 0, 0);
1763             testGroup->addChild(new IndexedIndirectCase(testCtx, (name + "_single_command").c_str(), params));
1764 
1765             params.addCommand(vertexCount, 1, firstIndex, vertexOffset, 0);
1766             testGroup->addChild(new IndexedIndirectCase(testCtx, (name + "_multi_command").c_str(), params));
1767             break;
1768         }
1769         default:
1770             DE_FATAL("Unsupported draw command.");
1771         }
1772     }
1773 }
1774 
createDrawTests(tcu::TestCaseGroup * testGroup,const SharedGroupParams groupParams)1775 void createDrawTests(tcu::TestCaseGroup *testGroup, const SharedGroupParams groupParams)
1776 {
1777     for (uint32_t drawTypeIndex = 0; drawTypeIndex < DRAW_COMMAND_TYPE_DRAW_LAST; ++drawTypeIndex)
1778     {
1779         const DrawCommandType command(static_cast<DrawCommandType>(drawTypeIndex));
1780         de::MovePtr<tcu::TestCaseGroup> topologyGroup(
1781             new tcu::TestCaseGroup(testGroup->getTestContext(), getDrawCommandTypeName(command)));
1782 
1783         for (uint32_t topologyIdx = 0; topologyIdx != vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; ++topologyIdx)
1784         {
1785             const vk::VkPrimitiveTopology topology(static_cast<vk::VkPrimitiveTopology>(topologyIdx));
1786             const std::string groupName(de::toLower(getPrimitiveTopologyName(topology)).substr(22));
1787 
1788             // reduce number of tests for dynamic rendering cases where secondary command buffer is used
1789             if (groupParams->useSecondaryCmdBuffer && (topologyIdx % 2u))
1790                 continue;
1791 
1792             if (groupParams->nestedSecondaryCmdBuffer && drawTypeIndex != DRAW_COMMAND_TYPE_DRAW)
1793                 continue;
1794 
1795             // Testcases with a specific topology.
1796             addTestGroup(topologyGroup.get(), groupName, populateSubGroup,
1797                          TestCaseParams(command, topology, groupParams));
1798         }
1799 
1800         testGroup->addChild(topologyGroup.release());
1801     }
1802 
1803 #ifndef CTS_USES_VULKANSC
1804     de::MovePtr<tcu::TestCaseGroup> miscGroup(new tcu::TestCaseGroup(testGroup->getTestContext(), "misc"));
1805     if (groupParams->useDynamicRendering == false)
1806     {
1807         DrawIndexedIndirectParams params(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, groupParams,
1808                                          vk::VK_INDEX_TYPE_UINT32);
1809         params.addCommand(4, 1, 0, 0, 0);
1810         params.useMaintenance5 = true;
1811         miscGroup->addChild(new IndexedIndirectCase(testGroup->getTestContext(), "maintenance5", params));
1812     }
1813     testGroup->addChild(miscGroup.release());
1814 #endif // CTS_USES_VULKANSC
1815 }
1816 
createBasicDrawTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)1817 tcu::TestCaseGroup *createBasicDrawTests(tcu::TestContext &testCtx, const SharedGroupParams groupParams)
1818 {
1819     return createTestGroup(testCtx, "basic_draw", createDrawTests, groupParams);
1820 }
1821 
1822 } // namespace Draw
1823 } // namespace vkt
1824