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