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