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