blob: ca59f87afb53fc2c9552aa127c348d4ed1d9c6ad [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 Madill1f46bc12018-02-20 16:09:43 -050014#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
15#include "libANGLE/renderer/vulkan/RendererVk.h"
16#include "libANGLE/renderer/vulkan/vk_format_utils.h"
Jamie Madill26084d02018-04-09 13:44:04 -040017#include "libANGLE/renderer/vulkan/vk_helpers.h"
Jamie Madill1f46bc12018-02-20 16:09:43 -050018
19namespace rx
20{
Jamie Madill1f46bc12018-02-20 16:09:43 -050021namespace vk
22{
Jamie Madill1f46bc12018-02-20 16:09:43 -050023namespace
24{
Jamie Madill21061022018-07-12 23:56:30 -040025angle::Result InitAndBeginCommandBuffer(vk::Context *context,
26 const CommandPool &commandPool,
27 const VkCommandBufferInheritanceInfo &inheritanceInfo,
28 VkCommandBufferUsageFlags flags,
29 CommandBuffer *commandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -050030{
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
Jamie Madill21061022018-07-12 23:56:30 -040040 ANGLE_TRY(commandBuffer->init(context, createInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -050041
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
Jamie Madill21061022018-07-12 23:56:30 -040048 ANGLE_TRY(commandBuffer->begin(context, beginInfo));
49 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -050050}
51
Jamie Madill0da73fe2018-10-02 09:31:39 -040052const char *GetResourceTypeName(CommandGraphResourceType resourceType)
53{
54 switch (resourceType)
55 {
56 case CommandGraphResourceType::Buffer:
57 return "Buffer";
58 case CommandGraphResourceType::Framebuffer:
59 return "Framebuffer";
60 case CommandGraphResourceType::Image:
61 return "Image";
62 default:
63 UNREACHABLE();
64 return "";
65 }
66}
Jamie Madill1f46bc12018-02-20 16:09:43 -050067} // anonymous namespace
68
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040069// CommandGraphResource implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -040070CommandGraphResource::CommandGraphResource(CommandGraphResourceType resourceType)
71 : mCurrentWritingNode(nullptr), mResourceType(resourceType)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040072{
73}
74
Jamie Madill316c6062018-05-29 10:49:45 -040075CommandGraphResource::~CommandGraphResource() = default;
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040076
77void CommandGraphResource::updateQueueSerial(Serial queueSerial)
78{
79 ASSERT(queueSerial >= mStoredQueueSerial);
80
81 if (queueSerial > mStoredQueueSerial)
82 {
83 mCurrentWritingNode = nullptr;
84 mCurrentReadingNodes.clear();
85 mStoredQueueSerial = queueSerial;
86 }
87}
88
Jamie Madillc57ee252018-05-30 19:53:48 -040089bool CommandGraphResource::isResourceInUse(RendererVk *renderer) const
90{
91 return renderer->isSerialInUse(mStoredQueueSerial);
92}
93
94Serial CommandGraphResource::getStoredQueueSerial() const
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040095{
96 return mStoredQueueSerial;
97}
98
Jamie Madille2d22702018-09-19 08:11:48 -040099angle::Result CommandGraphResource::recordCommands(Context *context,
100 CommandBuffer **commandBufferOut)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400101{
Jamie Madill21061022018-07-12 23:56:30 -0400102 updateQueueSerial(context->getRenderer()->getCurrentQueueSerial());
Jamie Madill5dca6512018-05-30 10:53:51 -0400103
Jamie Madille2d22702018-09-19 08:11:48 -0400104 if (!hasChildlessWritingNode() || hasStartedRenderPass())
Jamie Madill316c6062018-05-29 10:49:45 -0400105 {
Jamie Madille2d22702018-09-19 08:11:48 -0400106 finishCurrentCommands(context->getRenderer());
107 return mCurrentWritingNode->beginOutsideRenderPassRecording(
108 context, context->getRenderer()->getCommandPool(), commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400109 }
110
111 CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
112 if (!outsideRenderPassCommands->valid())
113 {
114 ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
Jamie Madill21061022018-07-12 23:56:30 -0400115 context, context->getRenderer()->getCommandPool(), commandBufferOut));
Jamie Madill316c6062018-05-29 10:49:45 -0400116 }
117 else
118 {
119 *commandBufferOut = outsideRenderPassCommands;
120 }
121
Jamie Madill21061022018-07-12 23:56:30 -0400122 return angle::Result::Continue();
Jamie Madill316c6062018-05-29 10:49:45 -0400123}
124
Jamie Madill5dca6512018-05-30 10:53:51 -0400125bool CommandGraphResource::appendToStartedRenderPass(RendererVk *renderer,
126 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400127{
Jamie Madill5dca6512018-05-30 10:53:51 -0400128 updateQueueSerial(renderer->getCurrentQueueSerial());
129 if (hasStartedRenderPass())
130 {
131 *commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands();
132 return true;
133 }
134 else
135 {
136 return false;
137 }
Jamie Madill316c6062018-05-29 10:49:45 -0400138}
139
Jamie Madill316c6062018-05-29 10:49:45 -0400140const gl::Rectangle &CommandGraphResource::getRenderPassRenderArea() const
141{
142 ASSERT(hasStartedRenderPass());
143 return mCurrentWritingNode->getRenderPassRenderArea();
144}
145
Jamie Madill21061022018-07-12 23:56:30 -0400146angle::Result CommandGraphResource::beginRenderPass(Context *context,
147 const Framebuffer &framebuffer,
148 const gl::Rectangle &renderArea,
149 const RenderPassDesc &renderPassDesc,
150 const std::vector<VkClearValue> &clearValues,
151 CommandBuffer **commandBufferOut) const
Jamie Madill316c6062018-05-29 10:49:45 -0400152{
153 // Hard-code RenderPass to clear the first render target to the current clear value.
154 // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
155 mCurrentWritingNode->storeRenderPassInfo(framebuffer, renderArea, renderPassDesc, clearValues);
156
Jamie Madill21061022018-07-12 23:56:30 -0400157 return mCurrentWritingNode->beginInsideRenderPassRecording(context, commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400158}
159
Jamie Madille2d22702018-09-19 08:11:48 -0400160void CommandGraphResource::finishCurrentCommands(RendererVk *renderer)
Jamie Madill316c6062018-05-29 10:49:45 -0400161{
Jamie Madill86ce2102018-05-22 11:54:42 -0400162 CommandGraphNode *newCommands = renderer->getCommandGraph()->allocateNode();
Jamie Madill0da73fe2018-10-02 09:31:39 -0400163 newCommands->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
Jamie Madill86ce2102018-05-22 11:54:42 -0400164 onWriteImpl(newCommands, renderer->getCurrentQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400165}
166
167void CommandGraphResource::addWriteDependency(CommandGraphResource *writingResource)
168{
169 CommandGraphNode *writingNode = writingResource->mCurrentWritingNode;
170 ASSERT(writingNode);
171
Jamie Madillc57ee252018-05-30 19:53:48 -0400172 onWriteImpl(writingNode, writingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400173}
174
175void CommandGraphResource::onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial)
176{
177 updateQueueSerial(currentSerial);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400178
Jamie Madill9cceac42018-03-31 14:19:16 -0400179 // Make sure any open reads and writes finish before we execute 'writingNode'.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400180 if (!mCurrentReadingNodes.empty())
181 {
182 CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes, writingNode);
183 mCurrentReadingNodes.clear();
184 }
185
186 if (mCurrentWritingNode && mCurrentWritingNode != writingNode)
187 {
188 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, writingNode);
189 }
190
191 mCurrentWritingNode = writingNode;
192}
193
Jamie Madill316c6062018-05-29 10:49:45 -0400194void CommandGraphResource::addReadDependency(CommandGraphResource *readingResource)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400195{
Jamie Madillc57ee252018-05-30 19:53:48 -0400196 updateQueueSerial(readingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400197
198 CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
199 ASSERT(readingNode);
Jamie Madill9cceac42018-03-31 14:19:16 -0400200
201 if (hasChildlessWritingNode())
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400202 {
Jamie Madill9cceac42018-03-31 14:19:16 -0400203 // Ensure 'readingNode' happens after the current writing node.
204 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
205 }
206
207 // Add the read node to the list of nodes currently reading this resource.
208 mCurrentReadingNodes.push_back(readingNode);
209}
210
Jamie Madill1f46bc12018-02-20 16:09:43 -0500211// CommandGraphNode implementation.
Jamie Madill316c6062018-05-29 10:49:45 -0400212CommandGraphNode::CommandGraphNode()
213 : mRenderPassClearValues{}, mHasChildren(false), mVisitedState(VisitedState::Unvisited)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500214{
215}
216
217CommandGraphNode::~CommandGraphNode()
218{
219 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
220
221 // Command buffers are managed by the command pool, so don't need to be freed.
222 mOutsideRenderPassCommands.releaseHandle();
223 mInsideRenderPassCommands.releaseHandle();
224}
225
226CommandBuffer *CommandGraphNode::getOutsideRenderPassCommands()
227{
228 ASSERT(!mHasChildren);
229 return &mOutsideRenderPassCommands;
230}
231
Jamie Madill21061022018-07-12 23:56:30 -0400232angle::Result CommandGraphNode::beginOutsideRenderPassRecording(Context *context,
233 const CommandPool &commandPool,
234 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500235{
236 ASSERT(!mHasChildren);
237
238 VkCommandBufferInheritanceInfo inheritanceInfo;
239 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
240 inheritanceInfo.pNext = nullptr;
241 inheritanceInfo.renderPass = VK_NULL_HANDLE;
242 inheritanceInfo.subpass = 0;
243 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
244 inheritanceInfo.occlusionQueryEnable = VK_FALSE;
245 inheritanceInfo.queryFlags = 0;
246 inheritanceInfo.pipelineStatistics = 0;
247
Jamie Madill21061022018-07-12 23:56:30 -0400248 ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500249 &mOutsideRenderPassCommands));
250
251 *commandsOut = &mOutsideRenderPassCommands;
Jamie Madill21061022018-07-12 23:56:30 -0400252 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500253}
254
Jamie Madill21061022018-07-12 23:56:30 -0400255angle::Result CommandGraphNode::beginInsideRenderPassRecording(Context *context,
256 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500257{
258 ASSERT(!mHasChildren);
259
260 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
261 // TODO(jmadill): Support query for compatible/conformant render pass. htto://anglebug.com/2361
262 RenderPass *compatibleRenderPass;
Jamie Madill21061022018-07-12 23:56:30 -0400263 ANGLE_TRY(context->getRenderer()->getCompatibleRenderPass(context, mRenderPassDesc,
264 &compatibleRenderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500265
266 VkCommandBufferInheritanceInfo inheritanceInfo;
267 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
268 inheritanceInfo.pNext = nullptr;
269 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
270 inheritanceInfo.subpass = 0;
271 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
272 inheritanceInfo.occlusionQueryEnable = VK_FALSE;
273 inheritanceInfo.queryFlags = 0;
274 inheritanceInfo.pipelineStatistics = 0;
275
276 ANGLE_TRY(InitAndBeginCommandBuffer(
Jamie Madill21061022018-07-12 23:56:30 -0400277 context, context->getRenderer()->getCommandPool(), inheritanceInfo,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500278 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
279
280 *commandsOut = &mInsideRenderPassCommands;
Jamie Madill21061022018-07-12 23:56:30 -0400281 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500282}
283
284void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
285 const gl::Rectangle renderArea,
Jamie Madillbcf467f2018-05-23 09:46:00 -0400286 const vk::RenderPassDesc &renderPassDesc,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500287 const std::vector<VkClearValue> &clearValues)
288{
Jamie Madillbcf467f2018-05-23 09:46:00 -0400289 mRenderPassDesc = renderPassDesc;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500290 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
291 mRenderPassRenderArea = renderArea;
292 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
293}
294
Jamie Madill1f46bc12018-02-20 16:09:43 -0500295// static
296void CommandGraphNode::SetHappensBeforeDependency(CommandGraphNode *beforeNode,
297 CommandGraphNode *afterNode)
298{
Jamie Madill9cceac42018-03-31 14:19:16 -0400299 ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500300 afterNode->mParents.emplace_back(beforeNode);
301 beforeNode->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500302}
303
304// static
305void CommandGraphNode::SetHappensBeforeDependencies(
306 const std::vector<CommandGraphNode *> &beforeNodes,
307 CommandGraphNode *afterNode)
308{
309 afterNode->mParents.insert(afterNode->mParents.end(), beforeNodes.begin(), beforeNodes.end());
310
311 // TODO(jmadill): is there a faster way to do this?
312 for (CommandGraphNode *beforeNode : beforeNodes)
313 {
314 beforeNode->setHasChildren();
315
316 ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
317 }
318}
319
320bool CommandGraphNode::hasParents() const
321{
322 return !mParents.empty();
323}
324
325void CommandGraphNode::setHasChildren()
326{
327 mHasChildren = true;
328}
329
Jamie Madill1f46bc12018-02-20 16:09:43 -0500330// Do not call this in anything but testing code, since it's slow.
331bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
332{
333 std::set<CommandGraphNode *> visitedList;
334 std::vector<CommandGraphNode *> openList;
335 openList.insert(openList.begin(), mParents.begin(), mParents.end());
336 while (!openList.empty())
337 {
338 CommandGraphNode *current = openList.back();
339 openList.pop_back();
340 if (visitedList.count(current) == 0)
341 {
342 if (current == parent)
343 {
344 return true;
345 }
346 visitedList.insert(current);
347 openList.insert(openList.end(), current->mParents.begin(), current->mParents.end());
348 }
349 }
350
351 return false;
352}
353
354VisitedState CommandGraphNode::visitedState() const
355{
356 return mVisitedState;
357}
358
359void CommandGraphNode::visitParents(std::vector<CommandGraphNode *> *stack)
360{
361 ASSERT(mVisitedState == VisitedState::Unvisited);
362 stack->insert(stack->end(), mParents.begin(), mParents.end());
363 mVisitedState = VisitedState::Ready;
364}
365
Jamie Madill21061022018-07-12 23:56:30 -0400366angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
367 Serial serial,
368 RenderPassCache *renderPassCache,
369 CommandBuffer *primaryCommandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500370{
371 if (mOutsideRenderPassCommands.valid())
372 {
Jamie Madill21061022018-07-12 23:56:30 -0400373 ANGLE_TRY(mOutsideRenderPassCommands.end(context));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500374 primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
375 }
376
377 if (mInsideRenderPassCommands.valid())
378 {
379 // Pull a compatible RenderPass from the cache.
380 // TODO(jmadill): Insert real ops and layout transitions.
381 RenderPass *renderPass = nullptr;
Jamie Madill21061022018-07-12 23:56:30 -0400382 ANGLE_TRY(renderPassCache->getCompatibleRenderPass(context, serial, mRenderPassDesc,
383 &renderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500384
Jamie Madill21061022018-07-12 23:56:30 -0400385 ANGLE_TRY(mInsideRenderPassCommands.end(context));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500386
387 VkRenderPassBeginInfo beginInfo;
388 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
389 beginInfo.pNext = nullptr;
390 beginInfo.renderPass = renderPass->getHandle();
391 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
392 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
393 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
394 beginInfo.renderArea.extent.width = static_cast<uint32_t>(mRenderPassRenderArea.width);
395 beginInfo.renderArea.extent.height = static_cast<uint32_t>(mRenderPassRenderArea.height);
396 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
397 beginInfo.pClearValues = mRenderPassClearValues.data();
398
399 primaryCommandBuffer->beginRenderPass(beginInfo,
400 VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
401 primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
402 primaryCommandBuffer->endRenderPass();
403 }
404
405 mVisitedState = VisitedState::Visited;
Jamie Madill21061022018-07-12 23:56:30 -0400406 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500407}
408
Jamie Madill0da73fe2018-10-02 09:31:39 -0400409const std::vector<CommandGraphNode *> &CommandGraphNode::getParentsForDiagnostics() const
410{
411 return mParents;
412}
413
414void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType,
415 uintptr_t resourceID)
416{
417 mResourceType = resourceType;
418 mResourceID = resourceID;
419}
420
Luc Ferron14f48172018-04-11 08:43:28 -0400421const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
422{
423 return mRenderPassRenderArea;
424}
425
Jamie Madill1f46bc12018-02-20 16:09:43 -0500426// CommandGraph implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -0400427CommandGraph::CommandGraph(bool enableGraphDiagnostics)
428 : mEnableGraphDiagnostics(enableGraphDiagnostics)
429{
430}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500431
432CommandGraph::~CommandGraph()
433{
434 ASSERT(empty());
435}
436
437CommandGraphNode *CommandGraph::allocateNode()
438{
439 // TODO(jmadill): Use a pool allocator for the CPU node allocations.
440 CommandGraphNode *newCommands = new CommandGraphNode();
441 mNodes.emplace_back(newCommands);
442 return newCommands;
443}
444
Jamie Madill21061022018-07-12 23:56:30 -0400445angle::Result CommandGraph::submitCommands(Context *context,
446 Serial serial,
447 RenderPassCache *renderPassCache,
448 CommandPool *commandPool,
449 CommandBuffer *primaryCommandBufferOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500450{
451 VkCommandBufferAllocateInfo primaryInfo;
452 primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
453 primaryInfo.pNext = nullptr;
454 primaryInfo.commandPool = commandPool->getHandle();
455 primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
456 primaryInfo.commandBufferCount = 1;
457
Jamie Madill21061022018-07-12 23:56:30 -0400458 ANGLE_TRY(primaryCommandBufferOut->init(context, primaryInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500459
460 if (mNodes.empty())
461 {
Jamie Madill21061022018-07-12 23:56:30 -0400462 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500463 }
464
Jamie Madill0da73fe2018-10-02 09:31:39 -0400465 if (mEnableGraphDiagnostics)
466 {
467 dumpGraphDotFile(std::cout);
468 }
469
Jamie Madill1f46bc12018-02-20 16:09:43 -0500470 std::vector<CommandGraphNode *> nodeStack;
471
472 VkCommandBufferBeginInfo beginInfo;
473 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
474 beginInfo.pNext = nullptr;
475 beginInfo.flags = 0;
476 beginInfo.pInheritanceInfo = nullptr;
477
Jamie Madill21061022018-07-12 23:56:30 -0400478 ANGLE_TRY(primaryCommandBufferOut->begin(context, beginInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500479
480 for (CommandGraphNode *topLevelNode : mNodes)
481 {
482 // Only process commands that don't have child commands. The others will be pulled in
483 // automatically. Also skip commands that have already been visited.
484 if (topLevelNode->hasChildren() || topLevelNode->visitedState() != VisitedState::Unvisited)
485 continue;
486
487 nodeStack.push_back(topLevelNode);
488
489 while (!nodeStack.empty())
490 {
491 CommandGraphNode *node = nodeStack.back();
492
493 switch (node->visitedState())
494 {
495 case VisitedState::Unvisited:
496 node->visitParents(&nodeStack);
497 break;
498 case VisitedState::Ready:
Jamie Madill21061022018-07-12 23:56:30 -0400499 ANGLE_TRY(node->visitAndExecute(context, serial, renderPassCache,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500500 primaryCommandBufferOut));
501 nodeStack.pop_back();
502 break;
503 case VisitedState::Visited:
504 nodeStack.pop_back();
505 break;
506 default:
507 UNREACHABLE();
508 break;
509 }
510 }
511 }
512
Jamie Madill21061022018-07-12 23:56:30 -0400513 ANGLE_TRY(primaryCommandBufferOut->end(context));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500514
515 // TODO(jmadill): Use pool allocation so we don't need to deallocate command graph.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400516 for (CommandGraphNode *node : mNodes)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500517 {
518 delete node;
519 }
520 mNodes.clear();
521
Jamie Madill21061022018-07-12 23:56:30 -0400522 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500523}
524
525bool CommandGraph::empty() const
526{
527 return mNodes.empty();
528}
529
Jamie Madill0da73fe2018-10-02 09:31:39 -0400530// Dumps the command graph into a dot file that works with graphviz.
531void CommandGraph::dumpGraphDotFile(std::ostream &out) const
532{
533 // This ID maps a node pointer to a monatonic ID. It allows us to look up parent node IDs.
534 std::map<const CommandGraphNode *, int> nodeIDMap;
535 std::map<uintptr_t, int> objectIDMap;
536
537 // Map nodes to ids.
538 for (size_t nodeIndex = 0; nodeIndex < mNodes.size(); ++nodeIndex)
539 {
540 const CommandGraphNode *node = mNodes[nodeIndex];
541 nodeIDMap[node] = static_cast<int>(nodeIndex) + 1;
542 }
543
544 int bufferIDCounter = 1;
545 int framebufferIDCounter = 1;
546 int imageIDCounter = 1;
547
548 out << "digraph {" << std::endl;
549
550 for (const CommandGraphNode *node : mNodes)
551 {
552 int nodeID = nodeIDMap[node];
553
554 std::stringstream strstr;
555 strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics());
556 strstr << " ";
557
558 auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
559 if (it != objectIDMap.end())
560 {
561 strstr << it->second;
562 }
563 else
564 {
565 int id = 0;
566
567 switch (node->getResourceTypeForDiagnostics())
568 {
569 case CommandGraphResourceType::Buffer:
570 id = bufferIDCounter++;
571 break;
572 case CommandGraphResourceType::Framebuffer:
573 id = framebufferIDCounter++;
574 break;
575 case CommandGraphResourceType::Image:
576 id = imageIDCounter++;
577 break;
578 default:
579 UNREACHABLE();
580 break;
581 }
582
583 objectIDMap[node->getResourceIDForDiagnostics()] = id;
584 strstr << id;
585 }
586
587 const std::string &label = strstr.str();
588 out << " " << nodeID << "[label =<" << label << "<BR/> <FONT POINT-SIZE=\"10\">Node ID "
589 << nodeID << "</FONT>>];" << std::endl;
590 }
591
592 for (const CommandGraphNode *node : mNodes)
593 {
594 int nodeID = nodeIDMap[node];
595
596 for (const CommandGraphNode *parent : node->getParentsForDiagnostics())
597 {
598 int parentID = nodeIDMap[parent];
599 out << " " << parentID << " -> " << nodeID << ";" << std::endl;
600 }
601 }
602
603 out << "}" << std::endl;
604}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500605} // namespace vk
606} // namespace rx