Test dynamic rendering with draw tests
[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         bool                                                            useDynamicRendering;
109
110         DrawParamsBase ()
111         {}
112
113         DrawParamsBase (const vk::VkPrimitiveTopology top, bool dynamicRendering)
114                 : topology      (top)
115                 , useDynamicRendering(dynamicRendering)
116         {}
117 };
118
119 struct IndexedParamsBase
120 {
121         std::vector<deUint32>   indexes;
122         const vk::VkIndexType   indexType;
123
124         IndexedParamsBase (const vk::VkIndexType indexT)
125                 : indexType     (indexT)
126         {}
127 };
128
129 // Structs to store draw parameters
130 struct DrawParams : DrawParamsBase
131 {
132         // vkCmdDraw parameters is like a single VkDrawIndirectCommand
133         vk::VkDrawIndirectCommand       params;
134
135         DrawParams (const vk::VkPrimitiveTopology top, bool dynamicRendering, const deUint32 vertexC, const deUint32 instanceC, const deUint32 firstV, const deUint32 firstI)
136                 : DrawParamsBase        (top, dynamicRendering)
137         {
138                 params.vertexCount              = vertexC;
139                 params.instanceCount    = instanceC;
140                 params.firstVertex              = firstV;
141                 params.firstInstance    = firstI;
142         }
143 };
144
145 struct DrawIndexedParams : DrawParamsBase, IndexedParamsBase
146 {
147         // vkCmdDrawIndexed parameters is like a single VkDrawIndexedIndirectCommand
148         vk::VkDrawIndexedIndirectCommand        params;
149
150         DrawIndexedParams (const vk::VkPrimitiveTopology top, bool dynamicRendering, const vk::VkIndexType indexT, const deUint32 indexC, const deUint32 instanceC, const deUint32 firstIdx, const deInt32 vertexO, const deUint32 firstIns)
151                 : DrawParamsBase        (top, dynamicRendering)
152                 , IndexedParamsBase     (indexT)
153         {
154                 params.indexCount               = indexC;
155                 params.instanceCount    = instanceC;
156                 params.firstIndex               = firstIdx;
157                 params.vertexOffset             = vertexO;
158                 params.firstInstance    = firstIns;
159         }
160 };
161
162 struct DrawIndirectParams : DrawParamsBase
163 {
164         std::vector<vk::VkDrawIndirectCommand>  commands;
165
166         DrawIndirectParams (const vk::VkPrimitiveTopology top, bool dynamicRendering)
167                 : DrawParamsBase        (top, dynamicRendering)
168         {}
169
170         void addCommand (const deUint32 vertexC, const deUint32 instanceC, const deUint32 firstV, const deUint32 firstI)
171         {
172                 vk::VkDrawIndirectCommand       cmd;
173                 cmd.vertexCount                         = vertexC;
174                 cmd.instanceCount                       = instanceC;
175                 cmd.firstVertex                         = firstV;
176                 cmd.firstInstance                       = firstI;
177
178                 commands.push_back(cmd);
179         }
180 };
181
182 struct DrawIndexedIndirectParams : DrawParamsBase, IndexedParamsBase
183 {
184         std::vector<vk::VkDrawIndexedIndirectCommand>   commands;
185
186         DrawIndexedIndirectParams (const vk::VkPrimitiveTopology top, bool dynamicRendering, const vk::VkIndexType indexT)
187                 : DrawParamsBase        (top, dynamicRendering)
188                 , IndexedParamsBase     (indexT)
189         {}
190
191         void addCommand (const deUint32 indexC, const deUint32 instanceC, const deUint32 firstIdx, const deInt32 vertexO, const deUint32 firstIns)
192         {
193                 vk::VkDrawIndexedIndirectCommand        cmd;
194                 cmd.indexCount                                          = indexC;
195                 cmd.instanceCount                                       = instanceC;
196                 cmd.firstIndex                                          = firstIdx;
197                 cmd.vertexOffset                                        = vertexO;
198                 cmd.firstInstance                                       = firstIns;
199
200                 commands.push_back(cmd);
201         }
202 };
203
204 // Reference renderer shaders
205 class PassthruVertShader : public rr::VertexShader
206 {
207 public:
208         PassthruVertShader (void)
209         : rr::VertexShader (2, 1)
210         {
211                 m_inputs[0].type        = rr::GENERICVECTYPE_FLOAT;
212                 m_inputs[1].type        = rr::GENERICVECTYPE_FLOAT;
213                 m_outputs[0].type       = rr::GENERICVECTYPE_FLOAT;
214         }
215
216         void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
217         {
218                 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
219                 {
220                         packets[packetNdx]->position = rr::readVertexAttribFloat(inputs[0],
221                                                                                                                                          packets[packetNdx]->instanceNdx,
222                                                                                                                                          packets[packetNdx]->vertexNdx);
223
224                         tcu::Vec4 color = rr::readVertexAttribFloat(inputs[1],
225                                                                                                                 packets[packetNdx]->instanceNdx,
226                                                                                                                 packets[packetNdx]->vertexNdx);
227
228                         packets[packetNdx]->outputs[0] = color;
229                 }
230         }
231 };
232
233 class PassthruFragShader : public rr::FragmentShader
234 {
235 public:
236         PassthruFragShader (void)
237                 : rr::FragmentShader(1, 1)
238         {
239                 m_inputs[0].type        = rr::GENERICVECTYPE_FLOAT;
240                 m_outputs[0].type       = rr::GENERICVECTYPE_FLOAT;
241         }
242
243         void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
244         {
245                 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
246                 {
247                         rr::FragmentPacket& packet = packets[packetNdx];
248                         for (deUint32 fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; ++fragNdx)
249                         {
250                                 tcu::Vec4 color = rr::readVarying<float>(packet, context, 0, fragNdx);
251                                 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
252                         }
253                 }
254         }
255 };
256
257 inline bool imageCompare (tcu::TestLog& log, const tcu::ConstPixelBufferAccess& reference, const tcu::ConstPixelBufferAccess& result, const vk::VkPrimitiveTopology topology)
258 {
259         if (topology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
260         {
261                 return tcu::intThresholdPositionDeviationCompare(
262                         log, "Result", "Image comparison result", reference, result,
263                         tcu::UVec4(4u),                                 // color threshold
264                         tcu::IVec3(1, 1, 0),                    // position deviation tolerance
265                         true,                                                   // don't check the pixels at the boundary
266                         tcu::COMPARE_LOG_RESULT);
267         }
268         else
269                 return tcu::fuzzyCompare(log, "Result", "Image comparison result", reference, result, 0.053f, tcu::COMPARE_LOG_RESULT);
270 }
271
272 class DrawTestInstanceBase : public TestInstance
273 {
274 public:
275                                                                         DrawTestInstanceBase    (Context& context);
276         virtual                                                 ~DrawTestInstanceBase   (void) = 0;
277         void                                                    initialize                              (const DrawParamsBase& data);
278         void                                                    initPipeline                    (const vk::VkDevice device);
279         void                                                    beginRenderPass                 (void);
280         void                                                    endRenderPass                   (void);
281
282         // Specialize this function for each type
283         virtual tcu::TestStatus                 iterate                                 (void) = 0;
284 protected:
285         // Specialize this function for each type
286         virtual void                                    generateDrawData                (void) = 0;
287         void                                                    generateRefImage                (const tcu::PixelBufferAccess& access, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const;
288
289         DrawParamsBase                                                                                  m_data;
290         const vk::DeviceInterface&                                                              m_vk;
291         vk::Move<vk::VkPipeline>                                                                m_pipeline;
292         vk::Move<vk::VkPipelineLayout>                                                  m_pipelineLayout;
293         vk::VkFormat                                                                                    m_colorAttachmentFormat;
294         de::SharedPtr<Image>                                                                    m_colorTargetImage;
295         vk::Move<vk::VkImageView>                                                               m_colorTargetView;
296         vk::Move<vk::VkRenderPass>                                                              m_renderPass;
297         vk::Move<vk::VkFramebuffer>                                                             m_framebuffer;
298         PipelineCreateInfo::VertexInputState                                    m_vertexInputState;
299         de::SharedPtr<Buffer>                                                                   m_vertexBuffer;
300         vk::Move<vk::VkCommandPool>                                                             m_cmdPool;
301         vk::Move<vk::VkCommandBuffer>                                                   m_cmdBuffer;
302
303         enum
304         {
305                 WIDTH = 256,
306                 HEIGHT = 256
307         };
308 };
309
310 DrawTestInstanceBase::DrawTestInstanceBase (Context& context)
311         : vkt::TestInstance                     (context)
312         , m_vk                                          (context.getDeviceInterface())
313         , m_colorAttachmentFormat       (vk::VK_FORMAT_R8G8B8A8_UNORM)
314 {
315 }
316
317 DrawTestInstanceBase::~DrawTestInstanceBase (void)
318 {
319 }
320
321 void DrawTestInstanceBase::initialize (const DrawParamsBase& data)
322 {
323         m_data  = data;
324
325         const vk::VkDevice      device                          = m_context.getDevice();
326         const deUint32          queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
327
328         const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
329         m_pipelineLayout                                                = vk::createPipelineLayout(m_vk, device, &pipelineLayoutCreateInfo);
330
331         const vk::VkExtent3D targetImageExtent  = { WIDTH, HEIGHT, 1 };
332         const ImageCreateInfo targetImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, targetImageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT,
333                 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);
334
335         m_colorTargetImage                                              = Image::createAndAlloc(m_vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
336
337         const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
338         m_colorTargetView                                               = vk::createImageView(m_vk, device, &colorTargetViewInfo);
339
340         // create render pass only when we are not using dynamic rendering
341         if (!m_data.useDynamicRendering)
342         {
343                 RenderPassCreateInfo renderPassCreateInfo;
344                 renderPassCreateInfo.addAttachment(AttachmentDescription(m_colorAttachmentFormat,
345                                                                                                                                  vk::VK_SAMPLE_COUNT_1_BIT,
346                                                                                                                                  vk::VK_ATTACHMENT_LOAD_OP_LOAD,
347                                                                                                                                  vk::VK_ATTACHMENT_STORE_OP_STORE,
348                                                                                                                                  vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
349                                                                                                                                  vk::VK_ATTACHMENT_STORE_OP_STORE,
350                                                                                                                                  vk::VK_IMAGE_LAYOUT_GENERAL,
351                                                                                                                                  vk::VK_IMAGE_LAYOUT_GENERAL));
352
353                 const vk::VkAttachmentReference colorAttachmentReference
354                 {
355                         0,
356                         vk::VK_IMAGE_LAYOUT_GENERAL
357                 };
358
359                 renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
360                                                                                                                    0,
361                                                                                                                    0,
362                                                                                                                    DE_NULL,
363                                                                                                                    1,
364                                                                                                                    &colorAttachmentReference,
365                                                                                                                    DE_NULL,
366                                                                                                                    AttachmentReference(),
367                                                                                                                    0,
368                                                                                                                    DE_NULL));
369
370                 m_renderPass = vk::createRenderPass(m_vk, device, &renderPassCreateInfo);
371
372                 // create framebuffer
373                 std::vector<vk::VkImageView>    colorAttachments                { *m_colorTargetView };
374                 const FramebufferCreateInfo             framebufferCreateInfo   (*m_renderPass, colorAttachments, WIDTH, HEIGHT, 1);
375                 m_framebuffer = vk::createFramebuffer(m_vk, device, &framebufferCreateInfo);
376         }
377
378         const vk::VkVertexInputBindingDescription vertexInputBindingDescription =
379         {
380                 0,
381                 (deUint32)sizeof(tcu::Vec4) * 2,
382                 vk::VK_VERTEX_INPUT_RATE_VERTEX,
383         };
384
385         const vk::VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] =
386         {
387                 {
388                         0u,
389                         0u,
390                         vk::VK_FORMAT_R32G32B32A32_SFLOAT,
391                         0u
392                 },
393                 {
394                         1u,
395                         0u,
396                         vk::VK_FORMAT_R32G32B32A32_SFLOAT,
397                         (deUint32)(sizeof(float)* 4),
398                 }
399         };
400
401         m_vertexInputState = PipelineCreateInfo::VertexInputState(1,
402                                                                                                                           &vertexInputBindingDescription,
403                                                                                                                           2,
404                                                                                                                           vertexInputAttributeDescriptions);
405
406         const vk::VkDeviceSize dataSize = m_data.vertices.size() * sizeof(PositionColorVertex);
407         m_vertexBuffer = Buffer::createAndAlloc(m_vk, device, BufferCreateInfo(dataSize,
408                 vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
409
410         deUint8* ptr = reinterpret_cast<deUint8*>(m_vertexBuffer->getBoundMemory().getHostPtr());
411         deMemcpy(ptr, &(m_data.vertices[0]), static_cast<size_t>(dataSize));
412
413         vk::flushAlloc(m_vk, device, m_vertexBuffer->getBoundMemory());
414
415         const CmdPoolCreateInfo cmdPoolCreateInfo(queueFamilyIndex);
416         m_cmdPool       = vk::createCommandPool(m_vk, device, &cmdPoolCreateInfo);
417         m_cmdBuffer     = vk::allocateCommandBuffer(m_vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
418
419         initPipeline(device);
420 }
421
422 void DrawTestInstanceBase::initPipeline (const vk::VkDevice device)
423 {
424         const vk::Unique<vk::VkShaderModule>    vs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("vert"), 0));
425         const vk::Unique<vk::VkShaderModule>    fs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("frag"), 0));
426
427         const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState;
428
429         vk::VkViewport viewport = vk::makeViewport(WIDTH, HEIGHT);
430         vk::VkRect2D scissor    = vk::makeRect2D(WIDTH, HEIGHT);
431
432         // when dynamic_rendering is tested then renderPass won't be created and VK_NULL_HANDLE will be used here
433         PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
434         pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
435         pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
436         pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(m_vertexInputState));
437         pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(m_data.topology));
438         pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
439         pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
440         pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
441         pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
442         pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
443
444         vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo
445         {
446                 vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
447                 DE_NULL,
448                 0u,
449                 1u,
450                 &m_colorAttachmentFormat,
451                 vk::VK_FORMAT_UNDEFINED
452         };
453
454         if (m_data.useDynamicRendering)
455                 pipelineCreateInfo.pNext = &renderingCreateInfo;
456
457         m_pipeline = vk::createGraphicsPipeline(m_vk, device, DE_NULL, &pipelineCreateInfo);
458 }
459
460 void DrawTestInstanceBase::beginRenderPass (void)
461 {
462         const vk::VkClearValue clearColor { { { 0.0f, 0.0f, 0.0f, 1.0f } } };
463
464         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
465
466         initialTransitionColor2DImage(m_vk, *m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
467                                                                   vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
468
469         const ImageSubresourceRange subresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT);
470         m_vk.cmdClearColorImage(*m_cmdBuffer, m_colorTargetImage->object(),
471                 vk::VK_IMAGE_LAYOUT_GENERAL, &clearColor.color, 1, &subresourceRange);
472
473         const vk::VkMemoryBarrier memBarrier =
474         {
475                 vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER,
476                 DE_NULL,
477                 vk::VK_ACCESS_TRANSFER_WRITE_BIT,
478                 vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
479         };
480
481         m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
482                 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
483                 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
484
485         const vk::VkRect2D      renderArea      = vk::makeRect2D(WIDTH, HEIGHT);
486
487         if (m_data.useDynamicRendering)
488                 vk::beginRendering(m_vk, *m_cmdBuffer, *m_colorTargetView, renderArea, clearColor);
489         else
490                 vk::beginRenderPass(m_vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, renderArea, 1u, &clearColor);
491 }
492
493 void DrawTestInstanceBase::endRenderPass (void)
494 {
495         if (m_data.useDynamicRendering)
496                 vk::endRendering(m_vk, *m_cmdBuffer);
497         else
498                 vk::endRenderPass(m_vk, *m_cmdBuffer);
499 }
500
501 void DrawTestInstanceBase::generateRefImage (const tcu::PixelBufferAccess& access, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const
502 {
503         const PassthruVertShader                                vertShader;
504         const PassthruFragShader                                fragShader;
505         const rr::Program                                               program                 (&vertShader, &fragShader);
506         const rr::MultisamplePixelBufferAccess  colorBuffer             = rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(access);
507         const rr::RenderTarget                                  renderTarget    (colorBuffer);
508         const rr::RenderState                                   renderState             ((rr::ViewportState(colorBuffer)), m_context.getDeviceProperties().limits.subPixelPrecisionBits);
509         const rr::Renderer                                              renderer;
510
511         const rr::VertexAttrib  vertexAttribs[] =
512         {
513                 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &vertices[0]),
514                 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &colors[0])
515         };
516
517         renderer.draw(rr::DrawCommand(renderState,
518                                                                   renderTarget,
519                                                                   program,
520                                                                   DE_LENGTH_OF_ARRAY(vertexAttribs),
521                                                                   &vertexAttribs[0],
522                                                                   rr::PrimitiveList(mapVkPrimitiveTopology(m_data.topology), (deUint32)vertices.size(), 0)));
523 }
524
525 template<typename T>
526 class DrawTestInstance : public DrawTestInstanceBase
527 {
528 public:
529                                                         DrawTestInstance                (Context& context, const T& data);
530         virtual                                 ~DrawTestInstance               (void);
531         virtual void                    generateDrawData                (void);
532         virtual tcu::TestStatus iterate                                 (void);
533 private:
534         T                                               m_data;
535 };
536
537 template<typename T>
538 DrawTestInstance<T>::DrawTestInstance (Context& context, const T& data)
539         : DrawTestInstanceBase  (context)
540         , m_data                                (data)
541 {
542         generateDrawData();
543         initialize(m_data);
544 }
545
546 template<typename T>
547 DrawTestInstance<T>::~DrawTestInstance (void)
548 {
549 }
550
551 template<typename T>
552 void DrawTestInstance<T>::generateDrawData (void)
553 {
554         DE_FATAL("Using the general case of this function is forbidden!");
555 }
556
557 template<typename T>
558 tcu::TestStatus DrawTestInstance<T>::iterate (void)
559 {
560         DE_FATAL("Using the general case of this function is forbidden!");
561         return tcu::TestStatus::fail("");
562 }
563
564 template<typename T>
565 class DrawTestCase : public TestCase
566 {
567         public:
568                                                                         DrawTestCase            (tcu::TestContext& context, const char* name, const char* desc, const T data);
569                                                                         ~DrawTestCase           (void);
570         virtual void                                    initPrograms            (vk::SourceCollections& programCollection) const;
571         virtual void                                    initShaderSources       (void);
572         virtual void                                    checkSupport            (Context& context) const;
573         virtual TestInstance*                   createInstance          (Context& context) const;
574
575 private:
576         T                                                                                                       m_data;
577         std::string                                                                                     m_vertShaderSource;
578         std::string                                                                                     m_fragShaderSource;
579 };
580
581 template<typename T>
582 DrawTestCase<T>::DrawTestCase (tcu::TestContext& context, const char* name, const char* desc, const T data)
583         : vkt::TestCase (context, name, desc)
584         , m_data                (data)
585 {
586         initShaderSources();
587 }
588
589 template<typename T>
590 DrawTestCase<T>::~DrawTestCase  (void)
591 {
592 }
593
594 template<typename T>
595 void DrawTestCase<T>::initPrograms (vk::SourceCollections& programCollection) const
596 {
597         programCollection.glslSources.add("vert") << glu::VertexSource(m_vertShaderSource);
598         programCollection.glslSources.add("frag") << glu::FragmentSource(m_fragShaderSource);
599 }
600
601 template<typename T>
602 void DrawTestCase<T>::checkSupport (Context& context) const
603 {
604         if (m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY ||
605                 m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY ||
606                 m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY ||
607                 m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY)
608         {
609                 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
610         }
611
612         if (m_data.useDynamicRendering)
613                 context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
614
615         if (m_data.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
616                 context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
617                 !context.getPortabilitySubsetFeatures().triangleFans)
618         {
619                 TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
620         }
621 }
622
623 template<typename T>
624 void DrawTestCase<T>::initShaderSources (void)
625 {
626         std::stringstream vertShader;
627         vertShader      << "#version 430\n"
628                                 << "layout(location = 0) in vec4 in_position;\n"
629                                 << "layout(location = 1) in vec4 in_color;\n"
630                                 << "layout(location = 0) out vec4 out_color;\n"
631
632                                 << "out gl_PerVertex {\n"
633                                 << "    vec4  gl_Position;\n"
634                                 << "    float gl_PointSize;\n"
635                                 << "};\n"
636                                 << "void main() {\n"
637                                 << "    gl_PointSize = 1.0;\n"
638                                 << "    gl_Position  = in_position;\n"
639                                 << "    out_color    = in_color;\n"
640                                 << "}\n";
641
642         m_vertShaderSource = vertShader.str();
643
644         std::stringstream fragShader;
645         fragShader      << "#version 430\n"
646                                 << "layout(location = 0) in vec4 in_color;\n"
647                                 << "layout(location = 0) out vec4 out_color;\n"
648                                 << "void main()\n"
649                                 << "{\n"
650                                 << "    out_color = in_color;\n"
651                                 << "}\n";
652
653         m_fragShaderSource = fragShader.str();
654 }
655
656 template<typename T>
657 TestInstance* DrawTestCase<T>::createInstance (Context& context) const
658 {
659         return new DrawTestInstance<T>(context, m_data);
660 }
661
662 // Specialized cases
663 template<>
664 void DrawTestInstance<DrawParams>::generateDrawData (void)
665 {
666         de::Random              rnd                     (SEED ^ m_data.params.firstVertex ^ m_data.params.vertexCount);
667
668         const deUint32  vectorSize      = m_data.params.firstVertex + m_data.params.vertexCount;
669
670         // Initialize the vector
671         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)));
672
673         // Fill only the used indexes
674         for (deUint32 vertexIdx = m_data.params.firstVertex; vertexIdx < vectorSize; ++vertexIdx)
675         {
676                 const float f0 = rnd.getFloat(-1.0f, 1.0f);
677                 const float f1 = rnd.getFloat(-1.0f, 1.0f);
678
679                 m_data.vertices[vertexIdx] = PositionColorVertex(
680                         tcu::Vec4(f0, f1, 1.0f, 1.0f),  // Coord
681                         tcu::randomVec4(rnd));                  // Color
682         }
683 }
684
685 template<>
686 tcu::TestStatus DrawTestInstance<DrawParams>::iterate (void)
687 {
688         tcu::TestLog                    &log                            = m_context.getTestContext().getLog();
689         const vk::VkQueue               queue                           = m_context.getUniversalQueue();
690         const vk::VkDevice              device                          = m_context.getDevice();
691
692         beginRenderPass();
693
694         const vk::VkDeviceSize  vertexBufferOffset      = 0;
695         const vk::VkBuffer              vertexBuffer            = m_vertexBuffer->object();
696
697         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
698         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
699         m_vk.cmdDraw(*m_cmdBuffer, m_data.params.vertexCount, m_data.params.instanceCount, m_data.params.firstVertex, m_data.params.firstInstance);
700         endRenderPass();
701         endCommandBuffer(m_vk, *m_cmdBuffer);
702
703         submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
704
705         // Validation
706         tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
707         tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
708
709         std::vector<tcu::Vec4>  vertices;
710         std::vector<tcu::Vec4>  colors;
711
712         for (std::vector<PositionColorVertex>::const_iterator vertex = m_data.vertices.begin() + m_data.params.firstVertex; vertex != m_data.vertices.end(); ++vertex)
713         {
714                 vertices.push_back(vertex->position);
715                 colors.push_back(vertex->color);
716         }
717         generateRefImage(refImage.getAccess(), vertices, colors);
718
719         const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
720         const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
721                 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
722
723         qpTestResult res = QP_TEST_RESULT_PASS;
724
725         if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
726                 res = QP_TEST_RESULT_FAIL;
727
728         return tcu::TestStatus(res, qpGetTestResultName(res));
729 }
730
731 template<>
732 void DrawTestInstance<DrawIndexedParams>::generateDrawData (void)
733 {
734         de::Random              rnd                     (SEED ^ m_data.params.firstIndex ^ m_data.params.indexCount);
735         const deUint32  indexSize       = m_data.params.firstIndex + m_data.params.indexCount;
736
737         // Initialize the vector with zeros
738         m_data.indexes = std::vector<deUint32>(indexSize, 0);
739
740         deUint32                highestIndex    = 0;    // Store to highest index to calculate the vertices size
741         // Fill the indexes from firstIndex
742         for (deUint32 idx = 0; idx < m_data.params.indexCount; ++idx)
743         {
744                 deUint32        vertexIdx       = rnd.getInt(m_data.params.vertexOffset, INDEX_LIMIT);
745                 highestIndex = (vertexIdx > highestIndex) ? vertexIdx : highestIndex;
746
747                 m_data.indexes[m_data.params.firstIndex + idx]  = vertexIdx;
748         }
749
750         // Fill up the vertex coordinates with zeros until the highestIndex including the vertexOffset
751         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)));
752
753         // Generate random vertex only where you have index pointing at
754         for (std::vector<deUint32>::const_iterator indexIt = m_data.indexes.begin() + m_data.params.firstIndex; indexIt != m_data.indexes.end(); ++indexIt)
755         {
756                 // Get iterator to the vertex position  with the vertexOffset
757                 std::vector<PositionColorVertex>::iterator vertexIt = m_data.vertices.begin() + m_data.params.vertexOffset + *indexIt;
758
759                 tcu::VecAccess<float, 4, 4>     positionAccess = vertexIt->position.xyzw();
760                 const float f0 = rnd.getFloat(-1.0f, 1.0f);
761                 const float f1 = rnd.getFloat(-1.0f, 1.0f);
762                 positionAccess = tcu::Vec4(f0, f1, 1.0f, 1.0f);
763
764                 tcu::VecAccess<float, 4, 4>     colorAccess = vertexIt->color.xyzw();
765                 colorAccess = tcu::randomVec4(rnd);
766         }
767 }
768
769 template<>
770 tcu::TestStatus DrawTestInstance<DrawIndexedParams>::iterate (void)
771 {
772         tcu::TestLog                            &log                            = m_context.getTestContext().getLog();
773         const vk::DeviceInterface&      vk                                      = m_context.getDeviceInterface();
774         const vk::VkDevice                      vkDevice                        = m_context.getDevice();
775         const deUint32                          queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
776         const vk::VkQueue                       queue                           = m_context.getUniversalQueue();
777         vk::Allocator&                          allocator                       = m_context.getDefaultAllocator();
778
779         beginRenderPass();
780
781         const vk::VkDeviceSize  vertexBufferOffset = 0;
782         const vk::VkBuffer      vertexBuffer = m_vertexBuffer->object();
783
784         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
785         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
786
787         const deUint32  bufferSize      = (deUint32)(m_data.indexes.size() * sizeof(deUint32));
788
789         vk::Move<vk::VkBuffer>  indexBuffer;
790
791         const vk::VkBufferCreateInfo    bufferCreateInfo =
792         {
793                 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,       // VkStructureType              sType;
794                 DE_NULL,                                                                        // const void*                  pNext;
795                 0u,                                                                                     // VkBufferCreateFlags  flags;
796                 bufferSize,                                                                     // VkDeviceSize                 size;
797                 vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT,           // VkBufferUsageFlags   usage;
798                 vk::VK_SHARING_MODE_EXCLUSIVE,                          // VkSharingMode                sharingMode;
799                 1u,                                                                                     // deUint32                             queueFamilyIndexCount;
800                 &queueFamilyIndex,                                                      // const deUint32*              pQueueFamilyIndices;
801         };
802
803         indexBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
804
805         de::MovePtr<vk::Allocation>     indexAlloc;
806
807         indexAlloc = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indexBuffer), vk::MemoryRequirement::HostVisible);
808         VK_CHECK(vk.bindBufferMemory(vkDevice, *indexBuffer, indexAlloc->getMemory(), indexAlloc->getOffset()));
809
810         deMemcpy(indexAlloc->getHostPtr(), &(m_data.indexes[0]), bufferSize);
811
812         vk::flushAlloc(m_vk, vkDevice, *indexAlloc);
813
814         m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
815         m_vk.cmdDrawIndexed(*m_cmdBuffer, m_data.params.indexCount, m_data.params.instanceCount, m_data.params.firstIndex, m_data.params.vertexOffset, m_data.params.firstInstance);
816         endRenderPass();
817         endCommandBuffer(m_vk, *m_cmdBuffer);
818
819         submitCommandsAndWait(m_vk, vkDevice, queue, m_cmdBuffer.get());
820
821         // Validation
822         tcu::TextureLevel       refImage        (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
823         tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
824
825         std::vector<tcu::Vec4>  vertices;
826         std::vector<tcu::Vec4>  colors;
827
828         for (std::vector<deUint32>::const_iterator it = m_data.indexes.begin() + m_data.params.firstIndex; it != m_data.indexes.end(); ++it)
829         {
830                 deUint32 idx = m_data.params.vertexOffset + *it;
831                 vertices.push_back(m_data.vertices[idx].position);
832                 colors.push_back(m_data.vertices[idx].color);
833         }
834         generateRefImage(refImage.getAccess(), vertices, colors);
835
836         const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
837         const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
838                 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
839
840         qpTestResult res = QP_TEST_RESULT_PASS;
841
842         if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
843                 res = QP_TEST_RESULT_FAIL;
844
845         return tcu::TestStatus(res, qpGetTestResultName(res));
846 }
847
848 template<>
849 void DrawTestInstance<DrawIndirectParams>::generateDrawData (void)
850 {
851         de::Random      rnd(SEED ^ m_data.commands[0].vertexCount ^ m_data.commands[0].firstVertex);
852
853         deUint32 lastIndex      = 0;
854
855         // Find the interval which will be used
856         for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
857         {
858                 const deUint32  index = it->firstVertex + it->vertexCount;
859                 lastIndex       = (index > lastIndex) ? index : lastIndex;
860         }
861
862         // Initialize with zeros
863         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)));
864
865         // Generate random vertices only where necessary
866         for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
867         {
868                 std::vector<PositionColorVertex>::iterator vertexStart = m_data.vertices.begin() + it->firstVertex;
869
870                 for (deUint32 idx = 0; idx < it->vertexCount; ++idx)
871                 {
872                         std::vector<PositionColorVertex>::iterator vertexIt = vertexStart + idx;
873
874                         tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
875                         const float f0 = rnd.getFloat(-1.0f, 1.0f);
876                         const float f1 = rnd.getFloat(-1.0f, 1.0f);
877                         positionAccess = tcu::Vec4(f0, f1, 1.0f, 1.0f);
878
879                         tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
880                         colorAccess = tcu::randomVec4(rnd);
881                 }
882         }
883 }
884
885 template<>
886 tcu::TestStatus DrawTestInstance<DrawIndirectParams>::iterate (void)
887 {
888         tcu::TestLog                                            &log                            = m_context.getTestContext().getLog();
889         const vk::DeviceInterface&                      vk                                      = m_context.getDeviceInterface();
890         const vk::VkDevice                                      vkDevice                        = m_context.getDevice();
891         vk::Allocator&                                          allocator                       = m_context.getDefaultAllocator();
892         const vk::VkQueue                                       queue                           = m_context.getUniversalQueue();
893         const deUint32                                          queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
894         const vk::VkPhysicalDeviceFeatures      features                        = m_context.getDeviceFeatures();
895
896         beginRenderPass();
897
898         const vk::VkDeviceSize  vertexBufferOffset      = 0;
899         const vk::VkBuffer              vertexBuffer            = m_vertexBuffer->object();
900
901         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
902         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
903
904         vk::Move<vk::VkBuffer>          indirectBuffer;
905         de::MovePtr<vk::Allocation>     indirectAlloc;
906
907         {
908                 const vk::VkDeviceSize  indirectInfoSize        = m_data.commands.size() * sizeof(vk::VkDrawIndirectCommand);
909
910                 const vk::VkBufferCreateInfo    indirectCreateInfo =
911                 {
912                         vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,       // VkStructureType              sType;
913                         DE_NULL,                                                                        // const void*                  pNext;
914                         0u,                                                                                     // VkBufferCreateFlags  flags;
915                         indirectInfoSize,                                                       // VkDeviceSize                 size;
916                         vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,        // VkBufferUsageFlags   usage;
917                         vk::VK_SHARING_MODE_EXCLUSIVE,                          // VkSharingMode                sharingMode;
918                         1u,                                                                                     // deUint32                             queueFamilyIndexCount;
919                         &queueFamilyIndex,                                                      // const deUint32*              pQueueFamilyIndices;
920                 };
921
922                 indirectBuffer  = createBuffer(vk, vkDevice, &indirectCreateInfo);
923                 indirectAlloc   = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indirectBuffer), vk::MemoryRequirement::HostVisible);
924                 VK_CHECK(vk.bindBufferMemory(vkDevice, *indirectBuffer, indirectAlloc->getMemory(), indirectAlloc->getOffset()));
925
926                 deMemcpy(indirectAlloc->getHostPtr(), &(m_data.commands[0]), (size_t)indirectInfoSize);
927
928                 vk::flushAlloc(m_vk, vkDevice, *indirectAlloc);
929         }
930
931         // If multiDrawIndirect not supported execute single calls
932         if (m_data.commands.size() > 1 && !(features.multiDrawIndirect))
933         {
934                 for (deUint32 cmdIdx = 0; cmdIdx < m_data.commands.size(); ++cmdIdx)
935                 {
936                         const deUint32  offset  = (deUint32)(indirectAlloc->getOffset() + cmdIdx * sizeof(vk::VkDrawIndirectCommand));
937                         m_vk.cmdDrawIndirect(*m_cmdBuffer, *indirectBuffer, offset, 1, sizeof(vk::VkDrawIndirectCommand));
938                 }
939         }
940         else
941         {
942                 m_vk.cmdDrawIndirect(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset(), (deUint32)m_data.commands.size(), sizeof(vk::VkDrawIndirectCommand));
943         }
944
945         endRenderPass();
946         endCommandBuffer(m_vk, *m_cmdBuffer);
947
948         submitCommandsAndWait(m_vk, vkDevice, queue, m_cmdBuffer.get());
949
950         // Validation
951         tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
952         tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
953
954         for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
955         {
956                 std::vector<tcu::Vec4>  vertices;
957                 std::vector<tcu::Vec4>  colors;
958
959                 std::vector<PositionColorVertex>::const_iterator        firstIt = m_data.vertices.begin() + it->firstVertex;
960                 std::vector<PositionColorVertex>::const_iterator        lastIt  = firstIt + it->vertexCount;
961
962                 for (std::vector<PositionColorVertex>::const_iterator vertex = firstIt; vertex != lastIt; ++vertex)
963                 {
964                         vertices.push_back(vertex->position);
965                         colors.push_back(vertex->color);
966                 }
967                 generateRefImage(refImage.getAccess(), vertices, colors);
968         }
969
970         const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
971         const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
972                 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
973
974         qpTestResult res = QP_TEST_RESULT_PASS;
975
976         if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
977                 res = QP_TEST_RESULT_FAIL;
978
979         return tcu::TestStatus(res, qpGetTestResultName(res));
980 }
981
982 template<>
983 void DrawTestInstance<DrawIndexedIndirectParams>::generateDrawData (void)
984 {
985         de::Random              rnd                     (SEED ^ m_data.commands[0].firstIndex ^ m_data.commands[0].indexCount);
986
987         deUint32                lastIndex       = 0;
988
989         // Get the maximum range of indexes
990         for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
991         {
992                 const deUint32  index           = it->firstIndex + it->indexCount;
993                                                 lastIndex       = (index > lastIndex) ? index : lastIndex;
994         }
995
996         // Initialize the vector with zeros
997         m_data.indexes = std::vector<deUint32>(lastIndex, 0);
998
999         deUint32        highestIndex    = 0;
1000
1001         // Generate random indexes for the ranges
1002         for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
1003         {
1004                 for (deUint32 idx = 0; idx < it->indexCount; ++idx)
1005                 {
1006                         const deUint32  vertexIdx       = rnd.getInt(it->vertexOffset, INDEX_LIMIT);
1007                         const deUint32  maxIndex        = vertexIdx + it->vertexOffset;
1008
1009                         highestIndex = (maxIndex > highestIndex) ? maxIndex : highestIndex;
1010                         m_data.indexes[it->firstIndex + idx] = vertexIdx;
1011                 }
1012         }
1013
1014         // Initialize the vertex vector
1015         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)));
1016
1017         // Generate random vertices in the used locations
1018         for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator cmdIt = m_data.commands.begin(); cmdIt != m_data.commands.end(); ++cmdIt)
1019         {
1020                 deUint32        firstIdx        = cmdIt->firstIndex;
1021                 deUint32        lastIdx         = firstIdx + cmdIt->indexCount;
1022
1023                 for (deUint32 idx = firstIdx; idx < lastIdx; ++idx)
1024                 {
1025                         std::vector<PositionColorVertex>::iterator      vertexIt = m_data.vertices.begin() + cmdIt->vertexOffset + m_data.indexes[idx];
1026
1027                         tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
1028                         const float f0 = rnd.getFloat(-1.0f, 1.0f);
1029                         const float f1 = rnd.getFloat(-1.0f, 1.0f);
1030                         positionAccess = tcu::Vec4(f0, f1, 1.0f, 1.0f);
1031
1032                         tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
1033                         colorAccess = tcu::randomVec4(rnd);
1034                 }
1035         }
1036 }
1037
1038 template<>
1039 tcu::TestStatus DrawTestInstance<DrawIndexedIndirectParams>::iterate (void)
1040 {
1041         tcu::TestLog                                            &log                            = m_context.getTestContext().getLog();
1042         const vk::DeviceInterface&                      vk                                      = m_context.getDeviceInterface();
1043         const vk::VkDevice                                      vkDevice                        = m_context.getDevice();
1044         const deUint32                                          queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
1045         const vk::VkQueue                                       queue                           = m_context.getUniversalQueue();
1046         vk::Allocator&                                          allocator                       = m_context.getDefaultAllocator();
1047         const vk::VkPhysicalDeviceFeatures      features                        = m_context.getDeviceFeatures();
1048
1049         beginRenderPass();
1050
1051         const vk::VkDeviceSize  vertexBufferOffset      = 0;
1052         const vk::VkBuffer              vertexBuffer            = m_vertexBuffer->object();
1053
1054         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1055         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1056
1057         vk::Move<vk::VkBuffer>          indirectBuffer;
1058         de::MovePtr<vk::Allocation>     indirectAlloc;
1059
1060         {
1061                 const vk::VkDeviceSize  indirectInfoSize        = m_data.commands.size() * sizeof(vk::VkDrawIndexedIndirectCommand);
1062
1063                 const vk::VkBufferCreateInfo    indirectCreateInfo =
1064                 {
1065                         vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,       // VkStructureType              sType;
1066                         DE_NULL,                                                                        // const void*                  pNext;
1067                         0u,                                                                                     // VkBufferCreateFlags  flags;
1068                         indirectInfoSize,                                                       // VkDeviceSize                 size;
1069                         vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,        // VkBufferUsageFlags   usage;
1070                         vk::VK_SHARING_MODE_EXCLUSIVE,                          // VkSharingMode                sharingMode;
1071                         1u,                                                                                     // deUint32                             queueFamilyIndexCount;
1072                         &queueFamilyIndex,                                                      // const deUint32*              pQueueFamilyIndices;
1073                 };
1074
1075                 indirectBuffer  = createBuffer(vk, vkDevice, &indirectCreateInfo);
1076                 indirectAlloc   = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indirectBuffer), vk::MemoryRequirement::HostVisible);
1077                 VK_CHECK(vk.bindBufferMemory(vkDevice, *indirectBuffer, indirectAlloc->getMemory(), indirectAlloc->getOffset()));
1078
1079                 deMemcpy(indirectAlloc->getHostPtr(), &(m_data.commands[0]), (size_t)indirectInfoSize);
1080
1081                 vk::flushAlloc(m_vk, vkDevice, *indirectAlloc);
1082         }
1083
1084         const deUint32  bufferSize = (deUint32)(m_data.indexes.size() * sizeof(deUint32));
1085
1086         vk::Move<vk::VkBuffer>                  indexBuffer;
1087
1088         const vk::VkBufferCreateInfo    bufferCreateInfo =
1089         {
1090                 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,       // VkStructureType              sType;
1091                 DE_NULL,                                                                        // const void*                  pNext;
1092                 0u,                                                                                     // VkBufferCreateFlags  flags;
1093                 bufferSize,                                                                     // VkDeviceSize                 size;
1094                 vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT,           // VkBufferUsageFlags   usage;
1095                 vk::VK_SHARING_MODE_EXCLUSIVE,                          // VkSharingMode                sharingMode;
1096                 1u,                                                                                     // deUint32                             queueFamilyIndexCount;
1097                 &queueFamilyIndex,                                                      // const deUint32*              pQueueFamilyIndices;
1098         };
1099
1100         indexBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
1101
1102         de::MovePtr<vk::Allocation>     indexAlloc;
1103
1104         indexAlloc = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indexBuffer), vk::MemoryRequirement::HostVisible);
1105         VK_CHECK(vk.bindBufferMemory(vkDevice, *indexBuffer, indexAlloc->getMemory(), indexAlloc->getOffset()));
1106
1107         deMemcpy(indexAlloc->getHostPtr(), &(m_data.indexes[0]), bufferSize);
1108
1109         vk::flushAlloc(m_vk, vkDevice, *indexAlloc);
1110
1111         m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
1112
1113         // If multiDrawIndirect not supported execute single calls
1114         if (m_data.commands.size() > 1 && !(features.multiDrawIndirect))
1115         {
1116                 for (deUint32 cmdIdx = 0; cmdIdx < m_data.commands.size(); ++cmdIdx)
1117                 {
1118                         const deUint32  offset  = (deUint32)(indirectAlloc->getOffset() + cmdIdx * sizeof(vk::VkDrawIndexedIndirectCommand));
1119                         m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, *indirectBuffer, offset, 1, sizeof(vk::VkDrawIndexedIndirectCommand));
1120                 }
1121         }
1122         else
1123         {
1124                 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset(), (deUint32)m_data.commands.size(), sizeof(vk::VkDrawIndexedIndirectCommand));
1125         }
1126
1127         endRenderPass();
1128         endCommandBuffer(m_vk, *m_cmdBuffer);
1129
1130         submitCommandsAndWait(m_vk, vkDevice, queue, m_cmdBuffer.get());
1131
1132         // Validation
1133         tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
1134         tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1135
1136         for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator cmd = m_data.commands.begin(); cmd != m_data.commands.end(); ++cmd)
1137         {
1138                 std::vector<tcu::Vec4>  vertices;
1139                 std::vector<tcu::Vec4>  colors;
1140
1141                 for (deUint32 idx = 0; idx < cmd->indexCount; ++idx)
1142                 {
1143                         const deUint32 vertexIndex = cmd->vertexOffset + m_data.indexes[cmd->firstIndex + idx];
1144                         vertices.push_back(m_data.vertices[vertexIndex].position);
1145                         colors.push_back(m_data.vertices[vertexIndex].color);
1146                 }
1147                 generateRefImage(refImage.getAccess(), vertices, colors);
1148         }
1149
1150         const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
1151         const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
1152                 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1153
1154         qpTestResult res = QP_TEST_RESULT_PASS;
1155
1156         if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
1157                 res = QP_TEST_RESULT_FAIL;
1158
1159         return tcu::TestStatus(res, qpGetTestResultName(res));
1160 }
1161
1162 typedef DrawTestCase<DrawParams>                                DrawCase;
1163 typedef DrawTestCase<DrawIndexedParams>                 IndexedCase;
1164 typedef DrawTestCase<DrawIndirectParams>                IndirectCase;
1165 typedef DrawTestCase<DrawIndexedIndirectParams> IndexedIndirectCase;
1166
1167 struct TestCaseParams
1168 {
1169         const DrawCommandType                   command;
1170         const vk::VkPrimitiveTopology   topology;
1171         const bool                                              useDynamicRendering;
1172
1173         TestCaseParams (const DrawCommandType cmd, const vk::VkPrimitiveTopology top, bool dynamicRendering)
1174                 : command                               (cmd)
1175                 , topology                              (top)
1176                 , useDynamicRendering   (dynamicRendering)
1177         {}
1178 };
1179
1180 }       // anonymous
1181
1182 void populateSubGroup (tcu::TestCaseGroup* testGroup, const TestCaseParams caseParams)
1183 {
1184         de::Random                                              rnd                                             (SEED ^ deStringHash(testGroup->getName()));
1185         tcu::TestContext&                               testCtx                                 = testGroup->getTestContext();
1186         const DrawCommandType                   command                                 = caseParams.command;
1187         const vk::VkPrimitiveTopology   topology                                = caseParams.topology;
1188         const bool                                              useDynamicRendering             = caseParams.useDynamicRendering;
1189         const deUint32                                  primitiveCountArrLength = DE_LENGTH_OF_ARRAY(PRIMITIVE_COUNT);
1190
1191         for (deUint32 primitiveCountIdx = 0; primitiveCountIdx < primitiveCountArrLength; ++primitiveCountIdx)
1192         {
1193                 const deUint32 primitives = PRIMITIVE_COUNT[primitiveCountIdx];
1194
1195                 // when testing VK_KHR_dynamic_rendering there is no need to duplicate tests for all primitive counts; use just 1 and 45
1196                 if (useDynamicRendering && (primitiveCountIdx != 0) && (primitiveCountIdx != primitiveCountArrLength-1))
1197                         continue;
1198
1199                 deUint32        multiplier      = 1;
1200                 deUint32        offset          = 0;
1201                 // Calculated by Vulkan 23.1
1202                 switch (topology)
1203                 {
1204                         case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:                                                                                                      break;
1205                         case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:                                               multiplier = 2;                         break;
1206                         case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:                                                                                                      break;
1207                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:                                   multiplier = 3;                         break;
1208                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:                                                                                          break;
1209                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:                                                                    offset = 1;     break;
1210                         case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:                multiplier = 4; offset = 1;     break;
1211                         case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:                                               offset = 1;     break;
1212                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:    multiplier = 6;                         break;
1213                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:   multiplier = 2;                         break;
1214                         default:                                                                                                                DE_FATAL("Unsupported topology.");
1215                 }
1216
1217                 const deUint32  vertexCount             = multiplier * primitives + offset;
1218                 std::string             name                    = de::toString(primitives);
1219
1220                 switch (command)
1221                 {
1222                         case DRAW_COMMAND_TYPE_DRAW:
1223                         {
1224                                 deUint32        firstPrimitive  = rnd.getInt(0, primitives);
1225                                 deUint32        firstVertex             = multiplier * firstPrimitive;
1226                                 testGroup->addChild(new DrawCase(testCtx, name.c_str(), "vkCmdDraw testcase.",
1227                                         DrawParams(topology, useDynamicRendering, vertexCount, 1, firstVertex, 0))
1228                                 );
1229                                 break;
1230                         }
1231                         case DRAW_COMMAND_TYPE_DRAW_INDEXED:
1232                         {
1233                                 deUint32        firstIndex                      = rnd.getInt(0, OFFSET_LIMIT);
1234                                 deUint32        vertexOffset            = rnd.getInt(0, OFFSET_LIMIT);
1235                                 testGroup->addChild(new IndexedCase(testCtx, name.c_str(), "vkCmdDrawIndexed testcase.",
1236                                         DrawIndexedParams(topology, useDynamicRendering, vk::VK_INDEX_TYPE_UINT32, vertexCount, 1, firstIndex, vertexOffset, 0))
1237                                 );
1238                                 break;
1239                         }
1240                         case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
1241                         {
1242                                 deUint32        firstVertex             = rnd.getInt(0, OFFSET_LIMIT);
1243
1244                                 DrawIndirectParams      params  = DrawIndirectParams(topology, useDynamicRendering);
1245
1246                                 params.addCommand(vertexCount, 1, 0, 0);
1247                                 testGroup->addChild(new IndirectCase(testCtx, (name + "_single_command").c_str(), "vkCmdDrawIndirect testcase.", params));
1248
1249                                 params.addCommand(vertexCount, 1, firstVertex, 0);
1250                                 testGroup->addChild(new IndirectCase(testCtx, (name + "_multi_command").c_str(), "vkCmdDrawIndirect testcase.", params));
1251                                 break;
1252                         }
1253                         case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
1254                         {
1255                                 deUint32        firstIndex              = rnd.getInt(vertexCount, OFFSET_LIMIT);
1256                                 deUint32        vertexOffset    = rnd.getInt(vertexCount, OFFSET_LIMIT);
1257
1258                                 DrawIndexedIndirectParams       params  = DrawIndexedIndirectParams(topology, useDynamicRendering, vk::VK_INDEX_TYPE_UINT32);
1259                                 params.addCommand(vertexCount, 1, 0, 0, 0);
1260                                 testGroup->addChild(new IndexedIndirectCase(testCtx, (name + "_single_command").c_str(), "vkCmdDrawIndexedIndirect testcase.", params));
1261
1262                                 params.addCommand(vertexCount, 1, firstIndex, vertexOffset, 0);
1263                                 testGroup->addChild(new IndexedIndirectCase(testCtx, (name + "_multi_command").c_str(), "vkCmdDrawIndexedIndirect testcase.", params));
1264                                 break;
1265                         }
1266                         default:
1267                                 DE_FATAL("Unsupported draw command.");
1268                 }
1269         }
1270 }
1271
1272 void createDrawTests(tcu::TestCaseGroup* testGroup, bool useDynamicRendering)
1273 {
1274         for (deUint32 drawTypeIndex = 0; drawTypeIndex < DRAW_COMMAND_TYPE_DRAW_LAST; ++drawTypeIndex)
1275         {
1276                 const DrawCommandType                   command                 (static_cast<DrawCommandType>(drawTypeIndex));
1277                 de::MovePtr<tcu::TestCaseGroup> topologyGroup   (new tcu::TestCaseGroup(testGroup->getTestContext(), getDrawCommandTypeName(command), "Group for testing a specific draw command."));
1278
1279                 for (deUint32 topologyIdx = 0; topologyIdx != vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; ++topologyIdx)
1280                 {
1281                         const vk::VkPrimitiveTopology   topology        (static_cast<vk::VkPrimitiveTopology>(topologyIdx));
1282                         const std::string                               groupName       (de::toLower(getPrimitiveTopologyName(topology)).substr(22));
1283
1284                         addTestGroup(topologyGroup.get(), groupName, "Testcases with a specific topology.", populateSubGroup, TestCaseParams(command, topology, useDynamicRendering));
1285                 }
1286
1287                 testGroup->addChild(topologyGroup.release());
1288         }
1289 }
1290
1291 tcu::TestCaseGroup*     createBasicDrawTests (tcu::TestContext& testCtx, bool useDynamicRendering)
1292 {
1293         return createTestGroup(testCtx, "basic_draw", "Basic drawing tests", createDrawTests, useDynamicRendering);
1294 }
1295
1296 }       // DrawTests
1297 }       // vkt