Add tests for indexed indirect draw calls and VertexIndex semantics
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / draw / vktDrawIndirectTest.cpp
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Intel Corporation
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 Draw Indirect Test
23  *//*--------------------------------------------------------------------*/
24
25 #include "vktDrawIndirectTest.hpp"
26
27 #include "vktTestCaseUtil.hpp"
28 #include "vktDrawTestCaseUtil.hpp"
29
30 #include "vktDrawBaseClass.hpp"
31
32 #include "tcuTestLog.hpp"
33 #include "tcuResource.hpp"
34 #include "tcuImageCompare.hpp"
35 #include "tcuTextureUtil.hpp"
36 #include "tcuRGBA.hpp"
37
38 #include "vkDefs.hpp"
39
40 namespace vkt
41 {
42 namespace Draw
43 {
44 namespace
45 {
46
47 enum
48 {
49         VERTEX_OFFSET = 13
50 };
51
52 struct JunkData
53 {
54         JunkData()
55                 : varA  (0xcd)
56                 , varB  (0xcd)
57         {
58         }
59         const deUint16  varA;
60         const deUint32  varB;
61 };
62
63 enum DrawType
64 {
65         DRAW_TYPE_SEQUENTIAL,
66         DRAW_TYPE_INDEXED,
67
68         DRAWTYPE_LAST
69 };
70
71 struct DrawTypedTestSpec : public TestSpecBase
72 {
73         DrawType drawType;
74 };
75
76 class IndirectDraw : public DrawTestsBaseClass
77 {
78 public:
79         typedef DrawTypedTestSpec       TestSpec;
80
81                                                                 IndirectDraw    (Context &context, TestSpec testSpec);
82         virtual tcu::TestStatus         iterate                 (void);
83
84         template<typename T> void       addCommand              (const T&);
85
86 protected:
87         std::vector<char>               m_indirectBufferContents;
88         de::SharedPtr<Buffer>           m_indirectBuffer;
89         vk::VkDeviceSize                m_offsetInBuffer;
90         deUint32                        m_strideInBuffer;
91
92         deUint32                        m_drawCount;
93         JunkData                        m_junkData;
94
95         const DrawType                  m_drawType;
96         deBool                          m_isMultiDrawEnabled;
97         deUint32                        m_drawIndirectMaxCount;
98
99         de::SharedPtr<Buffer>           m_indexBuffer;
100 };
101
102 struct FirtsInstanceSupported
103 {
104         static deUint32 getFirstInstance        (void)                                                                                  { return 2; }
105         static bool             isTestSupported         (const vk::VkPhysicalDeviceFeatures& features)  { return features.drawIndirectFirstInstance == VK_TRUE; }
106 };
107
108 struct FirtsInstanceNotSupported
109 {
110         static deUint32 getFirstInstance        (void)                                                                                  { return 0; }
111         static bool             isTestSupported         (const vk::VkPhysicalDeviceFeatures&)                   { return true; }
112 };
113
114 template<class FirstInstanceSupport>
115 class IndirectDrawInstanced : public IndirectDraw
116 {
117 public:
118                                                                 IndirectDrawInstanced   (Context &context, TestSpec testSpec);
119         virtual tcu::TestStatus         iterate                                 (void);
120 };
121
122 IndirectDraw::IndirectDraw (Context &context, TestSpec testSpec)
123         : DrawTestsBaseClass    (context, testSpec.shaders[glu::SHADERTYPE_VERTEX], testSpec.shaders[glu::SHADERTYPE_FRAGMENT], testSpec.topology)
124         , m_drawType                    (testSpec.drawType)
125 {
126
127         int refVertexIndex = 2;
128
129         if (testSpec.drawType == DRAW_TYPE_INDEXED)
130         {
131                 for (int unusedIdx = 0; unusedIdx < VERTEX_OFFSET; unusedIdx++)
132                 {
133                         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
134                 }
135                 refVertexIndex += VERTEX_OFFSET;
136         }
137
138         m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
139         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
140
141         switch (m_topology)
142         {
143                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
144                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,     -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
145                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
146                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
147                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
148                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
149                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
150                         break;
151                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
152                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
153                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
154                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,     -0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
155                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
156                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
157                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
158                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
159                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
160                         break;
161                 default:
162                         DE_FATAL("Unknown topology");
163                         break;
164         }
165
166         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
167
168         initialize();
169
170         if (testSpec.drawType == DRAW_TYPE_INDEXED)
171         {
172                 const size_t indexBufferLength = m_data.size() - VERTEX_OFFSET;
173
174                 m_indexBuffer = Buffer::createAndAlloc(m_vk, m_context.getDevice(), BufferCreateInfo(sizeof(deUint32) * indexBufferLength, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT), m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
175                 deUint32* indices = reinterpret_cast<deUint32*>(m_indexBuffer->getBoundMemory().getHostPtr());
176                 for (size_t i = 0; i < indexBufferLength; i++)
177                 {
178                         indices[i] = static_cast<deUint32>(i);
179                 }
180                 vk::flushMappedMemoryRange(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory().getMemory(), m_indexBuffer->getBoundMemory().getOffset(), sizeof(deUint32) * indexBufferLength);
181         }
182
183         // Check device for multidraw support:
184         if (m_context.getDeviceFeatures().multiDrawIndirect)
185                 m_isMultiDrawEnabled = true;
186         else
187                 m_isMultiDrawEnabled = false;
188
189         m_drawIndirectMaxCount = m_context.getDeviceProperties().limits.maxDrawIndirectCount;
190
191 }
192
193 template<>
194 void IndirectDraw::addCommand<vk::VkDrawIndirectCommand> (const vk::VkDrawIndirectCommand& command)
195 {
196         DE_ASSERT(m_drawType == DRAW_TYPE_SEQUENTIAL);
197
198         const size_t currentSize = m_indirectBufferContents.size();
199
200         m_indirectBufferContents.resize(currentSize + sizeof(command));
201
202         deMemcpy(&m_indirectBufferContents[currentSize], &command, sizeof(command));
203 }
204
205 template<>
206 void IndirectDraw::addCommand<vk::VkDrawIndexedIndirectCommand>(const vk::VkDrawIndexedIndirectCommand& command)
207 {
208         DE_ASSERT(m_drawType == DRAW_TYPE_INDEXED);
209
210         const size_t currentSize = m_indirectBufferContents.size();
211
212         m_indirectBufferContents.resize(currentSize + sizeof(command));
213
214         deMemcpy(&m_indirectBufferContents[currentSize], &command, sizeof(command));
215 }
216
217 tcu::TestStatus IndirectDraw::iterate (void)
218 {
219         tcu::TestLog &log = m_context.getTestContext().getLog();
220         const vk::VkQueue queue = m_context.getUniversalQueue();
221
222         if (m_drawType == DRAW_TYPE_SEQUENTIAL)
223         {
224                 switch (m_topology)
225                 {
226                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
227                 {
228                         vk::VkDrawIndirectCommand drawCommands[] =
229                         {
230                                 {
231                                         3,              //vertexCount
232                                         1,              //instanceCount
233                                         2,              //firstVertex
234                                         0               //firstInstance
235                                 },
236                                 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
237                                 {
238                                         3,              //vertexCount
239                                         1,              //instanceCount
240                                         5,              //firstVertex
241                                         0               //firstInstance
242                                 }
243                         };
244                         addCommand(drawCommands[0]);
245                         addCommand(drawCommands[1]);
246                         addCommand(drawCommands[2]);
247                         break;
248                 }
249                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
250                 {
251                         vk::VkDrawIndirectCommand drawCommands[] =
252                         {
253                                 {
254                                         4,              //vertexCount
255                                         1,              //instanceCount
256                                         2,              //firstVertex
257                                         0               //firstInstance
258                                 },
259                                 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
260                                 {
261                                         4,              //vertexCount
262                                         1,              //instanceCount
263                                         6,              //firstVertex
264                                         0               //firstInstance
265                                 }
266                         };
267                         addCommand(drawCommands[0]);
268                         addCommand(drawCommands[1]);
269                         addCommand(drawCommands[2]);
270                         break;
271                 }
272                 default:
273                         TCU_FAIL("impossible");
274                 }
275
276                 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndirectCommand);
277         }
278         else if (m_drawType == DRAW_TYPE_INDEXED)
279         {
280                 switch (m_topology)
281                 {
282                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
283                 {
284                         vk::VkDrawIndexedIndirectCommand drawCommands[] =
285                         {
286                                 {
287                                         3,                                      // indexCount
288                                         1,                                      // instanceCount
289                                         2,                                      // firstIndex
290                                         VERTEX_OFFSET,          // vertexOffset
291                                         0,                                      // firstInstance
292                                 },
293                                 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride)
294                                 {
295                                         3,                                      // indexCount
296                                         1,                                      // instanceCount
297                                         5,                                      // firstIndex
298                                         VERTEX_OFFSET,          // vertexOffset
299                                         0,                                      // firstInstance
300                                 }
301                         };
302                         addCommand(drawCommands[0]);
303                         addCommand(drawCommands[1]);
304                         addCommand(drawCommands[2]);
305                         break;
306                 }
307                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
308                 {
309                         vk::VkDrawIndexedIndirectCommand drawCommands[] =
310                         {
311                                 {
312                                         4,                              // indexCount
313                                         1,                              // instanceCount
314                                         2,                              // firstIndex
315                                         VERTEX_OFFSET,  // vertexOffset
316                                         0,                              // firstInstance
317                                 },
318                                 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride)
319                                 {
320                                         4,                              // indexCount
321                                         1,                              // instanceCount
322                                         6,                              // firstIndex
323                                         VERTEX_OFFSET,  // vertexOffset
324                                         0,                              // firstInstance
325                                 }
326                         };
327                         addCommand(drawCommands[0]);
328                         addCommand(drawCommands[1]);
329                         addCommand(drawCommands[2]);
330                         break;
331                 }
332                 default:
333                         TCU_FAIL("impossible");
334                 }
335
336                 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndexedIndirectCommand);
337         }
338
339         m_drawCount                     = 2;
340         m_offsetInBuffer        = sizeof(m_junkData);
341
342         beginRenderPass();
343
344         const vk::VkDeviceSize vertexBufferOffset       = 0;
345         const vk::VkBuffer vertexBuffer                         = m_vertexBuffer->object();
346
347         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
348
349         const vk::VkDeviceSize dataSize = m_indirectBufferContents.size();
350
351         m_indirectBuffer = Buffer::createAndAlloc(      m_vk,
352                                                                                                 m_context.getDevice(),
353                                                                                                 BufferCreateInfo(dataSize + m_offsetInBuffer,
354                                                                                                                                  vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
355                                                                                                 m_context.getDefaultAllocator(),
356                                                                                                 vk::MemoryRequirement::HostVisible);
357
358         deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
359
360         deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer));
361         deMemcpy(ptr + m_offsetInBuffer, &m_indirectBufferContents[0], static_cast<size_t>(dataSize));
362
363         vk::flushMappedMemoryRange(m_vk,
364                                                            m_context.getDevice(),
365                                                            m_indirectBuffer->getBoundMemory().getMemory(),
366                                                            m_indirectBuffer->getBoundMemory().getOffset(),
367                                                            dataSize);
368
369         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
370
371         if (m_drawType == DRAW_TYPE_INDEXED)
372         {
373                 m_vk.cmdBindIndexBuffer(*m_cmdBuffer, m_indexBuffer->object(), DE_NULL, vk::VK_INDEX_TYPE_UINT32);
374         }
375
376         if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
377         {
378                 switch (m_drawType)
379                 {
380                         case DRAW_TYPE_SEQUENTIAL:
381                                 m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
382                                 break;
383                         case DRAW_TYPE_INDEXED:
384                                 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
385                                 break;
386                         default:
387                                 TCU_FAIL("impossible");
388                 }
389         }
390         else
391         {
392                 for (deUint32 drawNdx = 0; drawNdx < m_drawCount; drawNdx++)
393                 {
394                         switch (m_drawType)
395                         {
396                                 case DRAW_TYPE_SEQUENTIAL:
397                                         m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
398                                         break;
399                                 case DRAW_TYPE_INDEXED:
400                                         m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
401                                         break;
402                                 default:
403                                         TCU_FAIL("impossible");
404                         }
405                 }
406         }
407         m_vk.cmdEndRenderPass(*m_cmdBuffer);
408         m_vk.endCommandBuffer(*m_cmdBuffer);
409
410         vk::VkSubmitInfo submitInfo =
411         {
412                 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,      // VkStructureType                      sType;
413                 DE_NULL,                                                        // const void*                          pNext;
414                 0,                                                                              // deUint32                                     waitSemaphoreCount;
415                 DE_NULL,                                                                // const VkSemaphore*           pWaitSemaphores;
416                 (const vk::VkPipelineStageFlags*)DE_NULL,
417                 1,                                                                              // deUint32                                     commandBufferCount;
418                 &m_cmdBuffer.get(),                                     // const VkCommandBuffer*       pCommandBuffers;
419                 0,                                                                              // deUint32                                     signalSemaphoreCount;
420                 DE_NULL                                                         // const VkSemaphore*           pSignalSemaphores;
421         };
422         VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
423
424         VK_CHECK(m_vk.queueWaitIdle(queue));
425
426         // Validation
427         tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
428         referenceFrame.allocLevel(0);
429
430         const deInt32 frameWidth        = referenceFrame.getWidth();
431         const deInt32 frameHeight       = referenceFrame.getHeight();
432
433         tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
434
435         ReferenceImageCoordinates refCoords;
436
437         for (int y = 0; y < frameHeight; y++)
438         {
439                 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
440
441                 for (int x = 0; x < frameWidth; x++)
442                 {
443                         const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
444
445                         if ((yCoord >= refCoords.bottom &&
446                                  yCoord <= refCoords.top        &&
447                                  xCoord >= refCoords.left       &&
448                                  xCoord <= refCoords.right))
449                                 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
450                 }
451         }
452
453         const vk::VkOffset3D zeroOffset                                 = { 0, 0, 0 };
454         const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
455                 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
456
457         qpTestResult res = QP_TEST_RESULT_PASS;
458
459         if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
460                 referenceFrame.getLevel(0), renderedFrame, 0.05f,
461                 tcu::COMPARE_LOG_RESULT)) {
462                 res = QP_TEST_RESULT_FAIL;
463         }
464
465         return tcu::TestStatus(res, qpGetTestResultName(res));
466
467 }
468
469 template<class FirstInstanceSupport>
470 IndirectDrawInstanced<FirstInstanceSupport>::IndirectDrawInstanced (Context &context, TestSpec testSpec)
471         : IndirectDraw(context, testSpec)
472 {
473         if (!FirstInstanceSupport::isTestSupported(m_context.getDeviceFeatures()))
474         {
475                 throw tcu::NotSupportedError("Required 'drawIndirectFirstInstance' feature is not supported");
476         }
477 }
478
479 template<class FirstInstanceSupport>
480 tcu::TestStatus IndirectDrawInstanced<FirstInstanceSupport>::iterate (void)
481 {
482         tcu::TestLog &log = m_context.getTestContext().getLog();
483         const vk::VkQueue queue = m_context.getUniversalQueue();
484
485         if (m_drawType == DRAW_TYPE_SEQUENTIAL)
486         {
487                 switch (m_topology)
488                 {
489                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
490                         {
491                                 vk::VkDrawIndirectCommand drawCmd[] =
492                                 {
493                                         {
494                                                 3,                                                                                      //vertexCount
495                                                 4,                                                                                      //instanceCount
496                                                 2,                                                                                      //firstVertex
497                                                 FirstInstanceSupport::getFirstInstance()        //firstInstance
498                                         },
499                                         { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
500                                         {
501                                                 3,                                                                                      //vertexCount
502                                                 4,                                                                                      //instanceCount
503                                                 5,                                                                                      //firstVertex
504                                                 FirstInstanceSupport::getFirstInstance()        //firstInstance
505                                         }
506                                 };
507                                 addCommand(drawCmd[0]);
508                                 addCommand(drawCmd[1]);
509                                 addCommand(drawCmd[2]);
510                                 break;
511                         }
512                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
513                         {
514                                 vk::VkDrawIndirectCommand drawCmd[] =
515                                 {
516                                         {
517                                                 4,                                                                                      //vertexCount
518                                                 4,                                                                                      //instanceCount
519                                                 2,                                                                                      //firstVertex
520                                                 FirstInstanceSupport::getFirstInstance()        //firstInstance
521                                         },
522                                         { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 },
523                                         {
524                                                 4,                                                                                      //vertexCount
525                                                 4,                                                                                      //instanceCount
526                                                 6,                                                                                      //firstVertex
527                                                 FirstInstanceSupport::getFirstInstance()        //firstInstance
528                                         }
529                                 };
530                                 addCommand(drawCmd[0]);
531                                 addCommand(drawCmd[1]);
532                                 addCommand(drawCmd[2]);
533                                 break;
534                         }
535                         default:
536                                 TCU_FAIL("impossible");
537                                 break;
538                 }
539
540                 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndirectCommand);
541         }
542         else if (m_drawType == DRAW_TYPE_INDEXED)
543         {
544                 switch (m_topology)
545                 {
546                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
547                         {
548                                 vk::VkDrawIndexedIndirectCommand drawCmd[] =
549                                 {
550                                         {
551                                                 3,                                                                                      // indexCount
552                                                 4,                                                                                      // instanceCount
553                                                 2,                                                                                      // firstIndex
554                                                 VERTEX_OFFSET,                                                          // vertexOffset
555                                                 FirstInstanceSupport::getFirstInstance()        // firstInstance
556                                         },
557                                         { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 },        // junk (stride)
558                                         {
559                                                 3,                                                                                      // indexCount
560                                                 4,                                                                                      // instanceCount
561                                                 5,                                                                                      // firstIndex
562                                                 VERTEX_OFFSET,                                                          // vertexOffset
563                                                 FirstInstanceSupport::getFirstInstance()        // firstInstance
564                                         }
565                                 };
566                                 addCommand(drawCmd[0]);
567                                 addCommand(drawCmd[1]);
568                                 addCommand(drawCmd[2]);
569                                 break;
570                         }
571                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
572                         {
573                                 vk::VkDrawIndexedIndirectCommand drawCmd[] =
574                                 {
575                                         {
576                                                 4,                                                                                      // indexCount
577                                                 4,                                                                                      // instanceCount
578                                                 2,                                                                                      // firstIndex
579                                                 VERTEX_OFFSET,                                                          // vertexOffset
580                                                 FirstInstanceSupport::getFirstInstance()        // firstInstance
581                                         },
582                                         { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 },        // junk (stride)
583                                         {
584                                                 4,                                                                                      // indexCount
585                                                 4,                                                                                      // instanceCount
586                                                 6,                                                                                      // firstIndex
587                                                 VERTEX_OFFSET,                                                          // vertexOffset
588                                                 FirstInstanceSupport::getFirstInstance()        // firstInstance
589                                         }
590                                 };
591                                 addCommand(drawCmd[0]);
592                                 addCommand(drawCmd[1]);
593                                 addCommand(drawCmd[2]);
594                                 break;
595                         }
596                         default:
597                                 TCU_FAIL("impossible");
598                                 break;
599                 }
600
601                 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndexedIndirectCommand);
602         }
603
604         m_drawCount                     = 2;
605         m_offsetInBuffer        = sizeof(m_junkData);
606
607         beginRenderPass();
608
609         const vk::VkDeviceSize vertexBufferOffset = 0;
610         const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
611
612         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
613
614         const vk::VkDeviceSize dataSize = m_indirectBufferContents.size();
615
616         m_indirectBuffer = Buffer::createAndAlloc(      m_vk,
617                                                                                                 m_context.getDevice(),
618                                                                                                 BufferCreateInfo(dataSize + m_offsetInBuffer,
619                                                                                                                                  vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
620                                                                                                 m_context.getDefaultAllocator(),
621                                                                                                 vk::MemoryRequirement::HostVisible);
622
623         deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
624
625         deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer));
626         deMemcpy((ptr + m_offsetInBuffer), &m_indirectBufferContents[0], static_cast<size_t>(dataSize));
627
628         vk::flushMappedMemoryRange(m_vk,
629                                                            m_context.getDevice(),
630                                                            m_indirectBuffer->getBoundMemory().getMemory(),
631                                                            m_indirectBuffer->getBoundMemory().getOffset(),
632                                                            dataSize);
633
634         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
635
636         if (m_drawType == DRAW_TYPE_INDEXED)
637         {
638                 m_vk.cmdBindIndexBuffer(*m_cmdBuffer, m_indexBuffer->object(), DE_NULL, vk::VK_INDEX_TYPE_UINT32);
639         }
640
641         if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
642         {
643                 switch (m_drawType)
644                 {
645                         case DRAW_TYPE_SEQUENTIAL:
646                                 m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
647                                 break;
648                         case DRAW_TYPE_INDEXED:
649                                 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
650                                 break;
651                         default:
652                                 TCU_FAIL("impossible");
653                 }
654         }
655         else
656         {
657                 for (deUint32 drawNdx = 0; drawNdx < m_drawCount; drawNdx++)
658                 {
659                         switch (m_drawType)
660                         {
661                                 case DRAW_TYPE_SEQUENTIAL:
662                                         m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
663                                         break;
664                                 case DRAW_TYPE_INDEXED:
665                                         m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
666                                         break;
667                                 default:
668                                         TCU_FAIL("impossible");
669                         }
670                 }
671         }
672         m_vk.cmdEndRenderPass(*m_cmdBuffer);
673         m_vk.endCommandBuffer(*m_cmdBuffer);
674
675         vk::VkSubmitInfo submitInfo =
676         {
677                 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,      // VkStructureType                      sType;
678                 DE_NULL,                                                        // const void*                          pNext;
679                 0,                                                                              // deUint32                                     waitSemaphoreCount;
680                 DE_NULL,                                                                // const VkSemaphore*           pWaitSemaphores;
681                 (const vk::VkPipelineStageFlags*)DE_NULL,
682                 1,                                                                              // deUint32                                     commandBufferCount;
683                 &m_cmdBuffer.get(),                                     // const VkCommandBuffer*       pCommandBuffers;
684                 0,                                                                              // deUint32                                     signalSemaphoreCount;
685                 DE_NULL                                                         // const VkSemaphore*           pSignalSemaphores;
686         };
687         VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
688
689         VK_CHECK(m_vk.queueWaitIdle(queue));
690
691         // Validation
692         VK_CHECK(m_vk.queueWaitIdle(queue));
693
694         tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
695
696         referenceFrame.allocLevel(0);
697
698         const deInt32 frameWidth        = referenceFrame.getWidth();
699         const deInt32 frameHeight       = referenceFrame.getHeight();
700
701         tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
702
703         ReferenceImageInstancedCoordinates refInstancedCoords;
704
705         for (int y = 0; y < frameHeight; y++)
706         {
707                 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
708
709                 for (int x = 0; x < frameWidth; x++)
710                 {
711                         const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
712
713                         if ((yCoord >= refInstancedCoords.bottom        &&
714                                  yCoord <= refInstancedCoords.top               &&
715                                  xCoord >= refInstancedCoords.left              &&
716                                  xCoord <= refInstancedCoords.right))
717                                 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
718                 }
719         }
720
721         const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
722         const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
723                 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
724
725         qpTestResult res = QP_TEST_RESULT_PASS;
726
727         if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
728                 referenceFrame.getLevel(0), renderedFrame, 0.05f,
729                 tcu::COMPARE_LOG_RESULT)) {
730                 res = QP_TEST_RESULT_FAIL;
731         }
732
733         return tcu::TestStatus(res, qpGetTestResultName(res));
734
735         }
736
737 }       // anonymous
738
739 IndirectDrawTests::IndirectDrawTests (tcu::TestContext& testCtx)
740         : TestCaseGroup(testCtx, "indirect_draw", "indirect drawing simple geometry")
741 {
742         /* Left blank on purpose */
743 }
744
745 IndirectDrawTests::~IndirectDrawTests (void) {}
746
747
748 void IndirectDrawTests::init (void)
749 {
750         for (int drawTypeIdx = 0; drawTypeIdx < DRAWTYPE_LAST; drawTypeIdx++)
751         {
752                 std::string drawTypeStr;
753                 switch (drawTypeIdx)
754                 {
755                         case DRAW_TYPE_SEQUENTIAL:
756                                 drawTypeStr = "sequential";
757                                 break;
758                         case DRAW_TYPE_INDEXED:
759                                 drawTypeStr = "indexed";
760                                 break;
761                         default:
762                                 TCU_FAIL("impossible");
763                 }
764
765                 tcu::TestCaseGroup* drawTypeGroup = new tcu::TestCaseGroup(m_testCtx, drawTypeStr.c_str(), ("Draws geometry using " + drawTypeStr + "draw call").c_str());
766                 {
767                         tcu::TestCaseGroup* indirectDrawGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw", "Draws geometry");
768                         {
769                                 IndirectDraw::TestSpec testSpec;
770                                 testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
771                                 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetch.vert";
772                                 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
773                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
774                                 indirectDrawGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_list", "Draws triangle list", testSpec));
775                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
776                                 indirectDrawGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec));
777                         }
778                         drawTypeGroup->addChild(indirectDrawGroup);
779
780
781                         tcu::TestCaseGroup* indirectDrawInstancedGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_instanced", "Draws an instanced geometry");
782                         {
783                                 tcu::TestCaseGroup*     noFirstInstanceGroup = new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance");
784                                 {
785                                         IndirectDrawInstanced<FirtsInstanceNotSupported>::TestSpec testSpec;
786                                         testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
787
788                                         testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstanced.vert";
789                                         testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
790
791                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
792                                         noFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirtsInstanceNotSupported> >(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec));
793                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
794                                         noFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirtsInstanceNotSupported> >(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec));
795                                 }
796                                 indirectDrawInstancedGroup->addChild(noFirstInstanceGroup);
797
798                                 tcu::TestCaseGroup*     firstInstanceGroup = new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature");
799                                 {
800                                         IndirectDrawInstanced<FirtsInstanceSupported>::TestSpec testSpec;
801                                         testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
802
803                                         testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstancedFirstInstance.vert";
804                                         testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
805
806                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
807                                         firstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirtsInstanceSupported> >(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec));
808                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
809                                         firstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirtsInstanceSupported> >(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec));
810                                 }
811                                 indirectDrawInstancedGroup->addChild(firstInstanceGroup);
812                         }
813                         drawTypeGroup->addChild(indirectDrawInstancedGroup);
814                 }
815
816                 addChild(drawTypeGroup);
817         }
818 }
819
820 }       // DrawTests
821 }       // vkt