blob: ca96fdd26916789f340c04a08ff0385b0b0a9900 [file] [log] [blame]
Jamie Madill49ac74b2017-12-21 14:42:33 -05001//
2// Copyright 2017 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6// CommandBufferNode:
7// Deferred work constructed by GL calls, that will later be flushed to Vulkan.
8//
9
10#include "libANGLE/renderer/vulkan/CommandBufferNode.h"
11
12#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
13#include "libANGLE/renderer/vulkan/RendererVk.h"
Jamie Madill3c424b42018-01-19 12:35:09 -050014#include "libANGLE/renderer/vulkan/vk_format_utils.h"
Jamie Madill49ac74b2017-12-21 14:42:33 -050015
16namespace rx
17{
18
19namespace vk
20{
21
22namespace
23{
24
25Error InitAndBeginCommandBuffer(VkDevice device,
26 const CommandPool &commandPool,
27 const VkCommandBufferInheritanceInfo &inheritanceInfo,
28 VkCommandBufferUsageFlags flags,
29 CommandBuffer *commandBuffer)
30{
31 ASSERT(!commandBuffer->valid());
32
33 VkCommandBufferAllocateInfo createInfo;
34 createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
35 createInfo.pNext = nullptr;
36 createInfo.commandPool = commandPool.getHandle();
37 createInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
38 createInfo.commandBufferCount = 1;
39
40 ANGLE_TRY(commandBuffer->init(device, createInfo));
41
42 VkCommandBufferBeginInfo beginInfo;
43 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
44 beginInfo.pNext = nullptr;
45 beginInfo.flags = flags | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
46 beginInfo.pInheritanceInfo = &inheritanceInfo;
47
48 ANGLE_TRY(commandBuffer->begin(beginInfo));
49 return NoError();
50}
51
52} // anonymous namespace
53
54// CommandBufferNode implementation.
55
56CommandBufferNode::CommandBufferNode()
Jamie Madill0e654542018-02-07 14:50:06 -050057 : mHasHappensAfterDependencies(false),
58 mVisitedState(VisitedState::Unvisited),
59 mIsFinishedRecording(false)
Jamie Madill49ac74b2017-12-21 14:42:33 -050060{
61}
62
63CommandBufferNode::~CommandBufferNode()
64{
65 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
66
67 // Command buffers are managed by the command pool, so don't need to be freed.
68 mOutsideRenderPassCommands.releaseHandle();
69 mInsideRenderPassCommands.releaseHandle();
70}
71
72CommandBuffer *CommandBufferNode::getOutsideRenderPassCommands()
73{
Jamie Madill0e654542018-02-07 14:50:06 -050074 ASSERT(!mIsFinishedRecording);
Jamie Madill49ac74b2017-12-21 14:42:33 -050075 return &mOutsideRenderPassCommands;
76}
77
78CommandBuffer *CommandBufferNode::getInsideRenderPassCommands()
79{
Jamie Madill0e654542018-02-07 14:50:06 -050080 ASSERT(!mIsFinishedRecording);
Jamie Madill49ac74b2017-12-21 14:42:33 -050081 return &mInsideRenderPassCommands;
82}
83
84Error CommandBufferNode::startRecording(VkDevice device,
85 const CommandPool &commandPool,
86 CommandBuffer **commandsOut)
87{
Jamie Madill0e654542018-02-07 14:50:06 -050088 ASSERT(!mIsFinishedRecording);
89
Jamie Madill49ac74b2017-12-21 14:42:33 -050090 VkCommandBufferInheritanceInfo inheritanceInfo;
91 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
92 inheritanceInfo.pNext = nullptr;
93 inheritanceInfo.renderPass = VK_NULL_HANDLE;
94 inheritanceInfo.subpass = 0;
95 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
96 inheritanceInfo.occlusionQueryEnable = VK_FALSE;
97 inheritanceInfo.queryFlags = 0;
98 inheritanceInfo.pipelineStatistics = 0;
99
100 ANGLE_TRY(InitAndBeginCommandBuffer(device, commandPool, inheritanceInfo, 0,
101 &mOutsideRenderPassCommands));
102
103 *commandsOut = &mOutsideRenderPassCommands;
104 return NoError();
105}
106
107Error CommandBufferNode::startRenderPassRecording(RendererVk *renderer, CommandBuffer **commandsOut)
108{
Jamie Madill0e654542018-02-07 14:50:06 -0500109 ASSERT(!mIsFinishedRecording);
110
Jamie Madill49ac74b2017-12-21 14:42:33 -0500111 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
112 // TODO(jmadill): Use different query method for compatible vs conformant render pass.
113 vk::RenderPass *compatibleRenderPass;
114 ANGLE_TRY(renderer->getCompatibleRenderPass(mRenderPassDesc, &compatibleRenderPass));
115
116 VkCommandBufferInheritanceInfo inheritanceInfo;
117 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
118 inheritanceInfo.pNext = nullptr;
119 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
120 inheritanceInfo.subpass = 0;
121 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
122 inheritanceInfo.occlusionQueryEnable = VK_FALSE;
123 inheritanceInfo.queryFlags = 0;
124 inheritanceInfo.pipelineStatistics = 0;
125
126 ANGLE_TRY(InitAndBeginCommandBuffer(
127 renderer->getDevice(), renderer->getCommandPool(), inheritanceInfo,
128 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
129
130 *commandsOut = &mInsideRenderPassCommands;
131 return NoError();
132}
133
Jamie Madill0e654542018-02-07 14:50:06 -0500134bool CommandBufferNode::isFinishedRecording() const
135{
136 return mIsFinishedRecording;
137}
138
139void CommandBufferNode::finishRecording()
140{
141 mIsFinishedRecording = true;
142}
143
Jamie Madill49ac74b2017-12-21 14:42:33 -0500144void CommandBufferNode::storeRenderPassInfo(const Framebuffer &framebuffer,
145 const gl::Rectangle renderArea,
146 const std::vector<VkClearValue> &clearValues)
147{
148 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
149 mRenderPassRenderArea = renderArea;
150 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
151}
152
153void CommandBufferNode::appendColorRenderTarget(Serial serial, RenderTargetVk *colorRenderTarget)
154{
155 // TODO(jmadill): Layout transition?
156 mRenderPassDesc.packColorAttachment(*colorRenderTarget->format, colorRenderTarget->samples);
Jamie Madill0e654542018-02-07 14:50:06 -0500157 colorRenderTarget->resource->onWriteResource(this, serial);
Jamie Madill49ac74b2017-12-21 14:42:33 -0500158}
159
160void CommandBufferNode::appendDepthStencilRenderTarget(Serial serial,
161 RenderTargetVk *depthStencilRenderTarget)
162{
163 // TODO(jmadill): Layout transition?
164 mRenderPassDesc.packDepthStencilAttachment(*depthStencilRenderTarget->format,
165 depthStencilRenderTarget->samples);
Jamie Madill0e654542018-02-07 14:50:06 -0500166 depthStencilRenderTarget->resource->onWriteResource(this, serial);
Jamie Madill49ac74b2017-12-21 14:42:33 -0500167}
168
169void CommandBufferNode::initAttachmentDesc(VkAttachmentDescription *desc)
170{
171 desc->flags = 0;
172 desc->format = VK_FORMAT_UNDEFINED;
173 desc->samples = static_cast<VkSampleCountFlagBits>(0);
174 desc->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
175 desc->storeOp = VK_ATTACHMENT_STORE_OP_STORE;
176 desc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
177 desc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
178 desc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
179 desc->finalLayout = VK_IMAGE_LAYOUT_UNDEFINED;
180}
181
Jamie Madill0e654542018-02-07 14:50:06 -0500182// static
183void CommandBufferNode::SetHappensBeforeDependency(CommandBufferNode *beforeNode,
184 CommandBufferNode *afterNode)
Jamie Madill49ac74b2017-12-21 14:42:33 -0500185{
Jamie Madill0e654542018-02-07 14:50:06 -0500186 afterNode->mHappensBeforeDependencies.emplace_back(beforeNode);
187 beforeNode->setHasHappensAfterDependencies();
188 beforeNode->finishRecording();
189 ASSERT(beforeNode != afterNode && !beforeNode->happensAfter(afterNode));
Jamie Madill49ac74b2017-12-21 14:42:33 -0500190}
191
Jamie Madill0e654542018-02-07 14:50:06 -0500192// static
193void CommandBufferNode::SetHappensBeforeDependencies(
194 const std::vector<CommandBufferNode *> &beforeNodes,
195 CommandBufferNode *afterNode)
Jamie Madill49ac74b2017-12-21 14:42:33 -0500196{
Jamie Madill0e654542018-02-07 14:50:06 -0500197 afterNode->mHappensBeforeDependencies.insert(afterNode->mHappensBeforeDependencies.end(),
198 beforeNodes.begin(), beforeNodes.end());
Jamie Madill49ac74b2017-12-21 14:42:33 -0500199
200 // TODO(jmadill): is there a faster way to do this?
Jamie Madill0e654542018-02-07 14:50:06 -0500201 for (CommandBufferNode *beforeNode : beforeNodes)
Jamie Madill49ac74b2017-12-21 14:42:33 -0500202 {
Jamie Madill0e654542018-02-07 14:50:06 -0500203 beforeNode->setHasHappensAfterDependencies();
204 beforeNode->finishRecording();
205
206 ASSERT(beforeNode != afterNode && !beforeNode->happensAfter(afterNode));
Jamie Madill49ac74b2017-12-21 14:42:33 -0500207 }
208}
209
Jamie Madill0e654542018-02-07 14:50:06 -0500210bool CommandBufferNode::hasHappensBeforeDependencies() const
Jamie Madill49ac74b2017-12-21 14:42:33 -0500211{
Jamie Madill0e654542018-02-07 14:50:06 -0500212 return !mHappensBeforeDependencies.empty();
Jamie Madill49ac74b2017-12-21 14:42:33 -0500213}
214
Jamie Madill0e654542018-02-07 14:50:06 -0500215void CommandBufferNode::setHasHappensAfterDependencies()
Jamie Madill49ac74b2017-12-21 14:42:33 -0500216{
Jamie Madill0e654542018-02-07 14:50:06 -0500217 mHasHappensAfterDependencies = true;
Jamie Madill49ac74b2017-12-21 14:42:33 -0500218}
219
Jamie Madill0e654542018-02-07 14:50:06 -0500220bool CommandBufferNode::hasHappensAfterDependencies() const
Jamie Madill49ac74b2017-12-21 14:42:33 -0500221{
Jamie Madill0e654542018-02-07 14:50:06 -0500222 return mHasHappensAfterDependencies;
Jamie Madill49ac74b2017-12-21 14:42:33 -0500223}
224
225// Do not call this in anything but testing code, since it's slow.
Jamie Madill0e654542018-02-07 14:50:06 -0500226bool CommandBufferNode::happensAfter(CommandBufferNode *beforeNode)
Jamie Madill49ac74b2017-12-21 14:42:33 -0500227{
228 std::set<CommandBufferNode *> visitedList;
229 std::vector<CommandBufferNode *> openList;
Jamie Madill0e654542018-02-07 14:50:06 -0500230 openList.insert(openList.begin(), mHappensBeforeDependencies.begin(),
231 mHappensBeforeDependencies.end());
Jamie Madill49ac74b2017-12-21 14:42:33 -0500232 while (!openList.empty())
233 {
Jamie Madill0e654542018-02-07 14:50:06 -0500234 CommandBufferNode *checkNode = openList.back();
Jamie Madill49ac74b2017-12-21 14:42:33 -0500235 openList.pop_back();
Jamie Madill0e654542018-02-07 14:50:06 -0500236 if (visitedList.count(checkNode) == 0)
Jamie Madill49ac74b2017-12-21 14:42:33 -0500237 {
Jamie Madill0e654542018-02-07 14:50:06 -0500238 if (checkNode == beforeNode)
Jamie Madill49ac74b2017-12-21 14:42:33 -0500239 {
240 return true;
241 }
Jamie Madill0e654542018-02-07 14:50:06 -0500242 visitedList.insert(checkNode);
243 openList.insert(openList.end(), checkNode->mHappensBeforeDependencies.begin(),
244 checkNode->mHappensBeforeDependencies.end());
Jamie Madill49ac74b2017-12-21 14:42:33 -0500245 }
246 }
247
248 return false;
249}
250
251VisitedState CommandBufferNode::visitedState() const
252{
253 return mVisitedState;
254}
255
256void CommandBufferNode::visitDependencies(std::vector<CommandBufferNode *> *stack)
257{
258 ASSERT(mVisitedState == VisitedState::Unvisited);
Jamie Madill0e654542018-02-07 14:50:06 -0500259 stack->insert(stack->end(), mHappensBeforeDependencies.begin(),
260 mHappensBeforeDependencies.end());
Jamie Madill49ac74b2017-12-21 14:42:33 -0500261 mVisitedState = VisitedState::Ready;
262}
263
264vk::Error CommandBufferNode::visitAndExecute(RendererVk *renderer,
265 vk::CommandBuffer *primaryCommandBuffer)
266{
267 if (mOutsideRenderPassCommands.valid())
268 {
269 mOutsideRenderPassCommands.end();
270 primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
271 }
272
273 if (mInsideRenderPassCommands.valid())
274 {
275 // Pull a compatible RenderPass from the cache.
276 // TODO(jmadill): Insert real ops and layout transitions.
277 vk::RenderPass *renderPass = nullptr;
278 ANGLE_TRY(renderer->getCompatibleRenderPass(mRenderPassDesc, &renderPass));
279
280 mInsideRenderPassCommands.end();
281
282 VkRenderPassBeginInfo beginInfo;
283 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
284 beginInfo.pNext = nullptr;
285 beginInfo.renderPass = renderPass->getHandle();
286 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
287 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
288 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
289 beginInfo.renderArea.extent.width = static_cast<uint32_t>(mRenderPassRenderArea.width);
290 beginInfo.renderArea.extent.height = static_cast<uint32_t>(mRenderPassRenderArea.height);
291 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
292 beginInfo.pClearValues = mRenderPassClearValues.data();
293
294 primaryCommandBuffer->beginRenderPass(beginInfo,
295 VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
296 primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
297 primaryCommandBuffer->endRenderPass();
298 }
299
300 mVisitedState = VisitedState::Visited;
301 return vk::NoError();
302}
303
304} // namespace vk
305} // namespace rx