1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Intel Corporation
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * \brief Draw Indirect Test
23 *//*--------------------------------------------------------------------*/
25 #include "vktDrawIndirectTest.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vktDrawTestCaseUtil.hpp"
29 #include "../compute/vktComputeTestsUtil.hpp"
31 #include "vktDrawBaseClass.hpp"
33 #include "tcuTestLog.hpp"
34 #include "tcuResource.hpp"
35 #include "tcuImageCompare.hpp"
36 #include "tcuTextureUtil.hpp"
37 #include "tcuRGBA.hpp"
38 #include "vkQueryUtil.hpp"
41 #include "vkCmdUtil.hpp"
42 #include "vkBuilderUtil.hpp"
43 #include "vkObjUtil.hpp"
44 #include "vkTypeUtil.hpp"
45 #include "vkBarrierUtil.hpp"
78 enum class IndirectCountType
87 struct DrawTypedTestSpec : public TestSpecBase
89 DrawTypedTestSpec(const SharedGroupParams groupParams_)
90 : TestSpecBase{ {}, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, groupParams_ }
91 , drawType(DRAWTYPE_LAST)
92 , testFirstInstanceNdx(false)
93 , testIndirectCountExt(IndirectCountType::NONE)
94 , dataFromCompute(false)
98 bool testFirstInstanceNdx;
99 IndirectCountType testIndirectCountExt;
100 bool dataFromCompute;
103 class IndirectDraw : public DrawTestsBaseClass
106 typedef DrawTypedTestSpec TestSpec;
108 IndirectDraw (Context &context, TestSpec testSpec);
109 virtual tcu::TestStatus iterate (void);
111 void draw (vk::VkCommandBuffer cmdBuffer);
112 template<typename T> void addCommand (const T&);
115 void setVertexBuffer (void);
116 void setFirstInstanceVertexBuffer (void);
117 void negateDataUsingCompute (vk::VkDeviceSize indirectBufferSize, vk::VkDeviceSize countBufferSize);
119 std::vector<char> m_indirectBufferContents;
120 de::SharedPtr<Buffer> m_indirectBuffer;
121 vk::VkDeviceSize m_offsetInBuffer;
122 deUint32 m_strideInBuffer;
124 const IndirectCountType m_testIndirectCountExt;
125 de::SharedPtr<Buffer> m_indirectCountBuffer;
126 vk::VkDeviceSize m_offsetInCountBuffer;
127 const deUint32 m_indirectCountExtDrawPadding;
129 deUint32 m_drawCount;
132 const DrawType m_drawType;
133 const bool m_testFirstInstanceNdx;
134 deBool m_isMultiDrawEnabled;
135 deUint32 m_drawIndirectMaxCount;
136 deBool m_dataFromComputeShader;
138 de::SharedPtr<Buffer> m_indexBuffer;
140 vk::Move<vk::VkDescriptorSetLayout> m_descriptorSetLayout;
141 vk::Move<vk::VkDescriptorPool> m_descriptorPool;
142 vk::Move<vk::VkDescriptorSet> m_descriptorSetIndirectBuffer;
143 vk::Move<vk::VkDescriptorSet> m_descriptorSetCountBuffer;
144 vk::Move<vk::VkShaderModule> m_computeShaderModule;
145 vk::Move<vk::VkPipelineLayout> m_pipelineLayout;
146 vk::Move<vk::VkPipeline> m_computePipeline;
149 struct FirstInstanceSupported
151 static deUint32 getFirstInstance (void) { return 2; }
152 static bool isTestSupported (const vk::VkPhysicalDeviceFeatures& features) { return features.drawIndirectFirstInstance == VK_TRUE; }
155 struct FirstInstanceNotSupported
157 static deUint32 getFirstInstance (void) { return 0; }
158 static bool isTestSupported (const vk::VkPhysicalDeviceFeatures&) { return true; }
161 template<class FirstInstanceSupport>
162 class IndirectDrawInstanced : public IndirectDraw
165 IndirectDrawInstanced (Context &context, TestSpec testSpec);
166 virtual tcu::TestStatus iterate (void);
169 void IndirectDraw::setVertexBuffer (void)
171 int refVertexIndex = 2;
173 if (m_drawType == DRAW_TYPE_INDEXED)
175 for (int unusedIdx = 0; unusedIdx < VERTEX_OFFSET; unusedIdx++)
177 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
179 refVertexIndex += VERTEX_OFFSET;
182 m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
183 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
187 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
188 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
189 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
190 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
191 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
192 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
193 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
195 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
196 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
197 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
198 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
199 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
200 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
201 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
202 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
203 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refVertexIndex++));
206 DE_FATAL("Unknown topology");
210 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
213 void IndirectDraw::setFirstInstanceVertexBuffer (void)
215 if (m_context.getDeviceFeatures().drawIndirectFirstInstance != VK_TRUE)
217 TCU_THROW(NotSupportedError, "Required 'drawIndirectFirstInstance' feature is not supported");
220 if (m_drawType == DRAW_TYPE_INDEXED)
222 for (int unusedIdx = 0; unusedIdx < VERTEX_OFFSET; unusedIdx++)
224 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
228 m_data.push_back(VertexElementData(tcu::Vec4( 1.0f, -1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
229 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
233 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
235 int refInstanceIndex = 1;
236 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
237 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
238 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
240 refInstanceIndex = 0;
241 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
242 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
243 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
246 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
248 int refInstanceIndex = 1;
249 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
250 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
251 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
252 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, -0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
254 refInstanceIndex = 0;
255 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
256 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, 0.3f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
257 m_data.push_back(VertexElementData(tcu::Vec4(-0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
258 m_data.push_back(VertexElementData(tcu::Vec4( 0.3f, 0.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), refInstanceIndex));
262 DE_FATAL("Unknown topology");
266 m_data.push_back(VertexElementData(tcu::Vec4(-1.0f, 1.0f, 1.0f, 1.0f), tcu::RGBA::blue().toVec(), -1));
269 // When testing indirect data generation from a compute shader, the original data is negated bitwise
270 // and compute shader restores it before being used in an indirect draw.
271 void IndirectDraw::negateDataUsingCompute(vk::VkDeviceSize indirectBufferSize, vk::VkDeviceSize countBufferSize)
273 m_descriptorSetLayout = vk::DescriptorSetLayoutBuilder().addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT).build(m_vk, m_context.getDevice());
274 m_descriptorPool = vk::DescriptorPoolBuilder().addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u).build(m_vk, m_context.getDevice(), vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 2u);
278 m_descriptorSetIndirectBuffer = vk::makeDescriptorSet(m_vk, m_context.getDevice(), *m_descriptorPool, *m_descriptorSetLayout);
279 const vk::VkDescriptorBufferInfo bufferDescriptorInfo = vk::makeDescriptorBufferInfo(m_indirectBuffer->object(), 0ull, indirectBufferSize);
280 vk::DescriptorSetUpdateBuilder()
281 .writeSingle(*m_descriptorSetIndirectBuffer, vk::DescriptorSetUpdateBuilder::Location::binding(0u),
282 vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescriptorInfo)
283 .update(m_vk, m_context.getDevice());
286 // Indirect count buffer
287 if (m_testIndirectCountExt != IndirectCountType::NONE)
289 m_descriptorSetCountBuffer = vk::makeDescriptorSet(m_vk, m_context.getDevice(), *m_descriptorPool, *m_descriptorSetLayout);
290 const vk::VkDescriptorBufferInfo bufferDescriptorInfo = vk::makeDescriptorBufferInfo(m_indirectCountBuffer->object(), 0ull, countBufferSize);
291 vk::DescriptorSetUpdateBuilder()
292 .writeSingle(*m_descriptorSetCountBuffer, vk::DescriptorSetUpdateBuilder::Location::binding(0u),
293 vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferDescriptorInfo)
294 .update(m_vk, m_context.getDevice());
297 m_computeShaderModule = vk::createShaderModule(m_vk, m_context.getDevice(), m_context.getBinaryCollection().get("vulkan/draw/NegateData.comp"), 0u);
298 m_pipelineLayout = vk::makePipelineLayout(m_vk, m_context.getDevice(), *m_descriptorSetLayout);
299 m_computePipeline = makeComputePipeline(m_vk, m_context.getDevice(), *m_pipelineLayout, *m_computeShaderModule);
301 const vk::VkBufferMemoryBarrier hostWriteBarrier = vk::makeBufferMemoryBarrier(vk::VK_ACCESS_HOST_WRITE_BIT, vk::VK_ACCESS_SHADER_READ_BIT, m_indirectBuffer->object(), 0ull, indirectBufferSize);
302 const vk::VkBufferMemoryBarrier indirectDrawBarrier = vk::makeBufferMemoryBarrier(vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_ACCESS_INDIRECT_COMMAND_READ_BIT, m_indirectBuffer->object(), 0ull, indirectBufferSize);
304 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *m_computePipeline);
305 m_vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0u, 1u, &m_descriptorSetIndirectBuffer.get(), 0u, DE_NULL);
306 m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_HOST_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 1, &hostWriteBarrier, 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
307 m_vk.cmdDispatch(*m_cmdBuffer, 1, 1, 1);
308 m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 1, &indirectDrawBarrier, 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
310 if (m_testIndirectCountExt != IndirectCountType::NONE)
312 m_vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0u, 1u, &m_descriptorSetCountBuffer.get(), 0u, DE_NULL);
313 m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_HOST_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 1, &hostWriteBarrier, 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
314 m_vk.cmdDispatch(*m_cmdBuffer, 1, 1, 1);
315 m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 1, &indirectDrawBarrier, 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
319 IndirectDraw::IndirectDraw (Context &context, TestSpec testSpec)
320 : DrawTestsBaseClass (context, testSpec.shaders[glu::SHADERTYPE_VERTEX], testSpec.shaders[glu::SHADERTYPE_FRAGMENT], testSpec.groupParams, testSpec.topology)
321 , m_testIndirectCountExt (testSpec.testIndirectCountExt)
322 , m_indirectCountExtDrawPadding (1u)
323 , m_drawType (testSpec.drawType)
324 , m_testFirstInstanceNdx (testSpec.testFirstInstanceNdx)
325 , m_dataFromComputeShader (testSpec.dataFromCompute)
327 if (m_testFirstInstanceNdx)
328 setFirstInstanceVertexBuffer();
334 if (testSpec.drawType == DRAW_TYPE_INDEXED)
336 const size_t indexBufferLength = m_data.size() - VERTEX_OFFSET;
338 m_indexBuffer = Buffer::createAndAlloc(m_vk, m_context.getDevice(), BufferCreateInfo(sizeof(deUint32) * indexBufferLength, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT), m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
339 deUint32* indices = reinterpret_cast<deUint32*>(m_indexBuffer->getBoundMemory().getHostPtr());
340 for (size_t i = 0; i < indexBufferLength; i++)
342 indices[i] = static_cast<deUint32>(i);
344 vk::flushAlloc(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory());
347 // Check device for multidraw support:
348 if (!m_context.getDeviceFeatures().multiDrawIndirect || m_testFirstInstanceNdx)
349 m_isMultiDrawEnabled = false;
351 m_isMultiDrawEnabled = true;
353 m_drawIndirectMaxCount = m_context.getDeviceProperties().limits.maxDrawIndirectCount;
357 void IndirectDraw::addCommand<vk::VkDrawIndirectCommand> (const vk::VkDrawIndirectCommand& command)
359 DE_ASSERT(m_drawType == DRAW_TYPE_SEQUENTIAL);
361 const size_t currentSize = m_indirectBufferContents.size();
363 m_indirectBufferContents.resize(currentSize + sizeof(command));
365 deMemcpy(&m_indirectBufferContents[currentSize], &command, sizeof(command));
369 void IndirectDraw::addCommand<vk::VkDrawIndexedIndirectCommand> (const vk::VkDrawIndexedIndirectCommand& command)
371 DE_ASSERT(m_drawType == DRAW_TYPE_INDEXED);
373 const size_t currentSize = m_indirectBufferContents.size();
375 m_indirectBufferContents.resize(currentSize + sizeof(command));
377 deMemcpy(&m_indirectBufferContents[currentSize], &command, sizeof(command));
380 void IndirectDraw::draw (vk::VkCommandBuffer cmdBuffer)
382 const vk::VkDeviceSize vertexBufferOffset = 0;
383 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
385 m_vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
386 m_vk.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
387 if (m_drawType == DRAW_TYPE_INDEXED)
388 m_vk.cmdBindIndexBuffer(cmdBuffer, m_indexBuffer->object(), DE_NULL, vk::VK_INDEX_TYPE_UINT32);
390 if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
394 case DRAW_TYPE_SEQUENTIAL:
396 if (m_testIndirectCountExt != IndirectCountType::NONE)
398 const deUint32 maxDrawCount = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_indirectCountExtDrawPadding : 0u);
399 m_vk.cmdDrawIndirectCount(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer,
400 m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
404 m_vk.cmdDrawIndirect(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
407 case DRAW_TYPE_INDEXED:
409 if (m_testIndirectCountExt != IndirectCountType::NONE)
411 const deUint32 maxDrawCount = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_indirectCountExtDrawPadding : 0u);
412 m_vk.cmdDrawIndexedIndirectCount(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer,
413 m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
417 m_vk.cmdDrawIndexedIndirect(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer, m_drawCount, m_strideInBuffer);
421 TCU_FAIL("impossible");
426 for (deUint32 drawNdx = 0; drawNdx < m_drawCount; drawNdx++)
430 case DRAW_TYPE_SEQUENTIAL:
432 if (m_testIndirectCountExt != IndirectCountType::NONE)
434 const deUint32 maxDrawCount = (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_drawCount + m_indirectCountExtDrawPadding : 1u);
435 m_vk.cmdDrawIndirectCount(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer,
436 m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
440 m_vk.cmdDrawIndirect(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
443 case DRAW_TYPE_INDEXED:
445 if (m_testIndirectCountExt != IndirectCountType::NONE)
447 const deUint32 maxDrawCount = (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? m_drawCount + m_indirectCountExtDrawPadding : 1u);
448 m_vk.cmdDrawIndexedIndirectCount(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer,
449 m_indirectCountBuffer->object(), m_offsetInCountBuffer, maxDrawCount,
453 m_vk.cmdDrawIndexedIndirect(cmdBuffer, m_indirectBuffer->object(), m_offsetInBuffer + drawNdx*m_strideInBuffer, 1u, 0u);
457 TCU_FAIL("impossible");
463 tcu::TestStatus IndirectDraw::iterate (void)
465 tcu::TestLog& log = m_context.getTestContext().getLog();
466 const vk::VkQueue queue = m_context.getUniversalQueue();
467 const vk::VkDevice device = m_context.getDevice();
470 m_offsetInBuffer = sizeof(m_junkData);
471 const deUint32 m_bufferDrawCount = 2u * m_drawCount;
473 if (m_drawType == DRAW_TYPE_SEQUENTIAL)
477 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
479 vk::VkDrawIndirectCommand drawCommands[] =
485 (m_testFirstInstanceNdx ? 1u : 0u) //firstInstance
487 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
495 addCommand(drawCommands[0]);
496 addCommand(drawCommands[1]);
497 addCommand(drawCommands[2]);
498 addCommand(drawCommands[1]);
499 if (m_testIndirectCountExt != IndirectCountType::NONE)
501 // Add padding data to the buffer to make sure it's large enough.
502 for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
504 addCommand(drawCommands[1]);
505 addCommand(drawCommands[1]);
510 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
512 vk::VkDrawIndirectCommand drawCommands[] =
518 (m_testFirstInstanceNdx ? 1u : 0u) //firstInstance
520 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
528 addCommand(drawCommands[0]);
529 addCommand(drawCommands[1]);
530 addCommand(drawCommands[2]);
531 addCommand(drawCommands[1]);
532 if (m_testIndirectCountExt != IndirectCountType::NONE)
534 // Add padding data to the buffer to make sure it's large enough.
535 for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
537 addCommand(drawCommands[1]);
538 addCommand(drawCommands[1]);
544 TCU_FAIL("impossible");
547 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndirectCommand);
549 else if (m_drawType == DRAW_TYPE_INDEXED)
553 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
555 vk::VkDrawIndexedIndirectCommand drawCommands[] =
561 VERTEX_OFFSET, // vertexOffset
562 (m_testFirstInstanceNdx ? 1u : 0u), // firstInstance
564 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride)
569 VERTEX_OFFSET, // vertexOffset
573 addCommand(drawCommands[0]);
574 addCommand(drawCommands[1]);
575 addCommand(drawCommands[2]);
576 addCommand(drawCommands[1]);
577 if (m_testIndirectCountExt != IndirectCountType::NONE)
579 // Add padding data to the buffer to make sure it's large enough.
580 for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
582 addCommand(drawCommands[1]);
583 addCommand(drawCommands[1]);
588 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
590 vk::VkDrawIndexedIndirectCommand drawCommands[] =
596 VERTEX_OFFSET, // vertexOffset
597 (m_testFirstInstanceNdx ? 1u : 0u), // firstInstance
599 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride)
604 VERTEX_OFFSET, // vertexOffset
608 addCommand(drawCommands[0]);
609 addCommand(drawCommands[1]);
610 addCommand(drawCommands[2]);
611 addCommand(drawCommands[1]);
612 if (m_testIndirectCountExt != IndirectCountType::NONE)
614 // Add padding data to the buffer to make sure it's large enough.
615 for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
617 addCommand(drawCommands[1]);
618 addCommand(drawCommands[1]);
624 TCU_FAIL("impossible");
627 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndexedIndirectCommand);
630 const vk::VkDeviceSize dataSize = m_indirectBufferContents.size();
631 const vk::VkDeviceSize indirectBufferSize = dataSize + m_offsetInBuffer;
632 vk::VkBufferUsageFlags usageFlags = vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
633 if (m_dataFromComputeShader)
634 usageFlags |= vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
636 m_indirectBuffer = Buffer::createAndAlloc( m_vk,
637 m_context.getDevice(),
638 BufferCreateInfo(indirectBufferSize, usageFlags),
639 m_context.getDefaultAllocator(),
640 vk::MemoryRequirement::HostVisible);
642 deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
644 deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer));
645 deMemcpy(ptr + m_offsetInBuffer, &m_indirectBufferContents[0], static_cast<size_t>(dataSize));
647 if (m_dataFromComputeShader)
649 // Negate all the buffer data and let a compute shader restore it to original.
650 for (int i = 0; i < static_cast<int>(indirectBufferSize); i++)
652 ptr[i] = static_cast<deUint8>(~ptr[i]);
656 vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
658 m_offsetInCountBuffer = sizeof(tcu::Vec3);
659 const vk::VkDeviceSize countBufferSize = m_offsetInCountBuffer + sizeof(m_drawCount);
661 if (m_testIndirectCountExt != IndirectCountType::NONE)
663 m_indirectCountBuffer = Buffer::createAndAlloc(m_vk,
664 m_context.getDevice(),
665 BufferCreateInfo(countBufferSize, usageFlags),
666 m_context.getDefaultAllocator(),
667 vk::MemoryRequirement::HostVisible);
669 deUint8* countBufferPtr = reinterpret_cast<deUint8*>(m_indirectCountBuffer->getBoundMemory().getHostPtr());
671 // For IndirectCountType::PARAM_LIMIT, the real limit will be set using the call parameter.
672 if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
673 *(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? 0u : m_indirectCountExtDrawPadding);
675 *(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? 1u : m_drawCount + m_indirectCountExtDrawPadding);
677 if (m_dataFromComputeShader)
679 // Negate all the buffer data and let a compute shader restore it to original.
680 for (int i = 0; i < static_cast<int>(countBufferSize); i++)
682 countBufferPtr[i] = static_cast<deUint8>(~countBufferPtr[i]);
686 vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectCountBuffer->getBoundMemory());
689 #ifndef CTS_USES_VULKANSC
690 if (m_groupParams->useSecondaryCmdBuffer)
692 // record secondary command buffer
693 if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
695 beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
696 beginDynamicRender(*m_secCmdBuffer);
699 beginSecondaryCmdBuffer(m_vk);
701 draw(*m_secCmdBuffer);
703 if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
704 endDynamicRender(*m_secCmdBuffer);
706 endCommandBuffer(m_vk, *m_secCmdBuffer);
708 // record primary command buffer
709 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
711 if (m_dataFromComputeShader)
712 negateDataUsingCompute(indirectBufferSize, countBufferSize);
716 if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
717 beginDynamicRender(*m_cmdBuffer, vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
719 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
721 if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
722 endDynamicRender(*m_cmdBuffer);
724 endCommandBuffer(m_vk, *m_cmdBuffer);
726 else if (m_groupParams->useDynamicRendering)
728 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
730 if (m_dataFromComputeShader)
731 negateDataUsingCompute(indirectBufferSize, countBufferSize);
734 beginDynamicRender(*m_cmdBuffer);
738 endDynamicRender(*m_cmdBuffer);
739 endCommandBuffer(m_vk, *m_cmdBuffer);
741 #endif // CTS_USES_VULKANSC
743 if (!m_groupParams->useDynamicRendering)
745 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
747 if (m_dataFromComputeShader)
748 negateDataUsingCompute(indirectBufferSize, countBufferSize);
751 beginLegacyRender(*m_cmdBuffer);
755 endLegacyRender(*m_cmdBuffer);
756 endCommandBuffer(m_vk, *m_cmdBuffer);
759 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
762 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
763 referenceFrame.allocLevel(0);
765 const deInt32 frameWidth = referenceFrame.getWidth();
766 const deInt32 frameHeight = referenceFrame.getHeight();
768 tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
770 ReferenceImageCoordinates refCoords;
772 for (int y = 0; y < frameHeight; y++)
774 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
776 for (int x = 0; x < frameWidth; x++)
778 const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
780 if ((yCoord >= refCoords.bottom &&
781 yCoord <= refCoords.top &&
782 xCoord >= refCoords.left &&
783 xCoord <= refCoords.right))
784 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
788 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
789 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
790 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
792 qpTestResult res = QP_TEST_RESULT_PASS;
794 if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
795 referenceFrame.getLevel(0), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
797 res = QP_TEST_RESULT_FAIL;
800 return tcu::TestStatus(res, qpGetTestResultName(res));
803 template<class FirstInstanceSupport>
804 IndirectDrawInstanced<FirstInstanceSupport>::IndirectDrawInstanced (Context &context, TestSpec testSpec)
805 : IndirectDraw(context, testSpec)
807 if (!FirstInstanceSupport::isTestSupported(m_context.getDeviceFeatures()))
809 throw tcu::NotSupportedError("Required 'drawIndirectFirstInstance' feature is not supported");
813 template<class FirstInstanceSupport>
814 tcu::TestStatus IndirectDrawInstanced<FirstInstanceSupport>::iterate (void)
816 tcu::TestLog& log = m_context.getTestContext().getLog();
817 const vk::VkQueue queue = m_context.getUniversalQueue();
818 const vk::VkDevice device = m_context.getDevice();
821 m_offsetInBuffer = sizeof(m_junkData);
822 const deUint32 m_bufferDrawCount = 2u * m_drawCount;
824 if (m_drawType == DRAW_TYPE_SEQUENTIAL)
828 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
830 vk::VkDrawIndirectCommand drawCmd[] =
836 FirstInstanceSupport::getFirstInstance() //firstInstance
838 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 }, // junk (stride)
843 FirstInstanceSupport::getFirstInstance() //firstInstance
846 addCommand(drawCmd[0]);
847 addCommand(drawCmd[1]);
848 addCommand(drawCmd[2]);
849 if (m_testIndirectCountExt != IndirectCountType::NONE)
851 // Add padding data to the buffer to make sure it's large enough.
852 for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
854 addCommand(drawCmd[1]);
855 addCommand(drawCmd[1]);
860 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
862 vk::VkDrawIndirectCommand drawCmd[] =
868 FirstInstanceSupport::getFirstInstance() //firstInstance
870 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deUint32)-9 },
875 FirstInstanceSupport::getFirstInstance() //firstInstance
878 addCommand(drawCmd[0]);
879 addCommand(drawCmd[1]);
880 addCommand(drawCmd[2]);
881 if (m_testIndirectCountExt != IndirectCountType::NONE)
883 // Add padding data to the buffer to make sure it's large enough.
884 for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
886 addCommand(drawCmd[1]);
887 addCommand(drawCmd[1]);
893 TCU_FAIL("impossible");
897 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndirectCommand);
899 else if (m_drawType == DRAW_TYPE_INDEXED)
903 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
905 vk::VkDrawIndexedIndirectCommand drawCmd[] =
911 VERTEX_OFFSET, // vertexOffset
912 FirstInstanceSupport::getFirstInstance() // firstInstance
914 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride)
919 VERTEX_OFFSET, // vertexOffset
920 FirstInstanceSupport::getFirstInstance() // firstInstance
923 addCommand(drawCmd[0]);
924 addCommand(drawCmd[1]);
925 addCommand(drawCmd[2]);
926 if (m_testIndirectCountExt != IndirectCountType::NONE)
928 // Add padding data to the buffer to make sure it's large enough.
929 for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
931 addCommand(drawCmd[1]);
932 addCommand(drawCmd[1]);
937 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
939 vk::VkDrawIndexedIndirectCommand drawCmd[] =
945 VERTEX_OFFSET, // vertexOffset
946 FirstInstanceSupport::getFirstInstance() // firstInstance
948 { (deUint32)-4, (deUint32)-2, (deUint32)-11, (deInt32)9, (deUint32)-7 }, // junk (stride)
953 VERTEX_OFFSET, // vertexOffset
954 FirstInstanceSupport::getFirstInstance() // firstInstance
957 addCommand(drawCmd[0]);
958 addCommand(drawCmd[1]);
959 addCommand(drawCmd[2]);
960 if (m_testIndirectCountExt != IndirectCountType::NONE)
962 // Add padding data to the buffer to make sure it's large enough.
963 for (deUint32 i = 0; i < m_bufferDrawCount; ++i)
965 addCommand(drawCmd[1]);
966 addCommand(drawCmd[1]);
972 TCU_FAIL("impossible");
976 m_strideInBuffer = 2 * (deUint32)sizeof(vk::VkDrawIndexedIndirectCommand);
979 const vk::VkDeviceSize dataSize = m_indirectBufferContents.size();
980 const vk::VkDeviceSize indirectBufferSize = dataSize + m_offsetInBuffer;
981 vk::VkBufferUsageFlags usageFlags = vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
982 if (m_dataFromComputeShader)
983 usageFlags |= vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
985 m_indirectBuffer = Buffer::createAndAlloc( m_vk,
986 m_context.getDevice(),
987 BufferCreateInfo(indirectBufferSize, usageFlags),
988 m_context.getDefaultAllocator(),
989 vk::MemoryRequirement::HostVisible);
991 deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
993 deMemcpy(ptr, &m_junkData, static_cast<size_t>(m_offsetInBuffer));
994 deMemcpy((ptr + m_offsetInBuffer), &m_indirectBufferContents[0], static_cast<size_t>(dataSize));
996 if (m_dataFromComputeShader)
998 // Negate all the buffer data and let a compute shader restore it to original.
999 for (int i = 0; i < static_cast<int>(indirectBufferSize); i++)
1001 ptr[i] = static_cast<deUint8>(~ptr[i]);
1005 vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
1007 m_offsetInCountBuffer = sizeof(tcu::Vec3);
1008 const vk::VkDeviceSize countBufferSize = m_offsetInCountBuffer + sizeof(m_drawCount);
1010 if (m_testIndirectCountExt != IndirectCountType::NONE)
1012 m_indirectCountBuffer = Buffer::createAndAlloc(m_vk,
1013 m_context.getDevice(),
1014 BufferCreateInfo(countBufferSize, usageFlags),
1015 m_context.getDefaultAllocator(),
1016 vk::MemoryRequirement::HostVisible);
1018 deUint8* countBufferPtr = reinterpret_cast<deUint8*>(m_indirectCountBuffer->getBoundMemory().getHostPtr());
1020 // For IndirectCountType::PARAM_LIMIT, the real limit will be set using the call parameter.
1021 if (m_isMultiDrawEnabled && m_drawCount <= m_drawIndirectMaxCount)
1022 *(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = m_drawCount + (m_testIndirectCountExt == IndirectCountType::BUFFER_LIMIT ? 0u : m_indirectCountExtDrawPadding);
1024 *(deUint32*)(countBufferPtr + m_offsetInCountBuffer) = 1u;
1026 if (m_dataFromComputeShader)
1028 // Negate all the buffer data and let a compute shader restore it to original.
1029 for (int i = 0; i < static_cast<int>(countBufferSize); i++)
1031 countBufferPtr[i] = static_cast<deUint8>(~countBufferPtr[i]);
1035 vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectCountBuffer->getBoundMemory());
1038 #ifndef CTS_USES_VULKANSC
1039 if (m_groupParams->useSecondaryCmdBuffer)
1041 // record secondary command buffer
1042 if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1044 beginSecondaryCmdBuffer(m_vk, vk::VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT);
1045 beginDynamicRender(*m_secCmdBuffer);
1048 beginSecondaryCmdBuffer(m_vk);
1050 draw(*m_secCmdBuffer);
1052 if (m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1053 endDynamicRender(*m_secCmdBuffer);
1055 endCommandBuffer(m_vk, *m_secCmdBuffer);
1057 // record primary command buffer
1058 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1060 if (m_dataFromComputeShader)
1061 negateDataUsingCompute(indirectBufferSize, countBufferSize);
1063 preRenderBarriers();
1065 if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1066 beginDynamicRender(*m_cmdBuffer, vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
1068 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1u, &*m_secCmdBuffer);
1070 if (!m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1071 endDynamicRender(*m_cmdBuffer);
1073 endCommandBuffer(m_vk, *m_cmdBuffer);
1075 else if(m_groupParams->useDynamicRendering)
1077 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1079 if (m_dataFromComputeShader)
1080 negateDataUsingCompute(indirectBufferSize, countBufferSize);
1082 preRenderBarriers();
1083 beginDynamicRender(*m_cmdBuffer);
1085 endDynamicRender(*m_cmdBuffer);
1087 endCommandBuffer(m_vk, *m_cmdBuffer);
1089 #endif // CTS_USES_VULKANSC
1091 if (!m_groupParams->useDynamicRendering)
1093 beginCommandBuffer(m_vk, *m_cmdBuffer, 0u);
1095 if (m_dataFromComputeShader)
1096 negateDataUsingCompute(indirectBufferSize, countBufferSize);
1098 preRenderBarriers();
1099 beginLegacyRender(*m_cmdBuffer);
1101 endLegacyRender(*m_cmdBuffer);
1103 endCommandBuffer(m_vk, *m_cmdBuffer);
1106 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
1109 VK_CHECK(m_vk.queueWaitIdle(queue));
1111 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5 + static_cast<float>(HEIGHT)));
1113 referenceFrame.allocLevel(0);
1115 const deInt32 frameWidth = referenceFrame.getWidth();
1116 const deInt32 frameHeight = referenceFrame.getHeight();
1118 tcu::clear(referenceFrame.getLevel(0), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1120 ReferenceImageInstancedCoordinates refInstancedCoords;
1122 for (int y = 0; y < frameHeight; y++)
1124 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
1126 for (int x = 0; x < frameWidth; x++)
1128 const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
1130 if ((yCoord >= refInstancedCoords.bottom &&
1131 yCoord <= refInstancedCoords.top &&
1132 xCoord >= refInstancedCoords.left &&
1133 xCoord <= refInstancedCoords.right))
1134 referenceFrame.getLevel(0).setPixel(tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y);
1138 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
1139 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
1140 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
1142 qpTestResult res = QP_TEST_RESULT_PASS;
1144 if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
1145 referenceFrame.getLevel(0), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
1147 res = QP_TEST_RESULT_FAIL;
1150 return tcu::TestStatus(res, qpGetTestResultName(res));
1153 void checkSupport(Context& context, IndirectDraw::TestSpec testSpec)
1155 if (testSpec.testIndirectCountExt != IndirectCountType::NONE)
1156 context.requireDeviceFunctionality("VK_KHR_draw_indirect_count");
1158 if (testSpec.groupParams->useDynamicRendering)
1159 context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
1164 IndirectDrawTests::IndirectDrawTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams)
1165 : TestCaseGroup (testCtx, "indirect_draw", "indirect drawing simple geometry")
1166 , m_groupParams (groupParams)
1168 /* Left blank on purpose */
1171 IndirectDrawTests::~IndirectDrawTests (void) {}
1174 void IndirectDrawTests::init (void)
1176 for (auto dataFromCompute : {false, true})
1177 for (int drawTypeIdx = 0; drawTypeIdx < DRAWTYPE_LAST; drawTypeIdx++)
1179 // reduce number of tests for dynamic rendering cases where secondary command buffer is used
1180 if (m_groupParams->useSecondaryCmdBuffer && (dataFromCompute == m_groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass))
1183 std::string drawTypeStr;
1184 switch (drawTypeIdx)
1186 case DRAW_TYPE_SEQUENTIAL:
1187 drawTypeStr = "sequential";
1189 case DRAW_TYPE_INDEXED:
1190 drawTypeStr = "indexed";
1193 TCU_FAIL("impossible");
1196 if (dataFromCompute)
1197 drawTypeStr += "_data_from_compute";
1199 tcu::TestCaseGroup* drawTypeGroup = new tcu::TestCaseGroup(m_testCtx, drawTypeStr.c_str(), ("Draws geometry using " + drawTypeStr + "draw call").c_str());
1201 tcu::TestCaseGroup* indirectDrawGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw", "Draws geometry");
1202 tcu::TestCaseGroup* indirectDrawCountGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_count", "Draws geometry with VK_KHR_draw_indirect_count extension");
1203 tcu::TestCaseGroup* indirectDrawParamCountGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_param_count", "Draws geometry with VK_KHR_draw_indirect_count extension and limit draws count with call parameter");
1205 IndirectDraw::TestSpec testSpec(m_groupParams);
1206 testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1207 testSpec.dataFromCompute = dataFromCompute;
1208 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetch.vert";
1209 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1210 if (dataFromCompute)
1211 testSpec.shaders[glu::SHADERTYPE_COMPUTE] = "vulkan/draw/NegateData.comp";
1213 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1214 indirectDrawGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1215 (m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1216 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1217 indirectDrawGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1218 (m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1220 testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1221 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1222 indirectDrawCountGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1223 (m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1224 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1225 indirectDrawCountGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1226 (m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1228 testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1229 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1230 indirectDrawParamCountGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1231 (m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1232 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1233 indirectDrawParamCountGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1234 (m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1236 drawTypeGroup->addChild(indirectDrawGroup);
1237 drawTypeGroup->addChild(indirectDrawCountGroup);
1238 drawTypeGroup->addChild(indirectDrawParamCountGroup);
1241 tcu::TestCaseGroup* indirectDrawFirstInstanceGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_first_instance", "Draws geometry with different first instance in one commandbuffer");
1242 tcu::TestCaseGroup* indirectDrawCountFirstInstanceGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_count_first_instance", "Draws geometry with VK_KHR_draw_indirect_count extension with different first instance in one commandbuffer");
1243 tcu::TestCaseGroup* indirectDrawParamCountFirstInstanceGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_param_count_first_instance", "Draws geometry with VK_KHR_draw_indirect_count extension with different first instance in one commandbuffer and limit draws count with call parameter");
1245 IndirectDraw::TestSpec testSpec(m_groupParams);
1246 testSpec.testFirstInstanceNdx = true;
1247 testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1248 testSpec.dataFromCompute = dataFromCompute;
1249 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstanceIndex.vert";
1250 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1251 if (dataFromCompute)
1252 testSpec.shaders[glu::SHADERTYPE_COMPUTE] = "vulkan/draw/NegateData.comp";
1254 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1255 indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1256 (m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1257 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1258 indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1259 (m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1261 testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1262 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1263 indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1264 (m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1265 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1266 indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1267 (m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1269 testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1270 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1271 indirectDrawParamCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1272 (m_testCtx, "triangle_list", "Draws triangle list", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1273 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1274 indirectDrawParamCountFirstInstanceGroup->addChild(new InstanceFactory<IndirectDraw, FunctionSupport1<IndirectDraw::TestSpec> >
1275 (m_testCtx, "triangle_strip", "Draws triangle strip", testSpec, FunctionSupport1<IndirectDraw::TestSpec>::Args(checkSupport, testSpec)));
1277 drawTypeGroup->addChild(indirectDrawFirstInstanceGroup);
1278 drawTypeGroup->addChild(indirectDrawCountFirstInstanceGroup);
1279 drawTypeGroup->addChild(indirectDrawParamCountFirstInstanceGroup);
1282 tcu::TestCaseGroup* indirectDrawInstancedGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_instanced", "Draws an instanced geometry");
1283 tcu::TestCaseGroup* indirectDrawCountInstancedGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_count_instanced", "Draws an instanced geometry with VK_KHR_draw_indirect_count extension");
1284 tcu::TestCaseGroup* indirectDrawParamCountInstancedGroup = new tcu::TestCaseGroup(m_testCtx, "indirect_draw_param_count_instanced", "Draws an instanced geometry with VK_KHR_draw_indirect_count extension and limit draws count with call parameter");
1286 tcu::TestCaseGroup* indirectDrawNoFirstInstanceGroup = new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance");
1287 tcu::TestCaseGroup* indirectDrawCountNoFirstInstanceGroup = new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance");
1288 tcu::TestCaseGroup* indirectDrawParamCountNoFirstInstanceGroup = new tcu::TestCaseGroup(m_testCtx, "no_first_instance", "Use 0 as firstInstance");
1290 typedef IndirectDrawInstanced<FirstInstanceNotSupported> IDFirstInstanceNotSupported;
1292 IDFirstInstanceNotSupported::TestSpec testSpec(m_groupParams);
1293 testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1294 testSpec.dataFromCompute = dataFromCompute;
1296 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstanced.vert";
1297 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1298 if (dataFromCompute)
1299 testSpec.shaders[glu::SHADERTYPE_COMPUTE] = "vulkan/draw/NegateData.comp";
1301 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1302 indirectDrawNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1303 (m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1304 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1305 indirectDrawNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1306 (m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1308 testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1309 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1310 indirectDrawCountNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1311 (m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1312 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1313 indirectDrawCountNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1314 (m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1316 testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1317 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1318 indirectDrawParamCountNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1319 (m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1320 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1321 indirectDrawParamCountNoFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceNotSupported, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec> >
1322 (m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceNotSupported::TestSpec>::Args(checkSupport, testSpec)));
1324 indirectDrawInstancedGroup->addChild(indirectDrawNoFirstInstanceGroup);
1325 indirectDrawCountInstancedGroup->addChild(indirectDrawCountNoFirstInstanceGroup);
1326 indirectDrawParamCountInstancedGroup->addChild(indirectDrawParamCountNoFirstInstanceGroup);
1328 tcu::TestCaseGroup* indirectDrawFirstInstanceGroup = new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature");
1329 tcu::TestCaseGroup* indirectDrawCountFirstInstanceGroup = new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature");
1330 tcu::TestCaseGroup* indirectDrawParamCountFirstInstanceGroup = new tcu::TestCaseGroup(m_testCtx, "first_instance", "Use drawIndirectFirstInstance optional feature");
1332 typedef IndirectDrawInstanced<FirstInstanceSupported> IDFirstInstanceSupported;
1334 IDFirstInstanceSupported::TestSpec testSpec(m_groupParams);
1335 testSpec.drawType = static_cast<DrawType>(drawTypeIdx);
1336 testSpec.dataFromCompute = dataFromCompute;
1338 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/draw/VertexFetchInstancedFirstInstance.vert";
1339 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/draw/VertexFetch.frag";
1340 if (dataFromCompute)
1341 testSpec.shaders[glu::SHADERTYPE_COMPUTE] = "vulkan/draw/NegateData.comp";
1343 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1344 indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1345 (m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1346 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1347 indirectDrawFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1348 (m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1350 testSpec.testIndirectCountExt = IndirectCountType::BUFFER_LIMIT;
1351 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1352 indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1353 (m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1354 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1355 indirectDrawCountFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1356 (m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1358 testSpec.testIndirectCountExt = IndirectCountType::PARAM_LIMIT;
1359 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1360 indirectDrawParamCountFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1361 (m_testCtx, "triangle_list", "Draws an instanced triangle list", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1362 testSpec.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1363 indirectDrawParamCountFirstInstanceGroup->addChild(new InstanceFactory<IDFirstInstanceSupported, FunctionSupport1<IDFirstInstanceSupported::TestSpec> >
1364 (m_testCtx, "triangle_strip", "Draws an instanced triangle strip", testSpec, FunctionSupport1<IDFirstInstanceSupported::TestSpec>::Args(checkSupport, testSpec)));
1366 indirectDrawInstancedGroup->addChild(indirectDrawFirstInstanceGroup);
1367 indirectDrawCountInstancedGroup->addChild(indirectDrawCountFirstInstanceGroup);
1368 indirectDrawParamCountInstancedGroup->addChild(indirectDrawParamCountFirstInstanceGroup);
1370 drawTypeGroup->addChild(indirectDrawInstancedGroup);
1371 drawTypeGroup->addChild(indirectDrawCountInstancedGroup);
1372 drawTypeGroup->addChild(indirectDrawParamCountInstancedGroup);
1375 addChild(drawTypeGroup);