1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2018 The Khronos Group Inc.
6  * Copyright (c) 2018 Danylo Piliaiev <[email protected]>
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 Conditional Rendering Test Utils
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktConditionalRenderingTestUtil.hpp"
26 #include "vktDrawCreateInfoUtil.hpp"
27 #include "vkQueryUtil.hpp"
28 #include "vkCmdUtil.hpp"
29 #include "vkTypeUtil.hpp"
30 
31 namespace vkt
32 {
33 namespace conditional
34 {
35 
checkConditionalRenderingCapabilities(vkt::Context & context,const ConditionalData & data)36 void checkConditionalRenderingCapabilities(vkt::Context &context, const ConditionalData &data)
37 {
38     context.requireDeviceFunctionality("VK_EXT_conditional_rendering");
39 
40     const auto &conditionalRenderingFeatures = context.getConditionalRenderingFeaturesEXT();
41 
42     if (conditionalRenderingFeatures.conditionalRendering == VK_FALSE)
43         TCU_FAIL("conditionalRendering feature not supported but VK_EXT_conditional_rendering present");
44 
45     if (data.conditionInherited && !conditionalRenderingFeatures.inheritedConditionalRendering)
46         TCU_THROW(NotSupportedError, "Device does not support inherited conditional rendering");
47 
48     if (data.secondaryCommandBufferNested)
49     {
50         context.requireDeviceFunctionality("VK_EXT_nested_command_buffer");
51         const auto &features =
52             *vk::findStructure<vk::VkPhysicalDeviceNestedCommandBufferFeaturesEXT>(&context.getDeviceFeatures2());
53         if (!features.nestedCommandBuffer)
54             TCU_THROW(NotSupportedError, "nestedCommandBuffer is not supported");
55     }
56 }
57 
checkNestedRenderPassCapabilities(vkt::Context & context)58 void checkNestedRenderPassCapabilities(vkt::Context &context)
59 {
60     context.requireDeviceFunctionality("VK_EXT_nested_command_buffer");
61     const auto &features =
62         *vk::findStructure<vk::VkPhysicalDeviceNestedCommandBufferFeaturesEXT>(&context.getDeviceFeatures2());
63     if (!features.nestedCommandBuffer)
64         TCU_THROW(NotSupportedError, "nestedCommandBuffer is not supported");
65     if (!features.nestedCommandBufferRendering)
66         TCU_THROW(NotSupportedError, "nestedCommandBufferRendering is not supported");
67 }
68 
createConditionalRenderingBuffer(vkt::Context & context,const ConditionalData & data)69 de::SharedPtr<Draw::Buffer> createConditionalRenderingBuffer(vkt::Context &context, const ConditionalData &data)
70 {
71     const auto &vk        = context.getDeviceInterface();
72     const auto device     = context.getDevice();
73     const auto queueIndex = context.getUniversalQueueFamilyIndex();
74     const auto queue      = context.getUniversalQueue();
75     auto &alloc           = context.getDefaultAllocator();
76 
77     // When padding the condition value, it will be surounded by two additional values with nonzero bytes in them.
78     // When choosing to apply an offset to the allocation, the offset will be four times the size of the condition variable.
79     const auto bufferSize =
80         static_cast<vk::VkDeviceSize>(sizeof(data.conditionValue)) * (data.padConditionValue ? 3ull : 1ull);
81     const auto dataOffset = static_cast<vk::VkDeviceSize>(data.padConditionValue ? sizeof(data.conditionValue) : 0);
82     const auto allocOffset =
83         static_cast<vk::VkDeviceSize>(sizeof(data.conditionValue) * (data.allocationOffset ? 4u : 0u));
84 
85     // Create host-visible buffer. This may be the final buffer or only a staging buffer.
86     const auto hostUsage = ((data.memoryType == HOST) ? vk::VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT :
87                                                         vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
88     de::SharedPtr<Draw::Buffer> hostBuffer =
89         Draw::Buffer::createAndAlloc(vk, device, Draw::BufferCreateInfo(bufferSize, hostUsage), alloc,
90                                      vk::MemoryRequirement::HostVisible, allocOffset);
91 
92     // Copy data to host buffer.
93     uint8_t *conditionBufferPtr = reinterpret_cast<uint8_t *>(hostBuffer->getHostPtr());
94     deMemset(conditionBufferPtr, 1, static_cast<size_t>(bufferSize));
95     deMemcpy(conditionBufferPtr + dataOffset, &data.conditionValue, sizeof(data.conditionValue));
96     vk::flushAlloc(vk, context.getDevice(), hostBuffer->getBoundMemory());
97 
98     // Return host buffer if appropriate.
99     if (data.memoryType == HOST)
100         return hostBuffer;
101 
102     // Create and return device-local buffer otherwise, after copying host-visible buffer contents to it.
103     const auto deviceLocalUsage =
104         (vk::VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
105     de::SharedPtr<Draw::Buffer> deviceLocalBuffer =
106         Draw::Buffer::createAndAlloc(vk, device, Draw::BufferCreateInfo(bufferSize, deviceLocalUsage), alloc,
107                                      vk::MemoryRequirement::Local, allocOffset);
108 
109     const auto cmdPool   = vk::makeCommandPool(vk, device, queueIndex);
110     const auto cmdBuffer = vk::allocateCommandBuffer(vk, device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
111     const auto copyInfo  = vk::makeBufferCopy(0ull, 0ull, bufferSize);
112 
113     vk::beginCommandBuffer(vk, *cmdBuffer);
114     vk.cmdCopyBuffer(*cmdBuffer, hostBuffer->object(), deviceLocalBuffer->object(), 1, &copyInfo);
115     vk::endCommandBuffer(vk, *cmdBuffer);
116     vk::submitCommandsAndWait(vk, device, queue, *cmdBuffer);
117 
118     return deviceLocalBuffer;
119 }
120 
beginConditionalRendering(const vk::DeviceInterface & vk,vk::VkCommandBuffer cmdBuffer,Draw::Buffer & buffer,const ConditionalData & data)121 void beginConditionalRendering(const vk::DeviceInterface &vk, vk::VkCommandBuffer cmdBuffer, Draw::Buffer &buffer,
122                                const ConditionalData &data)
123 {
124     vk::VkConditionalRenderingBeginInfoEXT conditionalRenderingBeginInfo;
125     conditionalRenderingBeginInfo.sType  = vk::VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT;
126     conditionalRenderingBeginInfo.pNext  = nullptr;
127     conditionalRenderingBeginInfo.buffer = buffer.object();
128     conditionalRenderingBeginInfo.offset =
129         static_cast<vk::VkDeviceSize>(data.padConditionValue ? sizeof(data.conditionValue) : 0u);
130     conditionalRenderingBeginInfo.flags = data.conditionInverted ? vk::VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT : 0;
131 
132     vk.cmdBeginConditionalRenderingEXT(cmdBuffer, &conditionalRenderingBeginInfo);
133 }
134 
operator <<(std::ostream & str,ConditionalData const & c)135 std::ostream &operator<<(std::ostream &str, ConditionalData const &c)
136 {
137     const bool conditionEnabled = c.conditionInPrimaryCommandBuffer || c.conditionInSecondaryCommandBuffer;
138     str << (conditionEnabled ? "condition" : "no_condition");
139     str << (c.memoryType ? "_host_memory" : "_local_memory");
140 
141     if (c.conditionInSecondaryCommandBuffer || !conditionEnabled)
142     {
143         if (c.secondaryCommandBufferNested)
144         {
145             str << "_nested_buffer";
146         }
147         else
148         {
149             str << "_secondary_buffer";
150         }
151     }
152 
153     if (c.conditionInherited)
154     {
155         if (c.secondaryCommandBufferNested)
156         {
157             str << "_nested_inherited";
158         }
159         else
160         {
161             str << "_inherited";
162         }
163     }
164 
165     str << "_" << (c.expectCommandExecution ? "expect_execution" : "expect_noop");
166 
167     if (c.conditionInverted)
168     {
169         str << "_inverted";
170     }
171 
172     if (c.padConditionValue)
173     {
174         str << "_padded";
175     }
176 
177     if (c.clearInRenderPass)
178     {
179         str << "_rp_clear";
180     }
181 
182     return str;
183 }
184 
185 } // namespace conditional
186 } // namespace vkt
187