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