blob: 979b1e71e5f2e7074e288cf09f1a6ffde933122d [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 }
Jamie Madill0da73fe2018-10-02 09:31:39 -040077 default:
78 UNREACHABLE();
79 return "";
80 }
81}
Jamie Madill1f46bc12018-02-20 16:09:43 -050082} // anonymous namespace
83
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040084// CommandGraphResource implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -040085CommandGraphResource::CommandGraphResource(CommandGraphResourceType resourceType)
Jamie Madill193a2842018-10-30 17:28:41 -040086 : mResourceType(resourceType), mCurrentWritingNode(nullptr)
Jamie Madillb980c562018-11-27 11:34:27 -050087{}
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040088
Jamie Madill316c6062018-05-29 10:49:45 -040089CommandGraphResource::~CommandGraphResource() = default;
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040090
Jamie Madillc57ee252018-05-30 19:53:48 -040091bool CommandGraphResource::isResourceInUse(RendererVk *renderer) const
92{
93 return renderer->isSerialInUse(mStoredQueueSerial);
94}
95
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -040096bool CommandGraphResource::hasPendingWork(RendererVk *renderer) const
97{
98 // If the renderer has a queue serial higher than the stored one, the command buffers recorded
99 // by this resource have already been submitted, so there is no pending work.
100 return mStoredQueueSerial == renderer->getCurrentQueueSerial();
101}
102
Jamie Madill193a2842018-10-30 17:28:41 -0400103// RecordableGraphResource implementation.
104RecordableGraphResource::RecordableGraphResource(CommandGraphResourceType resourceType)
105 : CommandGraphResource(resourceType)
Jamie Madillb980c562018-11-27 11:34:27 -0500106{}
Jamie Madill193a2842018-10-30 17:28:41 -0400107
108RecordableGraphResource::~RecordableGraphResource() = default;
109
Jamie Madill193a2842018-10-30 17:28:41 -0400110angle::Result RecordableGraphResource::recordCommands(Context *context,
111 CommandBuffer **commandBufferOut)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400112{
Jamie Madill21061022018-07-12 23:56:30 -0400113 updateQueueSerial(context->getRenderer()->getCurrentQueueSerial());
Jamie Madill5dca6512018-05-30 10:53:51 -0400114
Jamie Madille2d22702018-09-19 08:11:48 -0400115 if (!hasChildlessWritingNode() || hasStartedRenderPass())
Jamie Madill316c6062018-05-29 10:49:45 -0400116 {
Jamie Madill193a2842018-10-30 17:28:41 -0400117 startNewCommands(context->getRenderer());
Jamie Madille2d22702018-09-19 08:11:48 -0400118 return mCurrentWritingNode->beginOutsideRenderPassRecording(
119 context, context->getRenderer()->getCommandPool(), commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400120 }
121
122 CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
123 if (!outsideRenderPassCommands->valid())
124 {
125 ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
Jamie Madill21061022018-07-12 23:56:30 -0400126 context, context->getRenderer()->getCommandPool(), commandBufferOut));
Jamie Madill316c6062018-05-29 10:49:45 -0400127 }
128 else
129 {
130 *commandBufferOut = outsideRenderPassCommands;
131 }
132
Jamie Madill7c985f52018-11-29 18:16:17 -0500133 return angle::Result::Continue;
Jamie Madill316c6062018-05-29 10:49:45 -0400134}
135
Jamie Madill193a2842018-10-30 17:28:41 -0400136const gl::Rectangle &RecordableGraphResource::getRenderPassRenderArea() const
Jamie Madill316c6062018-05-29 10:49:45 -0400137{
138 ASSERT(hasStartedRenderPass());
139 return mCurrentWritingNode->getRenderPassRenderArea();
140}
141
Jamie Madill85ca1892019-01-16 13:27:15 -0500142angle::Result RecordableGraphResource::beginRenderPass(ContextVk *contextVk,
Jamie Madill193a2842018-10-30 17:28:41 -0400143 const Framebuffer &framebuffer,
144 const gl::Rectangle &renderArea,
145 const RenderPassDesc &renderPassDesc,
146 const std::vector<VkClearValue> &clearValues,
147 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400148{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400149 // If a barrier has been inserted in the meantime, stop the command buffer.
150 if (!hasChildlessWritingNode())
151 {
Jamie Madill85ca1892019-01-16 13:27:15 -0500152 startNewCommands(contextVk->getRenderer());
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400153 }
154
Jamie Madill316c6062018-05-29 10:49:45 -0400155 // Hard-code RenderPass to clear the first render target to the current clear value.
156 // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
157 mCurrentWritingNode->storeRenderPassInfo(framebuffer, renderArea, renderPassDesc, clearValues);
158
Jamie Madill85ca1892019-01-16 13:27:15 -0500159 mCurrentWritingNode->setCommandBufferOwner(contextVk);
160
161 return mCurrentWritingNode->beginInsideRenderPassRecording(contextVk, commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400162}
163
Jamie Madill193a2842018-10-30 17:28:41 -0400164void RecordableGraphResource::addWriteDependency(RecordableGraphResource *writingResource)
Jamie Madill316c6062018-05-29 10:49:45 -0400165{
166 CommandGraphNode *writingNode = writingResource->mCurrentWritingNode;
167 ASSERT(writingNode);
168
Jamie Madillc57ee252018-05-30 19:53:48 -0400169 onWriteImpl(writingNode, writingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400170}
171
Jamie Madill193a2842018-10-30 17:28:41 -0400172void RecordableGraphResource::addReadDependency(RecordableGraphResource *readingResource)
173{
174 updateQueueSerial(readingResource->getStoredQueueSerial());
175
176 CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
177 ASSERT(readingNode);
178
Shahbaz Youssefib5ba5492019-01-02 15:19:22 -0500179 if (mCurrentWritingNode)
Jamie Madill193a2842018-10-30 17:28:41 -0400180 {
181 // Ensure 'readingNode' happens after the current writing node.
182 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
183 }
184
185 // Add the read node to the list of nodes currently reading this resource.
186 mCurrentReadingNodes.push_back(readingNode);
187}
188
189void RecordableGraphResource::finishCurrentCommands(RendererVk *renderer)
190{
191 startNewCommands(renderer);
192}
193
194void RecordableGraphResource::startNewCommands(RendererVk *renderer)
195{
196 CommandGraphNode *newCommands =
197 renderer->getCommandGraph()->allocateNode(CommandGraphNodeFunction::Generic);
198 newCommands->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
199 onWriteImpl(newCommands, renderer->getCurrentQueueSerial());
200}
201
202void RecordableGraphResource::onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial)
Jamie Madill316c6062018-05-29 10:49:45 -0400203{
204 updateQueueSerial(currentSerial);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400205
Jamie Madill9cceac42018-03-31 14:19:16 -0400206 // Make sure any open reads and writes finish before we execute 'writingNode'.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400207 if (!mCurrentReadingNodes.empty())
208 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400209 CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes.data(),
210 mCurrentReadingNodes.size(), writingNode);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400211 mCurrentReadingNodes.clear();
212 }
213
214 if (mCurrentWritingNode && mCurrentWritingNode != writingNode)
215 {
216 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, writingNode);
217 }
218
219 mCurrentWritingNode = writingNode;
220}
221
Jamie Madill193a2842018-10-30 17:28:41 -0400222// QueryGraphResource implementation.
Jamie Madillb980c562018-11-27 11:34:27 -0500223QueryGraphResource::QueryGraphResource() : CommandGraphResource(CommandGraphResourceType::Query) {}
Jamie Madill316c6062018-05-29 10:49:45 -0400224
Jamie Madill193a2842018-10-30 17:28:41 -0400225QueryGraphResource::~QueryGraphResource() = default;
Jamie Madill9cceac42018-03-31 14:19:16 -0400226
Jamie Madill193a2842018-10-30 17:28:41 -0400227void QueryGraphResource::beginQuery(Context *context,
228 const QueryPool *queryPool,
229 uint32_t queryIndex)
230{
231 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::BeginQuery);
232 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
233}
Jamie Madill9cceac42018-03-31 14:19:16 -0400234
Jamie Madill193a2842018-10-30 17:28:41 -0400235void QueryGraphResource::endQuery(Context *context, const QueryPool *queryPool, uint32_t queryIndex)
236{
237 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::EndQuery);
238 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
239}
240
241void QueryGraphResource::writeTimestamp(Context *context,
242 const QueryPool *queryPool,
243 uint32_t queryIndex)
244{
245 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::WriteTimestamp);
246 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
247}
248
249void QueryGraphResource::startNewCommands(RendererVk *renderer, CommandGraphNodeFunction function)
250{
251 CommandGraph *commandGraph = renderer->getCommandGraph();
252 CommandGraphNode *newNode = commandGraph->allocateNode(function);
253 newNode->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
254 commandGraph->setNewBarrier(newNode);
255
256 mStoredQueueSerial = renderer->getCurrentQueueSerial();
257 mCurrentWritingNode = newNode;
Jamie Madill9cceac42018-03-31 14:19:16 -0400258}
259
Jamie Madill1f46bc12018-02-20 16:09:43 -0500260// CommandGraphNode implementation.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400261CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function)
262 : mRenderPassClearValues{},
263 mFunction(function),
264 mQueryPool(VK_NULL_HANDLE),
265 mQueryIndex(0),
266 mHasChildren(false),
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500267 mVisitedState(VisitedState::Unvisited),
268 mGlobalMemoryBarrierSrcAccess(0),
Jamie Madill85ca1892019-01-16 13:27:15 -0500269 mGlobalMemoryBarrierDstAccess(0),
270 mCommandBufferOwner(nullptr)
Jamie Madillb980c562018-11-27 11:34:27 -0500271{}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500272
273CommandGraphNode::~CommandGraphNode()
274{
275 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
276
277 // Command buffers are managed by the command pool, so don't need to be freed.
278 mOutsideRenderPassCommands.releaseHandle();
279 mInsideRenderPassCommands.releaseHandle();
280}
281
282CommandBuffer *CommandGraphNode::getOutsideRenderPassCommands()
283{
284 ASSERT(!mHasChildren);
285 return &mOutsideRenderPassCommands;
286}
287
Jamie Madill21061022018-07-12 23:56:30 -0400288angle::Result CommandGraphNode::beginOutsideRenderPassRecording(Context *context,
289 const CommandPool &commandPool,
290 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500291{
292 ASSERT(!mHasChildren);
293
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400294 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500295 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
296 inheritanceInfo.renderPass = VK_NULL_HANDLE;
297 inheritanceInfo.subpass = 0;
298 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400299 inheritanceInfo.occlusionQueryEnable =
300 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500301 inheritanceInfo.queryFlags = 0;
302 inheritanceInfo.pipelineStatistics = 0;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500303
Jamie Madill21061022018-07-12 23:56:30 -0400304 ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500305 &mOutsideRenderPassCommands));
306
307 *commandsOut = &mOutsideRenderPassCommands;
Jamie Madill7c985f52018-11-29 18:16:17 -0500308 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500309}
310
Jamie Madill21061022018-07-12 23:56:30 -0400311angle::Result CommandGraphNode::beginInsideRenderPassRecording(Context *context,
312 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500313{
314 ASSERT(!mHasChildren);
315
316 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400317 // TODO(jmadill): Support query for compatible/conformant render pass. http://anglebug.com/2361
Jamie Madill1f46bc12018-02-20 16:09:43 -0500318 RenderPass *compatibleRenderPass;
Jamie Madill21061022018-07-12 23:56:30 -0400319 ANGLE_TRY(context->getRenderer()->getCompatibleRenderPass(context, mRenderPassDesc,
320 &compatibleRenderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500321
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400322 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500323 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
324 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
325 inheritanceInfo.subpass = 0;
326 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400327 inheritanceInfo.occlusionQueryEnable =
328 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500329 inheritanceInfo.queryFlags = 0;
330 inheritanceInfo.pipelineStatistics = 0;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500331
332 ANGLE_TRY(InitAndBeginCommandBuffer(
Jamie Madill21061022018-07-12 23:56:30 -0400333 context, context->getRenderer()->getCommandPool(), inheritanceInfo,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500334 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
335
336 *commandsOut = &mInsideRenderPassCommands;
Jamie Madill7c985f52018-11-29 18:16:17 -0500337 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500338}
339
340void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
341 const gl::Rectangle renderArea,
Jamie Madillbcf467f2018-05-23 09:46:00 -0400342 const vk::RenderPassDesc &renderPassDesc,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500343 const std::vector<VkClearValue> &clearValues)
344{
Jamie Madillbcf467f2018-05-23 09:46:00 -0400345 mRenderPassDesc = renderPassDesc;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500346 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
347 mRenderPassRenderArea = renderArea;
348 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
349}
350
Jamie Madill1f46bc12018-02-20 16:09:43 -0500351// static
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400352void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode **beforeNodes,
353 size_t beforeNodesCount,
354 CommandGraphNode *afterNode)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500355{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400356 afterNode->mParents.insert(afterNode->mParents.end(), beforeNodes,
357 beforeNodes + beforeNodesCount);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500358
359 // TODO(jmadill): is there a faster way to do this?
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400360 for (size_t i = 0; i < beforeNodesCount; ++i)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500361 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400362 beforeNodes[i]->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500363
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400364 ASSERT(beforeNodes[i] != afterNode && !beforeNodes[i]->isChildOf(afterNode));
365 }
366}
367
368void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode *beforeNode,
369 CommandGraphNode **afterNodes,
370 size_t afterNodesCount)
371{
372 for (size_t i = 0; i < afterNodesCount; ++i)
373 {
374 SetHappensBeforeDependency(beforeNode, afterNodes[i]);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500375 }
376}
377
378bool CommandGraphNode::hasParents() const
379{
380 return !mParents.empty();
381}
382
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400383void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIndex)
384{
385 ASSERT(mFunction == CommandGraphNodeFunction::BeginQuery ||
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400386 mFunction == CommandGraphNodeFunction::EndQuery ||
387 mFunction == CommandGraphNodeFunction::WriteTimestamp);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400388 mQueryPool = queryPool->getHandle();
389 mQueryIndex = queryIndex;
390}
391
Jamie Madill1f46bc12018-02-20 16:09:43 -0500392// Do not call this in anything but testing code, since it's slow.
393bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
394{
395 std::set<CommandGraphNode *> visitedList;
396 std::vector<CommandGraphNode *> openList;
397 openList.insert(openList.begin(), mParents.begin(), mParents.end());
398 while (!openList.empty())
399 {
400 CommandGraphNode *current = openList.back();
401 openList.pop_back();
402 if (visitedList.count(current) == 0)
403 {
404 if (current == parent)
405 {
406 return true;
407 }
408 visitedList.insert(current);
409 openList.insert(openList.end(), current->mParents.begin(), current->mParents.end());
410 }
411 }
412
413 return false;
414}
415
416VisitedState CommandGraphNode::visitedState() const
417{
418 return mVisitedState;
419}
420
421void CommandGraphNode::visitParents(std::vector<CommandGraphNode *> *stack)
422{
423 ASSERT(mVisitedState == VisitedState::Unvisited);
424 stack->insert(stack->end(), mParents.begin(), mParents.end());
425 mVisitedState = VisitedState::Ready;
426}
427
Jamie Madill21061022018-07-12 23:56:30 -0400428angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
429 Serial serial,
430 RenderPassCache *renderPassCache,
431 CommandBuffer *primaryCommandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500432{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400433 switch (mFunction)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500434 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400435 case CommandGraphNodeFunction::Generic:
436 ASSERT(mQueryPool == VK_NULL_HANDLE);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500437
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500438 // Record the deferred pipeline barrier if necessary.
439 ASSERT((mGlobalMemoryBarrierDstAccess == 0) == (mGlobalMemoryBarrierSrcAccess == 0));
440 if (mGlobalMemoryBarrierSrcAccess)
441 {
442 VkMemoryBarrier memoryBarrier = {};
443 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
444 memoryBarrier.srcAccessMask = mGlobalMemoryBarrierSrcAccess;
445 memoryBarrier.dstAccessMask = mGlobalMemoryBarrierDstAccess;
446
Shahbaz Youssefi471358f2018-11-28 15:21:55 -0500447 // Use the all pipe stage to keep the state management simple.
448 primaryCommandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
449 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1,
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500450 &memoryBarrier, 0, nullptr, 0, nullptr);
451 }
452
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400453 if (mOutsideRenderPassCommands.valid())
454 {
Yuly Novikov27780292018-11-09 11:19:49 -0500455 ANGLE_VK_TRY(context, mOutsideRenderPassCommands.end());
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400456 primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
457 }
Jamie Madill1f46bc12018-02-20 16:09:43 -0500458
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400459 if (mInsideRenderPassCommands.valid())
460 {
461 // Pull a compatible RenderPass from the cache.
462 // TODO(jmadill): Insert real ops and layout transitions.
463 RenderPass *renderPass = nullptr;
464 ANGLE_TRY(renderPassCache->getCompatibleRenderPass(context, serial, mRenderPassDesc,
465 &renderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500466
Yuly Novikov27780292018-11-09 11:19:49 -0500467 ANGLE_VK_TRY(context, mInsideRenderPassCommands.end());
Jamie Madill1f46bc12018-02-20 16:09:43 -0500468
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400469 VkRenderPassBeginInfo beginInfo = {};
470 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
471 beginInfo.renderPass = renderPass->getHandle();
472 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
473 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
474 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
475 beginInfo.renderArea.extent.width =
476 static_cast<uint32_t>(mRenderPassRenderArea.width);
477 beginInfo.renderArea.extent.height =
478 static_cast<uint32_t>(mRenderPassRenderArea.height);
479 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
480 beginInfo.pClearValues = mRenderPassClearValues.data();
481
482 primaryCommandBuffer->beginRenderPass(
483 beginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
484 primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
485 primaryCommandBuffer->endRenderPass();
486 }
487 break;
488
489 case CommandGraphNodeFunction::BeginQuery:
490 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
491 ASSERT(mQueryPool != VK_NULL_HANDLE);
492
493 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
494 primaryCommandBuffer->beginQuery(mQueryPool, mQueryIndex, 0);
495
496 break;
497
498 case CommandGraphNodeFunction::EndQuery:
499 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
500 ASSERT(mQueryPool != VK_NULL_HANDLE);
501
502 primaryCommandBuffer->endQuery(mQueryPool, mQueryIndex);
503
504 break;
505
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400506 case CommandGraphNodeFunction::WriteTimestamp:
507 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
508 ASSERT(mQueryPool != VK_NULL_HANDLE);
509
510 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
511 primaryCommandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, mQueryPool,
512 mQueryIndex);
513
514 break;
515
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400516 default:
517 UNREACHABLE();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500518 }
519
520 mVisitedState = VisitedState::Visited;
Jamie Madill7c985f52018-11-29 18:16:17 -0500521 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500522}
523
Jamie Madill0da73fe2018-10-02 09:31:39 -0400524const std::vector<CommandGraphNode *> &CommandGraphNode::getParentsForDiagnostics() const
525{
526 return mParents;
527}
528
529void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType,
530 uintptr_t resourceID)
531{
532 mResourceType = resourceType;
533 mResourceID = resourceID;
534}
535
Luc Ferron14f48172018-04-11 08:43:28 -0400536const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
537{
538 return mRenderPassRenderArea;
539}
540
Jamie Madill1f46bc12018-02-20 16:09:43 -0500541// CommandGraph implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -0400542CommandGraph::CommandGraph(bool enableGraphDiagnostics)
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400543 : mEnableGraphDiagnostics(enableGraphDiagnostics), mLastBarrierIndex(kInvalidNodeIndex)
Jamie Madillb980c562018-11-27 11:34:27 -0500544{}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500545
546CommandGraph::~CommandGraph()
547{
548 ASSERT(empty());
549}
550
Jamie Madill193a2842018-10-30 17:28:41 -0400551CommandGraphNode *CommandGraph::allocateNode(CommandGraphNodeFunction function)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500552{
553 // TODO(jmadill): Use a pool allocator for the CPU node allocations.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400554 CommandGraphNode *newCommands = new CommandGraphNode(function);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500555 mNodes.emplace_back(newCommands);
556 return newCommands;
557}
558
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400559void CommandGraph::setNewBarrier(CommandGraphNode *newBarrier)
560{
561 size_t previousBarrierIndex = 0;
562 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
563
564 // Add a dependency from previousBarrier to all nodes in (previousBarrier, newBarrier].
565 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
566 {
567 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
568 CommandGraphNode::SetHappensBeforeDependencies(
569 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
570 }
571
572 // Add a dependency from all nodes in (previousBarrier, newBarrier) to newBarrier.
573 addDependenciesToNextBarrier(previousBarrierIndex + 1, mNodes.size() - 1, newBarrier);
574
575 mLastBarrierIndex = mNodes.size() - 1;
576}
577
Jamie Madill21061022018-07-12 23:56:30 -0400578angle::Result CommandGraph::submitCommands(Context *context,
579 Serial serial,
580 RenderPassCache *renderPassCache,
581 CommandPool *commandPool,
582 CommandBuffer *primaryCommandBufferOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500583{
Shahbaz Youssefi3a482172018-10-11 10:34:44 -0400584 // There is no point in submitting an empty command buffer, so make sure not to call this
585 // function if there's nothing to do.
586 ASSERT(!mNodes.empty());
587
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400588 size_t previousBarrierIndex = 0;
589 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
590
591 // Add a dependency from previousBarrier to all nodes in (previousBarrier, end].
592 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
593 {
594 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
595 CommandGraphNode::SetHappensBeforeDependencies(
596 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
597 }
598
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400599 VkCommandBufferAllocateInfo primaryInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500600 primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
601 primaryInfo.commandPool = commandPool->getHandle();
602 primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
603 primaryInfo.commandBufferCount = 1;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500604
Yuly Novikov27780292018-11-09 11:19:49 -0500605 ANGLE_VK_TRY(context, primaryCommandBufferOut->init(context->getDevice(), primaryInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500606
Jamie Madill0da73fe2018-10-02 09:31:39 -0400607 if (mEnableGraphDiagnostics)
608 {
609 dumpGraphDotFile(std::cout);
610 }
611
Jamie Madill1f46bc12018-02-20 16:09:43 -0500612 std::vector<CommandGraphNode *> nodeStack;
613
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400614 VkCommandBufferBeginInfo beginInfo = {};
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400615 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
616 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
617 beginInfo.pInheritanceInfo = nullptr;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500618
Yuly Novikov27780292018-11-09 11:19:49 -0500619 ANGLE_VK_TRY(context, primaryCommandBufferOut->begin(beginInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500620
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400621 ANGLE_TRY(context->getRenderer()->traceGpuEvent(
622 context, primaryCommandBufferOut, TRACE_EVENT_PHASE_BEGIN, "Primary Command Buffer"));
623
Jamie Madill1f46bc12018-02-20 16:09:43 -0500624 for (CommandGraphNode *topLevelNode : mNodes)
625 {
626 // Only process commands that don't have child commands. The others will be pulled in
627 // automatically. Also skip commands that have already been visited.
628 if (topLevelNode->hasChildren() || topLevelNode->visitedState() != VisitedState::Unvisited)
629 continue;
630
631 nodeStack.push_back(topLevelNode);
632
633 while (!nodeStack.empty())
634 {
635 CommandGraphNode *node = nodeStack.back();
636
637 switch (node->visitedState())
638 {
639 case VisitedState::Unvisited:
640 node->visitParents(&nodeStack);
641 break;
642 case VisitedState::Ready:
Jamie Madill21061022018-07-12 23:56:30 -0400643 ANGLE_TRY(node->visitAndExecute(context, serial, renderPassCache,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500644 primaryCommandBufferOut));
645 nodeStack.pop_back();
646 break;
647 case VisitedState::Visited:
648 nodeStack.pop_back();
649 break;
650 default:
651 UNREACHABLE();
652 break;
653 }
654 }
655 }
656
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400657 ANGLE_TRY(context->getRenderer()->traceGpuEvent(
658 context, primaryCommandBufferOut, TRACE_EVENT_PHASE_END, "Primary Command Buffer"));
659
Yuly Novikov27780292018-11-09 11:19:49 -0500660 ANGLE_VK_TRY(context, primaryCommandBufferOut->end());
Jamie Madill1f46bc12018-02-20 16:09:43 -0500661
Yuly Novikovb56ddbb2018-11-02 16:53:18 -0400662 clear();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500663
Jamie Madill7c985f52018-11-29 18:16:17 -0500664 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500665}
666
667bool CommandGraph::empty() const
668{
669 return mNodes.empty();
670}
671
Yuly Novikovb56ddbb2018-11-02 16:53:18 -0400672void CommandGraph::clear()
673{
674 mLastBarrierIndex = kInvalidNodeIndex;
675
676 // TODO(jmadill): Use pool allocator for performance. http://anglebug.com/2951
677 for (CommandGraphNode *node : mNodes)
678 {
679 delete node;
680 }
681 mNodes.clear();
682}
683
Jamie Madill0da73fe2018-10-02 09:31:39 -0400684// Dumps the command graph into a dot file that works with graphviz.
685void CommandGraph::dumpGraphDotFile(std::ostream &out) const
686{
687 // This ID maps a node pointer to a monatonic ID. It allows us to look up parent node IDs.
688 std::map<const CommandGraphNode *, int> nodeIDMap;
689 std::map<uintptr_t, int> objectIDMap;
690
691 // Map nodes to ids.
692 for (size_t nodeIndex = 0; nodeIndex < mNodes.size(); ++nodeIndex)
693 {
694 const CommandGraphNode *node = mNodes[nodeIndex];
695 nodeIDMap[node] = static_cast<int>(nodeIndex) + 1;
696 }
697
698 int bufferIDCounter = 1;
699 int framebufferIDCounter = 1;
700 int imageIDCounter = 1;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400701 int queryIDCounter = 1;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400702
703 out << "digraph {" << std::endl;
704
705 for (const CommandGraphNode *node : mNodes)
706 {
707 int nodeID = nodeIDMap[node];
708
709 std::stringstream strstr;
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -0400710 strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics(), node->getFunction());
Jamie Madill0da73fe2018-10-02 09:31:39 -0400711 strstr << " ";
712
713 auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
714 if (it != objectIDMap.end())
715 {
716 strstr << it->second;
717 }
718 else
719 {
720 int id = 0;
721
722 switch (node->getResourceTypeForDiagnostics())
723 {
724 case CommandGraphResourceType::Buffer:
725 id = bufferIDCounter++;
726 break;
727 case CommandGraphResourceType::Framebuffer:
728 id = framebufferIDCounter++;
729 break;
730 case CommandGraphResourceType::Image:
731 id = imageIDCounter++;
732 break;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400733 case CommandGraphResourceType::Query:
734 id = queryIDCounter++;
735 break;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400736 default:
737 UNREACHABLE();
738 break;
739 }
740
741 objectIDMap[node->getResourceIDForDiagnostics()] = id;
742 strstr << id;
743 }
744
745 const std::string &label = strstr.str();
746 out << " " << nodeID << "[label =<" << label << "<BR/> <FONT POINT-SIZE=\"10\">Node ID "
747 << nodeID << "</FONT>>];" << std::endl;
748 }
749
750 for (const CommandGraphNode *node : mNodes)
751 {
752 int nodeID = nodeIDMap[node];
753
754 for (const CommandGraphNode *parent : node->getParentsForDiagnostics())
755 {
756 int parentID = nodeIDMap[parent];
757 out << " " << parentID << " -> " << nodeID << ";" << std::endl;
758 }
759 }
760
761 out << "}" << std::endl;
762}
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400763
764CommandGraphNode *CommandGraph::getLastBarrierNode(size_t *indexOut)
765{
766 *indexOut = mLastBarrierIndex == kInvalidNodeIndex ? 0 : mLastBarrierIndex;
767 return mLastBarrierIndex == kInvalidNodeIndex ? nullptr : mNodes[mLastBarrierIndex];
768}
769
770void CommandGraph::addDependenciesToNextBarrier(size_t begin,
771 size_t end,
772 CommandGraphNode *nextBarrier)
773{
774 for (size_t i = begin; i < end; ++i)
775 {
776 // As a small optimization, only add edges to childless nodes. The others have an
777 // indirect dependency.
778 if (!mNodes[i]->hasChildren())
779 {
780 CommandGraphNode::SetHappensBeforeDependency(mNodes[i], nextBarrier);
781 }
782 }
783}
784
Jamie Madill1f46bc12018-02-20 16:09:43 -0500785} // namespace vk
786} // namespace rx