blob: 2aef40709a17130e73b796e79efb999a81ad3418 [file] [log] [blame]
Jamie Madill1f46bc12018-02-20 16:09:43 -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// CommandGraph:
7// Deferred work constructed by GL calls, that will later be flushed to Vulkan.
8//
9
10#include "libANGLE/renderer/vulkan/CommandGraph.h"
11
Jamie Madill0da73fe2018-10-02 09:31:39 -040012#include <iostream>
13
Jamie Madill85ca1892019-01-16 13:27:15 -050014#include "libANGLE/renderer/vulkan/ContextVk.h"
Jamie Madill1f46bc12018-02-20 16:09:43 -050015#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
16#include "libANGLE/renderer/vulkan/RendererVk.h"
17#include "libANGLE/renderer/vulkan/vk_format_utils.h"
Jamie Madill26084d02018-04-09 13:44:04 -040018#include "libANGLE/renderer/vulkan/vk_helpers.h"
Jamie Madill1f46bc12018-02-20 16:09:43 -050019
Shahbaz Youssefi25224e72018-10-22 11:56:02 -040020#include "third_party/trace_event/trace_event.h"
21
Jamie Madill1f46bc12018-02-20 16:09:43 -050022namespace rx
23{
Jamie Madill1f46bc12018-02-20 16:09:43 -050024namespace vk
25{
Jamie Madill1f46bc12018-02-20 16:09:43 -050026namespace
27{
Jamie Madill21061022018-07-12 23:56:30 -040028angle::Result InitAndBeginCommandBuffer(vk::Context *context,
29 const CommandPool &commandPool,
30 const VkCommandBufferInheritanceInfo &inheritanceInfo,
31 VkCommandBufferUsageFlags flags,
32 CommandBuffer *commandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -050033{
34 ASSERT(!commandBuffer->valid());
35
Shahbaz Youssefi06270c92018-10-03 17:00:25 -040036 VkCommandBufferAllocateInfo createInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -050037 createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
38 createInfo.commandPool = commandPool.getHandle();
39 createInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
40 createInfo.commandBufferCount = 1;
Jamie Madill1f46bc12018-02-20 16:09:43 -050041
Yuly Novikov27780292018-11-09 11:19:49 -050042 ANGLE_VK_TRY(context, commandBuffer->init(context->getDevice(), createInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -050043
Shahbaz Youssefi06270c92018-10-03 17:00:25 -040044 VkCommandBufferBeginInfo beginInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -050045 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
46 beginInfo.flags = flags | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
47 beginInfo.pInheritanceInfo = &inheritanceInfo;
Jamie Madill1f46bc12018-02-20 16:09:43 -050048
Yuly Novikov27780292018-11-09 11:19:49 -050049 ANGLE_VK_TRY(context, commandBuffer->begin(beginInfo));
Jamie Madill7c985f52018-11-29 18:16:17 -050050 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -050051}
52
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040053const char *GetResourceTypeName(CommandGraphResourceType resourceType,
54 CommandGraphNodeFunction function)
Jamie Madill0da73fe2018-10-02 09:31:39 -040055{
56 switch (resourceType)
57 {
58 case CommandGraphResourceType::Buffer:
59 return "Buffer";
60 case CommandGraphResourceType::Framebuffer:
61 return "Framebuffer";
62 case CommandGraphResourceType::Image:
63 return "Image";
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -040064 case CommandGraphResourceType::Query:
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040065 switch (function)
66 {
67 case CommandGraphNodeFunction::BeginQuery:
68 return "BeginQuery";
69 case CommandGraphNodeFunction::EndQuery:
70 return "EndQuery";
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -040071 case CommandGraphNodeFunction::WriteTimestamp:
72 return "WriteTimestamp";
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040073 default:
74 UNREACHABLE();
75 return "Query";
76 }
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -050077 case CommandGraphResourceType::FenceSync:
78 switch (function)
79 {
80 case CommandGraphNodeFunction::SetFenceSync:
81 return "SetFenceSync";
82 case CommandGraphNodeFunction::WaitFenceSync:
83 return "WaitFenceSync";
84 default:
85 UNREACHABLE();
86 return "FenceSync";
87 }
Jamie Madill0da73fe2018-10-02 09:31:39 -040088 default:
89 UNREACHABLE();
90 return "";
91 }
92}
Jamie Madill1f46bc12018-02-20 16:09:43 -050093} // anonymous namespace
94
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040095// CommandGraphResource implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -040096CommandGraphResource::CommandGraphResource(CommandGraphResourceType resourceType)
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -050097 : mCurrentWritingNode(nullptr), mResourceType(resourceType)
Jamie Madillb980c562018-11-27 11:34:27 -050098{}
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040099
Jamie Madill316c6062018-05-29 10:49:45 -0400100CommandGraphResource::~CommandGraphResource() = default;
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400101
Jamie Madillc57ee252018-05-30 19:53:48 -0400102bool CommandGraphResource::isResourceInUse(RendererVk *renderer) const
103{
104 return renderer->isSerialInUse(mStoredQueueSerial);
105}
106
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500107angle::Result CommandGraphResource::recordCommands(Context *context,
108 CommandBuffer **commandBufferOut)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400109{
Jamie Madill21061022018-07-12 23:56:30 -0400110 updateQueueSerial(context->getRenderer()->getCurrentQueueSerial());
Jamie Madill5dca6512018-05-30 10:53:51 -0400111
Jamie Madille2d22702018-09-19 08:11:48 -0400112 if (!hasChildlessWritingNode() || hasStartedRenderPass())
Jamie Madill316c6062018-05-29 10:49:45 -0400113 {
Jamie Madill193a2842018-10-30 17:28:41 -0400114 startNewCommands(context->getRenderer());
Jamie Madille2d22702018-09-19 08:11:48 -0400115 return mCurrentWritingNode->beginOutsideRenderPassRecording(
116 context, context->getRenderer()->getCommandPool(), commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400117 }
118
119 CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
120 if (!outsideRenderPassCommands->valid())
121 {
122 ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
Jamie Madill21061022018-07-12 23:56:30 -0400123 context, context->getRenderer()->getCommandPool(), commandBufferOut));
Jamie Madill316c6062018-05-29 10:49:45 -0400124 }
125 else
126 {
127 *commandBufferOut = outsideRenderPassCommands;
128 }
129
Jamie Madill7c985f52018-11-29 18:16:17 -0500130 return angle::Result::Continue;
Jamie Madill316c6062018-05-29 10:49:45 -0400131}
132
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500133const gl::Rectangle &CommandGraphResource::getRenderPassRenderArea() const
Jamie Madill316c6062018-05-29 10:49:45 -0400134{
135 ASSERT(hasStartedRenderPass());
136 return mCurrentWritingNode->getRenderPassRenderArea();
137}
138
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500139angle::Result CommandGraphResource::beginRenderPass(ContextVk *contextVk,
140 const Framebuffer &framebuffer,
141 const gl::Rectangle &renderArea,
142 const RenderPassDesc &renderPassDesc,
143 const std::vector<VkClearValue> &clearValues,
144 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400145{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400146 // If a barrier has been inserted in the meantime, stop the command buffer.
147 if (!hasChildlessWritingNode())
148 {
Jamie Madill85ca1892019-01-16 13:27:15 -0500149 startNewCommands(contextVk->getRenderer());
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400150 }
151
Jamie Madill316c6062018-05-29 10:49:45 -0400152 // Hard-code RenderPass to clear the first render target to the current clear value.
153 // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
154 mCurrentWritingNode->storeRenderPassInfo(framebuffer, renderArea, renderPassDesc, clearValues);
155
Jamie Madill85ca1892019-01-16 13:27:15 -0500156 mCurrentWritingNode->setCommandBufferOwner(contextVk);
157
158 return mCurrentWritingNode->beginInsideRenderPassRecording(contextVk, commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400159}
160
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500161void CommandGraphResource::addWriteDependency(CommandGraphResource *writingResource)
Jamie Madill316c6062018-05-29 10:49:45 -0400162{
163 CommandGraphNode *writingNode = writingResource->mCurrentWritingNode;
164 ASSERT(writingNode);
165
Jamie Madillc57ee252018-05-30 19:53:48 -0400166 onWriteImpl(writingNode, writingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400167}
168
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500169void CommandGraphResource::addReadDependency(CommandGraphResource *readingResource)
Jamie Madill193a2842018-10-30 17:28:41 -0400170{
171 updateQueueSerial(readingResource->getStoredQueueSerial());
172
173 CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
174 ASSERT(readingNode);
175
Shahbaz Youssefib5ba5492019-01-02 15:19:22 -0500176 if (mCurrentWritingNode)
Jamie Madill193a2842018-10-30 17:28:41 -0400177 {
178 // Ensure 'readingNode' happens after the current writing node.
179 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
180 }
181
182 // Add the read node to the list of nodes currently reading this resource.
183 mCurrentReadingNodes.push_back(readingNode);
184}
185
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500186void CommandGraphResource::finishCurrentCommands(RendererVk *renderer)
Jamie Madill193a2842018-10-30 17:28:41 -0400187{
188 startNewCommands(renderer);
189}
190
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500191void CommandGraphResource::startNewCommands(RendererVk *renderer)
Jamie Madill193a2842018-10-30 17:28:41 -0400192{
193 CommandGraphNode *newCommands =
194 renderer->getCommandGraph()->allocateNode(CommandGraphNodeFunction::Generic);
195 newCommands->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
196 onWriteImpl(newCommands, renderer->getCurrentQueueSerial());
197}
198
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500199void CommandGraphResource::onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial)
Jamie Madill316c6062018-05-29 10:49:45 -0400200{
201 updateQueueSerial(currentSerial);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400202
Jamie Madill9cceac42018-03-31 14:19:16 -0400203 // Make sure any open reads and writes finish before we execute 'writingNode'.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400204 if (!mCurrentReadingNodes.empty())
205 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400206 CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes.data(),
207 mCurrentReadingNodes.size(), writingNode);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400208 mCurrentReadingNodes.clear();
209 }
210
211 if (mCurrentWritingNode && mCurrentWritingNode != writingNode)
212 {
213 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, writingNode);
214 }
215
216 mCurrentWritingNode = writingNode;
217}
218
Jamie Madill1f46bc12018-02-20 16:09:43 -0500219// CommandGraphNode implementation.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400220CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function)
221 : mRenderPassClearValues{},
222 mFunction(function),
223 mQueryPool(VK_NULL_HANDLE),
224 mQueryIndex(0),
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500225 mFenceSyncEvent(VK_NULL_HANDLE),
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400226 mHasChildren(false),
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500227 mVisitedState(VisitedState::Unvisited),
228 mGlobalMemoryBarrierSrcAccess(0),
Jamie Madill85ca1892019-01-16 13:27:15 -0500229 mGlobalMemoryBarrierDstAccess(0),
230 mCommandBufferOwner(nullptr)
Jamie Madillb980c562018-11-27 11:34:27 -0500231{}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500232
233CommandGraphNode::~CommandGraphNode()
234{
235 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
236
237 // Command buffers are managed by the command pool, so don't need to be freed.
238 mOutsideRenderPassCommands.releaseHandle();
239 mInsideRenderPassCommands.releaseHandle();
240}
241
242CommandBuffer *CommandGraphNode::getOutsideRenderPassCommands()
243{
244 ASSERT(!mHasChildren);
245 return &mOutsideRenderPassCommands;
246}
247
Jamie Madill21061022018-07-12 23:56:30 -0400248angle::Result CommandGraphNode::beginOutsideRenderPassRecording(Context *context,
249 const CommandPool &commandPool,
250 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500251{
252 ASSERT(!mHasChildren);
253
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400254 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500255 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
256 inheritanceInfo.renderPass = VK_NULL_HANDLE;
257 inheritanceInfo.subpass = 0;
258 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400259 inheritanceInfo.occlusionQueryEnable =
260 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500261 inheritanceInfo.queryFlags = 0;
262 inheritanceInfo.pipelineStatistics = 0;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500263
Jamie Madill21061022018-07-12 23:56:30 -0400264 ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500265 &mOutsideRenderPassCommands));
266
267 *commandsOut = &mOutsideRenderPassCommands;
Jamie Madill7c985f52018-11-29 18:16:17 -0500268 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500269}
270
Jamie Madill21061022018-07-12 23:56:30 -0400271angle::Result CommandGraphNode::beginInsideRenderPassRecording(Context *context,
272 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500273{
274 ASSERT(!mHasChildren);
275
276 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400277 // TODO(jmadill): Support query for compatible/conformant render pass. http://anglebug.com/2361
Jamie Madill1f46bc12018-02-20 16:09:43 -0500278 RenderPass *compatibleRenderPass;
Jamie Madill21061022018-07-12 23:56:30 -0400279 ANGLE_TRY(context->getRenderer()->getCompatibleRenderPass(context, mRenderPassDesc,
280 &compatibleRenderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500281
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400282 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500283 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
284 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
285 inheritanceInfo.subpass = 0;
286 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400287 inheritanceInfo.occlusionQueryEnable =
288 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500289 inheritanceInfo.queryFlags = 0;
290 inheritanceInfo.pipelineStatistics = 0;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500291
292 ANGLE_TRY(InitAndBeginCommandBuffer(
Jamie Madill21061022018-07-12 23:56:30 -0400293 context, context->getRenderer()->getCommandPool(), inheritanceInfo,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500294 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
295
296 *commandsOut = &mInsideRenderPassCommands;
Jamie Madill7c985f52018-11-29 18:16:17 -0500297 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500298}
299
300void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
301 const gl::Rectangle renderArea,
Jamie Madillbcf467f2018-05-23 09:46:00 -0400302 const vk::RenderPassDesc &renderPassDesc,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500303 const std::vector<VkClearValue> &clearValues)
304{
Jamie Madillbcf467f2018-05-23 09:46:00 -0400305 mRenderPassDesc = renderPassDesc;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500306 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
307 mRenderPassRenderArea = renderArea;
308 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
309}
310
Jamie Madill1f46bc12018-02-20 16:09:43 -0500311// static
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400312void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode **beforeNodes,
313 size_t beforeNodesCount,
314 CommandGraphNode *afterNode)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500315{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400316 afterNode->mParents.insert(afterNode->mParents.end(), beforeNodes,
317 beforeNodes + beforeNodesCount);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500318
319 // TODO(jmadill): is there a faster way to do this?
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400320 for (size_t i = 0; i < beforeNodesCount; ++i)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500321 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400322 beforeNodes[i]->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500323
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400324 ASSERT(beforeNodes[i] != afterNode && !beforeNodes[i]->isChildOf(afterNode));
325 }
326}
327
328void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode *beforeNode,
329 CommandGraphNode **afterNodes,
330 size_t afterNodesCount)
331{
332 for (size_t i = 0; i < afterNodesCount; ++i)
333 {
334 SetHappensBeforeDependency(beforeNode, afterNodes[i]);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500335 }
336}
337
338bool CommandGraphNode::hasParents() const
339{
340 return !mParents.empty();
341}
342
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400343void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIndex)
344{
345 ASSERT(mFunction == CommandGraphNodeFunction::BeginQuery ||
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400346 mFunction == CommandGraphNodeFunction::EndQuery ||
347 mFunction == CommandGraphNodeFunction::WriteTimestamp);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400348 mQueryPool = queryPool->getHandle();
349 mQueryIndex = queryIndex;
350}
351
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500352void CommandGraphNode::setFenceSync(const vk::Event &event)
353{
354 ASSERT(mFunction == CommandGraphNodeFunction::SetFenceSync ||
355 mFunction == CommandGraphNodeFunction::WaitFenceSync);
356 mFenceSyncEvent = event.getHandle();
357}
358
Jamie Madill1f46bc12018-02-20 16:09:43 -0500359// Do not call this in anything but testing code, since it's slow.
360bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
361{
362 std::set<CommandGraphNode *> visitedList;
363 std::vector<CommandGraphNode *> openList;
364 openList.insert(openList.begin(), mParents.begin(), mParents.end());
365 while (!openList.empty())
366 {
367 CommandGraphNode *current = openList.back();
368 openList.pop_back();
369 if (visitedList.count(current) == 0)
370 {
371 if (current == parent)
372 {
373 return true;
374 }
375 visitedList.insert(current);
376 openList.insert(openList.end(), current->mParents.begin(), current->mParents.end());
377 }
378 }
379
380 return false;
381}
382
383VisitedState CommandGraphNode::visitedState() const
384{
385 return mVisitedState;
386}
387
388void CommandGraphNode::visitParents(std::vector<CommandGraphNode *> *stack)
389{
390 ASSERT(mVisitedState == VisitedState::Unvisited);
391 stack->insert(stack->end(), mParents.begin(), mParents.end());
392 mVisitedState = VisitedState::Ready;
393}
394
Jamie Madill21061022018-07-12 23:56:30 -0400395angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
396 Serial serial,
397 RenderPassCache *renderPassCache,
398 CommandBuffer *primaryCommandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500399{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400400 switch (mFunction)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500401 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400402 case CommandGraphNodeFunction::Generic:
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500403 ASSERT(mQueryPool == VK_NULL_HANDLE && mFenceSyncEvent == VK_NULL_HANDLE);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500404
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500405 // Record the deferred pipeline barrier if necessary.
406 ASSERT((mGlobalMemoryBarrierDstAccess == 0) == (mGlobalMemoryBarrierSrcAccess == 0));
407 if (mGlobalMemoryBarrierSrcAccess)
408 {
409 VkMemoryBarrier memoryBarrier = {};
410 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
411 memoryBarrier.srcAccessMask = mGlobalMemoryBarrierSrcAccess;
412 memoryBarrier.dstAccessMask = mGlobalMemoryBarrierDstAccess;
413
Shahbaz Youssefi471358f2018-11-28 15:21:55 -0500414 // Use the all pipe stage to keep the state management simple.
415 primaryCommandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
416 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1,
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500417 &memoryBarrier, 0, nullptr, 0, nullptr);
418 }
419
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400420 if (mOutsideRenderPassCommands.valid())
421 {
Yuly Novikov27780292018-11-09 11:19:49 -0500422 ANGLE_VK_TRY(context, mOutsideRenderPassCommands.end());
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400423 primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
424 }
Jamie Madill1f46bc12018-02-20 16:09:43 -0500425
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400426 if (mInsideRenderPassCommands.valid())
427 {
428 // Pull a compatible RenderPass from the cache.
429 // TODO(jmadill): Insert real ops and layout transitions.
430 RenderPass *renderPass = nullptr;
431 ANGLE_TRY(renderPassCache->getCompatibleRenderPass(context, serial, mRenderPassDesc,
432 &renderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500433
Yuly Novikov27780292018-11-09 11:19:49 -0500434 ANGLE_VK_TRY(context, mInsideRenderPassCommands.end());
Jamie Madill1f46bc12018-02-20 16:09:43 -0500435
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400436 VkRenderPassBeginInfo beginInfo = {};
437 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
438 beginInfo.renderPass = renderPass->getHandle();
439 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
440 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
441 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
442 beginInfo.renderArea.extent.width =
443 static_cast<uint32_t>(mRenderPassRenderArea.width);
444 beginInfo.renderArea.extent.height =
445 static_cast<uint32_t>(mRenderPassRenderArea.height);
446 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
447 beginInfo.pClearValues = mRenderPassClearValues.data();
448
449 primaryCommandBuffer->beginRenderPass(
450 beginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
451 primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
452 primaryCommandBuffer->endRenderPass();
453 }
454 break;
455
456 case CommandGraphNodeFunction::BeginQuery:
457 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
458 ASSERT(mQueryPool != VK_NULL_HANDLE);
459
460 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
461 primaryCommandBuffer->beginQuery(mQueryPool, mQueryIndex, 0);
462
463 break;
464
465 case CommandGraphNodeFunction::EndQuery:
466 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
467 ASSERT(mQueryPool != VK_NULL_HANDLE);
468
469 primaryCommandBuffer->endQuery(mQueryPool, mQueryIndex);
470
471 break;
472
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400473 case CommandGraphNodeFunction::WriteTimestamp:
474 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
475 ASSERT(mQueryPool != VK_NULL_HANDLE);
476
477 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
478 primaryCommandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, mQueryPool,
479 mQueryIndex);
480
481 break;
482
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500483 case CommandGraphNodeFunction::SetFenceSync:
484 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
485 ASSERT(mFenceSyncEvent != VK_NULL_HANDLE);
486
487 primaryCommandBuffer->setEvent(mFenceSyncEvent, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
488
489 break;
490
491 case CommandGraphNodeFunction::WaitFenceSync:
492 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
493 ASSERT(mFenceSyncEvent != VK_NULL_HANDLE);
494
495 // Fence Syncs are purely execution barriers, so there are no memory barriers attached.
496 primaryCommandBuffer->waitEvents(
497 1, &mFenceSyncEvent, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
498 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, nullptr, 0, nullptr, 0, nullptr);
499
500 break;
501
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400502 default:
503 UNREACHABLE();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500504 }
505
506 mVisitedState = VisitedState::Visited;
Jamie Madill7c985f52018-11-29 18:16:17 -0500507 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500508}
509
Jamie Madill0da73fe2018-10-02 09:31:39 -0400510const std::vector<CommandGraphNode *> &CommandGraphNode::getParentsForDiagnostics() const
511{
512 return mParents;
513}
514
515void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType,
516 uintptr_t resourceID)
517{
518 mResourceType = resourceType;
519 mResourceID = resourceID;
520}
521
Luc Ferron14f48172018-04-11 08:43:28 -0400522const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
523{
524 return mRenderPassRenderArea;
525}
526
Jamie Madill1f46bc12018-02-20 16:09:43 -0500527// CommandGraph implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -0400528CommandGraph::CommandGraph(bool enableGraphDiagnostics)
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400529 : mEnableGraphDiagnostics(enableGraphDiagnostics), mLastBarrierIndex(kInvalidNodeIndex)
Jamie Madillb980c562018-11-27 11:34:27 -0500530{}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500531
532CommandGraph::~CommandGraph()
533{
534 ASSERT(empty());
535}
536
Jamie Madill193a2842018-10-30 17:28:41 -0400537CommandGraphNode *CommandGraph::allocateNode(CommandGraphNodeFunction function)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500538{
539 // TODO(jmadill): Use a pool allocator for the CPU node allocations.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400540 CommandGraphNode *newCommands = new CommandGraphNode(function);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500541 mNodes.emplace_back(newCommands);
542 return newCommands;
543}
544
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500545CommandGraphNode *CommandGraph::allocateBarrierNode(CommandGraphResourceType resourceType,
546 CommandGraphNodeFunction function)
547{
548 CommandGraphNode *newNode = allocateNode(function);
549 newNode->setDiagnosticInfo(resourceType, 0);
550 setNewBarrier(newNode);
551
552 return newNode;
553}
554
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400555void CommandGraph::setNewBarrier(CommandGraphNode *newBarrier)
556{
557 size_t previousBarrierIndex = 0;
558 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
559
560 // Add a dependency from previousBarrier to all nodes in (previousBarrier, newBarrier].
561 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
562 {
563 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
564 CommandGraphNode::SetHappensBeforeDependencies(
565 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
566 }
567
568 // Add a dependency from all nodes in (previousBarrier, newBarrier) to newBarrier.
569 addDependenciesToNextBarrier(previousBarrierIndex + 1, mNodes.size() - 1, newBarrier);
570
571 mLastBarrierIndex = mNodes.size() - 1;
572}
573
Jamie Madill21061022018-07-12 23:56:30 -0400574angle::Result CommandGraph::submitCommands(Context *context,
575 Serial serial,
576 RenderPassCache *renderPassCache,
577 CommandPool *commandPool,
578 CommandBuffer *primaryCommandBufferOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500579{
Shahbaz Youssefi3a482172018-10-11 10:34:44 -0400580 // There is no point in submitting an empty command buffer, so make sure not to call this
581 // function if there's nothing to do.
582 ASSERT(!mNodes.empty());
583
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400584 size_t previousBarrierIndex = 0;
585 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
586
587 // Add a dependency from previousBarrier to all nodes in (previousBarrier, end].
588 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
589 {
590 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
591 CommandGraphNode::SetHappensBeforeDependencies(
592 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
593 }
594
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400595 VkCommandBufferAllocateInfo primaryInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500596 primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
597 primaryInfo.commandPool = commandPool->getHandle();
598 primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
599 primaryInfo.commandBufferCount = 1;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500600
Yuly Novikov27780292018-11-09 11:19:49 -0500601 ANGLE_VK_TRY(context, primaryCommandBufferOut->init(context->getDevice(), primaryInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500602
Jamie Madill0da73fe2018-10-02 09:31:39 -0400603 if (mEnableGraphDiagnostics)
604 {
605 dumpGraphDotFile(std::cout);
606 }
607
Jamie Madill1f46bc12018-02-20 16:09:43 -0500608 std::vector<CommandGraphNode *> nodeStack;
609
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400610 VkCommandBufferBeginInfo beginInfo = {};
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400611 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
612 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
613 beginInfo.pInheritanceInfo = nullptr;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500614
Yuly Novikov27780292018-11-09 11:19:49 -0500615 ANGLE_VK_TRY(context, primaryCommandBufferOut->begin(beginInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500616
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400617 ANGLE_TRY(context->getRenderer()->traceGpuEvent(
618 context, primaryCommandBufferOut, TRACE_EVENT_PHASE_BEGIN, "Primary Command Buffer"));
619
Jamie Madill1f46bc12018-02-20 16:09:43 -0500620 for (CommandGraphNode *topLevelNode : mNodes)
621 {
622 // Only process commands that don't have child commands. The others will be pulled in
623 // automatically. Also skip commands that have already been visited.
624 if (topLevelNode->hasChildren() || topLevelNode->visitedState() != VisitedState::Unvisited)
625 continue;
626
627 nodeStack.push_back(topLevelNode);
628
629 while (!nodeStack.empty())
630 {
631 CommandGraphNode *node = nodeStack.back();
632
633 switch (node->visitedState())
634 {
635 case VisitedState::Unvisited:
636 node->visitParents(&nodeStack);
637 break;
638 case VisitedState::Ready:
Jamie Madill21061022018-07-12 23:56:30 -0400639 ANGLE_TRY(node->visitAndExecute(context, serial, renderPassCache,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500640 primaryCommandBufferOut));
641 nodeStack.pop_back();
642 break;
643 case VisitedState::Visited:
644 nodeStack.pop_back();
645 break;
646 default:
647 UNREACHABLE();
648 break;
649 }
650 }
651 }
652
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400653 ANGLE_TRY(context->getRenderer()->traceGpuEvent(
654 context, primaryCommandBufferOut, TRACE_EVENT_PHASE_END, "Primary Command Buffer"));
655
Yuly Novikov27780292018-11-09 11:19:49 -0500656 ANGLE_VK_TRY(context, primaryCommandBufferOut->end());
Jamie Madill1f46bc12018-02-20 16:09:43 -0500657
Yuly Novikovb56ddbb2018-11-02 16:53:18 -0400658 clear();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500659
Jamie Madill7c985f52018-11-29 18:16:17 -0500660 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500661}
662
663bool CommandGraph::empty() const
664{
665 return mNodes.empty();
666}
667
Yuly Novikovb56ddbb2018-11-02 16:53:18 -0400668void CommandGraph::clear()
669{
670 mLastBarrierIndex = kInvalidNodeIndex;
671
672 // TODO(jmadill): Use pool allocator for performance. http://anglebug.com/2951
673 for (CommandGraphNode *node : mNodes)
674 {
675 delete node;
676 }
677 mNodes.clear();
678}
679
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500680void CommandGraph::beginQuery(const QueryPool *queryPool, uint32_t queryIndex)
681{
682 CommandGraphNode *newNode =
683 allocateBarrierNode(CommandGraphResourceType::Query, CommandGraphNodeFunction::BeginQuery);
684 newNode->setQueryPool(queryPool, queryIndex);
685}
686
687void CommandGraph::endQuery(const QueryPool *queryPool, uint32_t queryIndex)
688{
689 CommandGraphNode *newNode =
690 allocateBarrierNode(CommandGraphResourceType::Query, CommandGraphNodeFunction::EndQuery);
691 newNode->setQueryPool(queryPool, queryIndex);
692}
693
694void CommandGraph::writeTimestamp(const QueryPool *queryPool, uint32_t queryIndex)
695{
696 CommandGraphNode *newNode = allocateBarrierNode(CommandGraphResourceType::Query,
697 CommandGraphNodeFunction::WriteTimestamp);
698 newNode->setQueryPool(queryPool, queryIndex);
699}
700
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500701void CommandGraph::setFenceSync(const vk::Event &event)
702{
703 CommandGraphNode *newNode = allocateBarrierNode(CommandGraphResourceType::FenceSync,
704 CommandGraphNodeFunction::SetFenceSync);
705 newNode->setFenceSync(event);
706}
707
708void CommandGraph::waitFenceSync(const vk::Event &event)
709{
710 CommandGraphNode *newNode = allocateBarrierNode(CommandGraphResourceType::FenceSync,
711 CommandGraphNodeFunction::WaitFenceSync);
712 newNode->setFenceSync(event);
713}
714
Jamie Madill0da73fe2018-10-02 09:31:39 -0400715// Dumps the command graph into a dot file that works with graphviz.
716void CommandGraph::dumpGraphDotFile(std::ostream &out) const
717{
718 // This ID maps a node pointer to a monatonic ID. It allows us to look up parent node IDs.
719 std::map<const CommandGraphNode *, int> nodeIDMap;
720 std::map<uintptr_t, int> objectIDMap;
721
722 // Map nodes to ids.
723 for (size_t nodeIndex = 0; nodeIndex < mNodes.size(); ++nodeIndex)
724 {
725 const CommandGraphNode *node = mNodes[nodeIndex];
726 nodeIDMap[node] = static_cast<int>(nodeIndex) + 1;
727 }
728
729 int bufferIDCounter = 1;
730 int framebufferIDCounter = 1;
731 int imageIDCounter = 1;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400732 int queryIDCounter = 1;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400733
734 out << "digraph {" << std::endl;
735
736 for (const CommandGraphNode *node : mNodes)
737 {
738 int nodeID = nodeIDMap[node];
739
740 std::stringstream strstr;
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -0400741 strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics(), node->getFunction());
Jamie Madill0da73fe2018-10-02 09:31:39 -0400742 strstr << " ";
743
744 auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
745 if (it != objectIDMap.end())
746 {
747 strstr << it->second;
748 }
749 else
750 {
751 int id = 0;
752
753 switch (node->getResourceTypeForDiagnostics())
754 {
755 case CommandGraphResourceType::Buffer:
756 id = bufferIDCounter++;
757 break;
758 case CommandGraphResourceType::Framebuffer:
759 id = framebufferIDCounter++;
760 break;
761 case CommandGraphResourceType::Image:
762 id = imageIDCounter++;
763 break;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400764 case CommandGraphResourceType::Query:
765 id = queryIDCounter++;
766 break;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400767 default:
768 UNREACHABLE();
769 break;
770 }
771
772 objectIDMap[node->getResourceIDForDiagnostics()] = id;
773 strstr << id;
774 }
775
776 const std::string &label = strstr.str();
777 out << " " << nodeID << "[label =<" << label << "<BR/> <FONT POINT-SIZE=\"10\">Node ID "
778 << nodeID << "</FONT>>];" << std::endl;
779 }
780
781 for (const CommandGraphNode *node : mNodes)
782 {
783 int nodeID = nodeIDMap[node];
784
785 for (const CommandGraphNode *parent : node->getParentsForDiagnostics())
786 {
787 int parentID = nodeIDMap[parent];
788 out << " " << parentID << " -> " << nodeID << ";" << std::endl;
789 }
790 }
791
792 out << "}" << std::endl;
793}
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400794
795CommandGraphNode *CommandGraph::getLastBarrierNode(size_t *indexOut)
796{
797 *indexOut = mLastBarrierIndex == kInvalidNodeIndex ? 0 : mLastBarrierIndex;
798 return mLastBarrierIndex == kInvalidNodeIndex ? nullptr : mNodes[mLastBarrierIndex];
799}
800
801void CommandGraph::addDependenciesToNextBarrier(size_t begin,
802 size_t end,
803 CommandGraphNode *nextBarrier)
804{
805 for (size_t i = begin; i < end; ++i)
806 {
807 // As a small optimization, only add edges to childless nodes. The others have an
808 // indirect dependency.
809 if (!mNodes[i]->hasChildren())
810 {
811 CommandGraphNode::SetHappensBeforeDependency(mNodes[i], nextBarrier);
812 }
813 }
814}
815
Jamie Madill1f46bc12018-02-20 16:09:43 -0500816} // namespace vk
817} // namespace rx