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