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