Merge vk-gl-cts/opengl-es-cts-3.2.7 into vk-gl-cts/master
[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 #include "vkQueryUtil.hpp"
38
39 #include "vkDefs.hpp"
40 #include "vkCmdUtil.hpp"
41
42 namespace vkt
43 {
44 namespace Draw
45 {
46 namespace
47 {
48
49 enum
50 {
51         VERTEX_OFFSET = 13
52 };
53
54 struct JunkData
55 {
56         JunkData()
57                 : varA  (0xcd)
58                 , varB  (0xcd)
59         {
60         }
61         const deUint16  varA;
62         const deUint32  varB;
63 };
64
65 enum DrawType
66 {
67         DRAW_TYPE_SEQUENTIAL,
68         DRAW_TYPE_INDEXED,
69
70         DRAWTYPE_LAST
71 };
72
73 enum class IndirectCountType
74 {
75         NONE,
76         BUFFER_LIMIT,
77         PARAM_LIMIT,
78
79         LAST
80 };
81
82 struct DrawTypedTestSpec : public TestSpecBase
83 {
84         DrawTypedTestSpec()
85                 : drawType(DRAWTYPE_LAST)
86                 , testFirstInstanceNdx(false)
87                 , testIndirectCountExt(IndirectCountType::NONE)
88         {};
89
90         DrawType                        drawType;
91         bool                            testFirstInstanceNdx;
92         IndirectCountType       testIndirectCountExt;
93 };
94
95 class IndirectDraw : public DrawTestsBaseClass
96 {
97 public:
98         typedef DrawTypedTestSpec       TestSpec;
99
100                                                                 IndirectDraw    (Context &context, TestSpec testSpec);
101         virtual tcu::TestStatus         iterate                 (void);
102
103         template<typename T> void       addCommand              (const T&);
104
105 protected:
106         void                                            setVertexBuffer                                         (void);
107         void                                            setFirstInstanceVertexBuffer            (void);
108
109         std::vector<char>                       m_indirectBufferContents;
110         de::SharedPtr<Buffer>           m_indirectBuffer;
111         vk::VkDeviceSize                        m_offsetInBuffer;
112         deUint32                                        m_strideInBuffer;
113
114         const IndirectCountType         m_testIndirectCountExt;
115         de::SharedPtr<Buffer>           m_indirectCountBuffer;
116         vk::VkDeviceSize                        m_offsetInCountBuffer;
117         const deUint32                          m_indirectCountExtDrawPadding;
118
119         deUint32                                        m_drawCount;
120         JunkData                                        m_junkData;
121
122         const DrawType                          m_drawType;
123         const bool                                      m_testFirstInstanceNdx;
124         deBool                                          m_isMultiDrawEnabled;
125         deUint32                                        m_drawIndirectMaxCount;
126
127         de::SharedPtr<Buffer>           m_indexBuffer;
128 };
129
130 struct FirstInstanceSupported
131 {
132         static deUint32 getFirstInstance        (void)                                                                                  { return 2; }
133         static bool             isTestSupported         (const vk::VkPhysicalDeviceFeatures& features)  { return features.drawIndirectFirstInstance == VK_TRUE; }
134 };
135
136 struct FirstInstanceNotSupported
137 {
138         static deUint32 getFirstInstance        (void)                                                                                  { return 0; }
139         static bool             isTestSupported         (const vk::VkPhysicalDeviceFeatures&)                   { return true; }
140 };
141
142 template<class FirstInstanceSupport>
143 class IndirectDrawInstanced : public IndirectDraw
144 {
145 public:
146                                                                 IndirectDrawInstanced   (Context &context, TestSpec testSpec);
147         virtual tcu::TestStatus         iterate                                 (void);
148 };
149
150 void IndirectDraw::setVertexBuffer (void)
151 {
152         int refVertexIndex = 2;
153
154         if (m_drawType == DRAW_TYPE_INDEXED)
155         {
156                 for (int unusedIdx = 0; unusedIdx < VERTEX_OFFSET; unusedIdx++)
157                 {
158                         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
159                 }
160                 refVertexIndex += VERTEX_OFFSET;
161         }
162
163         m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
164         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
165
166         switch (m_topology)
167         {
168                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
169                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,     -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
170                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
171                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
172                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
173                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
174                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
175                         break;
176                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
177                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
178                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
179                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,     -0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
180                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
181                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
182                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
183                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
184                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
185                         break;
186                 default:
187                         DE_FATAL("Unknown topology");
188                         break;
189         }
190
191         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
192 }
193
194 void IndirectDraw::setFirstInstanceVertexBuffer (void)
195 {
196         if (m_context.getDeviceFeatures().drawIndirectFirstInstance != VK_TRUE)
197         {
198                 TCU_THROW(NotSupportedError, "Required 'drawIndirectFirstInstance' feature is not supported");
199         }
200
201         if (m_drawType == DRAW_TYPE_INDEXED)
202         {
203                 for (int unusedIdx = 0; unusedIdx < VERTEX_OFFSET; unusedIdx++)
204                 {
205                         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
206                 }
207         }
208
209         m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
210         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
211
212         switch (m_topology)
213         {
214                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
215                 {
216                         int refInstanceIndex = 1;
217                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,     -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
218                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
219                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
220
221                         refInstanceIndex = 0;
222                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
223                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
224                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
225                         break;
226                 }
227                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
228                 {
229                         int refInstanceIndex = 1;
230                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refInstanceIndex));
231                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refInstanceIndex));
232                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,     -0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refInstanceIndex));
233                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refInstanceIndex));
234
235                         refInstanceIndex = 0;
236                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refInstanceIndex));
237                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refInstanceIndex));
238                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refInstanceIndex));
239                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refInstanceIndex));
240                         break;
241                 }
242                 default:
243                         DE_FATAL("Unknown topology");
244                         break;
245         }
246
247         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
248 }
249
250 IndirectDraw::IndirectDraw (Context &context, TestSpec testSpec)
251         : DrawTestsBaseClass                            (context, testSpec.shaders[glu::SHADERTYPE_VERTEX], testSpec.shaders[glu::SHADERTYPE_FRAGMENT], testSpec.topology)
252         , m_testIndirectCountExt                        (testSpec.testIndirectCountExt)
253         , m_indirectCountExtDrawPadding         (1u)
254         , m_drawType                                            (testSpec.drawType)
255         , m_testFirstInstanceNdx                        (testSpec.testFirstInstanceNdx)
256 {
257         if (m_testFirstInstanceNdx)
258                 setFirstInstanceVertexBuffer();
259         else
260                 setVertexBuffer();
261
262         initialize();
263
264         if (testSpec.drawType == DRAW_TYPE_INDEXED)
265         {
266                 const size_t indexBufferLength = m_data.size() - VERTEX_OFFSET;
267
268                 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);
269                 deUint32* indices = reinterpret_cast<deUint32*>(m_indexBuffer->getBoundMemory().getHostPtr());
270                 for (size_t i = 0; i < indexBufferLength; i++)
271                 {
272                         indices[i] = static_cast<deUint32>(i);
273                 }
274                 vk::flushAlloc(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory());
275         }
276
277         // Check device for multidraw support:
278         if (!m_context.getDeviceFeatures().multiDrawIndirect || m_testFirstInstanceNdx)
279                 m_isMultiDrawEnabled = false;
280         else
281                 m_isMultiDrawEnabled = true;
282
283         m_drawIndirectMaxCount = m_context.getDeviceProperties().limits.maxDrawIndirectCount;
284 }
285
286 template<>
287 void IndirectDraw::addCommand<vk::VkDrawIndirectCommand> (const vk::VkDrawIndirectCommand& command)
288 {
289         DE_ASSERT(m_drawType == DRAW_TYPE_SEQUENTIAL);
290
291         const size_t currentSize = m_indirectBufferContents.size();
292
293         m_indirectBufferContents.resize(currentSize + sizeof(command));
294
295         deMemcpy(&m_indirectBufferContents[currentSize], &command, sizeof(command));
296 }
297
298 template<>
299 void IndirectDraw::addCommand<vk::VkDrawIndexedIndirectCommand> (const vk::VkDrawIndexedIndirectCommand& command)
300 {
301         DE_ASSERT(m_drawType == DRAW_TYPE_INDEXED);
302
303         const size_t currentSize = m_indirectBufferContents.size();
304
305         m_indirectBufferContents.resize(currentSize + sizeof(command));
306
307         deMemcpy(&m_indirectBufferContents[currentSize], &command, sizeof(command));
308 }
309
310 tcu::TestStatus IndirectDraw::iterate (void)
311 {
312         tcu::TestLog&           log             = m_context.getTestContext().getLog();
313         const vk::VkQueue       queue   = m_context.getUniversalQueue();
314         const vk::VkDevice      device  = m_context.getDevice();
315
316                                         m_drawCount                     = 2;
317                                         m_offsetInBuffer        = sizeof(m_junkData);
318         const deUint32  m_bufferDrawCount       = 2u * m_drawCount;
319
320         if (m_drawType == DRAW_TYPE_SEQUENTIAL)
321         {
322                 switch (m_topology)
323                 {
324                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
325                 {
326                         vk::VkDrawIndirectCommand drawCommands[] =
327                         {
328                                 {
329                                         3u,                                                                     //vertexCount
330                                         1u,                                                                     //instanceCount
331                                         2u,                                                                     //firstVertex
332                                         (m_testFirstInstanceNdx ? 1u : 0u)      //firstInstance
333                                 },
334                                 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
335                                 {
336                                         3u,                                                                     //vertexCount
337                                         1u,                                                                     //instanceCount
338                                         5u,                                                                     //firstVertex
339                                         0u                                                                      //firstInstance
340                                 }
341                         };
342                         addCommand(drawCommands[0]);
343                         addCommand(drawCommands[1]);
344                         addCommand(drawCommands[2]);
345                         addCommand(drawCommands[1]);
346                         if (m_testIndirectCountExt != IndirectCountType::NONE)
347                         {
348                                 // Add padding data to the buffer to make sure it's large enough.
349                                 for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
350                                 {
351                                         addCommand(drawCommands[1]);
352                                         addCommand(drawCommands[1]);
353                                 }
354                         }
355                         break;
356                 }
357                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
358                 {
359                         vk::VkDrawIndirectCommand drawCommands[] =
360                         {
361                                 {
362                                         4u,                                                                     //vertexCount
363                                         1u,                                                                     //instanceCount
364                                         2u,                                                                     //firstVertex
365                                         (m_testFirstInstanceNdx ? 1u : 0u)      //firstInstance
366                                 },
367                                 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
368                                 {
369                                         4u,                                                                     //vertexCount
370                                         1u,                                                                     //instanceCount
371                                         6u,                                                                     //firstVertex
372                                         0u                                                                      //firstInstance
373                                 }
374                         };
375                         addCommand(drawCommands[0]);
376                         addCommand(drawCommands[1]);
377                         addCommand(drawCommands[2]);
378                         addCommand(drawCommands[1]);
379                         if (m_testIndirectCountExt != IndirectCountType::NONE)
380                         {
381                                 // Add padding data to the buffer to make sure it's large enough.
382                                 for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
383                                 {
384                                         addCommand(drawCommands[1]);
385                                         addCommand(drawCommands[1]);
386                                 }
387                         }
388                         break;
389                 }
390                 default:
391                         TCU_FAIL("impossible");
392                 }
393
394                 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndirectCommand);
395         }
396         else if (m_drawType == DRAW_TYPE_INDEXED)
397         {
398                 switch (m_topology)
399                 {
400                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
401                 {
402                         vk::VkDrawIndexedIndirectCommand drawCommands[] =
403                         {
404                                 {
405                                         3u,                                                                     // indexCount
406                                         1u,                                                                     // instanceCount
407                                         2u,                                                                     // firstIndex
408                                         VERTEX_OFFSET,                                          // vertexOffset
409                                         (m_testFirstInstanceNdx ? 1u : 0u),     // firstInstance
410                                 },
411                                 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride)
412                                 {
413                                         3u,                                                                     // indexCount
414                                         1u,                                                                     // instanceCount
415                                         5u,                                                                     // firstIndex
416                                         VERTEX_OFFSET,                                          // vertexOffset
417                                         0u                                                                      // firstInstance
418                                 }
419                         };
420                         addCommand(drawCommands[0]);
421                         addCommand(drawCommands[1]);
422                         addCommand(drawCommands[2]);
423                         addCommand(drawCommands[1]);
424                         if (m_testIndirectCountExt != IndirectCountType::NONE)
425                         {
426                                 // Add padding data to the buffer to make sure it's large enough.
427                                 for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
428                                 {
429                                         addCommand(drawCommands[1]);
430                                         addCommand(drawCommands[1]);
431                                 }
432                         }
433                         break;
434                 }
435                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
436                 {
437                         vk::VkDrawIndexedIndirectCommand drawCommands[] =
438                         {
439                                 {
440                                         4u,                                                                     // indexCount
441                                         1u,                                                                     // instanceCount
442                                         2u,                                                                     // firstIndex
443                                         VERTEX_OFFSET,                                          // vertexOffset
444                                         (m_testFirstInstanceNdx ? 1u : 0u),     // firstInstance
445                                 },
446                                 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride)
447                                 {
448                                         4u,                                                                     // indexCount
449                                         1u,                                                                     // instanceCount
450                                         6u,                                                                     // firstIndex
451                                         VERTEX_OFFSET,                                          // vertexOffset
452                                         0u                                                                      // firstInstance
453                                 }
454                         };
455                         addCommand(drawCommands[0]);
456                         addCommand(drawCommands[1]);
457                         addCommand(drawCommands[2]);
458                         addCommand(drawCommands[1]);
459                         if (m_testIndirectCountExt != IndirectCountType::NONE)
460                         {
461                                 // Add padding data to the buffer to make sure it's large enough.
462                                 for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
463                                 {
464                                         addCommand(drawCommands[1]);
465                                         addCommand(drawCommands[1]);
466                                 }
467                         }
468                         break;
469                 }
470                 default:
471                         TCU_FAIL("impossible");
472                 }
473
474                 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndexedIndirectCommand);
475         }
476
477         beginRenderPass();
478
479         const vk::VkDeviceSize vertexBufferOffset       = 0;
480         const vk::VkBuffer vertexBuffer                         = m_vertexBuffer->object();
481
482         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
483
484         const vk::VkDeviceSize dataSize = m_indirectBufferContents.size();
485
486         m_indirectBuffer = Buffer::createAndAlloc(      m_vk,
487                                                                                                 m_context.getDevice(),
488                                                                                                 BufferCreateInfo(dataSize + m_offsetInBuffer,
489                                                                                                                                  vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
490                                                                                                 m_context.getDefaultAllocator(),
491                                                                                                 vk::MemoryRequirement::HostVisible);
492
493         deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
494
495         deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer));
496         deMemcpy(ptr + m_offsetInBuffer, &m_indirectBufferContents[0], static_cast<size_t>(dataSize));
497
498         vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
499
500         if (m_testIndirectCountExt != IndirectCountType::NONE)
501         {
502                 m_offsetInCountBuffer = sizeof(tcu::Vec3);
503                 m_indirectCountBuffer = Buffer::createAndAlloc(m_vk,
504                                                                                                            m_context.getDevice(),
505                                                                                                            BufferCreateInfo(m_offsetInCountBuffer + sizeof(m_drawCount),
506                                                                                                                                                 vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
507                                                                                                            m_context.getDefaultAllocator(),
508                                                                                                            vk::MemoryRequirement::HostVisible);
509
510                 deUint8* countBufferPtr = reinterpret_cast<deUint8*>(m_indirectCountBuffer->getBoundMemory().getHostPtr());
511
512                 // For IndirectCountType::PARAM_LIMIT, the real limit will be set using the call parameter.
513                 if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
514                         *(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? 0u : m_indirectCountExtDrawPadding);
515                 else
516                         *(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? 1u : m_drawCount + m_indirectCountExtDrawPadding);
517
518                 vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectCountBuffer->getBoundMemory());
519         }
520
521         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
522
523         if (m_drawType == DRAW_TYPE_INDEXED)
524         {
525                 m_vk.cmdBindIndexBuffer(*m_cmdBuffer, m_indexBuffer->object(), DE_NULL, vk::VK_INDEX_TYPE_UINT32);
526         }
527
528         if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
529         {
530                 switch (m_drawType)
531                 {
532                         case DRAW_TYPE_SEQUENTIAL:
533                         {
534                                 if (m_testIndirectCountExt != IndirectCountType::NONE)
535                                 {
536                                         const deUint32 maxDrawCount = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_indirectCountExtDrawPadding : 0u);
537                                         m_vk.cmdDrawIndirectCount(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer,
538                                                                                           m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
539                                                                                           m_strideInBuffer);
540                                 }
541                                 else
542                                         m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
543                                 break;
544                         }
545                         case DRAW_TYPE_INDEXED:
546                         {
547                                 if (m_testIndirectCountExt != IndirectCountType::NONE)
548                                 {
549                                         const deUint32 maxDrawCount = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_indirectCountExtDrawPadding : 0u);
550                                         m_vk.cmdDrawIndexedIndirectCount(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer,
551                                                                                                          m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
552                                                                                                          m_strideInBuffer);
553                                 }
554                                 else
555                                         m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
556                                 break;
557                         }
558                         default:
559                                 TCU_FAIL("impossible");
560                 }
561         }
562         else
563         {
564                 for (deUint32 drawNdx = 0; drawNdx < m_drawCount; drawNdx++)
565                 {
566                         switch (m_drawType)
567                         {
568                                 case DRAW_TYPE_SEQUENTIAL:
569                                 {
570                                         if (m_testIndirectCountExt != IndirectCountType::NONE)
571                                         {
572                                                 const deUint32 maxDrawCount = (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_drawCount + m_indirectCountExtDrawPadding : 1u);
573                                                 m_vk.cmdDrawIndirectCount(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer,
574                                                                                                   m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
575                                                                                                   m_strideInBuffer);
576                                         }
577                                         else
578                                                 m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
579                                         break;
580                                 }
581                                 case DRAW_TYPE_INDEXED:
582                                 {
583                                         if (m_testIndirectCountExt != IndirectCountType::NONE)
584                                         {
585                                                 const deUint32 maxDrawCount = (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_drawCount + m_indirectCountExtDrawPadding : 1u);
586                                                 m_vk.cmdDrawIndexedIndirectCount(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer,
587                                                                                                                  m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
588                                                                                                                  m_strideInBuffer);
589                                         }
590                                         else
591                                                 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
592                                         break;
593                                 }
594                                 default:
595                                         TCU_FAIL("impossible");
596                         }
597                 }
598         }
599         endRenderPass(m_vk, *m_cmdBuffer);
600         endCommandBuffer(m_vk, *m_cmdBuffer);
601
602         submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
603
604         // Validation
605         tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
606         referenceFrame.allocLevel(0);
607
608         const deInt32 frameWidth        = referenceFrame.getWidth();
609         const deInt32 frameHeight       = referenceFrame.getHeight();
610
611         tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
612
613         ReferenceImageCoordinates refCoords;
614
615         for (int y = 0; y < frameHeight; y++)
616         {
617                 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
618
619                 for (int x = 0; x < frameWidth; x++)
620                 {
621                         const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
622
623                         if ((yCoord >= refCoords.bottom &&
624                                  yCoord <= refCoords.top        &&
625                                  xCoord >= refCoords.left       &&
626                                  xCoord <= refCoords.right))
627                                 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
628                 }
629         }
630
631         const vk::VkOffset3D zeroOffset                                 = { 0, 0, 0 };
632         const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
633                 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
634
635         qpTestResult res = QP_TEST_RESULT_PASS;
636
637         if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
638                 referenceFrame.getLevel(0), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
639         {
640                 res = QP_TEST_RESULT_FAIL;
641         }
642
643         return tcu::TestStatus(res, qpGetTestResultName(res));
644 }
645
646 template<class FirstInstanceSupport>
647 IndirectDrawInstanced<FirstInstanceSupport>::IndirectDrawInstanced (Context &context, TestSpec testSpec)
648         : IndirectDraw(context, testSpec)
649 {
650         if (!FirstInstanceSupport::isTestSupported(m_context.getDeviceFeatures()))
651         {
652                 throw tcu::NotSupportedError("Required 'drawIndirectFirstInstance' feature is not supported");
653         }
654 }
655
656 template<class FirstInstanceSupport>
657 tcu::TestStatus IndirectDrawInstanced<FirstInstanceSupport>::iterate (void)
658 {
659         tcu::TestLog&           log             = m_context.getTestContext().getLog();
660         const vk::VkQueue       queue   = m_context.getUniversalQueue();
661         const vk::VkDevice      device  = m_context.getDevice();
662
663                                         m_drawCount                     = 2;
664                                         m_offsetInBuffer        = sizeof(m_junkData);
665         const deUint32  m_bufferDrawCount       = 2u * m_drawCount;
666
667         if (m_drawType == DRAW_TYPE_SEQUENTIAL)
668         {
669                 switch (m_topology)
670                 {
671                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
672                         {
673                                 vk::VkDrawIndirectCommand drawCmd[] =
674                                 {
675                                         {
676                                                 3,                                                                                      //vertexCount
677                                                 4,                                                                                      //instanceCount
678                                                 2,                                                                                      //firstVertex
679                                                 FirstInstanceSupport::getFirstInstance()        //firstInstance
680                                         },
681                                         { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
682                                         {
683                                                 3,                                                                                      //vertexCount
684                                                 4,                                                                                      //instanceCount
685                                                 5,                                                                                      //firstVertex
686                                                 FirstInstanceSupport::getFirstInstance()        //firstInstance
687                                         }
688                                 };
689                                 addCommand(drawCmd[0]);
690                                 addCommand(drawCmd[1]);
691                                 addCommand(drawCmd[2]);
692                                 if (m_testIndirectCountExt != IndirectCountType::NONE)
693                                 {
694                                         // Add padding data to the buffer to make sure it's large enough.
695                                         for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
696                                         {
697                                                 addCommand(drawCmd[1]);
698                                                 addCommand(drawCmd[1]);
699                                         }
700                                 }
701                                 break;
702                         }
703                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
704                         {
705                                 vk::VkDrawIndirectCommand drawCmd[] =
706                                 {
707                                         {
708                                                 4,                                                                                      //vertexCount
709                                                 4,                                                                                      //instanceCount
710                                                 2,                                                                                      //firstVertex
711                                                 FirstInstanceSupport::getFirstInstance()        //firstInstance
712                                         },
713                                         { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 },
714                                         {
715                                                 4,                                                                                      //vertexCount
716                                                 4,                                                                                      //instanceCount
717                                                 6,                                                                                      //firstVertex
718                                                 FirstInstanceSupport::getFirstInstance()        //firstInstance
719                                         }
720                                 };
721                                 addCommand(drawCmd[0]);
722                                 addCommand(drawCmd[1]);
723                                 addCommand(drawCmd[2]);
724                                 if (m_testIndirectCountExt != IndirectCountType::NONE)
725                                 {
726                                         // Add padding data to the buffer to make sure it's large enough.
727                                         for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
728                                         {
729                                                 addCommand(drawCmd[1]);
730                                                 addCommand(drawCmd[1]);
731                                         }
732                                 }
733                                 break;
734                         }
735                         default:
736                                 TCU_FAIL("impossible");
737                                 break;
738                 }
739
740                 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndirectCommand);
741         }
742         else if (m_drawType == DRAW_TYPE_INDEXED)
743         {
744                 switch (m_topology)
745                 {
746                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
747                         {
748                                 vk::VkDrawIndexedIndirectCommand drawCmd[] =
749                                 {
750                                         {
751                                                 3,                                                                                      // indexCount
752                                                 4,                                                                                      // instanceCount
753                                                 2,                                                                                      // firstIndex
754                                                 VERTEX_OFFSET,                                                          // vertexOffset
755                                                 FirstInstanceSupport::getFirstInstance()        // firstInstance
756                                         },
757                                         { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 },        // junk (stride)
758                                         {
759                                                 3,                                                                                      // indexCount
760                                                 4,                                                                                      // instanceCount
761                                                 5,                                                                                      // firstIndex
762                                                 VERTEX_OFFSET,                                                          // vertexOffset
763                                                 FirstInstanceSupport::getFirstInstance()        // firstInstance
764                                         }
765                                 };
766                                 addCommand(drawCmd[0]);
767                                 addCommand(drawCmd[1]);
768                                 addCommand(drawCmd[2]);
769                                 if (m_testIndirectCountExt != IndirectCountType::NONE)
770                                 {
771                                         // Add padding data to the buffer to make sure it's large enough.
772                                         for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
773                                         {
774                                                 addCommand(drawCmd[1]);
775                                                 addCommand(drawCmd[1]);
776                                         }
777                                 }
778                                 break;
779                         }
780                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
781                         {
782                                 vk::VkDrawIndexedIndirectCommand drawCmd[] =
783                                 {
784                                         {
785                                                 4,                                                                                      // indexCount
786                                                 4,                                                                                      // instanceCount
787                                                 2,                                                                                      // firstIndex
788                                                 VERTEX_OFFSET,                                                          // vertexOffset
789                                                 FirstInstanceSupport::getFirstInstance()        // firstInstance
790                                         },
791                                         { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 },        // junk (stride)
792                                         {
793                                                 4,                                                                                      // indexCount
794                                                 4,                                                                                      // instanceCount
795                                                 6,                                                                                      // firstIndex
796                                                 VERTEX_OFFSET,                                                          // vertexOffset
797                                                 FirstInstanceSupport::getFirstInstance()        // firstInstance
798                                         }
799                                 };
800                                 addCommand(drawCmd[0]);
801                                 addCommand(drawCmd[1]);
802                                 addCommand(drawCmd[2]);
803                                 if (m_testIndirectCountExt != IndirectCountType::NONE)
804                                 {
805                                         // Add padding data to the buffer to make sure it's large enough.
806                                         for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
807                                         {
808                                                 addCommand(drawCmd[1]);
809                                                 addCommand(drawCmd[1]);
810                                         }
811                                 }
812                                 break;
813                         }
814                         default:
815                                 TCU_FAIL("impossible");
816                                 break;
817                 }
818
819                 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndexedIndirectCommand);
820         }
821
822         beginRenderPass();
823
824         const vk::VkDeviceSize vertexBufferOffset = 0;
825         const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
826
827         m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
828
829         const vk::VkDeviceSize dataSize = m_indirectBufferContents.size();
830
831         m_indirectBuffer = Buffer::createAndAlloc(      m_vk,
832                                                                                                 m_context.getDevice(),
833                                                                                                 BufferCreateInfo(dataSize + m_offsetInBuffer,
834                                                                                                                                  vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
835                                                                                                 m_context.getDefaultAllocator(),
836                                                                                                 vk::MemoryRequirement::HostVisible);
837
838         deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
839
840         deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer));
841         deMemcpy((ptr + m_offsetInBuffer), &m_indirectBufferContents[0], static_cast<size_t>(dataSize));
842
843         vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
844
845         if (m_testIndirectCountExt != IndirectCountType::NONE)
846         {
847                 m_offsetInCountBuffer = sizeof(tcu::Vec3);
848                 m_indirectCountBuffer = Buffer::createAndAlloc(m_vk,
849                                                                                                            m_context.getDevice(),
850                                                                                                            BufferCreateInfo(m_offsetInCountBuffer + sizeof(m_drawCount),
851                                                                                                                                                 vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
852                                                                                                            m_context.getDefaultAllocator(),
853                                                                                                            vk::MemoryRequirement::HostVisible);
854
855                 deUint8* countBufferPtr = reinterpret_cast<deUint8*>(m_indirectCountBuffer->getBoundMemory().getHostPtr());
856
857                 // For IndirectCountType::PARAM_LIMIT, the real limit will be set using the call parameter.
858                 if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
859                         *(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? 0u : m_indirectCountExtDrawPadding);
860                 else
861                         *(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = 1u;
862
863                 vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectCountBuffer->getBoundMemory());
864         }
865
866         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
867
868         if (m_drawType == DRAW_TYPE_INDEXED)
869         {
870                 m_vk.cmdBindIndexBuffer(*m_cmdBuffer, m_indexBuffer->object(), DE_NULL, vk::VK_INDEX_TYPE_UINT32);
871         }
872
873         if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
874         {
875                 switch (m_drawType)
876                 {
877                         case DRAW_TYPE_SEQUENTIAL:
878                         {
879                                 if (m_testIndirectCountExt != IndirectCountType::NONE)
880                                 {
881                                         const deUint32 maxDrawCount = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_indirectCountExtDrawPadding : 0u);
882                                         m_vk.cmdDrawIndirectCount(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer,
883                                                                                           m_indirectCountBuffer->object(), m_offsetInCountBuffer,
884                                                                                           maxDrawCount, m_strideInBuffer);
885                                 }
886                                 else
887                                         m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
888                                 break;
889                         }
890                         case DRAW_TYPE_INDEXED:
891                         {
892                                 if (m_testIndirectCountExt != IndirectCountType::NONE)
893                                 {
894                                         const deUint32 maxDrawCount = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_indirectCountExtDrawPadding : 0u);
895                                         m_vk.cmdDrawIndexedIndirectCount(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer,
896                                                                                                          m_indirectCountBuffer->object(), m_offsetInCountBuffer,
897                                                                                                          maxDrawCount, m_strideInBuffer);
898                                 }
899                                 else
900                                         m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
901                                 break;
902                         }
903                         default:
904                                 TCU_FAIL("impossible");
905                 }
906         }
907         else
908         {
909                 for (deUint32 drawNdx = 0; drawNdx < m_drawCount; drawNdx++)
910                 {
911                         switch (m_drawType)
912                         {
913                                 case DRAW_TYPE_SEQUENTIAL:
914                                 {
915                                         if (m_testIndirectCountExt != IndirectCountType::NONE)
916                                         {
917                                                 const deUint32 maxDrawCount = (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_drawCount + m_indirectCountExtDrawPadding : 1u);
918                                                 m_vk.cmdDrawIndirectCount(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer,
919                                                                                                   m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
920                                                                                                   m_strideInBuffer);
921                                         }
922                                         else
923                                                 m_vk.cmdDrawIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
924                                         break;
925                                 }
926                                 case DRAW_TYPE_INDEXED:
927                                 {
928                                         if (m_testIndirectCountExt != IndirectCountType::NONE)
929                                         {
930                                                 const deUint32 maxDrawCount = (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_drawCount + m_indirectCountExtDrawPadding : 1u);
931                                                 m_vk.cmdDrawIndexedIndirectCount(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer,
932                                                                                                                  m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
933                                                                                                                  m_strideInBuffer);
934                                         }
935                                         else
936                                                 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
937                                         break;
938                                 }
939                                 default:
940                                         TCU_FAIL("impossible");
941                         }
942                 }
943         }
944         endRenderPass(m_vk, *m_cmdBuffer);
945         endCommandBuffer(m_vk, *m_cmdBuffer);
946
947         submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
948
949         // Validation
950         VK_CHECK(m_vk.queueWaitIdle(queue));
951
952         tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5 + static_cast<float>(HEIGHT)));
953
954         referenceFrame.allocLevel(0);
955
956         const deInt32 frameWidth        = referenceFrame.getWidth();
957         const deInt32 frameHeight       = referenceFrame.getHeight();
958
959         tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
960
961         ReferenceImageInstancedCoordinates refInstancedCoords;
962
963         for (int y = 0; y < frameHeight; y++)
964         {
965                 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
966
967                 for (int x = 0; x < frameWidth; x++)
968                 {
969                         const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
970
971                         if ((yCoord >= refInstancedCoords.bottom        &&
972                                  yCoord <= refInstancedCoords.top               &&
973                                  xCoord >= refInstancedCoords.left              &&
974                                  xCoord <= refInstancedCoords.right))
975                                 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
976                 }
977         }
978
979         const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
980         const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
981                 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
982
983         qpTestResult res = QP_TEST_RESULT_PASS;
984
985         if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
986                 referenceFrame.getLevel(0), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
987         {
988                 res = QP_TEST_RESULT_FAIL;
989         }
990
991         return tcu::TestStatus(res, qpGetTestResultName(res));
992 }
993
994 void checkIndirectCountExt (Context& context)
995 {
996         context.requireDeviceFunctionality("VK_KHR_draw_indirect_count");
997 }
998
999 }       // anonymous
1000
1001 IndirectDrawTests::IndirectDrawTests (tcu::TestContext& testCtx)
1002         : TestCaseGroup(testCtx, "indirect_draw", "indirect drawing simple geometry")
1003 {
1004         /* Left blank on purpose */
1005 }
1006
1007 IndirectDrawTests::~IndirectDrawTests (void) {}
1008
1009
1010 void IndirectDrawTests::init (void)
1011 {
1012         for (int drawTypeIdx = 0; drawTypeIdx < DRAWTYPE_LAST; drawTypeIdx++)
1013         {
1014                 std::string drawTypeStr;
1015                 switch (drawTypeIdx)
1016                 {
1017                         case DRAW_TYPE_SEQUENTIAL:
1018                                 drawTypeStr = "sequential";
1019                                 break;
1020                         case DRAW_TYPE_INDEXED:
1021                                 drawTypeStr = "indexed";
1022                                 break;
1023                         default:
1024                                 TCU_FAIL("impossible");
1025                 }
1026
1027                 tcu::TestCaseGroup* drawTypeGroup = new tcu::TestCaseGroup(m_testCtx, drawTypeStr.c_str(), ("Draws geometry using " + drawTypeStr + "draw call").c_str());
1028                 {
1029                         tcu::TestCaseGroup* indirectDrawGroup                   = new tcu::TestCaseGroup(m_testCtx, "indirect_draw", "Draws geometry");
1030                         tcu::TestCaseGroup* indirectDrawCountGroup              = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_count", "Draws geometry with VK_KHR_draw_indirect_count extension");
1031                         tcu::TestCaseGroup* indirectDrawParamCountGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_param_count", "Draws geometry with VK_KHR_draw_indirect_count extension and limit draws count with call parameter");
1032                         {
1033                                 IndirectDraw::TestSpec testSpec;
1034                                 testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1035                                 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetch.vert";
1036                                 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1037                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1038                                 indirectDrawGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_list", "Draws triangle list", testSpec));
1039                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1040                                 indirectDrawGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec));
1041
1042                                 testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1043                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1044                                 indirectDrawCountGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport0>(m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport0(checkIndirectCountExt)));
1045                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1046                                 indirectDrawCountGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport0>(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport0(checkIndirectCountExt)));
1047
1048                                 testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1049                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1050                                 indirectDrawParamCountGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport0>(m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport0(checkIndirectCountExt)));
1051                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1052                                 indirectDrawParamCountGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport0>(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport0(checkIndirectCountExt)));
1053                         }
1054                         drawTypeGroup->addChild(indirectDrawGroup);
1055                         drawTypeGroup->addChild(indirectDrawCountGroup);
1056                         drawTypeGroup->addChild(indirectDrawParamCountGroup);
1057
1058                         {
1059                                 tcu::TestCaseGroup* indirectDrawFirstInstanceGroup                              = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_first_instance", "Draws geometry with different first instance in one commandbuffer");
1060                                 tcu::TestCaseGroup* indirectDrawCountFirstInstanceGroup                 = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_count_first_instance", "Draws geometry with VK_KHR_draw_indirect_count extension with different first instance in one commandbuffer");
1061                                 tcu::TestCaseGroup* indirectDrawParamCountFirstInstanceGroup    = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_param_count_first_instance", "Draws geometry with VK_KHR_draw_indirect_count extension with different first instance in one commandbuffer and limit draws count with call parameter");
1062                                 {
1063                                         IndirectDraw::TestSpec testSpec;
1064                                         testSpec.testFirstInstanceNdx = true;
1065                                         testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1066                                         testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstanceIndex.vert";
1067                                         testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1068                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1069                                         indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_list", "Draws triangle list", testSpec));
1070                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1071                                         indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw>(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec));
1072
1073                                         testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1074                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1075                                         indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport0>(m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport0(checkIndirectCountExt)));
1076                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1077                                         indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport0>(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport0(checkIndirectCountExt)));
1078
1079                                         testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1080                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1081                                         indirectDrawParamCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport0>(m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport0(checkIndirectCountExt)));
1082                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1083                                         indirectDrawParamCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport0>(m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport0(checkIndirectCountExt)));
1084                                 }
1085                                 drawTypeGroup->addChild(indirectDrawFirstInstanceGroup);
1086                                 drawTypeGroup->addChild(indirectDrawCountFirstInstanceGroup);
1087                                 drawTypeGroup->addChild(indirectDrawParamCountFirstInstanceGroup);
1088                         }
1089
1090                         tcu::TestCaseGroup* indirectDrawInstancedGroup                          = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_instanced", "Draws an instanced geometry");
1091                         tcu::TestCaseGroup* indirectDrawCountInstancedGroup                     = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_count_instanced", "Draws an instanced geometry with VK_KHR_draw_indirect_count extension");
1092                         tcu::TestCaseGroup* indirectDrawParamCountInstancedGroup        = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_param_count_instanced", "Draws an instanced geometry with VK_KHR_draw_indirect_count extension and limit draws count with call parameter");
1093                         {
1094                                 tcu::TestCaseGroup*     indirectDrawNoFirstInstanceGroup                        = new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance");
1095                                 tcu::TestCaseGroup*     indirectDrawCountNoFirstInstanceGroup           = new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance");
1096                                 tcu::TestCaseGroup*     indirectDrawParamCountNoFirstInstanceGroup      = new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance");
1097                                 {
1098                                         IndirectDrawInstanced<FirstInstanceNotSupported>::TestSpec testSpec;
1099                                         testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1100
1101                                         testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstanced.vert";
1102                                         testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1103
1104                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1105                                         indirectDrawNoFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceNotSupported> >(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec));
1106                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1107                                         indirectDrawNoFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceNotSupported> >(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec));
1108
1109                                         testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1110                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1111                                         indirectDrawCountNoFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceNotSupported>, FunctionSupport0>(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport0(checkIndirectCountExt)));
1112                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1113                                         indirectDrawCountNoFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceNotSupported>, FunctionSupport0>(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport0(checkIndirectCountExt)));
1114
1115                                         testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1116                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1117                                         indirectDrawParamCountNoFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceNotSupported>, FunctionSupport0>(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport0(checkIndirectCountExt)));
1118                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1119                                         indirectDrawParamCountNoFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceNotSupported>, FunctionSupport0>(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport0(checkIndirectCountExt)));
1120                                 }
1121                                 indirectDrawInstancedGroup->addChild(indirectDrawNoFirstInstanceGroup);
1122                                 indirectDrawCountInstancedGroup->addChild(indirectDrawCountNoFirstInstanceGroup);
1123                                 indirectDrawParamCountInstancedGroup->addChild(indirectDrawParamCountNoFirstInstanceGroup);
1124
1125                                 tcu::TestCaseGroup*     indirectDrawFirstInstanceGroup                          = new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature");
1126                                 tcu::TestCaseGroup*     indirectDrawCountFirstInstanceGroup                     = new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature");
1127                                 tcu::TestCaseGroup*     indirectDrawParamCountFirstInstanceGroup        = new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature");
1128                                 {
1129                                         IndirectDrawInstanced<FirstInstanceSupported>::TestSpec testSpec;
1130                                         testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1131
1132                                         testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstancedFirstInstance.vert";
1133                                         testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1134
1135                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1136                                         indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceSupported> >(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec));
1137                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1138                                         indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceSupported> >(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec));
1139
1140                                         testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1141                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1142                                         indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceSupported>, FunctionSupport0>(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport0(checkIndirectCountExt)));
1143                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1144                                         indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceSupported>, FunctionSupport0>(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport0(checkIndirectCountExt)));
1145
1146                                         testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1147                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1148                                         indirectDrawParamCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceSupported>, FunctionSupport0>(m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport0(checkIndirectCountExt)));
1149                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1150                                         indirectDrawParamCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDrawInstanced<FirstInstanceSupported>, FunctionSupport0>(m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport0(checkIndirectCountExt)));
1151                                 }
1152                                 indirectDrawInstancedGroup->addChild(indirectDrawFirstInstanceGroup);
1153                                 indirectDrawCountInstancedGroup->addChild(indirectDrawCountFirstInstanceGroup);
1154                                 indirectDrawParamCountInstancedGroup->addChild(indirectDrawParamCountFirstInstanceGroup);
1155                         }
1156                         drawTypeGroup->addChild(indirectDrawInstancedGroup);
1157                         drawTypeGroup->addChild(indirectDrawCountInstancedGroup);
1158                         drawTypeGroup->addChild(indirectDrawParamCountInstancedGroup);
1159                 }
1160
1161                 addChild(drawTypeGroup);
1162         }
1163 }
1164
1165 }       // DrawTests
1166 }       // vkt