Merge vk-gl-cts/vulkan-cts-1.0.2 into vk-gl-cts/master
[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.053f, 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(), m_context.getUniversalQueueFamilyIndex());
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         m_cmdBuffer     = vk::allocateCommandBuffer(m_vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
414
415         initPipeline(device);
416 }
417
418 void DrawTestInstanceBase::initPipeline (const vk::VkDevice device)
419 {
420         const vk::Unique<vk::VkShaderModule>    vs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("vert"), 0));
421         const vk::Unique<vk::VkShaderModule>    fs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("frag"), 0));
422
423         const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState;
424
425         vk::VkViewport viewport;
426         viewport.x                              = 0;
427         viewport.y                              = 0;
428         viewport.width                  = static_cast<float>(WIDTH);
429         viewport.height                 = static_cast<float>(HEIGHT);
430         viewport.minDepth               = 0.0f;
431         viewport.maxDepth               = 1.0f;
432
433         vk::VkRect2D scissor;
434         scissor.offset.x                = 0;
435         scissor.offset.y                = 0;
436         scissor.extent.width    = WIDTH;
437         scissor.extent.height   = HEIGHT;
438
439         PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
440         pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
441         pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
442         pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(m_vertexInputState));
443         pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(m_data.topology));
444         pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
445         pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
446         pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
447         pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
448         pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
449
450         m_pipeline = vk::createGraphicsPipeline(m_vk, device, DE_NULL, &pipelineCreateInfo);
451 }
452
453 void DrawTestInstanceBase::beginRenderPass (void)
454 {
455         const vk::VkClearColorValue clearColor = { { 0.0f, 0.0f, 0.0f, 1.0f } };
456         const CmdBufferBeginInfo beginInfo;
457
458         m_vk.beginCommandBuffer(*m_cmdBuffer, &beginInfo);
459
460         initialTransitionColor2DImage(m_vk, *m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
461                                                                   vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
462
463         const ImageSubresourceRange subresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT);
464         m_vk.cmdClearColorImage(*m_cmdBuffer, m_colorTargetImage->object(),
465                 vk::VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &subresourceRange);
466
467         const vk::VkMemoryBarrier memBarrier =
468         {
469                 vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER,
470                 DE_NULL,
471                 vk::VK_ACCESS_TRANSFER_WRITE_BIT,
472                 vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
473         };
474
475         m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
476                 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
477                 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
478
479         const vk::VkRect2D renderArea = { { 0, 0 }, { WIDTH, HEIGHT } };
480         const RenderPassBeginInfo renderPassBegin(*m_renderPass, *m_framebuffer, renderArea);
481
482         m_vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBegin, vk::VK_SUBPASS_CONTENTS_INLINE);
483 }
484
485 void DrawTestInstanceBase::generateRefImage (const tcu::PixelBufferAccess& access, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const
486 {
487         const PassthruVertShader                                vertShader;
488         const PassthruFragShader                                fragShader;
489         const rr::Program                                               program                 (&vertShader, &fragShader);
490         const rr::MultisamplePixelBufferAccess  colorBuffer             = rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(access);
491         const rr::RenderTarget                                  renderTarget    (colorBuffer);
492         const rr::RenderState                                   renderState             ((rr::ViewportState(colorBuffer)));
493         const rr::Renderer                                              renderer;
494
495         const rr::VertexAttrib  vertexAttribs[] =
496         {
497                 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &vertices[0]),
498                 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &colors[0])
499         };
500
501         renderer.draw(rr::DrawCommand(renderState,
502                                                                   renderTarget,
503                                                                   program,
504                                                                   DE_LENGTH_OF_ARRAY(vertexAttribs),
505                                                                   &vertexAttribs[0],
506                                                                   rr::PrimitiveList(mapVkPrimitiveTopology(m_data.topology), (deUint32)vertices.size(), 0)));
507 }
508
509 template<typename T>
510 class DrawTestInstance : public DrawTestInstanceBase
511 {
512 public:
513                                                         DrawTestInstance                (Context& context, const T& data);
514         virtual                                 ~DrawTestInstance               (void);
515         virtual void                    generateDrawData                (void);
516         virtual tcu::TestStatus iterate                                 (void);
517 private:
518         T                                               m_data;
519 };
520
521 template<typename T>
522 DrawTestInstance<T>::DrawTestInstance (Context& context, const T& data)
523         : DrawTestInstanceBase  (context)
524         , m_data                                (data)
525 {
526         generateDrawData();
527         initialize(m_data);
528 }
529
530 template<typename T>
531 DrawTestInstance<T>::~DrawTestInstance (void)
532 {
533 }
534
535 template<typename T>
536 void DrawTestInstance<T>::generateDrawData (void)
537 {
538         DE_FATAL("Using the general case of this function is forbidden!");
539 }
540
541 template<typename T>
542 tcu::TestStatus DrawTestInstance<T>::iterate (void)
543 {
544         DE_FATAL("Using the general case of this function is forbidden!");
545         return tcu::TestStatus::fail("");
546 }
547
548 template<typename T>
549 class DrawTestCase : public TestCase
550 {
551         public:
552                                                                         DrawTestCase            (tcu::TestContext& context, const char* name, const char* desc, const T data);
553                                                                         ~DrawTestCase           (void);
554         virtual void                                    initPrograms            (vk::SourceCollections& programCollection) const;
555         virtual void                                    initShaderSources       (void);
556         virtual TestInstance*                   createInstance          (Context& context) const;
557
558 private:
559         T                                                                                                       m_data;
560         std::string                                                                                     m_vertShaderSource;
561         std::string                                                                                     m_fragShaderSource;
562 };
563
564 template<typename T>
565 DrawTestCase<T>::DrawTestCase (tcu::TestContext& context, const char* name, const char* desc, const T data)
566         : vkt::TestCase (context, name, desc)
567         , m_data                (data)
568 {
569         initShaderSources();
570 }
571
572 template<typename T>
573 DrawTestCase<T>::~DrawTestCase  (void)
574 {
575 }
576
577 template<typename T>
578 void DrawTestCase<T>::initPrograms (vk::SourceCollections& programCollection) const
579 {
580         programCollection.glslSources.add("vert") << glu::VertexSource(m_vertShaderSource);
581         programCollection.glslSources.add("frag") << glu::FragmentSource(m_fragShaderSource);
582 }
583
584 template<typename T>
585 void DrawTestCase<T>::initShaderSources (void)
586 {
587         std::stringstream vertShader;
588         vertShader      << "#version 430\n"
589                                 << "layout(location = 0) in vec4 in_position;\n"
590                                 << "layout(location = 1) in vec4 in_color;\n"
591                                 << "layout(location = 0) out vec4 out_color;\n"
592
593                                 << "out gl_PerVertex {\n"
594                                 << "    vec4  gl_Position;\n"
595                                 << "    float gl_PointSize;\n"
596                                 << "};\n"
597                                 << "void main() {\n"
598                                 << "    gl_PointSize = 1.0;\n"
599                                 << "    gl_Position  = in_position;\n"
600                                 << "    out_color    = in_color;\n"
601                                 << "}\n";
602
603         m_vertShaderSource = vertShader.str();
604
605         std::stringstream fragShader;
606         fragShader      << "#version 430\n"
607                                 << "layout(location = 0) in vec4 in_color;\n"
608                                 << "layout(location = 0) out vec4 out_color;\n"
609                                 << "void main()\n"
610                                 << "{\n"
611                                 << "    out_color = in_color;\n"
612                                 << "}\n";
613
614         m_fragShaderSource = fragShader.str();
615 }
616
617 template<typename T>
618 TestInstance* DrawTestCase<T>::createInstance (Context& context) const
619 {
620         return new DrawTestInstance<T>(context, m_data);
621 }
622
623 // Specialized cases
624 template<>
625 void DrawTestInstance<DrawParams>::generateDrawData (void)
626 {
627         de::Random              rnd                     (SEED ^ m_data.params.firstVertex ^ m_data.params.vertexCount);
628
629         const deUint32  vectorSize      = m_data.params.firstVertex + m_data.params.vertexCount;
630
631         // Initialize the vector
632         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)));
633
634         // Fill only the used indexes
635         for (deUint32 vertexIdx = m_data.params.firstVertex; vertexIdx < vectorSize; ++vertexIdx)
636         {
637                 m_data.vertices[vertexIdx] = PositionColorVertex(
638                         tcu::Vec4(rnd.getFloat(-1.0, 1.0), rnd.getFloat(-1.0, 1.0), 1.0, 1.0),                                                                          // Coord
639                         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
640         }
641 }
642
643 template<>
644 tcu::TestStatus DrawTestInstance<DrawParams>::iterate (void)
645 {
646         tcu::TestLog                    &log                            = m_context.getTestContext().getLog();
647         const vk::VkQueue               queue                           = m_context.getUniversalQueue();
648
649         beginRenderPass();
650
651         const vk::VkDeviceSize  vertexBufferOffset      = 0;
652         const vk::VkBuffer              vertexBuffer            = m_vertexBuffer->object();
653
654         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
655         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
656         m_vk.cmdDraw(*m_cmdBuffer, m_data.params.vertexCount, m_data.params.instanceCount, m_data.params.firstVertex, m_data.params.firstInstance);
657         m_vk.cmdEndRenderPass(*m_cmdBuffer);
658         m_vk.endCommandBuffer(*m_cmdBuffer);
659
660         vk::VkSubmitInfo        submitInfo =
661         {
662                 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,                      // VkStructureType                      sType;
663                 DE_NULL,                                                                        // const void*                          pNext;
664                 0,                                                                                      // deUint32                                     waitSemaphoreCount;
665                 DE_NULL,                                                                        // const VkSemaphore*           pWaitSemaphores;
666                 (const vk::VkPipelineStageFlags*)DE_NULL,
667                 1,                                                                                      // deUint32                                     commandBufferCount;
668                 &m_cmdBuffer.get(),                                                     // const VkCommandBuffer*       pCommandBuffers;
669                 0,                                                                                      // deUint32                                     signalSemaphoreCount;
670                 DE_NULL                                                                         // const VkSemaphore*           pSignalSemaphores;
671         };
672         VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
673
674         // Validation
675         tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
676         tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
677
678         std::vector<tcu::Vec4>  vertices;
679         std::vector<tcu::Vec4>  colors;
680
681         for (std::vector<PositionColorVertex>::const_iterator vertex = m_data.vertices.begin() + m_data.params.firstVertex; vertex != m_data.vertices.end(); ++vertex)
682         {
683                 vertices.push_back(vertex->position);
684                 colors.push_back(vertex->color);
685         }
686         generateRefImage(refImage.getAccess(), vertices, colors);
687
688         VK_CHECK(m_vk.queueWaitIdle(queue));
689
690         const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
691         const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
692                 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
693
694         qpTestResult res = QP_TEST_RESULT_PASS;
695
696         if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
697                 res = QP_TEST_RESULT_FAIL;
698
699         return tcu::TestStatus(res, qpGetTestResultName(res));
700 }
701
702 template<>
703 void DrawTestInstance<DrawIndexedParams>::generateDrawData (void)
704 {
705         de::Random              rnd                     (SEED ^ m_data.params.firstIndex ^ m_data.params.indexCount);
706         const deUint32  indexSize       = m_data.params.firstIndex + m_data.params.indexCount;
707
708         // Initialize the vector with zeros
709         m_data.indexes = std::vector<deUint32>(indexSize, 0);
710
711         deUint32                highestIndex    = 0;    // Store to highest index to calculate the vertices size
712         // Fill the indexes from firstIndex
713         for (deUint32 idx = 0; idx < m_data.params.indexCount; ++idx)
714         {
715                 deUint32        vertexIdx       = rnd.getInt(m_data.params.vertexOffset, INDEX_LIMIT);
716                 highestIndex = (vertexIdx > highestIndex) ? vertexIdx : highestIndex;
717
718                 m_data.indexes[m_data.params.firstIndex + idx]  = vertexIdx;
719         }
720
721         // Fill up the vertex coordinates with zeros until the highestIndex including the vertexOffset
722         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)));
723
724         // Generate random vertex only where you have index pointing at
725         for (std::vector<deUint32>::const_iterator indexIt = m_data.indexes.begin() + m_data.params.firstIndex; indexIt != m_data.indexes.end(); ++indexIt)
726         {
727                 // Get iterator to the vertex position  with the vertexOffset
728                 std::vector<PositionColorVertex>::iterator vertexIt = m_data.vertices.begin() + m_data.params.vertexOffset + *indexIt;
729
730                 tcu::VecAccess<float, 4, 4>     positionAccess = vertexIt->position.xyzw();
731                 positionAccess = tcu::Vec4(rnd.getFloat(-1.0, 1.0), rnd.getFloat(-1.0, 1.0), 1.0, 1.0);
732
733                 tcu::VecAccess<float, 4, 4>     colorAccess = vertexIt->color.xyzw();
734                 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));
735         }
736 }
737
738 template<>
739 tcu::TestStatus DrawTestInstance<DrawIndexedParams>::iterate (void)
740 {
741         tcu::TestLog                            &log                            = m_context.getTestContext().getLog();
742         const vk::DeviceInterface&      vk                                      = m_context.getDeviceInterface();
743         const vk::VkDevice                      vkDevice                        = m_context.getDevice();
744         const deUint32                          queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
745         const vk::VkQueue                       queue                           = m_context.getUniversalQueue();
746         vk::Allocator&                          allocator                       = m_context.getDefaultAllocator();
747
748         beginRenderPass();
749
750         const vk::VkDeviceSize  vertexBufferOffset = 0;
751         const vk::VkBuffer      vertexBuffer = m_vertexBuffer->object();
752
753         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
754         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
755
756         const deUint32  bufferSize      = (deUint32)(m_data.indexes.size() * sizeof(deUint32));
757
758         vk::Move<vk::VkBuffer>  indexBuffer;
759
760         const vk::VkBufferCreateInfo    bufferCreateInfo =
761         {
762                 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,       // VkStructureType              sType;
763                 DE_NULL,                                                                        // const void*                  pNext;
764                 0u,                                                                                     // VkBufferCreateFlags  flags;
765                 bufferSize,                                                                     // VkDeviceSize                 size;
766                 vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT,           // VkBufferUsageFlags   usage;
767                 vk::VK_SHARING_MODE_EXCLUSIVE,                          // VkSharingMode                sharingMode;
768                 1u,                                                                                     // deUint32                             queueFamilyIndexCount;
769                 &queueFamilyIndex,                                                      // const deUint32*              pQueueFamilyIndices;
770         };
771
772         indexBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
773
774         de::MovePtr<vk::Allocation>     indexAlloc;
775
776         indexAlloc = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indexBuffer), vk::MemoryRequirement::HostVisible);
777         VK_CHECK(vk.bindBufferMemory(vkDevice, *indexBuffer, indexAlloc->getMemory(), indexAlloc->getOffset()));
778
779         deMemcpy(indexAlloc->getHostPtr(), &(m_data.indexes[0]), bufferSize);
780
781         vk::flushMappedMemoryRange(m_vk, vkDevice, indexAlloc->getMemory(), indexAlloc->getOffset(), bufferSize);
782
783         m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
784         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);
785         m_vk.cmdEndRenderPass(*m_cmdBuffer);
786         m_vk.endCommandBuffer(*m_cmdBuffer);
787
788         vk::VkSubmitInfo        submitInfo =
789         {
790                 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,                      // VkStructureType                      sType;
791                 DE_NULL,                                                                        // const void*                          pNext;
792                 0,                                                                                      // deUint32                                     waitSemaphoreCount;
793                 DE_NULL,                                                                        // const VkSemaphore*           pWaitSemaphores;
794                 (const vk::VkPipelineStageFlags*)DE_NULL,
795                 1,                                                                                      // deUint32                                     commandBufferCount;
796                 &m_cmdBuffer.get(),                                                     // const VkCommandBuffer*       pCommandBuffers;
797                 0,                                                                                      // deUint32                                     signalSemaphoreCount;
798                 DE_NULL                                                                         // const VkSemaphore*           pSignalSemaphores;
799         };
800         VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
801
802         // Validation
803         tcu::TextureLevel       refImage        (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
804         tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
805
806         std::vector<tcu::Vec4>  vertices;
807         std::vector<tcu::Vec4>  colors;
808
809         for (std::vector<deUint32>::const_iterator it = m_data.indexes.begin() + m_data.params.firstIndex; it != m_data.indexes.end(); ++it)
810         {
811                 deUint32 idx = m_data.params.vertexOffset + *it;
812                 vertices.push_back(m_data.vertices[idx].position);
813                 colors.push_back(m_data.vertices[idx].color);
814         }
815         generateRefImage(refImage.getAccess(), vertices, colors);
816
817         VK_CHECK(m_vk.queueWaitIdle(queue));
818
819         const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
820         const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
821                 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
822
823         qpTestResult res = QP_TEST_RESULT_PASS;
824
825         if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
826                 res = QP_TEST_RESULT_FAIL;
827
828         return tcu::TestStatus(res, qpGetTestResultName(res));
829 }
830
831 template<>
832 void DrawTestInstance<DrawIndirectParams>::generateDrawData (void)
833 {
834         de::Random      rnd(SEED ^ m_data.commands[0].vertexCount ^ m_data.commands[0].firstVertex);
835
836         deUint32 lastIndex      = 0;
837
838         // Find the interval which will be used
839         for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
840         {
841                 const deUint32  index = it->firstVertex + it->vertexCount;
842                 lastIndex       = (index > lastIndex) ? index : lastIndex;
843         }
844
845         // Initialize with zeros
846         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)));
847
848         // Generate random vertices only where necessary
849         for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
850         {
851                 std::vector<PositionColorVertex>::iterator vertexStart = m_data.vertices.begin() + it->firstVertex;
852
853                 for (deUint32 idx = 0; idx < it->vertexCount; ++idx)
854                 {
855                         std::vector<PositionColorVertex>::iterator vertexIt = vertexStart + idx;
856
857                         tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
858                         positionAccess = tcu::Vec4(rnd.getFloat(-1.0, 1.0), rnd.getFloat(-1.0, 1.0), 1.0, 1.0);
859
860                         tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
861                         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));
862                 }
863         }
864 }
865
866 template<>
867 tcu::TestStatus DrawTestInstance<DrawIndirectParams>::iterate (void)
868 {
869         tcu::TestLog                                            &log                            = m_context.getTestContext().getLog();
870         const vk::DeviceInterface&                      vk                                      = m_context.getDeviceInterface();
871         const vk::VkDevice                                      vkDevice                        = m_context.getDevice();
872         vk::Allocator&                                          allocator                       = m_context.getDefaultAllocator();
873         const vk::VkQueue                                       queue                           = m_context.getUniversalQueue();
874         const deUint32                                          queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
875         const vk::VkPhysicalDeviceFeatures      features                        = m_context.getDeviceFeatures();
876
877         beginRenderPass();
878
879         const vk::VkDeviceSize  vertexBufferOffset      = 0;
880         const vk::VkBuffer              vertexBuffer            = m_vertexBuffer->object();
881
882         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
883         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
884
885         vk::Move<vk::VkBuffer>          indirectBuffer;
886         de::MovePtr<vk::Allocation>     indirectAlloc;
887
888         {
889                 const vk::VkDeviceSize  indirectInfoSize        = m_data.commands.size() * sizeof(vk::VkDrawIndirectCommand);
890
891                 const vk::VkBufferCreateInfo    indirectCreateInfo =
892                 {
893                         vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,       // VkStructureType              sType;
894                         DE_NULL,                                                                        // const void*                  pNext;
895                         0u,                                                                                     // VkBufferCreateFlags  flags;
896                         indirectInfoSize,                                                       // VkDeviceSize                 size;
897                         vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,        // VkBufferUsageFlags   usage;
898                         vk::VK_SHARING_MODE_EXCLUSIVE,                          // VkSharingMode                sharingMode;
899                         1u,                                                                                     // deUint32                             queueFamilyIndexCount;
900                         &queueFamilyIndex,                                                      // const deUint32*              pQueueFamilyIndices;
901                 };
902
903                 indirectBuffer  = createBuffer(vk, vkDevice, &indirectCreateInfo);
904                 indirectAlloc   = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indirectBuffer), vk::MemoryRequirement::HostVisible);
905                 VK_CHECK(vk.bindBufferMemory(vkDevice, *indirectBuffer, indirectAlloc->getMemory(), indirectAlloc->getOffset()));
906
907                 deMemcpy(indirectAlloc->getHostPtr(), &(m_data.commands[0]), (size_t)indirectInfoSize);
908
909                 vk::flushMappedMemoryRange(m_vk, vkDevice, indirectAlloc->getMemory(), indirectAlloc->getOffset(), indirectInfoSize);
910         }
911
912         // If multiDrawIndirect not supported execute single calls
913         if (m_data.commands.size() > 1 && !(features.multiDrawIndirect))
914         {
915                 for (deUint32 cmdIdx = 0; cmdIdx < m_data.commands.size(); ++cmdIdx)
916                 {
917                         const deUint32  offset  = (deUint32)(indirectAlloc->getOffset() + cmdIdx * sizeof(vk::VkDrawIndirectCommand));
918                         m_vk.cmdDrawIndirect(*m_cmdBuffer, *indirectBuffer, offset, 1, sizeof(vk::VkDrawIndirectCommand));
919                 }
920         }
921         else
922         {
923                 m_vk.cmdDrawIndirect(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset(), (deUint32)m_data.commands.size(), sizeof(vk::VkDrawIndirectCommand));
924         }
925
926         m_vk.cmdEndRenderPass(*m_cmdBuffer);
927         m_vk.endCommandBuffer(*m_cmdBuffer);
928
929         vk::VkSubmitInfo        submitInfo =
930         {
931                 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,                      // VkStructureType                      sType;
932                 DE_NULL,                                                                        // const void*                          pNext;
933                 0,                                                                                      // deUint32                                     waitSemaphoreCount;
934                 DE_NULL,                                                                        // const VkSemaphore*           pWaitSemaphores;
935                 (const vk::VkPipelineStageFlags*)DE_NULL,
936                 1,                                                                                      // deUint32                                     commandBufferCount;
937                 &m_cmdBuffer.get(),                                                     // const VkCommandBuffer*       pCommandBuffers;
938                 0,                                                                                      // deUint32                                     signalSemaphoreCount;
939                 DE_NULL                                                                         // const VkSemaphore*           pSignalSemaphores;
940         };
941         VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
942
943         // Validation
944         tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
945         tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
946
947         for (std::vector<vk::VkDrawIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
948         {
949                 std::vector<tcu::Vec4>  vertices;
950                 std::vector<tcu::Vec4>  colors;
951
952                 std::vector<PositionColorVertex>::const_iterator        firstIt = m_data.vertices.begin() + it->firstVertex;
953                 std::vector<PositionColorVertex>::const_iterator        lastIt  = firstIt + it->vertexCount;
954
955                 for (std::vector<PositionColorVertex>::const_iterator vertex = firstIt; vertex != lastIt; ++vertex)
956                 {
957                         vertices.push_back(vertex->position);
958                         colors.push_back(vertex->color);
959                 }
960                 generateRefImage(refImage.getAccess(), vertices, colors);
961         }
962
963         VK_CHECK(m_vk.queueWaitIdle(queue));
964
965         const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
966         const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
967                 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
968
969         qpTestResult res = QP_TEST_RESULT_PASS;
970
971         if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
972                 res = QP_TEST_RESULT_FAIL;
973
974         return tcu::TestStatus(res, qpGetTestResultName(res));
975 }
976
977 template<>
978 void DrawTestInstance<DrawIndexedIndirectParams>::generateDrawData (void)
979 {
980         de::Random              rnd                     (SEED ^ m_data.commands[0].firstIndex ^ m_data.commands[0].indexCount);
981
982         deUint32                lastIndex       = 0;
983
984         // Get the maximum range of indexes
985         for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
986         {
987                 const deUint32  index           = it->firstIndex + it->indexCount;
988                                                 lastIndex       = (index > lastIndex) ? index : lastIndex;
989         }
990
991         // Initialize the vector with zeros
992         m_data.indexes = std::vector<deUint32>(lastIndex, 0);
993
994         deUint32        highestIndex    = 0;
995
996         // Generate random indexes for the ranges
997         for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator it = m_data.commands.begin(); it != m_data.commands.end(); ++it)
998         {
999                 for (deUint32 idx = 0; idx < it->indexCount; ++idx)
1000                 {
1001                         const deUint32  vertexIdx       = rnd.getInt(it->vertexOffset, INDEX_LIMIT);
1002                         const deUint32  maxIndex        = vertexIdx + it->vertexOffset;
1003
1004                         highestIndex = (maxIndex > highestIndex) ? maxIndex : highestIndex;
1005                         m_data.indexes[it->firstIndex + idx] = vertexIdx;
1006                 }
1007         }
1008
1009         // Initialize the vertex vector
1010         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)));
1011
1012         // Generate random vertices in the used locations
1013         for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator cmdIt = m_data.commands.begin(); cmdIt != m_data.commands.end(); ++cmdIt)
1014         {
1015                 deUint32        firstIdx        = cmdIt->firstIndex;
1016                 deUint32        lastIdx         = firstIdx + cmdIt->indexCount;
1017
1018                 for (deUint32 idx = firstIdx; idx < lastIdx; ++idx)
1019                 {
1020                         std::vector<PositionColorVertex>::iterator      vertexIt = m_data.vertices.begin() + cmdIt->vertexOffset + m_data.indexes[idx];
1021
1022                         tcu::VecAccess<float, 4, 4> positionAccess = vertexIt->position.xyzw();
1023                         positionAccess = tcu::Vec4(rnd.getFloat(-1.0, 1.0), rnd.getFloat(-1.0, 1.0), 1.0, 1.0);
1024
1025                         tcu::VecAccess<float, 4, 4> colorAccess = vertexIt->color.xyzw();
1026                         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));
1027                 }
1028         }
1029 }
1030
1031 template<>
1032 tcu::TestStatus DrawTestInstance<DrawIndexedIndirectParams>::iterate (void)
1033 {
1034         tcu::TestLog                                            &log                            = m_context.getTestContext().getLog();
1035         const vk::DeviceInterface&                      vk                                      = m_context.getDeviceInterface();
1036         const vk::VkDevice                                      vkDevice                        = m_context.getDevice();
1037         const deUint32                                          queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
1038         const vk::VkQueue                                       queue                           = m_context.getUniversalQueue();
1039         vk::Allocator&                                          allocator                       = m_context.getDefaultAllocator();
1040         const vk::VkPhysicalDeviceFeatures      features                        = m_context.getDeviceFeatures();
1041
1042         beginRenderPass();
1043
1044         const vk::VkDeviceSize  vertexBufferOffset      = 0;
1045         const vk::VkBuffer              vertexBuffer            = m_vertexBuffer->object();
1046
1047         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1048         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
1049
1050         vk::Move<vk::VkBuffer>          indirectBuffer;
1051         de::MovePtr<vk::Allocation>     indirectAlloc;
1052
1053         {
1054                 const vk::VkDeviceSize  indirectInfoSize        = m_data.commands.size() * sizeof(vk::VkDrawIndexedIndirectCommand);
1055
1056                 const vk::VkBufferCreateInfo    indirectCreateInfo =
1057                 {
1058                         vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,       // VkStructureType              sType;
1059                         DE_NULL,                                                                        // const void*                  pNext;
1060                         0u,                                                                                     // VkBufferCreateFlags  flags;
1061                         indirectInfoSize,                                                       // VkDeviceSize                 size;
1062                         vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,        // VkBufferUsageFlags   usage;
1063                         vk::VK_SHARING_MODE_EXCLUSIVE,                          // VkSharingMode                sharingMode;
1064                         1u,                                                                                     // deUint32                             queueFamilyIndexCount;
1065                         &queueFamilyIndex,                                                      // const deUint32*              pQueueFamilyIndices;
1066                 };
1067
1068                 indirectBuffer  = createBuffer(vk, vkDevice, &indirectCreateInfo);
1069                 indirectAlloc   = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indirectBuffer), vk::MemoryRequirement::HostVisible);
1070                 VK_CHECK(vk.bindBufferMemory(vkDevice, *indirectBuffer, indirectAlloc->getMemory(), indirectAlloc->getOffset()));
1071
1072                 deMemcpy(indirectAlloc->getHostPtr(), &(m_data.commands[0]), (size_t)indirectInfoSize);
1073
1074                 vk::flushMappedMemoryRange(m_vk, vkDevice, indirectAlloc->getMemory(), indirectAlloc->getOffset(), indirectInfoSize);
1075         }
1076
1077         const deUint32  bufferSize = (deUint32)(m_data.indexes.size() * sizeof(deUint32));
1078
1079         vk::Move<vk::VkBuffer>                  indexBuffer;
1080
1081         const vk::VkBufferCreateInfo    bufferCreateInfo =
1082         {
1083                 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,       // VkStructureType              sType;
1084                 DE_NULL,                                                                        // const void*                  pNext;
1085                 0u,                                                                                     // VkBufferCreateFlags  flags;
1086                 bufferSize,                                                                     // VkDeviceSize                 size;
1087                 vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT,           // VkBufferUsageFlags   usage;
1088                 vk::VK_SHARING_MODE_EXCLUSIVE,                          // VkSharingMode                sharingMode;
1089                 1u,                                                                                     // deUint32                             queueFamilyIndexCount;
1090                 &queueFamilyIndex,                                                      // const deUint32*              pQueueFamilyIndices;
1091         };
1092
1093         indexBuffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
1094
1095         de::MovePtr<vk::Allocation>     indexAlloc;
1096
1097         indexAlloc = allocator.allocate(getBufferMemoryRequirements(vk, vkDevice, *indexBuffer), vk::MemoryRequirement::HostVisible);
1098         VK_CHECK(vk.bindBufferMemory(vkDevice, *indexBuffer, indexAlloc->getMemory(), indexAlloc->getOffset()));
1099
1100         deMemcpy(indexAlloc->getHostPtr(), &(m_data.indexes[0]), bufferSize);
1101
1102         vk::flushMappedMemoryRange(m_vk, vkDevice, indexAlloc->getMemory(), indexAlloc->getOffset(), bufferSize);
1103
1104         m_vk.cmdBindIndexBuffer(*m_cmdBuffer, *indexBuffer, 0u, m_data.indexType);
1105
1106         // If multiDrawIndirect not supported execute single calls
1107         if (m_data.commands.size() > 1 && !(features.multiDrawIndirect))
1108         {
1109                 for (deUint32 cmdIdx = 0; cmdIdx < m_data.commands.size(); ++cmdIdx)
1110                 {
1111                         const deUint32  offset  = (deUint32)(indirectAlloc->getOffset() + cmdIdx * sizeof(vk::VkDrawIndexedIndirectCommand));
1112                         m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, *indirectBuffer, offset, 1, sizeof(vk::VkDrawIndexedIndirectCommand));
1113                 }
1114         }
1115         else
1116         {
1117                 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, *indirectBuffer, indirectAlloc->getOffset(), (deUint32)m_data.commands.size(), sizeof(vk::VkDrawIndexedIndirectCommand));
1118         }
1119
1120         m_vk.cmdEndRenderPass(*m_cmdBuffer);
1121         m_vk.endCommandBuffer(*m_cmdBuffer);
1122
1123         vk::VkSubmitInfo        submitInfo =
1124         {
1125                 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,                      // VkStructureType                      sType;
1126                 DE_NULL,                                                                        // const void*                          pNext;
1127                 0,                                                                                      // deUint32                                     waitSemaphoreCount;
1128                 DE_NULL,                                                                        // const VkSemaphore*           pWaitSemaphores;
1129                 (const vk::VkPipelineStageFlags*)DE_NULL,
1130                 1,                                                                                      // deUint32                                     commandBufferCount;
1131                 &m_cmdBuffer.get(),                                                     // const VkCommandBuffer*       pCommandBuffers;
1132                 0,                                                                                      // deUint32                                     signalSemaphoreCount;
1133                 DE_NULL                                                                         // const VkSemaphore*           pSignalSemaphores;
1134         };
1135         VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
1136
1137         // Validation
1138         tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
1139         tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1140
1141         for (std::vector<vk::VkDrawIndexedIndirectCommand>::const_iterator cmd = m_data.commands.begin(); cmd != m_data.commands.end(); ++cmd)
1142         {
1143                 std::vector<tcu::Vec4>  vertices;
1144                 std::vector<tcu::Vec4>  colors;
1145
1146                 for (deUint32 idx = 0; idx < cmd->indexCount; ++idx)
1147                 {
1148                         const deUint32 vertexIndex = cmd->vertexOffset + m_data.indexes[cmd->firstIndex + idx];
1149                         vertices.push_back(m_data.vertices[vertexIndex].position);
1150                         colors.push_back(m_data.vertices[vertexIndex].color);
1151                 }
1152                 generateRefImage(refImage.getAccess(), vertices, colors);
1153         }
1154
1155         VK_CHECK(m_vk.queueWaitIdle(queue));
1156
1157         const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
1158         const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
1159                 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1160
1161         qpTestResult res = QP_TEST_RESULT_PASS;
1162
1163         if (!imageCompare(log, refImage.getAccess(), renderedFrame, m_data.topology))
1164                 res = QP_TEST_RESULT_FAIL;
1165
1166         return tcu::TestStatus(res, qpGetTestResultName(res));
1167 }
1168
1169 typedef DrawTestCase<DrawParams>                                DrawCase;
1170 typedef DrawTestCase<DrawIndexedParams>                 IndexedCase;
1171 typedef DrawTestCase<DrawIndirectParams>                IndirectCase;
1172 typedef DrawTestCase<DrawIndexedIndirectParams> IndexedIndirectCase;
1173
1174 struct TestCaseParams
1175 {
1176         const DrawCommandType                   command;
1177         const vk::VkPrimitiveTopology   topology;
1178
1179         TestCaseParams (const DrawCommandType cmd, const vk::VkPrimitiveTopology top)
1180                 : command       (cmd)
1181                 , topology      (top)
1182         {}
1183 };
1184
1185 }       // anonymous
1186
1187 void populateSubGroup (tcu::TestCaseGroup* testGroup, const TestCaseParams caseParams)
1188 {
1189         de::Random                                              rnd                     (SEED ^ deStringHash(testGroup->getName()));
1190         tcu::TestContext&                               testCtx         = testGroup->getTestContext();
1191         const DrawCommandType                   command         = caseParams.command;
1192         const vk::VkPrimitiveTopology   topology        = caseParams.topology;
1193
1194         for (deUint32 primitiveCountIdx = 0; primitiveCountIdx < DE_LENGTH_OF_ARRAY(PRIMITIVE_COUNT); ++primitiveCountIdx)
1195         {
1196                 const deUint32 primitives = PRIMITIVE_COUNT[primitiveCountIdx];
1197
1198                 deUint32        multiplier      = 1;
1199                 deUint32        offset          = 0;
1200                 // Calculated by Vulkan 23.1
1201                 switch (topology)
1202                 {
1203                         case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:                                                                                                      break;
1204                         case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:                                               multiplier = 2;                         break;
1205                         case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:                                                                                                      break;
1206                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:                                   multiplier = 3;                         break;
1207                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:                                                                                          break;
1208                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:                                                                    offset = 1;     break;
1209                         case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:                multiplier = 4; offset = 1;     break;
1210                         case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:                                               offset = 1;     break;
1211                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:    multiplier = 6;                         break;
1212                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:   multiplier = 2;                         break;
1213                         default:                                                                                                                DE_FATAL("Unsupported topology.");
1214                 }
1215
1216                 const deUint32  vertexCount             = multiplier * primitives + offset;
1217                 std::string             name                    = de::toString(primitives);
1218
1219                 switch (command)
1220                 {
1221                         case DRAW_COMMAND_TYPE_DRAW:
1222                         {
1223                                 deUint32        firstPrimitive  = rnd.getInt(0, primitives);
1224                                 deUint32        firstVertex             = multiplier * firstPrimitive;
1225                                 testGroup->addChild(new DrawCase(testCtx, name.c_str(), "vkCmdDraw testcase.",
1226                                         DrawParams(topology, vertexCount, 1, firstVertex, 0))
1227                                 );
1228                                 break;
1229                         }
1230                         case DRAW_COMMAND_TYPE_DRAW_INDEXED:
1231                         {
1232                                 deUint32        firstIndex                      = rnd.getInt(0, OFFSET_LIMIT);
1233                                 deUint32        vertexOffset            = rnd.getInt(0, OFFSET_LIMIT);
1234                                 testGroup->addChild(new IndexedCase(testCtx, name.c_str(), "vkCmdDrawIndexed testcase.",
1235                                         DrawIndexedParams(topology, vk::VK_INDEX_TYPE_UINT32, vertexCount, 1, firstIndex, vertexOffset, 0))
1236                                 );
1237                                 break;
1238                         }
1239                         case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
1240                         {
1241                                 deUint32        firstVertex             = rnd.getInt(0, OFFSET_LIMIT);
1242
1243                                 DrawIndirectParams      params  = DrawIndirectParams(topology);
1244
1245                                 params.addCommand(vertexCount, 1, 0, 0);
1246                                 testGroup->addChild(new IndirectCase(testCtx, (name + "_single_command").c_str(), "vkCmdDrawIndirect testcase.", params));
1247
1248                                 params.addCommand(vertexCount, 1, firstVertex, 0);
1249                                 testGroup->addChild(new IndirectCase(testCtx, (name + "_multi_command").c_str(), "vkCmdDrawIndirect testcase.", params));
1250                                 break;
1251                         }
1252                         case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
1253                         {
1254                                 deUint32        firstIndex              = rnd.getInt(vertexCount, OFFSET_LIMIT);
1255                                 deUint32        vertexOffset    = rnd.getInt(vertexCount, OFFSET_LIMIT);
1256
1257                                 DrawIndexedIndirectParams       params  = DrawIndexedIndirectParams(topology, vk::VK_INDEX_TYPE_UINT32);
1258                                 params.addCommand(vertexCount, 1, 0, 0, 0);
1259                                 testGroup->addChild(new IndexedIndirectCase(testCtx, (name + "_single_command").c_str(), "vkCmdDrawIndexedIndirect testcase.", params));
1260
1261                                 params.addCommand(vertexCount, 1, firstIndex, vertexOffset, 0);
1262                                 testGroup->addChild(new IndexedIndirectCase(testCtx, (name + "_multi_command").c_str(), "vkCmdDrawIndexedIndirect testcase.", params));
1263                                 break;
1264                         }
1265                         default:
1266                                 DE_FATAL("Unsupported draw command.");
1267                 }
1268         }
1269 }
1270
1271 void createTopologyGroups (tcu::TestCaseGroup* testGroup, const DrawCommandType cmdType)
1272 {
1273         for (deUint32 idx = 0; idx != vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; ++idx)
1274         {
1275                 const vk::VkPrimitiveTopology   topology        = vk::VkPrimitiveTopology(idx);
1276                 const std::string                               groupName       = de::toLower(getPrimitiveTopologyName(topology)).substr(22);
1277                 addTestGroup(testGroup, groupName, "Testcases with a specific topology.", populateSubGroup, TestCaseParams(cmdType, topology));
1278         }
1279 }
1280
1281 void createDrawTests (tcu::TestCaseGroup* testGroup)
1282 {
1283         for (deUint32 idx = 0; idx < DRAW_COMMAND_TYPE_DRAW_LAST; ++idx)
1284         {
1285                 const DrawCommandType   command = DrawCommandType(idx);
1286                 addTestGroup(testGroup, getDrawCommandTypeName(command), "Group for testing a specific draw command.", createTopologyGroups, command);
1287         }
1288 }
1289
1290 tcu::TestCaseGroup*     createBasicDrawTests (tcu::TestContext& testCtx)
1291 {
1292         return createTestGroup(testCtx, "basic_draw", "Basic drawing tests", createDrawTests);
1293 }
1294
1295 }       // DrawTests
1296 }       // vkt