1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2018 The Khronos Group Inc.
6 * Copyright (c) 2018 Danylo Piliaiev <danylo.piliaiev@gmail.com>
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 Test for conditional rendering of vkCmdDraw* functions
23 *//*--------------------------------------------------------------------*/
25 #include "vktConditionalDrawTests.hpp"
26 #include "vktConditionalRenderingTestUtil.hpp"
28 #include "vktTestCaseUtil.hpp"
29 #include "vktDrawTestCaseUtil.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"
40 #include "vkCmdUtil.hpp"
51 DRAW_COMMAND_TYPE_DRAW = 0,
52 DRAW_COMMAND_TYPE_DRAW_INDEXED,
53 DRAW_COMMAND_TYPE_DRAW_INDIRECT,
54 DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT,
55 DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT,
56 DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT,
58 DRAW_COMMAND_TYPE_DRAW_LAST
61 const char* getDrawCommandTypeName (DrawCommandType command)
65 case DRAW_COMMAND_TYPE_DRAW: return "draw";
66 case DRAW_COMMAND_TYPE_DRAW_INDEXED: return "draw_indexed";
67 case DRAW_COMMAND_TYPE_DRAW_INDIRECT: return "draw_indirect";
68 case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT: return "draw_indexed_indirect";
69 case DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT: return "draw_indirect_count";
70 case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT: return "draw_indexed_indirect_count";
71 default: DE_ASSERT(false);
76 struct ConditionalTestSpec : public Draw::TestSpecBase
78 DrawCommandType command;
80 ConditionalData conditionalData;
83 class ConditionalDraw : public Draw::DrawTestsBaseClass
86 typedef ConditionalTestSpec TestSpec;
88 ConditionalDraw (Context &context, ConditionalTestSpec testSpec);
90 virtual tcu::TestStatus iterate (void);
91 void createAndBindIndexBuffer (vk::VkCommandBuffer cmdBuffer);
92 void createIndirectBuffer (void);
93 void createIndexedIndirectBuffer (void);
94 void createIndirectCountBuffer (void);
95 void recordDraw (vk::VkCommandBuffer cmdBuffer);
98 const DrawCommandType m_command;
99 const deUint32 m_drawCalls;
101 const ConditionalData m_conditionalData;
102 de::SharedPtr<Draw::Buffer> m_conditionalBuffer;
104 vk::Move<vk::VkCommandBuffer> m_secondaryCmdBuffer;
106 std::vector<deUint32> m_indexes;
107 de::SharedPtr<Draw::Buffer> m_indexBuffer;
109 de::SharedPtr<Draw::Buffer> m_indirectBuffer;
110 de::SharedPtr<Draw::Buffer> m_indirectCountBuffer;
113 ConditionalDraw::ConditionalDraw (Context &context, ConditionalTestSpec testSpec)
114 : Draw::DrawTestsBaseClass(context, testSpec.shaders[glu::SHADERTYPE_VERTEX], testSpec.shaders[glu::SHADERTYPE_FRAGMENT], vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
115 , m_command(testSpec.command)
116 , m_drawCalls(testSpec.drawCalls)
117 , m_conditionalData(testSpec.conditionalData)
119 checkConditionalRenderingCapabilities(context, m_conditionalData);
121 const float minX = -0.3f;
122 const float maxX = 0.3f;
123 const float drawStep = 0.6f / static_cast<float>(m_drawCalls);
125 for (deUint32 drawIdx = 0; drawIdx < m_drawCalls; drawIdx++)
127 const float minY = minX + static_cast<float>(drawIdx) * drawStep;
128 const float maxY = minY + drawStep;
130 m_data.push_back(Draw::VertexElementData(tcu::Vec4( minX, maxY, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
131 m_data.push_back(Draw::VertexElementData(tcu::Vec4( minX, minY, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
132 m_data.push_back(Draw::VertexElementData(tcu::Vec4( maxX, maxY, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
134 m_data.push_back(Draw::VertexElementData(tcu::Vec4( minX, minY, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
135 m_data.push_back(Draw::VertexElementData(tcu::Vec4( maxX, maxY, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
136 m_data.push_back(Draw::VertexElementData(tcu::Vec4( maxX, minY, 0.5f, 1.0f), tcu::RGBA::blue().toVec(), 0));
139 m_data.push_back(Draw::VertexElementData(tcu::Vec4( -1.0f, 1.0f, 0.0f, 1.0f), tcu::RGBA::red().toVec(), 0));
140 m_data.push_back(Draw::VertexElementData(tcu::Vec4( -1.0f, -1.0f, 0.0f, 1.0f), tcu::RGBA::red().toVec(), 0));
141 m_data.push_back(Draw::VertexElementData(tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), tcu::RGBA::red().toVec(), 0));
143 m_data.push_back(Draw::VertexElementData(tcu::Vec4( -1.0f, -1.0f, 0.0f, 1.0f), tcu::RGBA::red().toVec(), 0));
144 m_data.push_back(Draw::VertexElementData(tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), tcu::RGBA::red().toVec(), 0));
145 m_data.push_back(Draw::VertexElementData(tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f), tcu::RGBA::red().toVec(), 0));
147 for (deUint32 index = 0; index < m_data.size(); index++)
149 m_indexes.push_back(index);
154 m_secondaryCmdBuffer = vk::allocateCommandBuffer(m_vk, m_context.getDevice(), *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY);
157 void ConditionalDraw::createAndBindIndexBuffer (vk::VkCommandBuffer cmdBuffer)
159 const vk::VkDeviceSize indexDataSize = m_indexes.size() * sizeof(deUint32);
160 m_indexBuffer = Draw::Buffer::createAndAlloc(m_vk, m_context.getDevice(),
161 Draw::BufferCreateInfo(indexDataSize,
162 vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT),
163 m_context.getDefaultAllocator(),
164 vk::MemoryRequirement::HostVisible);
166 deUint8* indexBufferPtr = reinterpret_cast<deUint8*>(m_indexBuffer->getBoundMemory().getHostPtr());
167 deMemcpy(indexBufferPtr, &m_indexes[0], static_cast<size_t>(indexDataSize));
169 vk::flushAlloc(m_vk, m_context.getDevice(), m_indexBuffer->getBoundMemory());
171 const vk::VkBuffer indexBuffer = m_indexBuffer->object();
172 m_vk.cmdBindIndexBuffer(cmdBuffer, indexBuffer, 0, vk::VK_INDEX_TYPE_UINT32);
175 void ConditionalDraw::createIndirectBuffer (void)
177 const vk::VkDrawIndirectCommand badDrawCommand =
181 m_drawCalls * 6u, // firstVertex
185 std::vector<vk::VkDrawIndirectCommand> drawCommands;
186 for (deUint32 drawIdx = 0; drawIdx < m_drawCalls; drawIdx++)
188 const vk::VkDrawIndirectCommand goodDrawCommand =
192 6u * drawIdx, // firstVertex
196 drawCommands.push_back(goodDrawCommand);
197 // *Bad* commands should not be rendered by vkCmdDrawIndirectCountKHR
198 drawCommands.push_back(badDrawCommand);
199 drawCommands.push_back(badDrawCommand);
202 const vk::VkDeviceSize drawCommandsSize = drawCommands.size() * sizeof(vk::VkDrawIndirectCommand);
204 m_indirectBuffer = Draw::Buffer::createAndAlloc(m_vk,
205 m_context.getDevice(),
206 Draw::BufferCreateInfo(drawCommandsSize,
207 vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
208 m_context.getDefaultAllocator(),
209 vk::MemoryRequirement::HostVisible);
211 deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
212 deMemcpy(ptr, &drawCommands[0], static_cast<size_t>(drawCommandsSize));
214 vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
217 void ConditionalDraw::createIndexedIndirectBuffer (void)
219 const vk::VkDrawIndexedIndirectCommand badDrawCommand =
223 m_drawCalls * 6u, // firstIndex
228 std::vector<vk::VkDrawIndexedIndirectCommand> drawCommands;
229 for (deUint32 drawIdx = 0; drawIdx < m_drawCalls; drawIdx++)
231 const vk::VkDrawIndexedIndirectCommand goodDrawCommand =
235 6u * drawIdx, // firstIndex
240 drawCommands.push_back(goodDrawCommand);
241 // *Bad* commands should not be rendered by vkCmdDrawIndexedIndirectCountKHR
242 drawCommands.push_back(badDrawCommand);
243 drawCommands.push_back(badDrawCommand);
246 const vk::VkDeviceSize drawCommandsSize = drawCommands.size() * sizeof(vk::VkDrawIndexedIndirectCommand);
248 m_indirectBuffer = Draw::Buffer::createAndAlloc(m_vk,
249 m_context.getDevice(),
250 Draw::BufferCreateInfo(drawCommandsSize,
251 vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
252 m_context.getDefaultAllocator(),
253 vk::MemoryRequirement::HostVisible);
255 deUint8* ptr = reinterpret_cast<deUint8*>(m_indirectBuffer->getBoundMemory().getHostPtr());
256 deMemcpy(ptr, &drawCommands[0], static_cast<size_t>(drawCommandsSize));
258 vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectBuffer->getBoundMemory());
261 void ConditionalDraw::createIndirectCountBuffer (void)
263 m_indirectCountBuffer = Draw::Buffer::createAndAlloc(m_vk,
264 m_context.getDevice(),
265 Draw::BufferCreateInfo(sizeof(deUint32),
266 vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
267 m_context.getDefaultAllocator(),
268 vk::MemoryRequirement::HostVisible);
270 deUint8* countBufferPtr = reinterpret_cast<deUint8*>(m_indirectCountBuffer->getBoundMemory().getHostPtr());
271 *(deUint32*)(countBufferPtr) = 1;
273 vk::flushAlloc(m_vk, m_context.getDevice(), m_indirectCountBuffer->getBoundMemory());
276 void ConditionalDraw::recordDraw(vk::VkCommandBuffer cmdBuffer)
278 for (deUint32 drawIdx = 0; drawIdx < m_drawCalls; drawIdx++)
280 /* Indirect buffer has next layout:
281 * goodCommand badCommand badCommand goodCommand badCommand badCommand ...
283 const vk::VkDeviceSize indirectOffset = sizeof(vk::VkDrawIndirectCommand) * drawIdx * 3;
284 const vk::VkDeviceSize indexedIndirectOffset = sizeof(vk::VkDrawIndexedIndirectCommand) * drawIdx * 3;
287 case DRAW_COMMAND_TYPE_DRAW:
289 m_vk.cmdDraw(cmdBuffer, 6, 1, 6 * drawIdx, 0);
292 case DRAW_COMMAND_TYPE_DRAW_INDEXED:
294 m_vk.cmdDrawIndexed(cmdBuffer, 6, 1, 6 * drawIdx, 0, 0);
297 case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
299 m_vk.cmdDrawIndirect(cmdBuffer, m_indirectBuffer->object(), indirectOffset, 1, 0);
302 case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
304 m_vk.cmdDrawIndexedIndirect(cmdBuffer, m_indirectBuffer->object(), indexedIndirectOffset, 1, 0);
307 case DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT:
309 m_vk.cmdDrawIndirectCount( cmdBuffer,
310 m_indirectBuffer->object(), indirectOffset,
311 m_indirectCountBuffer->object(), 0, 3,
312 sizeof(vk::VkDrawIndirectCommand));
315 case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT:
317 m_vk.cmdDrawIndexedIndirectCount(cmdBuffer,
318 m_indirectBuffer->object(), indexedIndirectOffset,
319 m_indirectCountBuffer->object(), 0, 3,
320 sizeof(vk::VkDrawIndexedIndirectCommand));
323 default: DE_ASSERT(false);
328 tcu::TestStatus ConditionalDraw::iterate (void)
330 tcu::TestLog& log = m_context.getTestContext().getLog();
331 const vk::VkQueue queue = m_context.getUniversalQueue();
332 const vk::VkDevice device = m_context.getDevice();
334 const bool useSecondaryCmdBuffer = m_conditionalData.conditionInherited || m_conditionalData.conditionInSecondaryCommandBuffer;
335 beginRenderPass(useSecondaryCmdBuffer ? vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : vk::VK_SUBPASS_CONTENTS_INLINE);
337 vk::VkCommandBuffer targetCmdBuffer = *m_cmdBuffer;
339 if (useSecondaryCmdBuffer)
341 const vk::VkCommandBufferInheritanceConditionalRenderingInfoEXT conditionalRenderingInheritanceInfo =
343 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT,
345 m_conditionalData.conditionInherited ? VK_TRUE : VK_FALSE // conditionalRenderingEnable
348 const vk::VkCommandBufferInheritanceInfo inheritanceInfo =
350 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
351 &conditionalRenderingInheritanceInfo,
352 *m_renderPass, // renderPass
354 *m_framebuffer, // framebuffer
355 VK_FALSE, // occlusionQueryEnable
356 (vk::VkQueryControlFlags)0u, // queryFlags
357 (vk::VkQueryPipelineStatisticFlags)0u, // pipelineStatistics
360 const vk::VkCommandBufferBeginInfo commandBufferBeginInfo =
362 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
364 vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT,
368 m_vk.beginCommandBuffer(*m_secondaryCmdBuffer, &commandBufferBeginInfo);
370 targetCmdBuffer = *m_secondaryCmdBuffer;
373 const vk::VkDeviceSize vertexBufferOffset = 0;
374 const vk::VkBuffer vertexBuffer = m_vertexBuffer->object();
376 m_vk.cmdBindVertexBuffers(targetCmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
380 case DRAW_COMMAND_TYPE_DRAW:
384 case DRAW_COMMAND_TYPE_DRAW_INDEXED:
386 createAndBindIndexBuffer(targetCmdBuffer);
389 case DRAW_COMMAND_TYPE_DRAW_INDIRECT:
391 createIndirectBuffer();
394 case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT:
396 createAndBindIndexBuffer(targetCmdBuffer);
397 createIndexedIndirectBuffer();
400 case DRAW_COMMAND_TYPE_DRAW_INDIRECT_COUNT:
402 createIndirectBuffer();
403 createIndirectCountBuffer();
406 case DRAW_COMMAND_TYPE_DRAW_INDEXED_INDIRECT_COUNT:
408 createAndBindIndexBuffer(targetCmdBuffer);
409 createIndexedIndirectBuffer();
410 createIndirectCountBuffer();
413 default: DE_ASSERT(false);
416 m_vk.cmdBindPipeline(targetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
418 m_conditionalBuffer = createConditionalRenderingBuffer(m_context, m_conditionalData);
420 if (m_conditionalData.conditionInSecondaryCommandBuffer)
422 beginConditionalRendering(m_vk, *m_secondaryCmdBuffer, *m_conditionalBuffer, m_conditionalData);
423 recordDraw(*m_secondaryCmdBuffer);
424 m_vk.cmdEndConditionalRenderingEXT(*m_secondaryCmdBuffer);
425 m_vk.endCommandBuffer(*m_secondaryCmdBuffer);
427 else if (m_conditionalData.conditionInherited)
429 recordDraw(*m_secondaryCmdBuffer);
430 m_vk.endCommandBuffer(*m_secondaryCmdBuffer);
433 if (m_conditionalData.conditionInPrimaryCommandBuffer)
435 beginConditionalRendering(m_vk, *m_cmdBuffer, *m_conditionalBuffer, m_conditionalData);
437 if (m_conditionalData.conditionInherited)
439 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1, &m_secondaryCmdBuffer.get());
443 recordDraw(*m_cmdBuffer);
446 m_vk.cmdEndConditionalRenderingEXT(*m_cmdBuffer);
448 else if (useSecondaryCmdBuffer)
450 m_vk.cmdExecuteCommands(*m_cmdBuffer, 1, &m_secondaryCmdBuffer.get());
453 endRenderPass(m_vk, *m_cmdBuffer);
454 endCommandBuffer(m_vk, *m_cmdBuffer);
456 submitCommandsAndWait(m_vk, device, queue, m_cmdBuffer.get());
459 tcu::Texture2D referenceFrame(vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5f + static_cast<float>(WIDTH)), (int)(0.5f + static_cast<float>(HEIGHT)));
460 referenceFrame.allocLevel(0);
462 const deInt32 frameWidth = referenceFrame.getWidth();
463 const deInt32 frameHeight = referenceFrame.getHeight();
465 const tcu::Vec4 clearColor = tcu::RGBA::black().toVec();
466 const tcu::Vec4 drawColor = tcu::RGBA::blue().toVec();
468 tcu::clear(referenceFrame.getLevel(0), clearColor);
470 const tcu::Vec4 referenceColor = m_conditionalData.expectCommandExecution ?
471 drawColor : clearColor;
473 Draw::ReferenceImageCoordinates refCoords;
475 for (int y = 0; y < frameHeight; y++)
477 const float yCoord = (float)(y / (0.5*frameHeight)) - 1.0f;
479 for (int x = 0; x < frameWidth; x++)
481 const float xCoord = (float)(x / (0.5*frameWidth)) - 1.0f;
483 if ((yCoord >= refCoords.bottom &&
484 yCoord <= refCoords.top &&
485 xCoord >= refCoords.left &&
486 xCoord <= refCoords.right))
487 referenceFrame.getLevel(0).setPixel(referenceColor, x, y);
491 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
492 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
493 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
495 qpTestResult res = QP_TEST_RESULT_PASS;
497 if (!tcu::fuzzyCompare(log, "Result", "Image comparison result",
498 referenceFrame.getLevel(0), renderedFrame, 0.05f,
499 tcu::COMPARE_LOG_RESULT))
501 res = QP_TEST_RESULT_FAIL;
504 return tcu::TestStatus(res, qpGetTestResultName(res));
509 ConditionalDrawTests::ConditionalDrawTests (tcu::TestContext &testCtx)
510 : TestCaseGroup (testCtx, "draw", "Conditional Rendering Of Draw Commands")
512 /* Left blank on purpose */
515 ConditionalDrawTests::~ConditionalDrawTests (void) {}
517 void ConditionalDrawTests::init (void)
519 for (int conditionNdx = 0; conditionNdx < DE_LENGTH_OF_ARRAY(conditional::s_testsData); conditionNdx++)
521 const ConditionalData& conditionData = conditional::s_testsData[conditionNdx];
523 tcu::TestCaseGroup* conditionalDrawRootGroup = new tcu::TestCaseGroup(m_testCtx, de::toString(conditionData).c_str(), "Conditionaly execute draw calls");
525 for (deUint32 commandTypeIdx = 0; commandTypeIdx < DRAW_COMMAND_TYPE_DRAW_LAST; ++commandTypeIdx)
527 const DrawCommandType command = DrawCommandType(commandTypeIdx);
529 ConditionalTestSpec testSpec;
530 testSpec.command = command;
531 testSpec.drawCalls = 4;
532 testSpec.conditionalData = conditionData;
533 testSpec.shaders[glu::SHADERTYPE_VERTEX] = "vulkan/dynamic_state/VertexFetch.vert";
534 testSpec.shaders[glu::SHADERTYPE_FRAGMENT] = "vulkan/dynamic_state/VertexFetch.frag";
536 conditionalDrawRootGroup->addChild(new Draw::InstanceFactory<ConditionalDraw>(m_testCtx, getDrawCommandTypeName(command), "", testSpec));
539 addChild(conditionalDrawRootGroup);