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