Fix missing dependency on sparse binds
[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 #include "../compute/vktComputeTestsUtil.hpp"
30
31 #include "vktDrawBaseClass.hpp"
32
33 #include "tcuTestLog.hpp"
34 #include "tcuResource.hpp"
35 #include "tcuImageCompare.hpp"
36 #include "tcuTextureUtil.hpp"
37 #include "tcuRGBA.hpp"
38 #include "vkQueryUtil.hpp"
39
40 #include "vkDefs.hpp"
41 #include "vkCmdUtil.hpp"
42 #include "vkBuilderUtil.hpp"
43 #include "vkObjUtil.hpp"
44 #include "vkTypeUtil.hpp"
45 #include "vkBarrierUtil.hpp"
46
47 namespace vkt
48 {
49 namespace Draw
50 {
51 namespace
52 {
53
54 enum
55 {
56         VERTEX_OFFSET = 13
57 };
58
59 struct JunkData
60 {
61         JunkData()
62                 : varA  (0xcd)
63                 , varB  (0xcd)
64         {
65         }
66         const deUint16  varA;
67         const deUint32  varB;
68 };
69
70 enum DrawType
71 {
72         DRAW_TYPE_SEQUENTIAL,
73         DRAW_TYPE_INDEXED,
74
75         DRAWTYPE_LAST
76 };
77
78 enum class IndirectCountType
79 {
80         NONE,
81         BUFFER_LIMIT,
82         PARAM_LIMIT,
83
84         LAST
85 };
86
87 struct DrawTypedTestSpec : public TestSpecBase
88 {
89         DrawTypedTestSpec(const SharedGroupParams groupParams_)
90                 : TestSpecBase{ {}, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, groupParams_ }
91                 , drawType(DRAWTYPE_LAST)
92                 , testFirstInstanceNdx(false)
93                 , testIndirectCountExt(IndirectCountType::NONE)
94                 , dataFromCompute(false)
95         {}
96
97         DrawType                        drawType;
98         bool                            testFirstInstanceNdx;
99         IndirectCountType       testIndirectCountExt;
100         bool                            dataFromCompute;
101 };
102
103 class IndirectDraw : public DrawTestsBaseClass
104 {
105 public:
106         typedef DrawTypedTestSpec                       TestSpec;
107
108                                                                                 IndirectDraw                                    (Context &context, TestSpec testSpec);
109         virtual tcu::TestStatus                         iterate                                                 (void);
110
111         void                                                            draw                                                    (vk::VkCommandBuffer cmdBuffer);
112         template<typename T> void                       addCommand                                              (const T&);
113
114 protected:
115         void                                                            setVertexBuffer                                 (void);
116         void                                                            setFirstInstanceVertexBuffer    (void);
117         void                                                            negateDataUsingCompute                  (vk::VkDeviceSize indirectBufferSize, vk::VkDeviceSize countBufferSize);
118
119         std::vector<char>                                       m_indirectBufferContents;
120         de::SharedPtr<Buffer>                           m_indirectBuffer;
121         vk::VkDeviceSize                                        m_offsetInBuffer;
122         deUint32                                                        m_strideInBuffer;
123
124         const IndirectCountType                         m_testIndirectCountExt;
125         de::SharedPtr<Buffer>                           m_indirectCountBuffer;
126         vk::VkDeviceSize                                        m_offsetInCountBuffer;
127         const deUint32                                          m_indirectCountExtDrawPadding;
128
129         deUint32                                                        m_drawCount;
130         JunkData                                                        m_junkData;
131
132         const DrawType                                          m_drawType;
133         const bool                                                      m_testFirstInstanceNdx;
134         deBool                                                          m_isMultiDrawEnabled;
135         deUint32                                                        m_drawIndirectMaxCount;
136         deBool                                                          m_dataFromComputeShader;
137
138         de::SharedPtr<Buffer>                           m_indexBuffer;
139
140         vk::Move<vk::VkDescriptorSetLayout>     m_descriptorSetLayout;
141         vk::Move<vk::VkDescriptorPool>          m_descriptorPool;
142         vk::Move<vk::VkDescriptorSet>           m_descriptorSetIndirectBuffer;
143         vk::Move<vk::VkDescriptorSet>           m_descriptorSetCountBuffer;
144         vk::Move<vk::VkShaderModule>            m_computeShaderModule;
145         vk::Move<vk::VkPipelineLayout>          m_pipelineLayout;
146         vk::Move<vk::VkPipeline>                        m_computePipeline;
147 };
148
149 struct FirstInstanceSupported
150 {
151         static deUint32 getFirstInstance        (void)                                                                                  { return 2; }
152         static bool             isTestSupported         (const vk::VkPhysicalDeviceFeatures& features)  { return features.drawIndirectFirstInstance == VK_TRUE; }
153 };
154
155 struct FirstInstanceNotSupported
156 {
157         static deUint32 getFirstInstance        (void)                                                                                  { return 0; }
158         static bool             isTestSupported         (const vk::VkPhysicalDeviceFeatures&)                   { return true; }
159 };
160
161 template<class FirstInstanceSupport>
162 class IndirectDrawInstanced : public IndirectDraw
163 {
164 public:
165                                                                 IndirectDrawInstanced   (Context &context, TestSpec testSpec);
166         virtual tcu::TestStatus         iterate                                 (void);
167 };
168
169 void IndirectDraw::setVertexBuffer (void)
170 {
171         int refVertexIndex = 2;
172
173         if (m_drawType == DRAW_TYPE_INDEXED)
174         {
175                 for (int unusedIdx = 0; unusedIdx < VERTEX_OFFSET; unusedIdx++)
176                 {
177                         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
178                 }
179                 refVertexIndex += VERTEX_OFFSET;
180         }
181
182         m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
183         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
184
185         switch (m_topology)
186         {
187                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
188                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,     -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
189                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
190                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
191                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
192                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
193                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
194                         break;
195                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
196                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
197                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
198                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,     -0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
199                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
200                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
201                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
202                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
203                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refVertexIndex++));
204                         break;
205                 default:
206                         DE_FATAL("Unknown topology");
207                         break;
208         }
209
210         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
211 }
212
213 void IndirectDraw::setFirstInstanceVertexBuffer (void)
214 {
215         if (m_context.getDeviceFeatures().drawIndirectFirstInstance != VK_TRUE)
216         {
217                 TCU_THROW(NotSupportedError, "Required 'drawIndirectFirstInstance' feature is not supported");
218         }
219
220         if (m_drawType == DRAW_TYPE_INDEXED)
221         {
222                 for (int unusedIdx = 0; unusedIdx < VERTEX_OFFSET; unusedIdx++)
223                 {
224                         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
225                 }
226         }
227
228         m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
229         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f,  1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
230
231         switch (m_topology)
232         {
233                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
234                 {
235                         int refInstanceIndex = 1;
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.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
239
240                         refInstanceIndex = 0;
241                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
242                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
243                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
244                         break;
245                 }
246                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
247                 {
248                         int refInstanceIndex = 1;
249                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refInstanceIndex));
250                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refInstanceIndex));
251                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,     -0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refInstanceIndex));
252                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,     -0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refInstanceIndex));
253
254                         refInstanceIndex = 0;
255                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refInstanceIndex));
256                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.3f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refInstanceIndex));
257                         m_data.push_back(VertexElementData(tcu::Vec4(-0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refInstanceIndex));
258                         m_data.push_back(VertexElementData(tcu::Vec4( 0.3f,      0.0f, 1.0f, 1.0f),      tcu::RGBA::blue().toVec(), refInstanceIndex));
259                         break;
260                 }
261                 default:
262                         DE_FATAL("Unknown topology");
263                         break;
264         }
265
266         m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
267 }
268
269 // When testing indirect data generation from a compute shader, the original data is negated bitwise
270 // and compute shader restores it before being used in an indirect draw.
271 void IndirectDraw::negateDataUsingCompute(vk::VkDeviceSize indirectBufferSize, vk::VkDeviceSize countBufferSize)
272 {
273         m_descriptorSetLayout   = vk::DescriptorSetLayoutBuilder().addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT).build(m_vk, m_context.getDevice());
274         m_descriptorPool                = vk::DescriptorPoolBuilder().addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u).build(m_vk, m_context.getDevice(), vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 2u);
275
276         // Indirect buffer
277         {
278                 m_descriptorSetIndirectBuffer = vk::makeDescriptorSet(m_vk, m_context.getDevice(), *m_descriptorPool, *m_descriptorSetLayout);
279                 const vk::VkDescriptorBufferInfo bufferDescriptorInfo = vk::makeDescriptorBufferInfo(m_indirectBuffer->object(), 0ull, indirectBufferSize);
280                 vk::DescriptorSetUpdateBuilder()
281                                 .writeSingle(*m_descriptorSetIndirectBuffer, vk::DescriptorSetUpdateBuilder::Location::binding(0u),
282                                                          vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescriptorInfo)
283                                 .update(m_vk, m_context.getDevice());
284         }
285
286         // Indirect count buffer
287         if (m_testIndirectCountExt != IndirectCountType::NONE)
288         {
289                 m_descriptorSetCountBuffer = vk::makeDescriptorSet(m_vk, m_context.getDevice(), *m_descriptorPool, *m_descriptorSetLayout);
290                 const vk::VkDescriptorBufferInfo bufferDescriptorInfo = vk::makeDescriptorBufferInfo(m_indirectCountBuffer->object(), 0ull, countBufferSize);
291                 vk::DescriptorSetUpdateBuilder()
292                                 .writeSingle(*m_descriptorSetCountBuffer, vk::DescriptorSetUpdateBuilder::Location::binding(0u),
293                                                          vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescriptorInfo)
294                                 .update(m_vk, m_context.getDevice());
295         }
296
297         m_computeShaderModule   = vk::createShaderModule(m_vk, m_context.getDevice(), m_context.getBinaryCollection().get("vulkan/draw/NegateData.comp"), 0u);
298         m_pipelineLayout                = vk::makePipelineLayout(m_vk, m_context.getDevice(), *m_descriptorSetLayout);
299         m_computePipeline               = makeComputePipeline(m_vk, m_context.getDevice(), *m_pipelineLayout, *m_computeShaderModule);
300
301         const vk::VkBufferMemoryBarrier         hostWriteBarrier        = vk::makeBufferMemoryBarrier(vk::VK_ACCESS_HOST_WRITE_BIT, vk::VK_ACCESS_SHADER_READ_BIT, m_indirectBuffer->object(), 0ull, indirectBufferSize);
302         const vk::VkBufferMemoryBarrier         indirectDrawBarrier     = vk::makeBufferMemoryBarrier(vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_ACCESS_INDIRECT_COMMAND_READ_BIT, m_indirectBuffer->object(), 0ull, indirectBufferSize);
303
304         m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *m_computePipeline);
305         m_vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0u, 1u, &m_descriptorSetIndirectBuffer.get(), 0u, DE_NULL);
306         m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_HOST_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 1, &hostWriteBarrier, 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
307         m_vk.cmdDispatch(*m_cmdBuffer, 1, 1, 1);
308         m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 1, &indirectDrawBarrier, 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
309
310         if (m_testIndirectCountExt != IndirectCountType::NONE)
311         {
312                 m_vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0u, 1u, &m_descriptorSetCountBuffer.get(), 0u, DE_NULL);
313                 m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_HOST_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 1, &hostWriteBarrier, 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
314                 m_vk.cmdDispatch(*m_cmdBuffer, 1, 1, 1);
315                 m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 1, &indirectDrawBarrier, 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
316         }
317 }
318
319 IndirectDraw::IndirectDraw (Context &context, TestSpec testSpec)
320         : DrawTestsBaseClass                            (context, testSpec.shaders[glu::SHADERTYPE_VERTEX], testSpec.shaders[glu::SHADERTYPE_FRAGMENT], testSpec.groupParams, testSpec.topology)
321         , m_testIndirectCountExt                        (testSpec.testIndirectCountExt)
322         , m_indirectCountExtDrawPadding         (1u)
323         , m_drawType                                            (testSpec.drawType)
324         , m_testFirstInstanceNdx                        (testSpec.testFirstInstanceNdx)
325         , m_dataFromComputeShader                       (testSpec.dataFromCompute)
326 {
327         if (m_testFirstInstanceNdx)
328                 setFirstInstanceVertexBuffer();
329         else
330                 setVertexBuffer();
331
332         initialize();
333
334         if (testSpec.drawType == DRAW_TYPE_INDEXED)
335         {
336                 const size_t indexBufferLength = m_data.size() - VERTEX_OFFSET;
337
338                 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);
339                 deUint32* indices = reinterpret_cast<deUint32*>(m_indexBuffer->getBoundMemory().getHostPtr());
340                 for (size_t i = 0; i < indexBufferLength; i++)
341                 {
342                         indices[i] = static_cast<deUint32>(i);
343                 }
344                 vk::flushAlloc(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory());
345         }
346
347         // Check device for multidraw support:
348         if (!m_context.getDeviceFeatures().multiDrawIndirect || m_testFirstInstanceNdx)
349                 m_isMultiDrawEnabled = false;
350         else
351                 m_isMultiDrawEnabled = true;
352
353         m_drawIndirectMaxCount = m_context.getDeviceProperties().limits.maxDrawIndirectCount;
354 }
355
356 template<>
357 void IndirectDraw::addCommand<vk::VkDrawIndirectCommand> (const vk::VkDrawIndirectCommand& command)
358 {
359         DE_ASSERT(m_drawType == DRAW_TYPE_SEQUENTIAL);
360
361         const size_t currentSize = m_indirectBufferContents.size();
362
363         m_indirectBufferContents.resize(currentSize + sizeof(command));
364
365         deMemcpy(&m_indirectBufferContents[currentSize], &command, sizeof(command));
366 }
367
368 template<>
369 void IndirectDraw::addCommand<vk::VkDrawIndexedIndirectCommand> (const vk::VkDrawIndexedIndirectCommand& command)
370 {
371         DE_ASSERT(m_drawType == DRAW_TYPE_INDEXED);
372
373         const size_t currentSize = m_indirectBufferContents.size();
374
375         m_indirectBufferContents.resize(currentSize + sizeof(command));
376
377         deMemcpy(&m_indirectBufferContents[currentSize], &command, sizeof(command));
378 }
379
380 void IndirectDraw::draw (vk::VkCommandBuffer cmdBuffer)
381 {
382         const vk::VkDeviceSize  vertexBufferOffset      = 0;
383         const vk::VkBuffer              vertexBuffer            = m_vertexBuffer->object();
384
385         m_vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
386         m_vk.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
387         if (m_drawType == DRAW_TYPE_INDEXED)
388                 m_vk.cmdBindIndexBuffer(cmdBuffer, m_indexBuffer->object(), DE_NULL, vk::VK_INDEX_TYPE_UINT32);
389
390         if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
391         {
392                 switch (m_drawType)
393                 {
394                         case DRAW_TYPE_SEQUENTIAL:
395                         {
396                                 if (m_testIndirectCountExt != IndirectCountType::NONE)
397                                 {
398                                         const deUint32 maxDrawCount = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_indirectCountExtDrawPadding : 0u);
399                                         m_vk.cmdDrawIndirectCount(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer,
400                                                                                           m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
401                                                                                           m_strideInBuffer);
402                                 }
403                                 else
404                                         m_vk.cmdDrawIndirect(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
405                                 break;
406                         }
407                         case DRAW_TYPE_INDEXED:
408                         {
409                                 if (m_testIndirectCountExt != IndirectCountType::NONE)
410                                 {
411                                         const deUint32 maxDrawCount = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_indirectCountExtDrawPadding : 0u);
412                                         m_vk.cmdDrawIndexedIndirectCount(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer,
413                                                                                                          m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
414                                                                                                          m_strideInBuffer);
415                                 }
416                                 else
417                                         m_vk.cmdDrawIndexedIndirect(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
418                                 break;
419                         }
420                         default:
421                                 TCU_FAIL("impossible");
422                 }
423         }
424         else
425         {
426                 for (deUint32 drawNdx = 0; drawNdx < m_drawCount; drawNdx++)
427                 {
428                         switch (m_drawType)
429                         {
430                                 case DRAW_TYPE_SEQUENTIAL:
431                                 {
432                                         if (m_testIndirectCountExt != IndirectCountType::NONE)
433                                         {
434                                                 const deUint32 maxDrawCount = (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_drawCount + m_indirectCountExtDrawPadding : 1u);
435                                                 m_vk.cmdDrawIndirectCount(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer,
436                                                                                                   m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
437                                                                                                   m_strideInBuffer);
438                                         }
439                                         else
440                                                 m_vk.cmdDrawIndirect(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
441                                         break;
442                                 }
443                                 case DRAW_TYPE_INDEXED:
444                                 {
445                                         if (m_testIndirectCountExt != IndirectCountType::NONE)
446                                         {
447                                                 const deUint32 maxDrawCount = (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_drawCount + m_indirectCountExtDrawPadding : 1u);
448                                                 m_vk.cmdDrawIndexedIndirectCount(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer,
449                                                                                                                  m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
450                                                                                                                  m_strideInBuffer);
451                                         }
452                                         else
453                                                 m_vk.cmdDrawIndexedIndirect(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
454                                         break;
455                                 }
456                                 default:
457                                         TCU_FAIL("impossible");
458                         }
459                 }
460         }
461 }
462
463 tcu::TestStatus IndirectDraw::iterate (void)
464 {
465         tcu::TestLog&           log             = m_context.getTestContext().getLog();
466         const vk::VkQueue       queue   = m_context.getUniversalQueue();
467         const vk::VkDevice      device  = m_context.getDevice();
468
469                                         m_drawCount                     = 2;
470                                         m_offsetInBuffer        = sizeof(m_junkData);
471         const deUint32  m_bufferDrawCount       = 2u * m_drawCount;
472
473         if (m_drawType == DRAW_TYPE_SEQUENTIAL)
474         {
475                 switch (m_topology)
476                 {
477                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
478                 {
479                         vk::VkDrawIndirectCommand drawCommands[] =
480                         {
481                                 {
482                                         3u,                                                                     //vertexCount
483                                         1u,                                                                     //instanceCount
484                                         2u,                                                                     //firstVertex
485                                         (m_testFirstInstanceNdx ? 1u : 0u)      //firstInstance
486                                 },
487                                 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
488                                 {
489                                         3u,                                                                     //vertexCount
490                                         1u,                                                                     //instanceCount
491                                         5u,                                                                     //firstVertex
492                                         0u                                                                      //firstInstance
493                                 }
494                         };
495                         addCommand(drawCommands[0]);
496                         addCommand(drawCommands[1]);
497                         addCommand(drawCommands[2]);
498                         addCommand(drawCommands[1]);
499                         if (m_testIndirectCountExt != IndirectCountType::NONE)
500                         {
501                                 // Add padding data to the buffer to make sure it's large enough.
502                                 for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
503                                 {
504                                         addCommand(drawCommands[1]);
505                                         addCommand(drawCommands[1]);
506                                 }
507                         }
508                         break;
509                 }
510                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
511                 {
512                         vk::VkDrawIndirectCommand drawCommands[] =
513                         {
514                                 {
515                                         4u,                                                                     //vertexCount
516                                         1u,                                                                     //instanceCount
517                                         2u,                                                                     //firstVertex
518                                         (m_testFirstInstanceNdx ? 1u : 0u)      //firstInstance
519                                 },
520                                 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
521                                 {
522                                         4u,                                                                     //vertexCount
523                                         1u,                                                                     //instanceCount
524                                         6u,                                                                     //firstVertex
525                                         0u                                                                      //firstInstance
526                                 }
527                         };
528                         addCommand(drawCommands[0]);
529                         addCommand(drawCommands[1]);
530                         addCommand(drawCommands[2]);
531                         addCommand(drawCommands[1]);
532                         if (m_testIndirectCountExt != IndirectCountType::NONE)
533                         {
534                                 // Add padding data to the buffer to make sure it's large enough.
535                                 for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
536                                 {
537                                         addCommand(drawCommands[1]);
538                                         addCommand(drawCommands[1]);
539                                 }
540                         }
541                         break;
542                 }
543                 default:
544                         TCU_FAIL("impossible");
545                 }
546
547                 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndirectCommand);
548         }
549         else if (m_drawType == DRAW_TYPE_INDEXED)
550         {
551                 switch (m_topology)
552                 {
553                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
554                 {
555                         vk::VkDrawIndexedIndirectCommand drawCommands[] =
556                         {
557                                 {
558                                         3u,                                                                     // indexCount
559                                         1u,                                                                     // instanceCount
560                                         2u,                                                                     // firstIndex
561                                         VERTEX_OFFSET,                                          // vertexOffset
562                                         (m_testFirstInstanceNdx ? 1u : 0u),     // firstInstance
563                                 },
564                                 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride)
565                                 {
566                                         3u,                                                                     // indexCount
567                                         1u,                                                                     // instanceCount
568                                         5u,                                                                     // firstIndex
569                                         VERTEX_OFFSET,                                          // vertexOffset
570                                         0u                                                                      // firstInstance
571                                 }
572                         };
573                         addCommand(drawCommands[0]);
574                         addCommand(drawCommands[1]);
575                         addCommand(drawCommands[2]);
576                         addCommand(drawCommands[1]);
577                         if (m_testIndirectCountExt != IndirectCountType::NONE)
578                         {
579                                 // Add padding data to the buffer to make sure it's large enough.
580                                 for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
581                                 {
582                                         addCommand(drawCommands[1]);
583                                         addCommand(drawCommands[1]);
584                                 }
585                         }
586                         break;
587                 }
588                 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
589                 {
590                         vk::VkDrawIndexedIndirectCommand drawCommands[] =
591                         {
592                                 {
593                                         4u,                                                                     // indexCount
594                                         1u,                                                                     // instanceCount
595                                         2u,                                                                     // firstIndex
596                                         VERTEX_OFFSET,                                          // vertexOffset
597                                         (m_testFirstInstanceNdx ? 1u : 0u),     // firstInstance
598                                 },
599                                 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride)
600                                 {
601                                         4u,                                                                     // indexCount
602                                         1u,                                                                     // instanceCount
603                                         6u,                                                                     // firstIndex
604                                         VERTEX_OFFSET,                                          // vertexOffset
605                                         0u                                                                      // firstInstance
606                                 }
607                         };
608                         addCommand(drawCommands[0]);
609                         addCommand(drawCommands[1]);
610                         addCommand(drawCommands[2]);
611                         addCommand(drawCommands[1]);
612                         if (m_testIndirectCountExt != IndirectCountType::NONE)
613                         {
614                                 // Add padding data to the buffer to make sure it's large enough.
615                                 for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
616                                 {
617                                         addCommand(drawCommands[1]);
618                                         addCommand(drawCommands[1]);
619                                 }
620                         }
621                         break;
622                 }
623                 default:
624                         TCU_FAIL("impossible");
625                 }
626
627                 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndexedIndirectCommand);
628         }
629
630         const vk::VkDeviceSize  dataSize                        = m_indirectBufferContents.size();
631         const vk::VkDeviceSize  indirectBufferSize      = dataSize + m_offsetInBuffer;
632         vk::VkBufferUsageFlags  usageFlags                      = vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
633         if (m_dataFromComputeShader)
634                 usageFlags |= vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
635
636         m_indirectBuffer = Buffer::createAndAlloc(      m_vk,
637                                                                                                 m_context.getDevice(),
638                                                                                                 BufferCreateInfo(indirectBufferSize, usageFlags),
639                                                                                                 m_context.getDefaultAllocator(),
640                                                                                                 vk::MemoryRequirement::HostVisible);
641
642         deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
643
644         deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer));
645         deMemcpy(ptr + m_offsetInBuffer, &m_indirectBufferContents[0], static_cast<size_t>(dataSize));
646
647         if (m_dataFromComputeShader)
648         {
649                 // Negate all the buffer data and let a compute shader restore it to original.
650                 for (int i = 0; i < static_cast<int>(indirectBufferSize); i++)
651                 {
652                         ptr[i] = static_cast<deUint8>(~ptr[i]);
653                 }
654         }
655
656         vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
657
658         m_offsetInCountBuffer = sizeof(tcu::Vec3);
659         const vk::VkDeviceSize countBufferSize  = m_offsetInCountBuffer + sizeof(m_drawCount);
660
661         if (m_testIndirectCountExt != IndirectCountType::NONE)
662         {
663                 m_indirectCountBuffer = Buffer::createAndAlloc(m_vk,
664                                                                                                            m_context.getDevice(),
665                                                                                                            BufferCreateInfo(countBufferSize, usageFlags),
666                                                                                                            m_context.getDefaultAllocator(),
667                                                                                                            vk::MemoryRequirement::HostVisible);
668
669                 deUint8* countBufferPtr = reinterpret_cast<deUint8*>(m_indirectCountBuffer->getBoundMemory().getHostPtr());
670
671                 // For IndirectCountType::PARAM_LIMIT, the real limit will be set using the call parameter.
672                 if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
673                         *(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? 0u : m_indirectCountExtDrawPadding);
674                 else
675                         *(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? 1u : m_drawCount + m_indirectCountExtDrawPadding);
676
677                 if (m_dataFromComputeShader)
678                 {
679                         // Negate all the buffer data and let a compute shader restore it to original.
680                         for (int i = 0; i < static_cast<int>(countBufferSize); i++)
681                         {
682                                 countBufferPtr[i] = static_cast<deUint8>(~countBufferPtr[i]);
683                         }
684                 }
685
686                 vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectCountBuffer->getBoundMemory());
687         }
688
689 #ifndef CTS_USES_VULKANSC
690         if (m_groupParams->useSecondaryCmdBuffer)
691         {
692                 // record secondary command buffer
693                 if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
694                 {
695                         beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
696                         beginDynamicRender(*m_secCmdBuffer);
697                 }
698                 else
699                         beginSecondaryCmdBuffer(m_vk);
700
701                 draw(*m_secCmdBuffer);
702
703                 if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
704                         endDynamicRender(*m_secCmdBuffer);
705
706                 endCommandBuffer(m_vk, *m_secCmdBuffer);
707
708                 // record primary command buffer
709                 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
710
711                 if (m_dataFromComputeShader)
712                         negateDataUsingCompute(indirectBufferSize, countBufferSize);
713
714                 preRenderBarriers();
715
716                 if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
717                         beginDynamicRender(*m_cmdBuffer, vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
718
719                 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
720
721                 if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
722                         endDynamicRender(*m_cmdBuffer);
723
724                 endCommandBuffer(m_vk, *m_cmdBuffer);
725         }
726         else if (m_groupParams->useDynamicRendering)
727         {
728                 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
729
730                 if (m_dataFromComputeShader)
731                         negateDataUsingCompute(indirectBufferSize, countBufferSize);
732
733                 preRenderBarriers();
734                 beginDynamicRender(*m_cmdBuffer);
735
736                 draw(*m_cmdBuffer);
737
738                 endDynamicRender(*m_cmdBuffer);
739                 endCommandBuffer(m_vk, *m_cmdBuffer);
740         }
741 #endif // CTS_USES_VULKANSC
742
743         if (!m_groupParams->useDynamicRendering)
744         {
745                 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
746
747                 if (m_dataFromComputeShader)
748                         negateDataUsingCompute(indirectBufferSize, countBufferSize);
749
750                 preRenderBarriers();
751                 beginLegacyRender(*m_cmdBuffer);
752
753                 draw(*m_cmdBuffer);
754
755                 endLegacyRender(*m_cmdBuffer);
756                 endCommandBuffer(m_vk, *m_cmdBuffer);
757         }
758
759         submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
760
761         // Validation
762         tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
763         referenceFrame.allocLevel(0);
764
765         const deInt32 frameWidth        = referenceFrame.getWidth();
766         const deInt32 frameHeight       = referenceFrame.getHeight();
767
768         tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
769
770         ReferenceImageCoordinates refCoords;
771
772         for (int y = 0; y < frameHeight; y++)
773         {
774                 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
775
776                 for (int x = 0; x < frameWidth; x++)
777                 {
778                         const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
779
780                         if ((yCoord >= refCoords.bottom &&
781                                  yCoord <= refCoords.top        &&
782                                  xCoord >= refCoords.left       &&
783                                  xCoord <= refCoords.right))
784                                 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
785                 }
786         }
787
788         const vk::VkOffset3D zeroOffset                                 = { 0, 0, 0 };
789         const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
790                 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
791
792         qpTestResult res = QP_TEST_RESULT_PASS;
793
794         if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
795                 referenceFrame.getLevel(0), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
796         {
797                 res = QP_TEST_RESULT_FAIL;
798         }
799
800         return tcu::TestStatus(res, qpGetTestResultName(res));
801 }
802
803 template<class FirstInstanceSupport>
804 IndirectDrawInstanced<FirstInstanceSupport>::IndirectDrawInstanced (Context &context, TestSpec testSpec)
805         : IndirectDraw(context, testSpec)
806 {
807         if (!FirstInstanceSupport::isTestSupported(m_context.getDeviceFeatures()))
808         {
809                 throw tcu::NotSupportedError("Required 'drawIndirectFirstInstance' feature is not supported");
810         }
811 }
812
813 template<class FirstInstanceSupport>
814 tcu::TestStatus IndirectDrawInstanced<FirstInstanceSupport>::iterate (void)
815 {
816         tcu::TestLog&           log             = m_context.getTestContext().getLog();
817         const vk::VkQueue       queue   = m_context.getUniversalQueue();
818         const vk::VkDevice      device  = m_context.getDevice();
819
820                                         m_drawCount                     = 2;
821                                         m_offsetInBuffer        = sizeof(m_junkData);
822         const deUint32  m_bufferDrawCount       = 2u * m_drawCount;
823
824         if (m_drawType == DRAW_TYPE_SEQUENTIAL)
825         {
826                 switch (m_topology)
827                 {
828                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
829                         {
830                                 vk::VkDrawIndirectCommand drawCmd[] =
831                                 {
832                                         {
833                                                 3,                                                                                      //vertexCount
834                                                 4,                                                                                      //instanceCount
835                                                 2,                                                                                      //firstVertex
836                                                 FirstInstanceSupport::getFirstInstance()        //firstInstance
837                                         },
838                                         { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
839                                         {
840                                                 3,                                                                                      //vertexCount
841                                                 4,                                                                                      //instanceCount
842                                                 5,                                                                                      //firstVertex
843                                                 FirstInstanceSupport::getFirstInstance()        //firstInstance
844                                         }
845                                 };
846                                 addCommand(drawCmd[0]);
847                                 addCommand(drawCmd[1]);
848                                 addCommand(drawCmd[2]);
849                                 if (m_testIndirectCountExt != IndirectCountType::NONE)
850                                 {
851                                         // Add padding data to the buffer to make sure it's large enough.
852                                         for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
853                                         {
854                                                 addCommand(drawCmd[1]);
855                                                 addCommand(drawCmd[1]);
856                                         }
857                                 }
858                                 break;
859                         }
860                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
861                         {
862                                 vk::VkDrawIndirectCommand drawCmd[] =
863                                 {
864                                         {
865                                                 4,                                                                                      //vertexCount
866                                                 4,                                                                                      //instanceCount
867                                                 2,                                                                                      //firstVertex
868                                                 FirstInstanceSupport::getFirstInstance()        //firstInstance
869                                         },
870                                         { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 },
871                                         {
872                                                 4,                                                                                      //vertexCount
873                                                 4,                                                                                      //instanceCount
874                                                 6,                                                                                      //firstVertex
875                                                 FirstInstanceSupport::getFirstInstance()        //firstInstance
876                                         }
877                                 };
878                                 addCommand(drawCmd[0]);
879                                 addCommand(drawCmd[1]);
880                                 addCommand(drawCmd[2]);
881                                 if (m_testIndirectCountExt != IndirectCountType::NONE)
882                                 {
883                                         // Add padding data to the buffer to make sure it's large enough.
884                                         for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
885                                         {
886                                                 addCommand(drawCmd[1]);
887                                                 addCommand(drawCmd[1]);
888                                         }
889                                 }
890                                 break;
891                         }
892                         default:
893                                 TCU_FAIL("impossible");
894                                 break;
895                 }
896
897                 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndirectCommand);
898         }
899         else if (m_drawType == DRAW_TYPE_INDEXED)
900         {
901                 switch (m_topology)
902                 {
903                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
904                         {
905                                 vk::VkDrawIndexedIndirectCommand drawCmd[] =
906                                 {
907                                         {
908                                                 3,                                                                                      // indexCount
909                                                 4,                                                                                      // instanceCount
910                                                 2,                                                                                      // firstIndex
911                                                 VERTEX_OFFSET,                                                          // vertexOffset
912                                                 FirstInstanceSupport::getFirstInstance()        // firstInstance
913                                         },
914                                         { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 },        // junk (stride)
915                                         {
916                                                 3,                                                                                      // indexCount
917                                                 4,                                                                                      // instanceCount
918                                                 5,                                                                                      // firstIndex
919                                                 VERTEX_OFFSET,                                                          // vertexOffset
920                                                 FirstInstanceSupport::getFirstInstance()        // firstInstance
921                                         }
922                                 };
923                                 addCommand(drawCmd[0]);
924                                 addCommand(drawCmd[1]);
925                                 addCommand(drawCmd[2]);
926                                 if (m_testIndirectCountExt != IndirectCountType::NONE)
927                                 {
928                                         // Add padding data to the buffer to make sure it's large enough.
929                                         for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
930                                         {
931                                                 addCommand(drawCmd[1]);
932                                                 addCommand(drawCmd[1]);
933                                         }
934                                 }
935                                 break;
936                         }
937                         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
938                         {
939                                 vk::VkDrawIndexedIndirectCommand drawCmd[] =
940                                 {
941                                         {
942                                                 4,                                                                                      // indexCount
943                                                 4,                                                                                      // instanceCount
944                                                 2,                                                                                      // firstIndex
945                                                 VERTEX_OFFSET,                                                          // vertexOffset
946                                                 FirstInstanceSupport::getFirstInstance()        // firstInstance
947                                         },
948                                         { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 },        // junk (stride)
949                                         {
950                                                 4,                                                                                      // indexCount
951                                                 4,                                                                                      // instanceCount
952                                                 6,                                                                                      // firstIndex
953                                                 VERTEX_OFFSET,                                                          // vertexOffset
954                                                 FirstInstanceSupport::getFirstInstance()        // firstInstance
955                                         }
956                                 };
957                                 addCommand(drawCmd[0]);
958                                 addCommand(drawCmd[1]);
959                                 addCommand(drawCmd[2]);
960                                 if (m_testIndirectCountExt != IndirectCountType::NONE)
961                                 {
962                                         // Add padding data to the buffer to make sure it's large enough.
963                                         for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
964                                         {
965                                                 addCommand(drawCmd[1]);
966                                                 addCommand(drawCmd[1]);
967                                         }
968                                 }
969                                 break;
970                         }
971                         default:
972                                 TCU_FAIL("impossible");
973                                 break;
974                 }
975
976                 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndexedIndirectCommand);
977         }
978
979         const vk::VkDeviceSize dataSize                         = m_indirectBufferContents.size();
980         const vk::VkDeviceSize indirectBufferSize       = dataSize + m_offsetInBuffer;
981         vk::VkBufferUsageFlags  usageFlags                      = vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
982         if (m_dataFromComputeShader)
983                 usageFlags |= vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
984
985         m_indirectBuffer = Buffer::createAndAlloc(      m_vk,
986                                                                                                 m_context.getDevice(),
987                                                                                                 BufferCreateInfo(indirectBufferSize, usageFlags),
988                                                                                                 m_context.getDefaultAllocator(),
989                                                                                                 vk::MemoryRequirement::HostVisible);
990
991         deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
992
993         deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer));
994         deMemcpy((ptr + m_offsetInBuffer), &m_indirectBufferContents[0], static_cast<size_t>(dataSize));
995
996         if (m_dataFromComputeShader)
997         {
998                 // Negate all the buffer data and let a compute shader restore it to original.
999                 for (int i = 0; i < static_cast<int>(indirectBufferSize); i++)
1000                 {
1001                         ptr[i] = static_cast<deUint8>(~ptr[i]);
1002                 }
1003         }
1004
1005         vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
1006
1007         m_offsetInCountBuffer = sizeof(tcu::Vec3);
1008         const vk::VkDeviceSize  countBufferSize = m_offsetInCountBuffer + sizeof(m_drawCount);
1009
1010         if (m_testIndirectCountExt != IndirectCountType::NONE)
1011         {
1012                 m_indirectCountBuffer = Buffer::createAndAlloc(m_vk,
1013                                                                                                            m_context.getDevice(),
1014                                                                                                            BufferCreateInfo(countBufferSize, usageFlags),
1015                                                                                                            m_context.getDefaultAllocator(),
1016                                                                                                            vk::MemoryRequirement::HostVisible);
1017
1018                 deUint8* countBufferPtr = reinterpret_cast<deUint8*>(m_indirectCountBuffer->getBoundMemory().getHostPtr());
1019
1020                 // For IndirectCountType::PARAM_LIMIT, the real limit will be set using the call parameter.
1021                 if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
1022                         *(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? 0u : m_indirectCountExtDrawPadding);
1023                 else
1024                         *(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = 1u;
1025
1026                 if (m_dataFromComputeShader)
1027                 {
1028                         // Negate all the buffer data and let a compute shader restore it to original.
1029                         for (int i = 0; i < static_cast<int>(countBufferSize); i++)
1030                         {
1031                                 countBufferPtr[i] = static_cast<deUint8>(~countBufferPtr[i]);
1032                         }
1033                 }
1034
1035                 vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectCountBuffer->getBoundMemory());
1036         }
1037
1038 #ifndef CTS_USES_VULKANSC
1039         if (m_groupParams->useSecondaryCmdBuffer)
1040         {
1041                 // record secondary command buffer
1042                 if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1043                 {
1044                         beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1045                         beginDynamicRender(*m_secCmdBuffer);
1046                 }
1047                 else
1048                         beginSecondaryCmdBuffer(m_vk);
1049
1050                 draw(*m_secCmdBuffer);
1051
1052                 if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1053                         endDynamicRender(*m_secCmdBuffer);
1054
1055                 endCommandBuffer(m_vk, *m_secCmdBuffer);
1056
1057                 // record primary command buffer
1058                 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1059
1060                 if (m_dataFromComputeShader)
1061                         negateDataUsingCompute(indirectBufferSize, countBufferSize);
1062
1063                 preRenderBarriers();
1064
1065                 if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1066                         beginDynamicRender(*m_cmdBuffer, vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
1067
1068                 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
1069
1070                 if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1071                         endDynamicRender(*m_cmdBuffer);
1072
1073                 endCommandBuffer(m_vk, *m_cmdBuffer);
1074         }
1075         else if(m_groupParams->useDynamicRendering)
1076         {
1077                 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1078
1079                 if (m_dataFromComputeShader)
1080                         negateDataUsingCompute(indirectBufferSize, countBufferSize);
1081
1082                 preRenderBarriers();
1083                 beginDynamicRender(*m_cmdBuffer);
1084                 draw(*m_cmdBuffer);
1085                 endDynamicRender(*m_cmdBuffer);
1086
1087                 endCommandBuffer(m_vk, *m_cmdBuffer);
1088         }
1089 #endif // CTS_USES_VULKANSC
1090
1091         if (!m_groupParams->useDynamicRendering)
1092         {
1093                 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1094
1095                 if (m_dataFromComputeShader)
1096                         negateDataUsingCompute(indirectBufferSize, countBufferSize);
1097
1098                 preRenderBarriers();
1099                 beginLegacyRender(*m_cmdBuffer);
1100                 draw(*m_cmdBuffer);
1101                 endLegacyRender(*m_cmdBuffer);
1102
1103                 endCommandBuffer(m_vk, *m_cmdBuffer);
1104         }
1105
1106         submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
1107
1108         // Validation
1109         VK_CHECK(m_vk.queueWaitIdle(queue));
1110
1111         tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5 + static_cast<float>(HEIGHT)));
1112
1113         referenceFrame.allocLevel(0);
1114
1115         const deInt32 frameWidth        = referenceFrame.getWidth();
1116         const deInt32 frameHeight       = referenceFrame.getHeight();
1117
1118         tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1119
1120         ReferenceImageInstancedCoordinates refInstancedCoords;
1121
1122         for (int y = 0; y < frameHeight; y++)
1123         {
1124                 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
1125
1126                 for (int x = 0; x < frameWidth; x++)
1127                 {
1128                         const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
1129
1130                         if ((yCoord >= refInstancedCoords.bottom        &&
1131                                  yCoord <= refInstancedCoords.top               &&
1132                                  xCoord >= refInstancedCoords.left              &&
1133                                  xCoord <= refInstancedCoords.right))
1134                                 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
1135                 }
1136         }
1137
1138         const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
1139         const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
1140                 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1141
1142         qpTestResult res = QP_TEST_RESULT_PASS;
1143
1144         if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
1145                 referenceFrame.getLevel(0), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
1146         {
1147                 res = QP_TEST_RESULT_FAIL;
1148         }
1149
1150         return tcu::TestStatus(res, qpGetTestResultName(res));
1151 }
1152
1153 void checkSupport(Context& context, IndirectDraw::TestSpec testSpec)
1154 {
1155         if (testSpec.testIndirectCountExt != IndirectCountType::NONE)
1156                 context.requireDeviceFunctionality("VK_KHR_draw_indirect_count");
1157
1158         if (testSpec.groupParams->useDynamicRendering)
1159                 context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
1160 }
1161
1162 }       // anonymous
1163
1164 IndirectDrawTests::IndirectDrawTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams)
1165         : TestCaseGroup         (testCtx, "indirect_draw", "indirect drawing simple geometry")
1166         , m_groupParams         (groupParams)
1167 {
1168         /* Left blank on purpose */
1169 }
1170
1171 IndirectDrawTests::~IndirectDrawTests (void) {}
1172
1173
1174 void IndirectDrawTests::init (void)
1175 {
1176         for (auto dataFromCompute : {false, true})
1177         for (int drawTypeIdx = 0; drawTypeIdx < DRAWTYPE_LAST; drawTypeIdx++)
1178         {
1179                 // reduce number of tests for dynamic rendering cases where secondary command buffer is used
1180                 if (m_groupParams->useSecondaryCmdBuffer && (dataFromCompute == m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass))
1181                         continue;
1182
1183                 std::string drawTypeStr;
1184                 switch (drawTypeIdx)
1185                 {
1186                         case DRAW_TYPE_SEQUENTIAL:
1187                                 drawTypeStr = "sequential";
1188                                 break;
1189                         case DRAW_TYPE_INDEXED:
1190                                 drawTypeStr = "indexed";
1191                                 break;
1192                         default:
1193                                 TCU_FAIL("impossible");
1194                 }
1195
1196                 if (dataFromCompute)
1197                         drawTypeStr += "_data_from_compute";
1198
1199                 tcu::TestCaseGroup* drawTypeGroup = new tcu::TestCaseGroup(m_testCtx, drawTypeStr.c_str(), ("Draws geometry using " + drawTypeStr + "draw call").c_str());
1200                 {
1201                         tcu::TestCaseGroup* indirectDrawGroup                   = new tcu::TestCaseGroup(m_testCtx, "indirect_draw", "Draws geometry");
1202                         tcu::TestCaseGroup* indirectDrawCountGroup              = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_count", "Draws geometry with VK_KHR_draw_indirect_count extension");
1203                         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");
1204                         {
1205                                 IndirectDraw::TestSpec testSpec(m_groupParams);
1206                                 testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1207                                 testSpec.dataFromCompute = dataFromCompute;
1208                                 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetch.vert";
1209                                 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1210                                 if (dataFromCompute)
1211                                         testSpec.shaders[glu::SHADERTYPE_COMPUTE] = "vulkan/draw/NegateData.comp";
1212
1213                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1214                                 indirectDrawGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1215                                         (m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1216                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1217                                 indirectDrawGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1218                                         (m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1219
1220                                 testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1221                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1222                                 indirectDrawCountGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1223                                         (m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1224                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1225                                 indirectDrawCountGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1226                                         (m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1227
1228                                 testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1229                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1230                                 indirectDrawParamCountGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1231                                         (m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1232                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1233                                 indirectDrawParamCountGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1234                                         (m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1235                         }
1236                         drawTypeGroup->addChild(indirectDrawGroup);
1237                         drawTypeGroup->addChild(indirectDrawCountGroup);
1238                         drawTypeGroup->addChild(indirectDrawParamCountGroup);
1239
1240                         {
1241                                 tcu::TestCaseGroup* indirectDrawFirstInstanceGroup                              = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_first_instance", "Draws geometry with different first instance in one commandbuffer");
1242                                 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");
1243                                 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");
1244                                 {
1245                                         IndirectDraw::TestSpec testSpec(m_groupParams);
1246                                         testSpec.testFirstInstanceNdx = true;
1247                                         testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1248                                         testSpec.dataFromCompute = dataFromCompute;
1249                                         testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstanceIndex.vert";
1250                                         testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1251                                         if (dataFromCompute)
1252                                                 testSpec.shaders[glu::SHADERTYPE_COMPUTE] = "vulkan/draw/NegateData.comp";
1253
1254                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1255                                         indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1256                                                 (m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1257                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1258                                         indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1259                                                 (m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1260
1261                                         testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1262                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1263                                         indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1264                                                 (m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1265                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1266                                         indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1267                                                 (m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1268
1269                                         testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1270                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1271                                         indirectDrawParamCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1272                                                 (m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1273                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1274                                         indirectDrawParamCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1275                                                 (m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1276                                 }
1277                                 drawTypeGroup->addChild(indirectDrawFirstInstanceGroup);
1278                                 drawTypeGroup->addChild(indirectDrawCountFirstInstanceGroup);
1279                                 drawTypeGroup->addChild(indirectDrawParamCountFirstInstanceGroup);
1280                         }
1281
1282                         tcu::TestCaseGroup* indirectDrawInstancedGroup                          = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_instanced", "Draws an instanced geometry");
1283                         tcu::TestCaseGroup* indirectDrawCountInstancedGroup                     = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_count_instanced", "Draws an instanced geometry with VK_KHR_draw_indirect_count extension");
1284                         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");
1285                         {
1286                                 tcu::TestCaseGroup*     indirectDrawNoFirstInstanceGroup                        = new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance");
1287                                 tcu::TestCaseGroup*     indirectDrawCountNoFirstInstanceGroup           = new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance");
1288                                 tcu::TestCaseGroup*     indirectDrawParamCountNoFirstInstanceGroup      = new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance");
1289                                 {
1290                                         typedef IndirectDrawInstanced<FirstInstanceNotSupported> IDFirstInstanceNotSupported;
1291
1292                                         IDFirstInstanceNotSupported::TestSpec testSpec(m_groupParams);
1293                                         testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1294                                         testSpec.dataFromCompute = dataFromCompute;
1295
1296                                         testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstanced.vert";
1297                                         testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1298                                         if (dataFromCompute)
1299                                                 testSpec.shaders[glu::SHADERTYPE_COMPUTE] = "vulkan/draw/NegateData.comp";
1300
1301                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1302                                         indirectDrawNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1303                                                 (m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1304                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1305                                         indirectDrawNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1306                                                 (m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1307
1308                                         testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1309                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1310                                         indirectDrawCountNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1311                                                 (m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1312                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1313                                         indirectDrawCountNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1314                                                 (m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1315
1316                                         testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1317                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1318                                         indirectDrawParamCountNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1319                                                 (m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1320                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1321                                         indirectDrawParamCountNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1322                                                 (m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1323                                 }
1324                                 indirectDrawInstancedGroup->addChild(indirectDrawNoFirstInstanceGroup);
1325                                 indirectDrawCountInstancedGroup->addChild(indirectDrawCountNoFirstInstanceGroup);
1326                                 indirectDrawParamCountInstancedGroup->addChild(indirectDrawParamCountNoFirstInstanceGroup);
1327
1328                                 tcu::TestCaseGroup*     indirectDrawFirstInstanceGroup                          = new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature");
1329                                 tcu::TestCaseGroup*     indirectDrawCountFirstInstanceGroup                     = new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature");
1330                                 tcu::TestCaseGroup*     indirectDrawParamCountFirstInstanceGroup        = new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature");
1331                                 {
1332                                         typedef IndirectDrawInstanced<FirstInstanceSupported> IDFirstInstanceSupported;
1333
1334                                         IDFirstInstanceSupported::TestSpec testSpec(m_groupParams);
1335                                         testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1336                                         testSpec.dataFromCompute = dataFromCompute;
1337
1338                                         testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstancedFirstInstance.vert";
1339                                         testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1340                                         if (dataFromCompute)
1341                                                 testSpec.shaders[glu::SHADERTYPE_COMPUTE] = "vulkan/draw/NegateData.comp";
1342
1343                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1344                                         indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1345                                                 (m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1346                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1347                                         indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1348                                                 (m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1349
1350                                         testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1351                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1352                                         indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1353                                                 (m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1354                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1355                                         indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1356                                                 (m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1357
1358                                         testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1359                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1360                                         indirectDrawParamCountFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1361                                                 (m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1362                                         testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1363                                         indirectDrawParamCountFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1364                                                 (m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1365                                 }
1366                                 indirectDrawInstancedGroup->addChild(indirectDrawFirstInstanceGroup);
1367                                 indirectDrawCountInstancedGroup->addChild(indirectDrawCountFirstInstanceGroup);
1368                                 indirectDrawParamCountInstancedGroup->addChild(indirectDrawParamCountFirstInstanceGroup);
1369                         }
1370                         drawTypeGroup->addChild(indirectDrawInstancedGroup);
1371                         drawTypeGroup->addChild(indirectDrawCountInstancedGroup);
1372                         drawTypeGroup->addChild(indirectDrawParamCountInstancedGroup);
1373                 }
1374
1375                 addChild(drawTypeGroup);
1376         }
1377 }
1378
1379 }       // DrawTests
1380 }       // vkt