blob: 5dbcc2d0dc85d2fd64b8490896b4f306f669a000 [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()
57 : mIsDependency(false), mVisitedState(VisitedState::Unvisited)
58{
59}
60
61CommandBufferNode::~CommandBufferNode()
62{
63 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
64
65 // Command buffers are managed by the command pool, so don't need to be freed.
66 mOutsideRenderPassCommands.releaseHandle();
67 mInsideRenderPassCommands.releaseHandle();
68}
69
70CommandBuffer *CommandBufferNode::getOutsideRenderPassCommands()
71{
72 return &mOutsideRenderPassCommands;
73}
74
75CommandBuffer *CommandBufferNode::getInsideRenderPassCommands()
76{
77 return &mInsideRenderPassCommands;
78}
79
80Error CommandBufferNode::startRecording(VkDevice device,
81 const CommandPool &commandPool,
82 CommandBuffer **commandsOut)
83{
84 VkCommandBufferInheritanceInfo inheritanceInfo;
85 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
86 inheritanceInfo.pNext = nullptr;
87 inheritanceInfo.renderPass = VK_NULL_HANDLE;
88 inheritanceInfo.subpass = 0;
89 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
90 inheritanceInfo.occlusionQueryEnable = VK_FALSE;
91 inheritanceInfo.queryFlags = 0;
92 inheritanceInfo.pipelineStatistics = 0;
93
94 ANGLE_TRY(InitAndBeginCommandBuffer(device, commandPool, inheritanceInfo, 0,
95 &mOutsideRenderPassCommands));
96
97 *commandsOut = &mOutsideRenderPassCommands;
98 return NoError();
99}
100
101Error CommandBufferNode::startRenderPassRecording(RendererVk *renderer, CommandBuffer **commandsOut)
102{
103 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
104 // TODO(jmadill): Use different query method for compatible vs conformant render pass.
105 vk::RenderPass *compatibleRenderPass;
106 ANGLE_TRY(renderer->getCompatibleRenderPass(mRenderPassDesc, &compatibleRenderPass));
107
108 VkCommandBufferInheritanceInfo inheritanceInfo;
109 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
110 inheritanceInfo.pNext = nullptr;
111 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
112 inheritanceInfo.subpass = 0;
113 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
114 inheritanceInfo.occlusionQueryEnable = VK_FALSE;
115 inheritanceInfo.queryFlags = 0;
116 inheritanceInfo.pipelineStatistics = 0;
117
118 ANGLE_TRY(InitAndBeginCommandBuffer(
119 renderer->getDevice(), renderer->getCommandPool(), inheritanceInfo,
120 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
121
122 *commandsOut = &mInsideRenderPassCommands;
123 return NoError();
124}
125
126void CommandBufferNode::storeRenderPassInfo(const Framebuffer &framebuffer,
127 const gl::Rectangle renderArea,
128 const std::vector<VkClearValue> &clearValues)
129{
130 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
131 mRenderPassRenderArea = renderArea;
132 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
133}
134
135void CommandBufferNode::appendColorRenderTarget(Serial serial, RenderTargetVk *colorRenderTarget)
136{
137 // TODO(jmadill): Layout transition?
138 mRenderPassDesc.packColorAttachment(*colorRenderTarget->format, colorRenderTarget->samples);
139 colorRenderTarget->resource->setWriteNode(serial, this);
140}
141
142void CommandBufferNode::appendDepthStencilRenderTarget(Serial serial,
143 RenderTargetVk *depthStencilRenderTarget)
144{
145 // TODO(jmadill): Layout transition?
146 mRenderPassDesc.packDepthStencilAttachment(*depthStencilRenderTarget->format,
147 depthStencilRenderTarget->samples);
148 depthStencilRenderTarget->resource->setWriteNode(serial, this);
149}
150
151void CommandBufferNode::initAttachmentDesc(VkAttachmentDescription *desc)
152{
153 desc->flags = 0;
154 desc->format = VK_FORMAT_UNDEFINED;
155 desc->samples = static_cast<VkSampleCountFlagBits>(0);
156 desc->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
157 desc->storeOp = VK_ATTACHMENT_STORE_OP_STORE;
158 desc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
159 desc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
160 desc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
161 desc->finalLayout = VK_IMAGE_LAYOUT_UNDEFINED;
162}
163
164void CommandBufferNode::addDependency(CommandBufferNode *node)
165{
166 mDependencies.emplace_back(node);
167 node->markAsDependency();
168 ASSERT(node != this && !node->hasDependency(this));
169}
170
171void CommandBufferNode::addDependencies(const std::vector<CommandBufferNode *> &nodes)
172{
173 mDependencies.insert(mDependencies.end(), nodes.begin(), nodes.end());
174
175 // TODO(jmadill): is there a faster way to do this?
176 for (CommandBufferNode *node : nodes)
177 {
178 node->markAsDependency();
179 ASSERT(node != this && !node->hasDependency(this));
180 }
181}
182
183bool CommandBufferNode::hasDependencies() const
184{
185 return !mDependencies.empty();
186}
187
188void CommandBufferNode::markAsDependency()
189{
190 mIsDependency = true;
191}
192
193bool CommandBufferNode::isDependency() const
194{
195 return mIsDependency;
196}
197
198// Do not call this in anything but testing code, since it's slow.
199bool CommandBufferNode::hasDependency(CommandBufferNode *searchNode)
200{
201 std::set<CommandBufferNode *> visitedList;
202 std::vector<CommandBufferNode *> openList;
203 openList.insert(openList.begin(), mDependencies.begin(), mDependencies.end());
204 while (!openList.empty())
205 {
206 CommandBufferNode *node = openList.back();
207 openList.pop_back();
208 if (visitedList.count(node) == 0)
209 {
210 if (node == searchNode)
211 {
212 return true;
213 }
214 visitedList.insert(node);
215 openList.insert(openList.end(), node->mDependencies.begin(), node->mDependencies.end());
216 }
217 }
218
219 return false;
220}
221
222VisitedState CommandBufferNode::visitedState() const
223{
224 return mVisitedState;
225}
226
227void CommandBufferNode::visitDependencies(std::vector<CommandBufferNode *> *stack)
228{
229 ASSERT(mVisitedState == VisitedState::Unvisited);
230 stack->insert(stack->end(), mDependencies.begin(), mDependencies.end());
231 mVisitedState = VisitedState::Ready;
232}
233
234vk::Error CommandBufferNode::visitAndExecute(RendererVk *renderer,
235 vk::CommandBuffer *primaryCommandBuffer)
236{
237 if (mOutsideRenderPassCommands.valid())
238 {
239 mOutsideRenderPassCommands.end();
240 primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
241 }
242
243 if (mInsideRenderPassCommands.valid())
244 {
245 // Pull a compatible RenderPass from the cache.
246 // TODO(jmadill): Insert real ops and layout transitions.
247 vk::RenderPass *renderPass = nullptr;
248 ANGLE_TRY(renderer->getCompatibleRenderPass(mRenderPassDesc, &renderPass));
249
250 mInsideRenderPassCommands.end();
251
252 VkRenderPassBeginInfo beginInfo;
253 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
254 beginInfo.pNext = nullptr;
255 beginInfo.renderPass = renderPass->getHandle();
256 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
257 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
258 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
259 beginInfo.renderArea.extent.width = static_cast<uint32_t>(mRenderPassRenderArea.width);
260 beginInfo.renderArea.extent.height = static_cast<uint32_t>(mRenderPassRenderArea.height);
261 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
262 beginInfo.pClearValues = mRenderPassClearValues.data();
263
264 primaryCommandBuffer->beginRenderPass(beginInfo,
265 VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
266 primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
267 primaryCommandBuffer->endRenderPass();
268 }
269
270 mVisitedState = VisitedState::Visited;
271 return vk::NoError();
272}
273
274} // namespace vk
275} // namespace rx