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