blob: c6420e821ea540e03b7249c106d30eaa625bd7e7 [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
12#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
13#include "libANGLE/renderer/vulkan/RendererVk.h"
14#include "libANGLE/renderer/vulkan/vk_format_utils.h"
Jamie Madill26084d02018-04-09 13:44:04 -040015#include "libANGLE/renderer/vulkan/vk_helpers.h"
Jamie Madill1f46bc12018-02-20 16:09:43 -050016
17namespace rx
18{
19
20namespace vk
21{
22
23namespace
24{
25
26Error InitAndBeginCommandBuffer(VkDevice device,
27 const CommandPool &commandPool,
28 const VkCommandBufferInheritanceInfo &inheritanceInfo,
29 VkCommandBufferUsageFlags flags,
30 CommandBuffer *commandBuffer)
31{
32 ASSERT(!commandBuffer->valid());
33
34 VkCommandBufferAllocateInfo createInfo;
35 createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
36 createInfo.pNext = nullptr;
37 createInfo.commandPool = commandPool.getHandle();
38 createInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
39 createInfo.commandBufferCount = 1;
40
41 ANGLE_TRY(commandBuffer->init(device, createInfo));
42
43 VkCommandBufferBeginInfo beginInfo;
44 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
45 beginInfo.pNext = nullptr;
46 beginInfo.flags = flags | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
47 beginInfo.pInheritanceInfo = &inheritanceInfo;
48
49 ANGLE_TRY(commandBuffer->begin(beginInfo));
50 return NoError();
51}
52
53} // anonymous namespace
54
Jamie Madilla5e06072018-05-18 14:36:05 -040055class CommandGraphNode final : angle::NonCopyable
56{
57 public:
58 CommandGraphNode();
59 ~CommandGraphNode();
60
61 // Immutable queries for when we're walking the commands tree.
62 CommandBuffer *getOutsideRenderPassCommands();
63 CommandBuffer *getInsideRenderPassCommands();
64
65 // For outside the render pass (copies, transitions, etc).
66 Error beginOutsideRenderPassRecording(VkDevice device,
67 const CommandPool &commandPool,
68 CommandBuffer **commandsOut);
69
70 // For rendering commands (draws).
71 Error beginInsideRenderPassRecording(RendererVk *renderer, CommandBuffer **commandsOut);
72
73 // storeRenderPassInfo and append*RenderTarget store info relevant to the RenderPass.
74 void storeRenderPassInfo(const Framebuffer &framebuffer,
75 const gl::Rectangle renderArea,
76 const vk::RenderPassDesc &renderPassDesc,
77 const std::vector<VkClearValue> &clearValues);
78
79 // Dependency commands order node execution in the command graph.
80 // Once a node has commands that must happen after it, recording is stopped and the node is
81 // frozen forever.
82 static void SetHappensBeforeDependency(CommandGraphNode *beforeNode,
83 CommandGraphNode *afterNode);
84 static void SetHappensBeforeDependencies(const std::vector<CommandGraphNode *> &beforeNodes,
85 CommandGraphNode *afterNode);
86 bool hasParents() const;
87 bool hasChildren() const;
88
89 // Commands for traversing the node on a flush operation.
90 VisitedState visitedState() const;
91 void visitParents(std::vector<CommandGraphNode *> *stack);
92 Error visitAndExecute(VkDevice device,
93 Serial serial,
94 RenderPassCache *renderPassCache,
95 CommandBuffer *primaryCommandBuffer);
96
97 const gl::Rectangle &getRenderPassRenderArea() const;
98
99 private:
100 void setHasChildren();
101
102 // Used for testing only.
103 bool isChildOf(CommandGraphNode *parent);
104
105 // Only used if we need a RenderPass for these commands.
106 RenderPassDesc mRenderPassDesc;
107 Framebuffer mRenderPassFramebuffer;
108 gl::Rectangle mRenderPassRenderArea;
109 gl::AttachmentArray<VkClearValue> mRenderPassClearValues;
110
111 // Keep a separate buffers for commands inside and outside a RenderPass.
112 // TODO(jmadill): We might not need inside and outside RenderPass commands separate.
113 CommandBuffer mOutsideRenderPassCommands;
114 CommandBuffer mInsideRenderPassCommands;
115
116 // Parents are commands that must be submitted before 'this' CommandNode can be submitted.
117 std::vector<CommandGraphNode *> mParents;
118
119 // If this is true, other commands exist that must be submitted after 'this' command.
120 bool mHasChildren;
121
122 // Used when traversing the dependency graph.
123 VisitedState mVisitedState;
124};
125
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400126// CommandGraphResource implementation.
127CommandGraphResource::CommandGraphResource() : mCurrentWritingNode(nullptr)
128{
129}
130
Jamie Madill316c6062018-05-29 10:49:45 -0400131CommandGraphResource::~CommandGraphResource() = default;
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400132
133void CommandGraphResource::updateQueueSerial(Serial queueSerial)
134{
135 ASSERT(queueSerial >= mStoredQueueSerial);
136
137 if (queueSerial > mStoredQueueSerial)
138 {
139 mCurrentWritingNode = nullptr;
140 mCurrentReadingNodes.clear();
141 mStoredQueueSerial = queueSerial;
142 }
143}
144
145Serial CommandGraphResource::getQueueSerial() const
146{
147 return mStoredQueueSerial;
148}
149
Jamie Madill9cceac42018-03-31 14:19:16 -0400150bool CommandGraphResource::hasChildlessWritingNode() const
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400151{
Jamie Madill9cceac42018-03-31 14:19:16 -0400152 return (mCurrentWritingNode != nullptr && !mCurrentWritingNode->hasChildren());
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400153}
154
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400155CommandGraphNode *CommandGraphResource::getNewWritingNode(RendererVk *renderer)
156{
Jamie Madilla5e06072018-05-18 14:36:05 -0400157 CommandGraphNode *newCommands = renderer->getCommandGraph()->allocateNode();
Jamie Madill316c6062018-05-29 10:49:45 -0400158 onWriteImpl(newCommands, renderer->getCurrentQueueSerial());
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400159 return newCommands;
160}
161
Jamie Madill316c6062018-05-29 10:49:45 -0400162bool CommandGraphResource::hasStartedWriteResource() const
163{
164 return hasChildlessWritingNode() &&
165 mCurrentWritingNode->getOutsideRenderPassCommands()->valid();
166}
167
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400168Error CommandGraphResource::beginWriteResource(RendererVk *renderer,
169 CommandBuffer **commandBufferOut)
170{
171 CommandGraphNode *commands = getNewWritingNode(renderer);
172
173 VkDevice device = renderer->getDevice();
174 ANGLE_TRY(commands->beginOutsideRenderPassRecording(device, renderer->getCommandPool(),
175 commandBufferOut));
176 return NoError();
177}
178
Jamie Madill316c6062018-05-29 10:49:45 -0400179Error CommandGraphResource::appendWriteResource(RendererVk *renderer,
180 CommandBuffer **commandBufferOut)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400181{
Jamie Madill316c6062018-05-29 10:49:45 -0400182 if (!hasChildlessWritingNode())
183 {
184 return beginWriteResource(renderer, commandBufferOut);
185 }
186
187 CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
188 if (!outsideRenderPassCommands->valid())
189 {
190 ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
191 renderer->getDevice(), renderer->getCommandPool(), commandBufferOut));
192 }
193 else
194 {
195 *commandBufferOut = outsideRenderPassCommands;
196 }
197
198 return NoError();
199}
200
201void CommandGraphResource::appendToRenderPass(class CommandBuffer **commandBufferOut) const
202{
203 ASSERT(hasStartedRenderPass());
204 *commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands();
205}
206
207bool CommandGraphResource::hasStartedRenderPass() const
208{
209 return hasChildlessWritingNode() && mCurrentWritingNode->getInsideRenderPassCommands()->valid();
210}
211
212const gl::Rectangle &CommandGraphResource::getRenderPassRenderArea() const
213{
214 ASSERT(hasStartedRenderPass());
215 return mCurrentWritingNode->getRenderPassRenderArea();
216}
217
218Error CommandGraphResource::beginRenderPass(RendererVk *renderer,
219 const Framebuffer &framebuffer,
220 const gl::Rectangle &renderArea,
221 const RenderPassDesc &renderPassDesc,
222 const std::vector<VkClearValue> &clearValues,
223 CommandBuffer **commandBufferOut) const
224{
225 // Hard-code RenderPass to clear the first render target to the current clear value.
226 // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
227 mCurrentWritingNode->storeRenderPassInfo(framebuffer, renderArea, renderPassDesc, clearValues);
228
229 return mCurrentWritingNode->beginInsideRenderPassRecording(renderer, commandBufferOut);
230}
231
232void CommandGraphResource::onResourceChanged(RendererVk *renderer)
233{
234 getNewWritingNode(renderer);
235}
236
237void CommandGraphResource::addWriteDependency(CommandGraphResource *writingResource)
238{
239 CommandGraphNode *writingNode = writingResource->mCurrentWritingNode;
240 ASSERT(writingNode);
241
242 onWriteImpl(writingNode, writingResource->getQueueSerial());
243}
244
245void CommandGraphResource::onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial)
246{
247 updateQueueSerial(currentSerial);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400248
Jamie Madill9cceac42018-03-31 14:19:16 -0400249 // Make sure any open reads and writes finish before we execute 'writingNode'.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400250 if (!mCurrentReadingNodes.empty())
251 {
252 CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes, writingNode);
253 mCurrentReadingNodes.clear();
254 }
255
256 if (mCurrentWritingNode && mCurrentWritingNode != writingNode)
257 {
258 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, writingNode);
259 }
260
261 mCurrentWritingNode = writingNode;
262}
263
Jamie Madill316c6062018-05-29 10:49:45 -0400264void CommandGraphResource::addReadDependency(CommandGraphResource *readingResource)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400265{
Jamie Madill316c6062018-05-29 10:49:45 -0400266 updateQueueSerial(readingResource->getQueueSerial());
267
268 CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
269 ASSERT(readingNode);
Jamie Madill9cceac42018-03-31 14:19:16 -0400270
271 if (hasChildlessWritingNode())
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400272 {
Jamie Madill9cceac42018-03-31 14:19:16 -0400273 // Ensure 'readingNode' happens after the current writing node.
274 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
275 }
276
277 // Add the read node to the list of nodes currently reading this resource.
278 mCurrentReadingNodes.push_back(readingNode);
279}
280
Jamie Madill1f46bc12018-02-20 16:09:43 -0500281// CommandGraphNode implementation.
Jamie Madill316c6062018-05-29 10:49:45 -0400282CommandGraphNode::CommandGraphNode()
283 : mRenderPassClearValues{}, mHasChildren(false), mVisitedState(VisitedState::Unvisited)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500284{
285}
286
287CommandGraphNode::~CommandGraphNode()
288{
289 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
290
291 // Command buffers are managed by the command pool, so don't need to be freed.
292 mOutsideRenderPassCommands.releaseHandle();
293 mInsideRenderPassCommands.releaseHandle();
294}
295
296CommandBuffer *CommandGraphNode::getOutsideRenderPassCommands()
297{
298 ASSERT(!mHasChildren);
299 return &mOutsideRenderPassCommands;
300}
301
302CommandBuffer *CommandGraphNode::getInsideRenderPassCommands()
303{
304 ASSERT(!mHasChildren);
305 return &mInsideRenderPassCommands;
306}
307
308Error CommandGraphNode::beginOutsideRenderPassRecording(VkDevice device,
309 const CommandPool &commandPool,
310 CommandBuffer **commandsOut)
311{
312 ASSERT(!mHasChildren);
313
314 VkCommandBufferInheritanceInfo inheritanceInfo;
315 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
316 inheritanceInfo.pNext = nullptr;
317 inheritanceInfo.renderPass = VK_NULL_HANDLE;
318 inheritanceInfo.subpass = 0;
319 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
320 inheritanceInfo.occlusionQueryEnable = VK_FALSE;
321 inheritanceInfo.queryFlags = 0;
322 inheritanceInfo.pipelineStatistics = 0;
323
324 ANGLE_TRY(InitAndBeginCommandBuffer(device, commandPool, inheritanceInfo, 0,
325 &mOutsideRenderPassCommands));
326
327 *commandsOut = &mOutsideRenderPassCommands;
328 return NoError();
329}
330
331Error CommandGraphNode::beginInsideRenderPassRecording(RendererVk *renderer,
332 CommandBuffer **commandsOut)
333{
334 ASSERT(!mHasChildren);
335
336 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
337 // TODO(jmadill): Support query for compatible/conformant render pass. htto://anglebug.com/2361
338 RenderPass *compatibleRenderPass;
339 ANGLE_TRY(renderer->getCompatibleRenderPass(mRenderPassDesc, &compatibleRenderPass));
340
341 VkCommandBufferInheritanceInfo inheritanceInfo;
342 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
343 inheritanceInfo.pNext = nullptr;
344 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
345 inheritanceInfo.subpass = 0;
346 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
347 inheritanceInfo.occlusionQueryEnable = VK_FALSE;
348 inheritanceInfo.queryFlags = 0;
349 inheritanceInfo.pipelineStatistics = 0;
350
351 ANGLE_TRY(InitAndBeginCommandBuffer(
352 renderer->getDevice(), renderer->getCommandPool(), inheritanceInfo,
353 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
354
355 *commandsOut = &mInsideRenderPassCommands;
356 return NoError();
357}
358
359void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
360 const gl::Rectangle renderArea,
Jamie Madillbcf467f2018-05-23 09:46:00 -0400361 const vk::RenderPassDesc &renderPassDesc,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500362 const std::vector<VkClearValue> &clearValues)
363{
Jamie Madillbcf467f2018-05-23 09:46:00 -0400364 mRenderPassDesc = renderPassDesc;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500365 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
366 mRenderPassRenderArea = renderArea;
367 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
368}
369
Jamie Madill1f46bc12018-02-20 16:09:43 -0500370// static
371void CommandGraphNode::SetHappensBeforeDependency(CommandGraphNode *beforeNode,
372 CommandGraphNode *afterNode)
373{
Jamie Madill9cceac42018-03-31 14:19:16 -0400374 ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500375 afterNode->mParents.emplace_back(beforeNode);
376 beforeNode->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500377}
378
379// static
380void CommandGraphNode::SetHappensBeforeDependencies(
381 const std::vector<CommandGraphNode *> &beforeNodes,
382 CommandGraphNode *afterNode)
383{
384 afterNode->mParents.insert(afterNode->mParents.end(), beforeNodes.begin(), beforeNodes.end());
385
386 // TODO(jmadill): is there a faster way to do this?
387 for (CommandGraphNode *beforeNode : beforeNodes)
388 {
389 beforeNode->setHasChildren();
390
391 ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
392 }
393}
394
395bool CommandGraphNode::hasParents() const
396{
397 return !mParents.empty();
398}
399
400void CommandGraphNode::setHasChildren()
401{
402 mHasChildren = true;
403}
404
405bool CommandGraphNode::hasChildren() const
406{
407 return mHasChildren;
408}
409
410// Do not call this in anything but testing code, since it's slow.
411bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
412{
413 std::set<CommandGraphNode *> visitedList;
414 std::vector<CommandGraphNode *> openList;
415 openList.insert(openList.begin(), mParents.begin(), mParents.end());
416 while (!openList.empty())
417 {
418 CommandGraphNode *current = openList.back();
419 openList.pop_back();
420 if (visitedList.count(current) == 0)
421 {
422 if (current == parent)
423 {
424 return true;
425 }
426 visitedList.insert(current);
427 openList.insert(openList.end(), current->mParents.begin(), current->mParents.end());
428 }
429 }
430
431 return false;
432}
433
434VisitedState CommandGraphNode::visitedState() const
435{
436 return mVisitedState;
437}
438
439void CommandGraphNode::visitParents(std::vector<CommandGraphNode *> *stack)
440{
441 ASSERT(mVisitedState == VisitedState::Unvisited);
442 stack->insert(stack->end(), mParents.begin(), mParents.end());
443 mVisitedState = VisitedState::Ready;
444}
445
446Error CommandGraphNode::visitAndExecute(VkDevice device,
447 Serial serial,
448 RenderPassCache *renderPassCache,
449 CommandBuffer *primaryCommandBuffer)
450{
451 if (mOutsideRenderPassCommands.valid())
452 {
453 mOutsideRenderPassCommands.end();
454 primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
455 }
456
457 if (mInsideRenderPassCommands.valid())
458 {
459 // Pull a compatible RenderPass from the cache.
460 // TODO(jmadill): Insert real ops and layout transitions.
461 RenderPass *renderPass = nullptr;
462 ANGLE_TRY(
463 renderPassCache->getCompatibleRenderPass(device, serial, mRenderPassDesc, &renderPass));
464
465 mInsideRenderPassCommands.end();
466
467 VkRenderPassBeginInfo beginInfo;
468 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
469 beginInfo.pNext = nullptr;
470 beginInfo.renderPass = renderPass->getHandle();
471 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
472 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
473 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
474 beginInfo.renderArea.extent.width = static_cast<uint32_t>(mRenderPassRenderArea.width);
475 beginInfo.renderArea.extent.height = static_cast<uint32_t>(mRenderPassRenderArea.height);
476 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
477 beginInfo.pClearValues = mRenderPassClearValues.data();
478
479 primaryCommandBuffer->beginRenderPass(beginInfo,
480 VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
481 primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
482 primaryCommandBuffer->endRenderPass();
483 }
484
485 mVisitedState = VisitedState::Visited;
486 return NoError();
487}
488
Luc Ferron14f48172018-04-11 08:43:28 -0400489const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
490{
491 return mRenderPassRenderArea;
492}
493
Jamie Madill1f46bc12018-02-20 16:09:43 -0500494// CommandGraph implementation.
Jamie Madill316c6062018-05-29 10:49:45 -0400495CommandGraph::CommandGraph() = default;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500496
497CommandGraph::~CommandGraph()
498{
499 ASSERT(empty());
500}
501
502CommandGraphNode *CommandGraph::allocateNode()
503{
504 // TODO(jmadill): Use a pool allocator for the CPU node allocations.
505 CommandGraphNode *newCommands = new CommandGraphNode();
506 mNodes.emplace_back(newCommands);
507 return newCommands;
508}
509
510Error CommandGraph::submitCommands(VkDevice device,
511 Serial serial,
512 RenderPassCache *renderPassCache,
513 CommandPool *commandPool,
514 CommandBuffer *primaryCommandBufferOut)
515{
516 VkCommandBufferAllocateInfo primaryInfo;
517 primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
518 primaryInfo.pNext = nullptr;
519 primaryInfo.commandPool = commandPool->getHandle();
520 primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
521 primaryInfo.commandBufferCount = 1;
522
523 ANGLE_TRY(primaryCommandBufferOut->init(device, primaryInfo));
524
525 if (mNodes.empty())
526 {
527 return NoError();
528 }
529
530 std::vector<CommandGraphNode *> nodeStack;
531
532 VkCommandBufferBeginInfo beginInfo;
533 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
534 beginInfo.pNext = nullptr;
535 beginInfo.flags = 0;
536 beginInfo.pInheritanceInfo = nullptr;
537
538 ANGLE_TRY(primaryCommandBufferOut->begin(beginInfo));
539
540 for (CommandGraphNode *topLevelNode : mNodes)
541 {
542 // Only process commands that don't have child commands. The others will be pulled in
543 // automatically. Also skip commands that have already been visited.
544 if (topLevelNode->hasChildren() || topLevelNode->visitedState() != VisitedState::Unvisited)
545 continue;
546
547 nodeStack.push_back(topLevelNode);
548
549 while (!nodeStack.empty())
550 {
551 CommandGraphNode *node = nodeStack.back();
552
553 switch (node->visitedState())
554 {
555 case VisitedState::Unvisited:
556 node->visitParents(&nodeStack);
557 break;
558 case VisitedState::Ready:
559 ANGLE_TRY(node->visitAndExecute(device, serial, renderPassCache,
560 primaryCommandBufferOut));
561 nodeStack.pop_back();
562 break;
563 case VisitedState::Visited:
564 nodeStack.pop_back();
565 break;
566 default:
567 UNREACHABLE();
568 break;
569 }
570 }
571 }
572
573 ANGLE_TRY(primaryCommandBufferOut->end());
574
575 // TODO(jmadill): Use pool allocation so we don't need to deallocate command graph.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400576 for (CommandGraphNode *node : mNodes)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500577 {
578 delete node;
579 }
580 mNodes.clear();
581
582 return NoError();
583}
584
585bool CommandGraph::empty() const
586{
587 return mNodes.empty();
588}
589
590} // namespace vk
591} // namespace rx