xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/draw/vktDrawIndirectTest.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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 #include <numeric>
48 #include <vector>
49 
50 namespace vkt
51 {
52 namespace Draw
53 {
54 namespace
55 {
56 
57 enum
58 {
59     VERTEX_OFFSET = 13
60 };
61 
62 enum
63 {
64     //INDEX_BUFFER_ALLOCATION_OFFSET = static_cast<int>(sizeof(tcu::Vec4)),
65     INDEX_BUFFER_ALLOCATION_OFFSET = 0,
66 };
67 
68 struct JunkData
69 {
JunkDatavkt::Draw::__anon95a9e7870111::JunkData70     JunkData()
71     {
72         for (auto &val : junk)
73             val = 0xEFBEADDEu;
74     }
75 
76     uint32_t junk[1024];
77 };
78 
79 enum DrawType
80 {
81     DRAW_TYPE_SEQUENTIAL,
82     DRAW_TYPE_INDEXED,
83 
84     DRAWTYPE_LAST
85 };
86 
87 enum class IndirectCountType
88 {
89     NONE,
90     BUFFER_LIMIT,
91     PARAM_LIMIT,
92 
93     LAST
94 };
95 
96 struct DrawTypedTestSpec : public TestSpecBase
97 {
DrawTypedTestSpecvkt::Draw::__anon95a9e7870111::DrawTypedTestSpec98     DrawTypedTestSpec(const SharedGroupParams groupParams_)
99         : TestSpecBase{{}, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, groupParams_}
100         , drawType(DRAWTYPE_LAST)
101         , testFirstInstanceNdx(false)
102         , testIndirectCountExt(IndirectCountType::NONE)
103         , dataFromCompute(false)
104         , useMemoryAccess(false)
105         , layerCount(1u)
106         , bindIndexBufferOffset(0ull)
107         , indexBufferAllocOffset(0ull)
108     {
109     }
110 
111     DrawType drawType;
112     bool testFirstInstanceNdx;
113     IndirectCountType testIndirectCountExt;
114     bool dataFromCompute;
115     bool useMemoryAccess;
116     uint32_t layerCount;
117     vk::VkDeviceSize bindIndexBufferOffset;
118     vk::VkDeviceSize indexBufferAllocOffset;
119 };
120 
121 class IndirectDraw : public DrawTestsBaseClass
122 {
123 public:
124     typedef DrawTypedTestSpec TestSpec;
125 
126     IndirectDraw(Context &context, TestSpec testSpec);
127     virtual tcu::TestStatus iterate(void);
128 
129     void draw(vk::VkCommandBuffer cmdBuffer);
130     template <typename T>
131     void addCommand(const T &);
132 
133 protected:
134     void setVertexBuffer(void);
135     void setFirstInstanceVertexBuffer(void);
136     void negateDataUsingCompute(vk::VkDeviceSize indirectBufferSize, vk::VkDeviceSize countBufferSize);
137     void countBufferBarrier(vk::VkBuffer indirectCountBuffer, vk::VkDeviceSize indirectCountBufferSize) const;
138 
139     std::vector<char> m_indirectBufferContents;
140     de::SharedPtr<Buffer> m_indirectBuffer;
141     vk::VkDeviceSize m_offsetInBuffer;
142     uint32_t m_strideInBuffer;
143 
144     const IndirectCountType m_testIndirectCountExt;
145     de::SharedPtr<Buffer> m_indirectCountBuffer;
146     vk::VkDeviceSize m_offsetInCountBuffer;
147     const uint32_t m_indirectCountExtDrawPadding;
148 
149     uint32_t m_drawCount;
150     JunkData m_junkData;
151 
152     const DrawType m_drawType;
153     const bool m_testFirstInstanceNdx;
154     bool m_isMultiDrawEnabled;
155     uint32_t m_drawIndirectMaxCount;
156     bool m_dataFromComputeShader;
157     bool m_useMemoryAccess;
158 
159     de::SharedPtr<Buffer> m_indexBuffer;
160     const vk::VkDeviceSize m_bindIndexBufferOffset;
161     const vk::VkDeviceSize m_indexBufferAllocOffset;
162 
163     vk::Move<vk::VkDescriptorSetLayout> m_descriptorSetLayout;
164     vk::Move<vk::VkDescriptorPool> m_descriptorPool;
165     vk::Move<vk::VkDescriptorSet> m_descriptorSetIndirectBuffer;
166     vk::Move<vk::VkDescriptorSet> m_descriptorSetCountBuffer;
167     vk::Move<vk::VkShaderModule> m_computeShaderModule;
168     vk::Move<vk::VkPipelineLayout> m_pipelineLayout;
169     vk::Move<vk::VkPipeline> m_computePipeline;
170 };
171 
172 struct FirstInstanceSupported
173 {
getFirstInstancevkt::Draw::__anon95a9e7870111::FirstInstanceSupported174     static uint32_t getFirstInstance(void)
175     {
176         return 2;
177     }
isTestSupportedvkt::Draw::__anon95a9e7870111::FirstInstanceSupported178     static bool isTestSupported(const vk::VkPhysicalDeviceFeatures &features)
179     {
180         return features.drawIndirectFirstInstance == VK_TRUE;
181     }
182 };
183 
184 struct FirstInstanceNotSupported
185 {
getFirstInstancevkt::Draw::__anon95a9e7870111::FirstInstanceNotSupported186     static uint32_t getFirstInstance(void)
187     {
188         return 0;
189     }
isTestSupportedvkt::Draw::__anon95a9e7870111::FirstInstanceNotSupported190     static bool isTestSupported(const vk::VkPhysicalDeviceFeatures &)
191     {
192         return true;
193     }
194 };
195 
196 template <class FirstInstanceSupport>
197 class IndirectDrawInstanced : public IndirectDraw
198 {
199 public:
200     IndirectDrawInstanced(Context &context, TestSpec testSpec);
201     virtual tcu::TestStatus iterate(void);
202 };
203 
setVertexBuffer(void)204 void IndirectDraw::setVertexBuffer(void)
205 {
206     int refVertexIndex = 2;
207 
208     if (m_drawType == DRAW_TYPE_INDEXED)
209     {
210         for (int unusedIdx = 0; unusedIdx < VERTEX_OFFSET; unusedIdx++)
211         {
212             m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
213         }
214         refVertexIndex += VERTEX_OFFSET;
215     }
216 
217     m_data.push_back(VertexElementData(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
218     m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
219 
220     switch (m_topology)
221     {
222     case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
223         m_data.push_back(
224             VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
225         m_data.push_back(
226             VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
227         m_data.push_back(
228             VertexElementData(tcu::Vec4(0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
229         m_data.push_back(
230             VertexElementData(tcu::Vec4(0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
231         m_data.push_back(
232             VertexElementData(tcu::Vec4(0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
233         m_data.push_back(
234             VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
235 
236         m_data.push_back(
237             VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refVertexIndex++));
238         m_data.push_back(
239             VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refVertexIndex++));
240         m_data.push_back(
241             VertexElementData(tcu::Vec4(0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refVertexIndex++));
242         m_data.push_back(
243             VertexElementData(tcu::Vec4(0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refVertexIndex++));
244         m_data.push_back(
245             VertexElementData(tcu::Vec4(0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refVertexIndex++));
246         m_data.push_back(
247             VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refVertexIndex++));
248         break;
249     case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
250         m_data.push_back(
251             VertexElementData(tcu::Vec4(-0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
252         m_data.push_back(
253             VertexElementData(tcu::Vec4(0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
254         m_data.push_back(
255             VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
256         m_data.push_back(
257             VertexElementData(tcu::Vec4(0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
258         m_data.push_back(
259             VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
260         m_data.push_back(
261             VertexElementData(tcu::Vec4(0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
262         m_data.push_back(
263             VertexElementData(tcu::Vec4(-0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
264         m_data.push_back(
265             VertexElementData(tcu::Vec4(0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
266 
267         m_data.push_back(
268             VertexElementData(tcu::Vec4(-0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refVertexIndex++));
269         m_data.push_back(
270             VertexElementData(tcu::Vec4(0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refVertexIndex++));
271         m_data.push_back(
272             VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refVertexIndex++));
273         m_data.push_back(
274             VertexElementData(tcu::Vec4(0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refVertexIndex++));
275         m_data.push_back(
276             VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refVertexIndex++));
277         m_data.push_back(
278             VertexElementData(tcu::Vec4(0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refVertexIndex++));
279         m_data.push_back(
280             VertexElementData(tcu::Vec4(-0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refVertexIndex++));
281         m_data.push_back(
282             VertexElementData(tcu::Vec4(0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refVertexIndex++));
283         break;
284     default:
285         DE_FATAL("Unknown topology");
286         break;
287     }
288 
289     m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
290 }
291 
setFirstInstanceVertexBuffer(void)292 void IndirectDraw::setFirstInstanceVertexBuffer(void)
293 {
294     if (m_context.getDeviceFeatures().drawIndirectFirstInstance != VK_TRUE)
295     {
296         TCU_THROW(NotSupportedError, "Required 'drawIndirectFirstInstance' feature is not supported");
297     }
298 
299     if (m_drawType == DRAW_TYPE_INDEXED)
300     {
301         for (int unusedIdx = 0; unusedIdx < VERTEX_OFFSET; unusedIdx++)
302         {
303             m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
304         }
305     }
306 
307     m_data.push_back(VertexElementData(tcu::Vec4(1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
308     m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
309 
310     switch (m_topology)
311     {
312     case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
313     {
314         int refInstanceIndex = 1;
315         m_data.push_back(
316             VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
317         m_data.push_back(
318             VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
319         m_data.push_back(
320             VertexElementData(tcu::Vec4(0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
321 
322         refInstanceIndex = 0;
323         m_data.push_back(
324             VertexElementData(tcu::Vec4(0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
325         m_data.push_back(
326             VertexElementData(tcu::Vec4(0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
327         m_data.push_back(
328             VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
329 
330         refInstanceIndex = 1;
331         m_data.push_back(
332             VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refInstanceIndex));
333         m_data.push_back(
334             VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refInstanceIndex));
335         m_data.push_back(
336             VertexElementData(tcu::Vec4(0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refInstanceIndex));
337 
338         refInstanceIndex = 0;
339         m_data.push_back(
340             VertexElementData(tcu::Vec4(0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refInstanceIndex));
341         m_data.push_back(
342             VertexElementData(tcu::Vec4(0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refInstanceIndex));
343         m_data.push_back(
344             VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refInstanceIndex));
345         break;
346     }
347     case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
348     {
349         int refInstanceIndex = 1;
350         m_data.push_back(
351             VertexElementData(tcu::Vec4(-0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
352         m_data.push_back(
353             VertexElementData(tcu::Vec4(0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
354         m_data.push_back(
355             VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
356         m_data.push_back(
357             VertexElementData(tcu::Vec4(0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
358 
359         refInstanceIndex = 0;
360         m_data.push_back(
361             VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
362         m_data.push_back(
363             VertexElementData(tcu::Vec4(0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
364         m_data.push_back(
365             VertexElementData(tcu::Vec4(-0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
366         m_data.push_back(
367             VertexElementData(tcu::Vec4(0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
368 
369         refInstanceIndex = 1;
370         m_data.push_back(
371             VertexElementData(tcu::Vec4(-0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refInstanceIndex));
372         m_data.push_back(
373             VertexElementData(tcu::Vec4(0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refInstanceIndex));
374         m_data.push_back(
375             VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refInstanceIndex));
376         m_data.push_back(
377             VertexElementData(tcu::Vec4(0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refInstanceIndex));
378 
379         refInstanceIndex = 0;
380         m_data.push_back(
381             VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refInstanceIndex));
382         m_data.push_back(
383             VertexElementData(tcu::Vec4(0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refInstanceIndex));
384         m_data.push_back(
385             VertexElementData(tcu::Vec4(-0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refInstanceIndex));
386         m_data.push_back(
387             VertexElementData(tcu::Vec4(0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::red().toVec(), refInstanceIndex));
388         break;
389     }
390     default:
391         DE_FATAL("Unknown topology");
392         break;
393     }
394 
395     m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
396 }
397 
398 // When testing indirect data generation from a compute shader, the original data is negated bitwise
399 // and compute shader restores it before being used in an indirect draw.
negateDataUsingCompute(vk::VkDeviceSize indirectBufferSize,vk::VkDeviceSize countBufferSize)400 void IndirectDraw::negateDataUsingCompute(vk::VkDeviceSize indirectBufferSize, vk::VkDeviceSize countBufferSize)
401 {
402     m_descriptorSetLayout =
403         vk::DescriptorSetLayoutBuilder()
404             .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
405             .build(m_vk, m_context.getDevice());
406     m_descriptorPool =
407         vk::DescriptorPoolBuilder()
408             .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u)
409             .build(m_vk, m_context.getDevice(), vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 2u);
410 
411     // Indirect buffer
412     {
413         m_descriptorSetIndirectBuffer =
414             vk::makeDescriptorSet(m_vk, m_context.getDevice(), *m_descriptorPool, *m_descriptorSetLayout);
415         const vk::VkDescriptorBufferInfo bufferDescriptorInfo =
416             vk::makeDescriptorBufferInfo(m_indirectBuffer->object(), 0ull, indirectBufferSize);
417         vk::DescriptorSetUpdateBuilder()
418             .writeSingle(*m_descriptorSetIndirectBuffer, vk::DescriptorSetUpdateBuilder::Location::binding(0u),
419                          vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescriptorInfo)
420             .update(m_vk, m_context.getDevice());
421     }
422 
423     // Indirect count buffer
424     if (m_testIndirectCountExt != IndirectCountType::NONE)
425     {
426         m_descriptorSetCountBuffer =
427             vk::makeDescriptorSet(m_vk, m_context.getDevice(), *m_descriptorPool, *m_descriptorSetLayout);
428         const vk::VkDescriptorBufferInfo bufferDescriptorInfo =
429             vk::makeDescriptorBufferInfo(m_indirectCountBuffer->object(), 0ull, countBufferSize);
430         vk::DescriptorSetUpdateBuilder()
431             .writeSingle(*m_descriptorSetCountBuffer, vk::DescriptorSetUpdateBuilder::Location::binding(0u),
432                          vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescriptorInfo)
433             .update(m_vk, m_context.getDevice());
434     }
435 
436     m_computeShaderModule = vk::createShaderModule(
437         m_vk, m_context.getDevice(), m_context.getBinaryCollection().get("vulkan/draw/NegateData.comp"), 0u);
438     m_pipelineLayout  = vk::makePipelineLayout(m_vk, m_context.getDevice(), *m_descriptorSetLayout);
439     m_computePipeline = makeComputePipeline(m_vk, m_context.getDevice(), *m_pipelineLayout, *m_computeShaderModule);
440 
441     const vk::VkBufferMemoryBarrier hostWriteBarrier =
442         vk::makeBufferMemoryBarrier(m_useMemoryAccess ? vk::VK_ACCESS_MEMORY_WRITE_BIT : vk::VK_ACCESS_HOST_WRITE_BIT,
443                                     m_useMemoryAccess ? vk::VK_ACCESS_MEMORY_READ_BIT : vk::VK_ACCESS_SHADER_READ_BIT,
444                                     m_indirectBuffer->object(), 0ull, indirectBufferSize);
445     const vk::VkBufferMemoryBarrier indirectDrawBarrier = vk::makeBufferMemoryBarrier(
446         m_useMemoryAccess ? vk::VK_ACCESS_MEMORY_WRITE_BIT : vk::VK_ACCESS_SHADER_WRITE_BIT,
447         m_useMemoryAccess ? vk::VK_ACCESS_MEMORY_READ_BIT : vk::VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
448         m_indirectBuffer->object(), 0ull, indirectBufferSize);
449 
450     m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *m_computePipeline);
451     m_vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0u, 1u,
452                                &m_descriptorSetIndirectBuffer.get(), 0u, DE_NULL);
453     m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_HOST_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
454                             (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier *)DE_NULL, 1, &hostWriteBarrier, 0,
455                             (const vk::VkImageMemoryBarrier *)DE_NULL);
456     m_vk.cmdDispatch(*m_cmdBuffer, 1, 1, 1);
457     m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
458                             vk::VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, (vk::VkDependencyFlags)0, 0,
459                             (const vk::VkMemoryBarrier *)DE_NULL, 1, &indirectDrawBarrier, 0,
460                             (const vk::VkImageMemoryBarrier *)DE_NULL);
461 
462     if (m_testIndirectCountExt != IndirectCountType::NONE)
463     {
464         m_vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0u, 1u,
465                                    &m_descriptorSetCountBuffer.get(), 0u, DE_NULL);
466         m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_HOST_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
467                                 (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier *)DE_NULL, 1, &hostWriteBarrier,
468                                 0, (const vk::VkImageMemoryBarrier *)DE_NULL);
469         m_vk.cmdDispatch(*m_cmdBuffer, 1, 1, 1);
470         m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
471                                 vk::VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, (vk::VkDependencyFlags)0, 0,
472                                 (const vk::VkMemoryBarrier *)DE_NULL, 1, &indirectDrawBarrier, 0,
473                                 (const vk::VkImageMemoryBarrier *)DE_NULL);
474     }
475 }
476 
IndirectDraw(Context & context,TestSpec testSpec)477 IndirectDraw::IndirectDraw(Context &context, TestSpec testSpec)
478     : DrawTestsBaseClass(context, testSpec.shaders[glu::SHADERTYPE_VERTEX], testSpec.shaders[glu::SHADERTYPE_FRAGMENT],
479                          testSpec.groupParams, testSpec.topology, testSpec.layerCount)
480     , m_testIndirectCountExt(testSpec.testIndirectCountExt)
481     , m_indirectCountExtDrawPadding(1u)
482     , m_drawType(testSpec.drawType)
483     , m_testFirstInstanceNdx(testSpec.testFirstInstanceNdx)
484     , m_dataFromComputeShader(testSpec.dataFromCompute)
485     , m_useMemoryAccess(testSpec.useMemoryAccess)
486     , m_bindIndexBufferOffset(testSpec.bindIndexBufferOffset)
487     , m_indexBufferAllocOffset(testSpec.indexBufferAllocOffset)
488 {
489     const auto &vki     = m_context.getInstanceInterface();
490     const auto physDev  = m_context.getPhysicalDevice();
491     const auto device   = m_context.getDevice();
492     const auto &devProp = m_context.getDeviceProperties();
493 
494     if (m_testFirstInstanceNdx)
495         setFirstInstanceVertexBuffer();
496     else
497         setVertexBuffer();
498 
499     initialize();
500 
501     if (testSpec.drawType == DRAW_TYPE_INDEXED)
502     {
503         const auto indexCount = m_data.size() - VERTEX_OFFSET;
504 
505         std::vector<uint32_t> indexVec(indexCount);
506         std::iota(indexVec.begin(), indexVec.end(), 0u);
507 
508         const auto bufferSize = de::dataSize(indexVec) + m_bindIndexBufferOffset;
509 
510         const vk::SimpleAllocator::OptionalOffsetParams offsetParams(
511             {devProp.limits.nonCoherentAtomSize, m_indexBufferAllocOffset});
512         vk::SimpleAllocator allocator(m_vk, device, vk::getPhysicalDeviceMemoryProperties(vki, physDev), offsetParams);
513 
514         m_indexBuffer =
515             Buffer::createAndAlloc(m_vk, device, BufferCreateInfo(bufferSize, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT),
516                                    allocator, vk::MemoryRequirement::HostVisible);
517 
518         const auto bufferStart = reinterpret_cast<char *>(m_indexBuffer->getBoundMemory().getHostPtr());
519         deMemset(bufferStart, 0xFF, static_cast<size_t>(m_bindIndexBufferOffset));
520         deMemcpy(bufferStart + m_bindIndexBufferOffset, de::dataOrNull(indexVec), de::dataSize(indexVec));
521 
522         vk::flushAlloc(m_vk, device, m_indexBuffer->getBoundMemory());
523     }
524 
525     // Check device for multidraw support:
526     if (!m_context.getDeviceFeatures().multiDrawIndirect || m_testFirstInstanceNdx)
527         m_isMultiDrawEnabled = false;
528     else
529         m_isMultiDrawEnabled = true;
530 
531     m_drawIndirectMaxCount = devProp.limits.maxDrawIndirectCount;
532 }
533 
534 template <>
addCommand(const vk::VkDrawIndirectCommand & command)535 void IndirectDraw::addCommand<vk::VkDrawIndirectCommand>(const vk::VkDrawIndirectCommand &command)
536 {
537     DE_ASSERT(m_drawType == DRAW_TYPE_SEQUENTIAL);
538 
539     const size_t currentSize = m_indirectBufferContents.size();
540 
541     m_indirectBufferContents.resize(currentSize + sizeof(command));
542 
543     deMemcpy(&m_indirectBufferContents[currentSize], &command, sizeof(command));
544 }
545 
546 template <>
addCommand(const vk::VkDrawIndexedIndirectCommand & command)547 void IndirectDraw::addCommand<vk::VkDrawIndexedIndirectCommand>(const vk::VkDrawIndexedIndirectCommand &command)
548 {
549     DE_ASSERT(m_drawType == DRAW_TYPE_INDEXED);
550 
551     const size_t currentSize = m_indirectBufferContents.size();
552 
553     m_indirectBufferContents.resize(currentSize + sizeof(command));
554 
555     deMemcpy(&m_indirectBufferContents[currentSize], &command, sizeof(command));
556 }
557 
draw(vk::VkCommandBuffer cmdBuffer)558 void IndirectDraw::draw(vk::VkCommandBuffer cmdBuffer)
559 {
560     const vk::VkDeviceSize vertexBufferOffset = 0;
561     const vk::VkBuffer vertexBuffer           = m_vertexBuffer->object();
562 
563     m_vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
564     m_vk.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
565     if (m_drawType == DRAW_TYPE_INDEXED)
566         m_vk.cmdBindIndexBuffer(cmdBuffer, m_indexBuffer->object(), m_bindIndexBufferOffset, vk::VK_INDEX_TYPE_UINT32);
567 
568     if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
569     {
570         switch (m_drawType)
571         {
572         case DRAW_TYPE_SEQUENTIAL:
573         {
574             if (m_testIndirectCountExt != IndirectCountType::NONE)
575             {
576                 const uint32_t maxDrawCount =
577                     m_drawCount +
578                     (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_indirectCountExtDrawPadding : 0u);
579                 m_vk.cmdDrawIndirectCount(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer,
580                                           m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
581                                           m_strideInBuffer);
582             }
583             else
584                 m_vk.cmdDrawIndirect(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount,
585                                      m_strideInBuffer);
586             break;
587         }
588         case DRAW_TYPE_INDEXED:
589         {
590             if (m_testIndirectCountExt != IndirectCountType::NONE)
591             {
592                 const uint32_t maxDrawCount =
593                     m_drawCount +
594                     (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_indirectCountExtDrawPadding : 0u);
595                 m_vk.cmdDrawIndexedIndirectCount(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer,
596                                                  m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
597                                                  m_strideInBuffer);
598             }
599             else
600                 m_vk.cmdDrawIndexedIndirect(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount,
601                                             m_strideInBuffer);
602             break;
603         }
604         default:
605             TCU_FAIL("impossible");
606         }
607     }
608     else
609     {
610         for (uint32_t drawNdx = 0; drawNdx < m_drawCount; drawNdx++)
611         {
612             switch (m_drawType)
613             {
614             case DRAW_TYPE_SEQUENTIAL:
615             {
616                 if (m_testIndirectCountExt != IndirectCountType::NONE)
617                 {
618                     const uint32_t maxDrawCount = (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ?
619                                                        m_drawCount + m_indirectCountExtDrawPadding :
620                                                        1u);
621                     m_vk.cmdDrawIndirectCount(
622                         cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx * m_strideInBuffer,
623                         m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount, m_strideInBuffer);
624                 }
625                 else
626                     m_vk.cmdDrawIndirect(cmdBuffer, m_indirectBuffer->object(),
627                                          m_offsetInBuffer + drawNdx * m_strideInBuffer, 1u, 0u);
628                 break;
629             }
630             case DRAW_TYPE_INDEXED:
631             {
632                 if (m_testIndirectCountExt != IndirectCountType::NONE)
633                 {
634                     const uint32_t maxDrawCount = (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ?
635                                                        m_drawCount + m_indirectCountExtDrawPadding :
636                                                        1u);
637                     m_vk.cmdDrawIndexedIndirectCount(
638                         cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx * m_strideInBuffer,
639                         m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount, m_strideInBuffer);
640                 }
641                 else
642                     m_vk.cmdDrawIndexedIndirect(cmdBuffer, m_indirectBuffer->object(),
643                                                 m_offsetInBuffer + drawNdx * m_strideInBuffer, 1u, 0u);
644                 break;
645             }
646             default:
647                 TCU_FAIL("impossible");
648             }
649         }
650     }
651 }
652 
iterate(void)653 tcu::TestStatus IndirectDraw::iterate(void)
654 {
655     tcu::TestLog &log         = m_context.getTestContext().getLog();
656     const vk::VkQueue queue   = m_context.getUniversalQueue();
657     const vk::VkDevice device = m_context.getDevice();
658 
659     m_drawCount                      = 2;
660     m_offsetInBuffer                 = sizeof(m_junkData);
661     const uint32_t m_bufferDrawCount = 2u * m_drawCount;
662 
663     if (m_drawType == DRAW_TYPE_SEQUENTIAL)
664     {
665         switch (m_topology)
666         {
667         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
668         {
669             vk::VkDrawIndirectCommand drawCommands[] = {
670                 {
671                     3u,                                //vertexCount
672                     1u,                                //instanceCount
673                     2u,                                //firstVertex
674                     (m_testFirstInstanceNdx ? 1u : 0u) //firstInstance
675                 },
676                 {(uint32_t)-4, (uint32_t)-2, (uint32_t)-11, (uint32_t)-9}, // junk (stride)
677                 {
678                     3u, //vertexCount
679                     1u, //instanceCount
680                     5u, //firstVertex
681                     0u  //firstInstance
682                 },
683                 {
684                     3u, //vertexCount
685                     1u, //instanceCount
686                     8u, //firstVertex
687                     0u  //firstInstance
688                 },
689                 {
690                     3u,  //vertexCount
691                     1u,  //instanceCount
692                     11u, //firstVertex
693                     0u   //firstInstance
694                 }};
695             addCommand(drawCommands[0]);
696             addCommand(drawCommands[1]);
697             addCommand(drawCommands[2]);
698             addCommand(drawCommands[1]);
699             if (m_testIndirectCountExt != IndirectCountType::NONE)
700             {
701                 // Add padding data to the buffer to make sure it's large enough.
702                 for (uint32_t i = 0; i < m_bufferDrawCount; ++i)
703                 {
704                     addCommand(drawCommands[3]);
705                     addCommand(drawCommands[1]);
706                     addCommand(drawCommands[4]);
707                     addCommand(drawCommands[1]);
708                 }
709             }
710             break;
711         }
712         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
713         {
714             vk::VkDrawIndirectCommand drawCommands[] = {
715                 {
716                     4u,                                //vertexCount
717                     1u,                                //instanceCount
718                     2u,                                //firstVertex
719                     (m_testFirstInstanceNdx ? 1u : 0u) //firstInstance
720                 },
721                 {(uint32_t)-4, (uint32_t)-2, (uint32_t)-11, (uint32_t)-9}, // junk (stride)
722                 {
723                     4u, //vertexCount
724                     1u, //instanceCount
725                     6u, //firstVertex
726                     0u  //firstInstance
727                 },
728                 {
729                     4u,  //vertexCount
730                     1u,  //instanceCount
731                     10u, //firstVertex
732                     0u   //firstInstance
733                 },
734                 {
735                     4u,  //vertexCount
736                     1u,  //instanceCount
737                     14u, //firstVertex
738                     0u   //firstInstance
739                 }};
740             addCommand(drawCommands[0]);
741             addCommand(drawCommands[1]);
742             addCommand(drawCommands[2]);
743             addCommand(drawCommands[1]);
744             if (m_testIndirectCountExt != IndirectCountType::NONE)
745             {
746                 // Add padding data to the buffer to make sure it's large enough.
747                 for (uint32_t i = 0; i < m_bufferDrawCount; ++i)
748                 {
749                     addCommand(drawCommands[3]);
750                     addCommand(drawCommands[1]);
751                     addCommand(drawCommands[4]);
752                     addCommand(drawCommands[1]);
753                 }
754             }
755             break;
756         }
757         default:
758             TCU_FAIL("impossible");
759         }
760 
761         m_strideInBuffer = 2 * (uint32_t)sizeof(vk::VkDrawIndirectCommand);
762     }
763     else if (m_drawType == DRAW_TYPE_INDEXED)
764     {
765         switch (m_topology)
766         {
767         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
768         {
769             vk::VkDrawIndexedIndirectCommand drawCommands[] = {
770                 {
771                     3u,                                 // indexCount
772                     1u,                                 // instanceCount
773                     2u,                                 // firstIndex
774                     VERTEX_OFFSET,                      // vertexOffset
775                     (m_testFirstInstanceNdx ? 1u : 0u), // firstInstance
776                 },
777                 {(uint32_t)-4, (uint32_t)-2, (uint32_t)-11, (int32_t)9, (uint32_t)-7}, // junk (stride)
778                 {
779                     3u,            // indexCount
780                     1u,            // instanceCount
781                     5u,            // firstIndex
782                     VERTEX_OFFSET, // vertexOffset
783                     0u             // firstInstance
784                 },
785                 {
786                     3u,            //vertexCount
787                     1u,            //instanceCount
788                     8u,            //firstVertex
789                     VERTEX_OFFSET, //vertexOffset
790                     0u             //firstInstance
791                 },
792                 {
793                     3u,            //vertexCount
794                     1u,            //instanceCount
795                     11u,           //firstVertex
796                     VERTEX_OFFSET, //vertexOffset
797                     0u             //firstInstance
798                 }};
799             addCommand(drawCommands[0]);
800             addCommand(drawCommands[1]);
801             addCommand(drawCommands[2]);
802             addCommand(drawCommands[1]);
803             if (m_testIndirectCountExt != IndirectCountType::NONE)
804             {
805                 // Add padding data to the buffer to make sure it's large enough.
806                 for (uint32_t i = 0; i < m_bufferDrawCount; ++i)
807                 {
808                     addCommand(drawCommands[3]);
809                     addCommand(drawCommands[1]);
810                     addCommand(drawCommands[4]);
811                     addCommand(drawCommands[1]);
812                 }
813             }
814             break;
815         }
816         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
817         {
818             vk::VkDrawIndexedIndirectCommand drawCommands[] = {
819                 {
820                     4u,                                 // indexCount
821                     1u,                                 // instanceCount
822                     2u,                                 // firstIndex
823                     VERTEX_OFFSET,                      // vertexOffset
824                     (m_testFirstInstanceNdx ? 1u : 0u), // firstInstance
825                 },
826                 {(uint32_t)-4, (uint32_t)-2, (uint32_t)-11, (int32_t)9, (uint32_t)-7}, // junk (stride)
827                 {
828                     4u,            // indexCount
829                     1u,            // instanceCount
830                     6u,            // firstIndex
831                     VERTEX_OFFSET, // vertexOffset
832                     0u             // firstInstance
833                 },
834                 {
835                     4u,            //vertexCount
836                     1u,            //instanceCount
837                     10u,           //firstVertex
838                     VERTEX_OFFSET, //vertexOffset
839                     0u             //firstInstance
840                 },
841                 {
842                     4u,            //vertexCount
843                     1u,            //instanceCount
844                     14u,           //firstVertex
845                     VERTEX_OFFSET, //vertexOffset
846                     0u             //firstInstance
847                 }};
848             addCommand(drawCommands[0]);
849             addCommand(drawCommands[1]);
850             addCommand(drawCommands[2]);
851             addCommand(drawCommands[1]);
852             if (m_testIndirectCountExt != IndirectCountType::NONE)
853             {
854                 // Add padding data to the buffer to make sure it's large enough.
855                 for (uint32_t i = 0; i < m_bufferDrawCount; ++i)
856                 {
857                     addCommand(drawCommands[3]);
858                     addCommand(drawCommands[1]);
859                     addCommand(drawCommands[4]);
860                     addCommand(drawCommands[1]);
861                 }
862             }
863             break;
864         }
865         default:
866             TCU_FAIL("impossible");
867         }
868 
869         m_strideInBuffer = 2 * (uint32_t)sizeof(vk::VkDrawIndexedIndirectCommand);
870     }
871 
872     const vk::VkDeviceSize dataSize           = m_indirectBufferContents.size();
873     const vk::VkDeviceSize indirectBufferSize = dataSize + m_offsetInBuffer;
874     vk::VkBufferUsageFlags usageFlags         = vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
875 
876     if (m_dataFromComputeShader)
877         usageFlags |= vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
878 
879     m_indirectBuffer = Buffer::createAndAlloc(
880         m_vk, m_context.getDevice(), BufferCreateInfo(indirectBufferSize, usageFlags), m_context.getDefaultAllocator(),
881         vk::MemoryRequirement::HostVisible, static_cast<vk::VkDeviceSize>(INDEX_BUFFER_ALLOCATION_OFFSET));
882 
883     uint8_t *ptr =
884         reinterpret_cast<uint8_t *>(m_indirectBuffer->getBoundMemory().getHostPtr()) + INDEX_BUFFER_ALLOCATION_OFFSET;
885 
886     deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer));
887     deMemcpy(ptr + m_offsetInBuffer, &m_indirectBufferContents[0], static_cast<size_t>(dataSize));
888 
889     if (m_dataFromComputeShader)
890     {
891         // Negate all the buffer data and let a compute shader restore it to original.
892         for (int i = 0; i < static_cast<int>(indirectBufferSize); i++)
893         {
894             ptr[i] = static_cast<uint8_t>(~ptr[i]);
895         }
896     }
897 
898     vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
899 
900     m_offsetInCountBuffer                  = sizeof(tcu::Vec3);
901     const vk::VkDeviceSize countBufferSize = m_offsetInCountBuffer + sizeof(m_drawCount);
902 
903     if (m_testIndirectCountExt != IndirectCountType::NONE)
904     {
905         m_indirectCountBuffer =
906             Buffer::createAndAlloc(m_vk, m_context.getDevice(), BufferCreateInfo(countBufferSize, usageFlags),
907                                    m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
908 
909         uint8_t *countBufferPtr = reinterpret_cast<uint8_t *>(m_indirectCountBuffer->getBoundMemory().getHostPtr());
910 
911         // For IndirectCountType::PARAM_LIMIT, the real limit will be set using the call parameter.
912         if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
913             *(uint32_t *)(countBufferPtr + m_offsetInCountBuffer) =
914                 m_drawCount +
915                 (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? 0u : m_indirectCountExtDrawPadding);
916         else
917             *(uint32_t *)(countBufferPtr + m_offsetInCountBuffer) =
918                 (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ?
919                      1u :
920                      m_drawCount + m_indirectCountExtDrawPadding);
921 
922         if (m_dataFromComputeShader)
923         {
924             // Negate all the buffer data and let a compute shader restore it to original.
925             for (int i = 0; i < static_cast<int>(countBufferSize); i++)
926             {
927                 countBufferPtr[i] = static_cast<uint8_t>(~countBufferPtr[i]);
928             }
929         }
930 
931         vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectCountBuffer->getBoundMemory());
932     }
933 
934 #ifndef CTS_USES_VULKANSC
935     if (m_groupParams->useSecondaryCmdBuffer)
936     {
937         // record secondary command buffer
938         if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
939         {
940             beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
941             beginDynamicRender(*m_secCmdBuffer);
942         }
943         else
944             beginSecondaryCmdBuffer(m_vk);
945 
946         draw(*m_secCmdBuffer);
947 
948         if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
949             endDynamicRender(*m_secCmdBuffer);
950 
951         endCommandBuffer(m_vk, *m_secCmdBuffer);
952 
953         // record primary command buffer
954         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
955 
956         if (m_dataFromComputeShader)
957             negateDataUsingCompute(indirectBufferSize, countBufferSize);
958 
959         preRenderBarriers();
960         if (m_testIndirectCountExt != IndirectCountType::NONE)
961             countBufferBarrier(m_indirectCountBuffer->object(), countBufferSize);
962 
963         if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
964             beginDynamicRender(*m_cmdBuffer, vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
965 
966         m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
967 
968         if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
969             endDynamicRender(*m_cmdBuffer);
970 
971         endCommandBuffer(m_vk, *m_cmdBuffer);
972     }
973     else if (m_groupParams->useDynamicRendering)
974     {
975         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
976 
977         if (m_dataFromComputeShader)
978             negateDataUsingCompute(indirectBufferSize, countBufferSize);
979 
980         preRenderBarriers();
981         if (m_testIndirectCountExt != IndirectCountType::NONE)
982             countBufferBarrier(m_indirectCountBuffer->object(), countBufferSize);
983         beginDynamicRender(*m_cmdBuffer);
984 
985         draw(*m_cmdBuffer);
986 
987         endDynamicRender(*m_cmdBuffer);
988         endCommandBuffer(m_vk, *m_cmdBuffer);
989     }
990 #endif // CTS_USES_VULKANSC
991 
992     if (!m_groupParams->useDynamicRendering)
993     {
994         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
995 
996         if (m_dataFromComputeShader)
997             negateDataUsingCompute(indirectBufferSize, countBufferSize);
998 
999         preRenderBarriers();
1000         if (m_testIndirectCountExt != IndirectCountType::NONE)
1001             countBufferBarrier(m_indirectCountBuffer->object(), countBufferSize);
1002         beginLegacyRender(*m_cmdBuffer);
1003 
1004         draw(*m_cmdBuffer);
1005 
1006         endLegacyRender(*m_cmdBuffer);
1007         endCommandBuffer(m_vk, *m_cmdBuffer);
1008     }
1009 
1010     submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
1011 
1012     // Validation
1013     tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)),
1014                                   (int)(0.5f + static_cast<float>(HEIGHT)));
1015     referenceFrame.allocLevel(0);
1016 
1017     const int32_t frameWidth  = referenceFrame.getWidth();
1018     const int32_t frameHeight = referenceFrame.getHeight();
1019 
1020     tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1021 
1022     ReferenceImageCoordinates refCoords;
1023 
1024     for (int y = 0; y < frameHeight; y++)
1025     {
1026         const float yCoord = (float)(y / (0.5 * frameHeight)) - 1.0f;
1027 
1028         for (int x = 0; x < frameWidth; x++)
1029         {
1030             const float xCoord = (float)(x / (0.5 * frameWidth)) - 1.0f;
1031 
1032             if ((yCoord >= refCoords.bottom && yCoord <= refCoords.top && xCoord >= refCoords.left &&
1033                  xCoord <= refCoords.right))
1034                 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
1035         }
1036     }
1037 
1038     const vk::VkOffset3D zeroOffset = {0, 0, 0};
1039     const tcu::ConstPixelBufferAccess renderedFrame =
1040         m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset,
1041                                         WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1042 
1043     qpTestResult res = QP_TEST_RESULT_PASS;
1044 
1045     if (!tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame.getLevel(0), renderedFrame, 0.05f,
1046                            tcu::COMPARE_LOG_RESULT))
1047     {
1048         res = QP_TEST_RESULT_FAIL;
1049     }
1050 
1051     return tcu::TestStatus(res, qpGetTestResultName(res));
1052 }
1053 
countBufferBarrier(vk::VkBuffer indirectCountBuffer,vk::VkDeviceSize indirectCountBufferSize) const1054 void IndirectDraw::countBufferBarrier(vk::VkBuffer indirectCountBuffer, vk::VkDeviceSize indirectCountBufferSize) const
1055 {
1056     const vk::VkBufferMemoryBarrier countBufferBarrier = vk::makeBufferMemoryBarrier(
1057         m_useMemoryAccess ? vk::VK_ACCESS_MEMORY_WRITE_BIT : vk::VK_ACCESS_SHADER_WRITE_BIT,
1058         m_useMemoryAccess ? vk::VK_ACCESS_MEMORY_READ_BIT : vk::VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
1059         indirectCountBuffer, 0ull, indirectCountBufferSize);
1060 
1061     m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
1062                             vk::VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, 0, 0, DE_NULL, 1, &countBufferBarrier, 0, DE_NULL);
1063 }
1064 
1065 template <class FirstInstanceSupport>
IndirectDrawInstanced(Context & context,TestSpec testSpec)1066 IndirectDrawInstanced<FirstInstanceSupport>::IndirectDrawInstanced(Context &context, TestSpec testSpec)
1067     : IndirectDraw(context, testSpec)
1068 {
1069     if (!FirstInstanceSupport::isTestSupported(m_context.getDeviceFeatures()))
1070     {
1071         throw tcu::NotSupportedError("Required 'drawIndirectFirstInstance' feature is not supported");
1072     }
1073 }
1074 
1075 template <class FirstInstanceSupport>
iterate(void)1076 tcu::TestStatus IndirectDrawInstanced<FirstInstanceSupport>::iterate(void)
1077 {
1078     tcu::TestLog &log         = m_context.getTestContext().getLog();
1079     const vk::VkQueue queue   = m_context.getUniversalQueue();
1080     const vk::VkDevice device = m_context.getDevice();
1081 
1082     m_drawCount                      = 2;
1083     m_offsetInBuffer                 = sizeof(m_junkData);
1084     const uint32_t m_bufferDrawCount = 2u * m_drawCount;
1085 
1086     if (m_drawType == DRAW_TYPE_SEQUENTIAL)
1087     {
1088         switch (m_topology)
1089         {
1090         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
1091         {
1092             vk::VkDrawIndirectCommand drawCmd[] = {
1093                 {
1094                     3,                                       //vertexCount
1095                     4,                                       //instanceCount
1096                     2,                                       //firstVertex
1097                     FirstInstanceSupport::getFirstInstance() //firstInstance
1098                 },
1099                 {(uint32_t)-4, (uint32_t)-2, (uint32_t)-11, (uint32_t)-9}, // junk (stride)
1100                 {
1101                     3,                                       //vertexCount
1102                     4,                                       //instanceCount
1103                     5,                                       //firstVertex
1104                     FirstInstanceSupport::getFirstInstance() //firstInstance
1105                 },
1106                 {
1107                     3u,                                      //vertexCount
1108                     4u,                                      //instanceCount
1109                     8u,                                      //firstVertex
1110                     FirstInstanceSupport::getFirstInstance() //firstInstance
1111                 },
1112                 {
1113                     3u,                                      //vertexCount
1114                     4u,                                      //instanceCount
1115                     11u,                                     //firstVertex
1116                     FirstInstanceSupport::getFirstInstance() //firstInstance
1117                 }};
1118             addCommand(drawCmd[0]);
1119             addCommand(drawCmd[1]);
1120             addCommand(drawCmd[2]);
1121             addCommand(drawCmd[1]);
1122             if (m_testIndirectCountExt != IndirectCountType::NONE)
1123             {
1124                 // Add padding data to the buffer to make sure it's large enough.
1125                 for (uint32_t i = 0; i < m_bufferDrawCount; ++i)
1126                 {
1127                     addCommand(drawCmd[3]);
1128                     addCommand(drawCmd[1]);
1129                     addCommand(drawCmd[4]);
1130                     addCommand(drawCmd[1]);
1131                 }
1132             }
1133             break;
1134         }
1135         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
1136         {
1137             vk::VkDrawIndirectCommand drawCmd[] = {{
1138                                                        4,                                       //vertexCount
1139                                                        4,                                       //instanceCount
1140                                                        2,                                       //firstVertex
1141                                                        FirstInstanceSupport::getFirstInstance() //firstInstance
1142                                                    },
1143                                                    {(uint32_t)-4, (uint32_t)-2, (uint32_t)-11, (uint32_t)-9},
1144                                                    {
1145                                                        4,                                       //vertexCount
1146                                                        4,                                       //instanceCount
1147                                                        6,                                       //firstVertex
1148                                                        FirstInstanceSupport::getFirstInstance() //firstInstance
1149                                                    },
1150                                                    {
1151                                                        4u,                                      //vertexCount
1152                                                        4u,                                      //instanceCount
1153                                                        10u,                                     //firstVertex
1154                                                        FirstInstanceSupport::getFirstInstance() //firstInstance
1155                                                    },
1156                                                    {
1157                                                        4u,                                      //vertexCount
1158                                                        4u,                                      //instanceCount
1159                                                        14u,                                     //firstVertex
1160                                                        FirstInstanceSupport::getFirstInstance() //firstInstance
1161                                                    }};
1162             addCommand(drawCmd[0]);
1163             addCommand(drawCmd[1]);
1164             addCommand(drawCmd[2]);
1165             addCommand(drawCmd[1]);
1166             if (m_testIndirectCountExt != IndirectCountType::NONE)
1167             {
1168                 // Add padding data to the buffer to make sure it's large enough.
1169                 for (uint32_t i = 0; i < m_bufferDrawCount; ++i)
1170                 {
1171                     addCommand(drawCmd[3]);
1172                     addCommand(drawCmd[1]);
1173                     addCommand(drawCmd[4]);
1174                     addCommand(drawCmd[1]);
1175                 }
1176             }
1177             break;
1178         }
1179         default:
1180             TCU_FAIL("impossible");
1181             break;
1182         }
1183 
1184         m_strideInBuffer = 2 * (uint32_t)sizeof(vk::VkDrawIndirectCommand);
1185     }
1186     else if (m_drawType == DRAW_TYPE_INDEXED)
1187     {
1188         switch (m_topology)
1189         {
1190         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
1191         {
1192             vk::VkDrawIndexedIndirectCommand drawCmd[] = {
1193                 {
1194                     3,                                       // indexCount
1195                     4,                                       // instanceCount
1196                     2,                                       // firstIndex
1197                     VERTEX_OFFSET,                           // vertexOffset
1198                     FirstInstanceSupport::getFirstInstance() // firstInstance
1199                 },
1200                 {(uint32_t)-4, (uint32_t)-2, (uint32_t)-11, (int32_t)9, (uint32_t)-7}, // junk (stride)
1201                 {
1202                     3,                                       // indexCount
1203                     4,                                       // instanceCount
1204                     5,                                       // firstIndex
1205                     VERTEX_OFFSET,                           // vertexOffset
1206                     FirstInstanceSupport::getFirstInstance() // firstInstance
1207                 },
1208                 {
1209                     3u,                                      // vertexCount
1210                     4u,                                      // instanceCount
1211                     8u,                                      // firstVertex
1212                     VERTEX_OFFSET,                           // vertexOffset
1213                     FirstInstanceSupport::getFirstInstance() // firstInstance
1214                 },
1215                 {
1216                     3u,                                      // vertexCount
1217                     4u,                                      // instanceCount
1218                     11u,                                     // firstVertex
1219                     VERTEX_OFFSET,                           // vertexOffset
1220                     FirstInstanceSupport::getFirstInstance() // firstInstance
1221                 }};
1222             addCommand(drawCmd[0]);
1223             addCommand(drawCmd[1]);
1224             addCommand(drawCmd[2]);
1225             addCommand(drawCmd[1]);
1226             if (m_testIndirectCountExt != IndirectCountType::NONE)
1227             {
1228                 // Add padding data to the buffer to make sure it's large enough.
1229                 for (uint32_t i = 0; i < m_bufferDrawCount; ++i)
1230                 {
1231                     addCommand(drawCmd[3]);
1232                     addCommand(drawCmd[1]);
1233                     addCommand(drawCmd[4]);
1234                     addCommand(drawCmd[1]);
1235                 }
1236             }
1237             break;
1238         }
1239         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
1240         {
1241             vk::VkDrawIndexedIndirectCommand drawCmd[] = {
1242                 {
1243                     4,                                       // indexCount
1244                     4,                                       // instanceCount
1245                     2,                                       // firstIndex
1246                     VERTEX_OFFSET,                           // vertexOffset
1247                     FirstInstanceSupport::getFirstInstance() // firstInstance
1248                 },
1249                 {(uint32_t)-4, (uint32_t)-2, (uint32_t)-11, (int32_t)9, (uint32_t)-7}, // junk (stride)
1250                 {
1251                     4,                                       // indexCount
1252                     4,                                       // instanceCount
1253                     6,                                       // firstIndex
1254                     VERTEX_OFFSET,                           // vertexOffset
1255                     FirstInstanceSupport::getFirstInstance() // firstInstance
1256                 },
1257                 {
1258                     4u,                                      // vertexCount
1259                     4u,                                      // instanceCount
1260                     10u,                                     // firstVertex
1261                     VERTEX_OFFSET,                           // vertexOffset
1262                     FirstInstanceSupport::getFirstInstance() // firstInstance
1263                 },
1264                 {
1265                     4u,                                      // vertexCount
1266                     4u,                                      // instanceCount
1267                     14u,                                     // firstVertex
1268                     VERTEX_OFFSET,                           // vertexOffset
1269                     FirstInstanceSupport::getFirstInstance() // firstInstance
1270                 }};
1271             addCommand(drawCmd[0]);
1272             addCommand(drawCmd[1]);
1273             addCommand(drawCmd[2]);
1274             addCommand(drawCmd[1]);
1275             if (m_testIndirectCountExt != IndirectCountType::NONE)
1276             {
1277                 // Add padding data to the buffer to make sure it's large enough.
1278                 for (uint32_t i = 0; i < m_bufferDrawCount; ++i)
1279                 {
1280                     addCommand(drawCmd[3]);
1281                     addCommand(drawCmd[1]);
1282                     addCommand(drawCmd[4]);
1283                     addCommand(drawCmd[1]);
1284                 }
1285             }
1286             break;
1287         }
1288         default:
1289             TCU_FAIL("impossible");
1290             break;
1291         }
1292 
1293         m_strideInBuffer = 2 * (uint32_t)sizeof(vk::VkDrawIndexedIndirectCommand);
1294     }
1295 
1296     const vk::VkDeviceSize dataSize           = m_indirectBufferContents.size();
1297     const vk::VkDeviceSize indirectBufferSize = dataSize + m_offsetInBuffer;
1298     vk::VkBufferUsageFlags usageFlags         = vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
1299 
1300     if (m_dataFromComputeShader)
1301         usageFlags |= vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
1302 
1303     m_indirectBuffer = Buffer::createAndAlloc(
1304         m_vk, m_context.getDevice(), BufferCreateInfo(indirectBufferSize, usageFlags), m_context.getDefaultAllocator(),
1305         vk::MemoryRequirement::HostVisible, static_cast<vk::VkDeviceSize>(INDEX_BUFFER_ALLOCATION_OFFSET));
1306 
1307     uint8_t *ptr =
1308         reinterpret_cast<uint8_t *>(m_indirectBuffer->getBoundMemory().getHostPtr()) + INDEX_BUFFER_ALLOCATION_OFFSET;
1309 
1310     deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer));
1311     deMemcpy((ptr + m_offsetInBuffer), &m_indirectBufferContents[0], static_cast<size_t>(dataSize));
1312 
1313     if (m_dataFromComputeShader)
1314     {
1315         // Negate all the buffer data and let a compute shader restore it to original.
1316         for (int i = 0; i < static_cast<int>(indirectBufferSize); i++)
1317         {
1318             ptr[i] = static_cast<uint8_t>(~ptr[i]);
1319         }
1320     }
1321 
1322     vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
1323 
1324     m_offsetInCountBuffer                  = sizeof(tcu::Vec3);
1325     const vk::VkDeviceSize countBufferSize = m_offsetInCountBuffer + sizeof(m_drawCount);
1326 
1327     if (m_testIndirectCountExt != IndirectCountType::NONE)
1328     {
1329         m_indirectCountBuffer =
1330             Buffer::createAndAlloc(m_vk, m_context.getDevice(), BufferCreateInfo(countBufferSize, usageFlags),
1331                                    m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
1332 
1333         uint8_t *countBufferPtr = reinterpret_cast<uint8_t *>(m_indirectCountBuffer->getBoundMemory().getHostPtr());
1334 
1335         // For IndirectCountType::PARAM_LIMIT, the real limit will be set using the call parameter.
1336         if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
1337             *(uint32_t *)(countBufferPtr + m_offsetInCountBuffer) =
1338                 m_drawCount +
1339                 (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? 0u : m_indirectCountExtDrawPadding);
1340         else
1341             *(uint32_t *)(countBufferPtr + m_offsetInCountBuffer) = 1u;
1342 
1343         if (m_dataFromComputeShader)
1344         {
1345             // Negate all the buffer data and let a compute shader restore it to original.
1346             for (int i = 0; i < static_cast<int>(countBufferSize); i++)
1347             {
1348                 countBufferPtr[i] = static_cast<uint8_t>(~countBufferPtr[i]);
1349             }
1350         }
1351 
1352         vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectCountBuffer->getBoundMemory());
1353     }
1354 
1355 #ifndef CTS_USES_VULKANSC
1356     if (m_groupParams->useSecondaryCmdBuffer)
1357     {
1358         // record secondary command buffer
1359         if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1360         {
1361             beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1362             beginDynamicRender(*m_secCmdBuffer);
1363         }
1364         else
1365             beginSecondaryCmdBuffer(m_vk);
1366 
1367         draw(*m_secCmdBuffer);
1368 
1369         if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1370             endDynamicRender(*m_secCmdBuffer);
1371 
1372         endCommandBuffer(m_vk, *m_secCmdBuffer);
1373 
1374         // record primary command buffer
1375         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1376 
1377         if (m_dataFromComputeShader)
1378             negateDataUsingCompute(indirectBufferSize, countBufferSize);
1379 
1380         preRenderBarriers();
1381         if (m_testIndirectCountExt != IndirectCountType::NONE)
1382             countBufferBarrier(m_indirectCountBuffer->object(), countBufferSize);
1383 
1384         if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1385             beginDynamicRender(*m_cmdBuffer, vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
1386 
1387         m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
1388 
1389         if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1390             endDynamicRender(*m_cmdBuffer);
1391 
1392         endCommandBuffer(m_vk, *m_cmdBuffer);
1393     }
1394     else if (m_groupParams->useDynamicRendering)
1395     {
1396         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1397 
1398         if (m_dataFromComputeShader)
1399             negateDataUsingCompute(indirectBufferSize, countBufferSize);
1400 
1401         preRenderBarriers();
1402         if (m_testIndirectCountExt != IndirectCountType::NONE)
1403             countBufferBarrier(m_indirectCountBuffer->object(), countBufferSize);
1404 
1405         beginDynamicRender(*m_cmdBuffer);
1406         draw(*m_cmdBuffer);
1407         endDynamicRender(*m_cmdBuffer);
1408 
1409         endCommandBuffer(m_vk, *m_cmdBuffer);
1410     }
1411 #endif // CTS_USES_VULKANSC
1412 
1413     if (!m_groupParams->useDynamicRendering)
1414     {
1415         beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1416 
1417         if (m_dataFromComputeShader)
1418             negateDataUsingCompute(indirectBufferSize, countBufferSize);
1419 
1420         preRenderBarriers();
1421         if (m_testIndirectCountExt != IndirectCountType::NONE)
1422             countBufferBarrier(m_indirectCountBuffer->object(), countBufferSize);
1423 
1424         beginLegacyRender(*m_cmdBuffer);
1425         draw(*m_cmdBuffer);
1426         endLegacyRender(*m_cmdBuffer);
1427 
1428         endCommandBuffer(m_vk, *m_cmdBuffer);
1429     }
1430 
1431     submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
1432 
1433     // Validation
1434     VK_CHECK(m_vk.queueWaitIdle(queue));
1435 
1436     tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)),
1437                                   (int)(0.5 + static_cast<float>(HEIGHT)));
1438 
1439     referenceFrame.allocLevel(0);
1440 
1441     const int32_t frameWidth  = referenceFrame.getWidth();
1442     const int32_t frameHeight = referenceFrame.getHeight();
1443 
1444     tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1445 
1446     ReferenceImageInstancedCoordinates refInstancedCoords;
1447 
1448     for (int y = 0; y < frameHeight; y++)
1449     {
1450         const float yCoord = (float)(y / (0.5 * frameHeight)) - 1.0f;
1451 
1452         for (int x = 0; x < frameWidth; x++)
1453         {
1454             const float xCoord = (float)(x / (0.5 * frameWidth)) - 1.0f;
1455 
1456             if ((yCoord >= refInstancedCoords.bottom && yCoord <= refInstancedCoords.top &&
1457                  xCoord >= refInstancedCoords.left && xCoord <= refInstancedCoords.right))
1458                 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
1459         }
1460     }
1461 
1462     const vk::VkOffset3D zeroOffset = {0, 0, 0};
1463     const tcu::ConstPixelBufferAccess renderedFrame =
1464         m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset,
1465                                         WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1466 
1467     qpTestResult res = QP_TEST_RESULT_PASS;
1468 
1469     if (!tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame.getLevel(0), renderedFrame, 0.05f,
1470                            tcu::COMPARE_LOG_RESULT))
1471     {
1472         res = QP_TEST_RESULT_FAIL;
1473     }
1474 
1475     return tcu::TestStatus(res, qpGetTestResultName(res));
1476 }
1477 
checkSupport(Context & context,IndirectDraw::TestSpec testSpec)1478 void checkSupport(Context &context, IndirectDraw::TestSpec testSpec)
1479 {
1480     if (testSpec.testIndirectCountExt != IndirectCountType::NONE)
1481         context.requireDeviceFunctionality("VK_KHR_draw_indirect_count");
1482 
1483     if (testSpec.groupParams->useDynamicRendering)
1484         context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
1485 
1486     if (testSpec.layerCount > 1u)
1487     {
1488         const auto &features = context.getMultiviewFeatures();
1489         if (!features.multiview)
1490             TCU_THROW(NotSupportedError, "multiview not supported");
1491     }
1492 }
1493 
1494 } // namespace
1495 
IndirectDrawTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)1496 IndirectDrawTests::IndirectDrawTests(tcu::TestContext &testCtx, const SharedGroupParams groupParams)
1497     : TestCaseGroup(testCtx, "indirect_draw")
1498     , m_groupParams(groupParams)
1499 {
1500     /* Left blank on purpose */
1501 }
1502 
~IndirectDrawTests(void)1503 IndirectDrawTests::~IndirectDrawTests(void)
1504 {
1505 }
1506 
init(void)1507 void IndirectDrawTests::init(void)
1508 {
1509     for (auto dataFromCompute : {false, true})
1510         for (int drawTypeIdx = 0; drawTypeIdx < DRAWTYPE_LAST; drawTypeIdx++)
1511             for (const auto bindIndexBufferOffset :
1512                  {vk::VkDeviceSize{0}, static_cast<vk::VkDeviceSize>(sizeof(uint32_t) * 4u)})
1513                 for (const auto indexBufferAllocOffset :
1514                      {vk::VkDeviceSize{0}, static_cast<vk::VkDeviceSize>(sizeof(tcu::Vec4))})
1515                 {
1516                     const bool nonZeroBindIndexBufferOffset = (bindIndexBufferOffset > 0);
1517                     const bool nonZeroAllocOffset           = (indexBufferAllocOffset > 0);
1518 
1519                     if (nonZeroBindIndexBufferOffset && drawTypeIdx != DRAW_TYPE_INDEXED)
1520                         continue;
1521 
1522                     if (nonZeroAllocOffset && drawTypeIdx != DRAW_TYPE_INDEXED)
1523                         continue;
1524 
1525                     // reduce number of tests for dynamic rendering cases where secondary command buffer is used
1526                     if (m_groupParams->useSecondaryCmdBuffer &&
1527                         (dataFromCompute == m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass))
1528                         continue;
1529 
1530                     std::string drawTypeStr;
1531                     switch (drawTypeIdx)
1532                     {
1533                     case DRAW_TYPE_SEQUENTIAL:
1534                         drawTypeStr = "sequential";
1535                         break;
1536                     case DRAW_TYPE_INDEXED:
1537                         drawTypeStr = "indexed";
1538                         break;
1539                     default:
1540                         TCU_FAIL("impossible");
1541                     }
1542 
1543                     if (dataFromCompute)
1544                         drawTypeStr += "_data_from_compute";
1545 
1546                     if (nonZeroBindIndexBufferOffset)
1547                         drawTypeStr += "_bind_offset_" + std::to_string(bindIndexBufferOffset);
1548 
1549                     if (nonZeroAllocOffset)
1550                         drawTypeStr += "_alloc_offset_" + std::to_string(indexBufferAllocOffset);
1551 
1552                     tcu::TestCaseGroup *drawTypeGroup = new tcu::TestCaseGroup(m_testCtx, drawTypeStr.c_str());
1553                     {
1554                         // Draws geometry
1555                         tcu::TestCaseGroup *indirectDrawGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw");
1556                         // Draws geometry with VK_KHR_draw_indirect_count extension
1557                         tcu::TestCaseGroup *indirectDrawCountGroup =
1558                             new tcu::TestCaseGroup(m_testCtx, "indirect_draw_count");
1559                         tcu::TestCaseGroup *indirectDrawParamCountGroup =
1560                             new tcu::TestCaseGroup(m_testCtx, "indirect_draw_param_count");
1561                         tcu::TestCaseGroup *indirectDrawMultiviewGroup =
1562                             new tcu::TestCaseGroup(m_testCtx, "indirect_draw_multiview");
1563                         {
1564                             IndirectDraw::TestSpec testSpec(m_groupParams);
1565                             testSpec.drawType                          = static_cast<DrawType>(drawTypeIdx);
1566                             testSpec.dataFromCompute                   = dataFromCompute;
1567                             testSpec.bindIndexBufferOffset             = bindIndexBufferOffset;
1568                             testSpec.indexBufferAllocOffset            = indexBufferAllocOffset;
1569                             testSpec.shaders[glu::SHADERTYPE_VERTEX]   = "vulkan/draw/VertexFetch.vert";
1570                             testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1571                             if (dataFromCompute)
1572                                 testSpec.shaders[glu::SHADERTYPE_COMPUTE] = "vulkan/draw/NegateData.comp";
1573 
1574                             testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1575                             indirectDrawGroup->addChild(
1576                                 new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec>>(
1577                                     m_testCtx, "triangle_list", testSpec,
1578                                     FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1579                             testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1580                             indirectDrawGroup->addChild(
1581                                 new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec>>(
1582                                     m_testCtx, "triangle_strip", testSpec,
1583                                     FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1584 
1585                             // test using V_ACCESS_MEMORY_WRITE/READ_BIT - there is no need to repeat this case for different drawing options
1586                             if (dataFromCompute && drawTypeIdx && !m_groupParams->useDynamicRendering &&
1587                                 !m_groupParams->useSecondaryCmdBuffer)
1588                             {
1589                                 testSpec.useMemoryAccess = true;
1590                                 indirectDrawGroup->addChild(
1591                                     new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec>>(
1592                                         m_testCtx, "triangle_strip_memory_access", testSpec,
1593                                         FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1594                                 testSpec.useMemoryAccess = false;
1595                             }
1596 
1597                             testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1598                             testSpec.topology             = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1599                             indirectDrawCountGroup->addChild(
1600                                 new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec>>(
1601                                     m_testCtx, "triangle_list", testSpec,
1602                                     FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1603                             testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1604                             indirectDrawCountGroup->addChild(
1605                                 new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec>>(
1606                                     m_testCtx, "triangle_strip", testSpec,
1607                                     FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1608 
1609                             // test using V_ACCESS_MEMORY_WRITE/READ_BIT - there is no need to repeat this case for different drawing options
1610                             if (dataFromCompute && drawTypeIdx && !m_groupParams->useDynamicRendering &&
1611                                 !m_groupParams->useSecondaryCmdBuffer)
1612                             {
1613                                 testSpec.useMemoryAccess = true;
1614                                 indirectDrawCountGroup->addChild(
1615                                     new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec>>(
1616                                         m_testCtx, "triangle_strip_memory_access", testSpec,
1617                                         FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1618                                 testSpec.useMemoryAccess = false;
1619                             }
1620 
1621                             testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1622                             testSpec.topology             = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1623                             indirectDrawParamCountGroup->addChild(
1624                                 new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec>>(
1625                                     m_testCtx, "triangle_list", testSpec,
1626                                     FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1627                             testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1628                             indirectDrawParamCountGroup->addChild(
1629                                 new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec>>(
1630                                     m_testCtx, "triangle_strip", testSpec,
1631                                     FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1632 
1633                             testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1634                             testSpec.topology             = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1635                             testSpec.layerCount           = 2u;
1636                             indirectDrawMultiviewGroup->addChild(
1637                                 new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec>>(
1638                                     m_testCtx, "triangle_list", testSpec,
1639                                     FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1640                         }
1641                         drawTypeGroup->addChild(indirectDrawGroup);
1642                         drawTypeGroup->addChild(indirectDrawCountGroup);
1643                         drawTypeGroup->addChild(indirectDrawParamCountGroup);
1644                         drawTypeGroup->addChild(indirectDrawMultiviewGroup);
1645 
1646                         {
1647                             tcu::TestCaseGroup *indirectDrawFirstInstanceGroup =
1648                                 new tcu::TestCaseGroup(m_testCtx, "indirect_draw_first_instance");
1649                             tcu::TestCaseGroup *indirectDrawCountFirstInstanceGroup =
1650                                 new tcu::TestCaseGroup(m_testCtx, "indirect_draw_count_first_instance");
1651                             tcu::TestCaseGroup *indirectDrawParamCountFirstInstanceGroup =
1652                                 new tcu::TestCaseGroup(m_testCtx, "indirect_draw_param_count_first_instance");
1653                             {
1654                                 IndirectDraw::TestSpec testSpec(m_groupParams);
1655                                 testSpec.testFirstInstanceNdx            = true;
1656                                 testSpec.drawType                        = static_cast<DrawType>(drawTypeIdx);
1657                                 testSpec.dataFromCompute                 = dataFromCompute;
1658                                 testSpec.bindIndexBufferOffset           = bindIndexBufferOffset;
1659                                 testSpec.indexBufferAllocOffset          = indexBufferAllocOffset;
1660                                 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstanceIndex.vert";
1661                                 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1662                                 if (dataFromCompute)
1663                                     testSpec.shaders[glu::SHADERTYPE_COMPUTE] = "vulkan/draw/NegateData.comp";
1664 
1665                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1666                                 indirectDrawFirstInstanceGroup->addChild(
1667                                     new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec>>(
1668                                         m_testCtx, "triangle_list", testSpec,
1669                                         FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1670                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1671                                 indirectDrawFirstInstanceGroup->addChild(
1672                                     new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec>>(
1673                                         m_testCtx, "triangle_strip", testSpec,
1674                                         FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1675 
1676                                 testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1677                                 testSpec.topology             = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1678                                 indirectDrawCountFirstInstanceGroup->addChild(
1679                                     new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec>>(
1680                                         m_testCtx, "triangle_list", testSpec,
1681                                         FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1682                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1683                                 indirectDrawCountFirstInstanceGroup->addChild(
1684                                     new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec>>(
1685                                         m_testCtx, "triangle_strip", testSpec,
1686                                         FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1687 
1688                                 testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1689                                 testSpec.topology             = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1690                                 indirectDrawParamCountFirstInstanceGroup->addChild(
1691                                     new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec>>(
1692                                         m_testCtx, "triangle_list", testSpec,
1693                                         FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1694                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1695                                 indirectDrawParamCountFirstInstanceGroup->addChild(
1696                                     new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec>>(
1697                                         m_testCtx, "triangle_strip", testSpec,
1698                                         FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1699                             }
1700                             drawTypeGroup->addChild(indirectDrawFirstInstanceGroup);
1701                             drawTypeGroup->addChild(indirectDrawCountFirstInstanceGroup);
1702                             drawTypeGroup->addChild(indirectDrawParamCountFirstInstanceGroup);
1703                         }
1704 
1705                         tcu::TestCaseGroup *indirectDrawInstancedGroup =
1706                             new tcu::TestCaseGroup(m_testCtx, "indirect_draw_instanced");
1707                         tcu::TestCaseGroup *indirectDrawCountInstancedGroup =
1708                             new tcu::TestCaseGroup(m_testCtx, "indirect_draw_count_instanced");
1709                         tcu::TestCaseGroup *indirectDrawParamCountInstancedGroup =
1710                             new tcu::TestCaseGroup(m_testCtx, "indirect_draw_param_count_instanced");
1711                         {
1712                             tcu::TestCaseGroup *indirectDrawNoFirstInstanceGroup =
1713                                 new tcu::TestCaseGroup(m_testCtx, "no_first_instance");
1714                             tcu::TestCaseGroup *indirectDrawCountNoFirstInstanceGroup =
1715                                 new tcu::TestCaseGroup(m_testCtx, "no_first_instance");
1716                             tcu::TestCaseGroup *indirectDrawParamCountNoFirstInstanceGroup =
1717                                 new tcu::TestCaseGroup(m_testCtx, "no_first_instance");
1718                             {
1719                                 typedef IndirectDrawInstanced<FirstInstanceNotSupported> IDFirstInstanceNotSupported;
1720 
1721                                 IDFirstInstanceNotSupported::TestSpec testSpec(m_groupParams);
1722                                 testSpec.drawType               = static_cast<DrawType>(drawTypeIdx);
1723                                 testSpec.dataFromCompute        = dataFromCompute;
1724                                 testSpec.bindIndexBufferOffset  = bindIndexBufferOffset;
1725                                 testSpec.indexBufferAllocOffset = indexBufferAllocOffset;
1726 
1727                                 testSpec.shaders[glu::SHADERTYPE_VERTEX]   = "vulkan/draw/VertexFetchInstanced.vert";
1728                                 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1729                                 if (dataFromCompute)
1730                                     testSpec.shaders[glu::SHADERTYPE_COMPUTE] = "vulkan/draw/NegateData.comp";
1731 
1732                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1733                                 indirectDrawNoFirstInstanceGroup->addChild(
1734                                     new InstanceFactory<IDFirstInstanceNotSupported,
1735                                                         FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>>(
1736                                         m_testCtx, "triangle_list", testSpec,
1737                                         FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport,
1738                                                                                                       testSpec)));
1739                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1740                                 indirectDrawNoFirstInstanceGroup->addChild(
1741                                     new InstanceFactory<IDFirstInstanceNotSupported,
1742                                                         FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>>(
1743                                         m_testCtx, "triangle_strip", testSpec,
1744                                         FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport,
1745                                                                                                       testSpec)));
1746 
1747                                 testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1748                                 testSpec.topology             = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1749                                 indirectDrawCountNoFirstInstanceGroup->addChild(
1750                                     new InstanceFactory<IDFirstInstanceNotSupported,
1751                                                         FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>>(
1752                                         m_testCtx, "triangle_list", testSpec,
1753                                         FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport,
1754                                                                                                       testSpec)));
1755                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1756                                 indirectDrawCountNoFirstInstanceGroup->addChild(
1757                                     new InstanceFactory<IDFirstInstanceNotSupported,
1758                                                         FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>>(
1759                                         m_testCtx, "triangle_strip", testSpec,
1760                                         FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport,
1761                                                                                                       testSpec)));
1762 
1763                                 testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1764                                 testSpec.topology             = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1765                                 indirectDrawParamCountNoFirstInstanceGroup->addChild(
1766                                     new InstanceFactory<IDFirstInstanceNotSupported,
1767                                                         FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>>(
1768                                         m_testCtx, "triangle_list", testSpec,
1769                                         FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport,
1770                                                                                                       testSpec)));
1771                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1772                                 indirectDrawParamCountNoFirstInstanceGroup->addChild(
1773                                     new InstanceFactory<IDFirstInstanceNotSupported,
1774                                                         FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>>(
1775                                         m_testCtx, "triangle_strip", testSpec,
1776                                         FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport,
1777                                                                                                       testSpec)));
1778                             }
1779                             indirectDrawInstancedGroup->addChild(indirectDrawNoFirstInstanceGroup);
1780                             indirectDrawCountInstancedGroup->addChild(indirectDrawCountNoFirstInstanceGroup);
1781                             indirectDrawParamCountInstancedGroup->addChild(indirectDrawParamCountNoFirstInstanceGroup);
1782 
1783                             tcu::TestCaseGroup *indirectDrawFirstInstanceGroup =
1784                                 new tcu::TestCaseGroup(m_testCtx, "first_instance");
1785                             tcu::TestCaseGroup *indirectDrawCountFirstInstanceGroup =
1786                                 new tcu::TestCaseGroup(m_testCtx, "first_instance");
1787                             tcu::TestCaseGroup *indirectDrawParamCountFirstInstanceGroup =
1788                                 new tcu::TestCaseGroup(m_testCtx, "first_instance");
1789                             {
1790                                 typedef IndirectDrawInstanced<FirstInstanceSupported> IDFirstInstanceSupported;
1791 
1792                                 IDFirstInstanceSupported::TestSpec testSpec(m_groupParams);
1793                                 testSpec.drawType               = static_cast<DrawType>(drawTypeIdx);
1794                                 testSpec.dataFromCompute        = dataFromCompute;
1795                                 testSpec.bindIndexBufferOffset  = bindIndexBufferOffset;
1796                                 testSpec.indexBufferAllocOffset = indexBufferAllocOffset;
1797 
1798                                 testSpec.shaders[glu::SHADERTYPE_VERTEX] =
1799                                     "vulkan/draw/VertexFetchInstancedFirstInstance.vert";
1800                                 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1801                                 if (dataFromCompute)
1802                                     testSpec.shaders[glu::SHADERTYPE_COMPUTE] = "vulkan/draw/NegateData.comp";
1803 
1804                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1805                                 indirectDrawFirstInstanceGroup->addChild(
1806                                     new InstanceFactory<IDFirstInstanceSupported,
1807                                                         FunctionSupport1<IDFirstInstanceSupported::TestSpec>>(
1808                                         m_testCtx, "triangle_list", testSpec,
1809                                         FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport,
1810                                                                                                    testSpec)));
1811                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1812                                 indirectDrawFirstInstanceGroup->addChild(
1813                                     new InstanceFactory<IDFirstInstanceSupported,
1814                                                         FunctionSupport1<IDFirstInstanceSupported::TestSpec>>(
1815                                         m_testCtx, "triangle_strip", testSpec,
1816                                         FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport,
1817                                                                                                    testSpec)));
1818 
1819                                 testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1820                                 testSpec.topology             = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1821                                 indirectDrawCountFirstInstanceGroup->addChild(
1822                                     new InstanceFactory<IDFirstInstanceSupported,
1823                                                         FunctionSupport1<IDFirstInstanceSupported::TestSpec>>(
1824                                         m_testCtx, "triangle_list", testSpec,
1825                                         FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport,
1826                                                                                                    testSpec)));
1827                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1828                                 indirectDrawCountFirstInstanceGroup->addChild(
1829                                     new InstanceFactory<IDFirstInstanceSupported,
1830                                                         FunctionSupport1<IDFirstInstanceSupported::TestSpec>>(
1831                                         m_testCtx, "triangle_strip", testSpec,
1832                                         FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport,
1833                                                                                                    testSpec)));
1834 
1835                                 testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1836                                 testSpec.topology             = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1837                                 indirectDrawParamCountFirstInstanceGroup->addChild(
1838                                     new InstanceFactory<IDFirstInstanceSupported,
1839                                                         FunctionSupport1<IDFirstInstanceSupported::TestSpec>>(
1840                                         m_testCtx, "triangle_list", testSpec,
1841                                         FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport,
1842                                                                                                    testSpec)));
1843                                 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1844                                 indirectDrawParamCountFirstInstanceGroup->addChild(
1845                                     new InstanceFactory<IDFirstInstanceSupported,
1846                                                         FunctionSupport1<IDFirstInstanceSupported::TestSpec>>(
1847                                         m_testCtx, "triangle_strip", testSpec,
1848                                         FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport,
1849                                                                                                    testSpec)));
1850                             }
1851                             indirectDrawInstancedGroup->addChild(indirectDrawFirstInstanceGroup);
1852                             indirectDrawCountInstancedGroup->addChild(indirectDrawCountFirstInstanceGroup);
1853                             indirectDrawParamCountInstancedGroup->addChild(indirectDrawParamCountFirstInstanceGroup);
1854                         }
1855                         drawTypeGroup->addChild(indirectDrawInstancedGroup);
1856                         drawTypeGroup->addChild(indirectDrawCountInstancedGroup);
1857                         drawTypeGroup->addChild(indirectDrawParamCountInstancedGroup);
1858                     }
1859 
1860                     addChild(drawTypeGroup);
1861                 }
1862 }
1863 
1864 } // namespace Draw
1865 } // namespace vkt
1866