blob: e9c20d4eb2b7247b4caf39acb93f06386e4111b3 [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 Madill5dca6512018-05-30 10:53:51 -0400182 updateQueueSerial(renderer->getCurrentQueueSerial());
183
Jamie Madill316c6062018-05-29 10:49:45 -0400184 if (!hasChildlessWritingNode())
185 {
186 return beginWriteResource(renderer, commandBufferOut);
187 }
188
189 CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
190 if (!outsideRenderPassCommands->valid())
191 {
192 ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
193 renderer->getDevice(), renderer->getCommandPool(), commandBufferOut));
194 }
195 else
196 {
197 *commandBufferOut = outsideRenderPassCommands;
198 }
199
200 return NoError();
201}
202
Jamie Madill5dca6512018-05-30 10:53:51 -0400203bool CommandGraphResource::appendToStartedRenderPass(RendererVk *renderer,
204 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400205{
Jamie Madill5dca6512018-05-30 10:53:51 -0400206 updateQueueSerial(renderer->getCurrentQueueSerial());
207 if (hasStartedRenderPass())
208 {
209 *commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands();
210 return true;
211 }
212 else
213 {
214 return false;
215 }
Jamie Madill316c6062018-05-29 10:49:45 -0400216}
217
218bool CommandGraphResource::hasStartedRenderPass() const
219{
220 return hasChildlessWritingNode() && mCurrentWritingNode->getInsideRenderPassCommands()->valid();
221}
222
223const gl::Rectangle &CommandGraphResource::getRenderPassRenderArea() const
224{
225 ASSERT(hasStartedRenderPass());
226 return mCurrentWritingNode->getRenderPassRenderArea();
227}
228
229Error CommandGraphResource::beginRenderPass(RendererVk *renderer,
230 const Framebuffer &framebuffer,
231 const gl::Rectangle &renderArea,
232 const RenderPassDesc &renderPassDesc,
233 const std::vector<VkClearValue> &clearValues,
234 CommandBuffer **commandBufferOut) const
235{
236 // Hard-code RenderPass to clear the first render target to the current clear value.
237 // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
238 mCurrentWritingNode->storeRenderPassInfo(framebuffer, renderArea, renderPassDesc, clearValues);
239
240 return mCurrentWritingNode->beginInsideRenderPassRecording(renderer, commandBufferOut);
241}
242
243void CommandGraphResource::onResourceChanged(RendererVk *renderer)
244{
245 getNewWritingNode(renderer);
246}
247
248void CommandGraphResource::addWriteDependency(CommandGraphResource *writingResource)
249{
250 CommandGraphNode *writingNode = writingResource->mCurrentWritingNode;
251 ASSERT(writingNode);
252
253 onWriteImpl(writingNode, writingResource->getQueueSerial());
254}
255
256void CommandGraphResource::onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial)
257{
258 updateQueueSerial(currentSerial);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400259
Jamie Madill9cceac42018-03-31 14:19:16 -0400260 // Make sure any open reads and writes finish before we execute 'writingNode'.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400261 if (!mCurrentReadingNodes.empty())
262 {
263 CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes, writingNode);
264 mCurrentReadingNodes.clear();
265 }
266
267 if (mCurrentWritingNode && mCurrentWritingNode != writingNode)
268 {
269 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, writingNode);
270 }
271
272 mCurrentWritingNode = writingNode;
273}
274
Jamie Madill316c6062018-05-29 10:49:45 -0400275void CommandGraphResource::addReadDependency(CommandGraphResource *readingResource)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400276{
Jamie Madill316c6062018-05-29 10:49:45 -0400277 updateQueueSerial(readingResource->getQueueSerial());
278
279 CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
280 ASSERT(readingNode);
Jamie Madill9cceac42018-03-31 14:19:16 -0400281
282 if (hasChildlessWritingNode())
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400283 {
Jamie Madill9cceac42018-03-31 14:19:16 -0400284 // Ensure 'readingNode' happens after the current writing node.
285 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
286 }
287
288 // Add the read node to the list of nodes currently reading this resource.
289 mCurrentReadingNodes.push_back(readingNode);
290}
291
Jamie Madill1f46bc12018-02-20 16:09:43 -0500292// CommandGraphNode implementation.
Jamie Madill316c6062018-05-29 10:49:45 -0400293CommandGraphNode::CommandGraphNode()
294 : mRenderPassClearValues{}, mHasChildren(false), mVisitedState(VisitedState::Unvisited)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500295{
296}
297
298CommandGraphNode::~CommandGraphNode()
299{
300 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
301
302 // Command buffers are managed by the command pool, so don't need to be freed.
303 mOutsideRenderPassCommands.releaseHandle();
304 mInsideRenderPassCommands.releaseHandle();
305}
306
307CommandBuffer *CommandGraphNode::getOutsideRenderPassCommands()
308{
309 ASSERT(!mHasChildren);
310 return &mOutsideRenderPassCommands;
311}
312
313CommandBuffer *CommandGraphNode::getInsideRenderPassCommands()
314{
315 ASSERT(!mHasChildren);
316 return &mInsideRenderPassCommands;
317}
318
319Error CommandGraphNode::beginOutsideRenderPassRecording(VkDevice device,
320 const CommandPool &commandPool,
321 CommandBuffer **commandsOut)
322{
323 ASSERT(!mHasChildren);
324
325 VkCommandBufferInheritanceInfo inheritanceInfo;
326 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
327 inheritanceInfo.pNext = nullptr;
328 inheritanceInfo.renderPass = VK_NULL_HANDLE;
329 inheritanceInfo.subpass = 0;
330 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
331 inheritanceInfo.occlusionQueryEnable = VK_FALSE;
332 inheritanceInfo.queryFlags = 0;
333 inheritanceInfo.pipelineStatistics = 0;
334
335 ANGLE_TRY(InitAndBeginCommandBuffer(device, commandPool, inheritanceInfo, 0,
336 &mOutsideRenderPassCommands));
337
338 *commandsOut = &mOutsideRenderPassCommands;
339 return NoError();
340}
341
342Error CommandGraphNode::beginInsideRenderPassRecording(RendererVk *renderer,
343 CommandBuffer **commandsOut)
344{
345 ASSERT(!mHasChildren);
346
347 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
348 // TODO(jmadill): Support query for compatible/conformant render pass. htto://anglebug.com/2361
349 RenderPass *compatibleRenderPass;
350 ANGLE_TRY(renderer->getCompatibleRenderPass(mRenderPassDesc, &compatibleRenderPass));
351
352 VkCommandBufferInheritanceInfo inheritanceInfo;
353 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
354 inheritanceInfo.pNext = nullptr;
355 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
356 inheritanceInfo.subpass = 0;
357 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
358 inheritanceInfo.occlusionQueryEnable = VK_FALSE;
359 inheritanceInfo.queryFlags = 0;
360 inheritanceInfo.pipelineStatistics = 0;
361
362 ANGLE_TRY(InitAndBeginCommandBuffer(
363 renderer->getDevice(), renderer->getCommandPool(), inheritanceInfo,
364 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
365
366 *commandsOut = &mInsideRenderPassCommands;
367 return NoError();
368}
369
370void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
371 const gl::Rectangle renderArea,
Jamie Madillbcf467f2018-05-23 09:46:00 -0400372 const vk::RenderPassDesc &renderPassDesc,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500373 const std::vector<VkClearValue> &clearValues)
374{
Jamie Madillbcf467f2018-05-23 09:46:00 -0400375 mRenderPassDesc = renderPassDesc;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500376 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
377 mRenderPassRenderArea = renderArea;
378 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
379}
380
Jamie Madill1f46bc12018-02-20 16:09:43 -0500381// static
382void CommandGraphNode::SetHappensBeforeDependency(CommandGraphNode *beforeNode,
383 CommandGraphNode *afterNode)
384{
Jamie Madill9cceac42018-03-31 14:19:16 -0400385 ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500386 afterNode->mParents.emplace_back(beforeNode);
387 beforeNode->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500388}
389
390// static
391void CommandGraphNode::SetHappensBeforeDependencies(
392 const std::vector<CommandGraphNode *> &beforeNodes,
393 CommandGraphNode *afterNode)
394{
395 afterNode->mParents.insert(afterNode->mParents.end(), beforeNodes.begin(), beforeNodes.end());
396
397 // TODO(jmadill): is there a faster way to do this?
398 for (CommandGraphNode *beforeNode : beforeNodes)
399 {
400 beforeNode->setHasChildren();
401
402 ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
403 }
404}
405
406bool CommandGraphNode::hasParents() const
407{
408 return !mParents.empty();
409}
410
411void CommandGraphNode::setHasChildren()
412{
413 mHasChildren = true;
414}
415
416bool CommandGraphNode::hasChildren() const
417{
418 return mHasChildren;
419}
420
421// Do not call this in anything but testing code, since it's slow.
422bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
423{
424 std::set<CommandGraphNode *> visitedList;
425 std::vector<CommandGraphNode *> openList;
426 openList.insert(openList.begin(), mParents.begin(), mParents.end());
427 while (!openList.empty())
428 {
429 CommandGraphNode *current = openList.back();
430 openList.pop_back();
431 if (visitedList.count(current) == 0)
432 {
433 if (current == parent)
434 {
435 return true;
436 }
437 visitedList.insert(current);
438 openList.insert(openList.end(), current->mParents.begin(), current->mParents.end());
439 }
440 }
441
442 return false;
443}
444
445VisitedState CommandGraphNode::visitedState() const
446{
447 return mVisitedState;
448}
449
450void CommandGraphNode::visitParents(std::vector<CommandGraphNode *> *stack)
451{
452 ASSERT(mVisitedState == VisitedState::Unvisited);
453 stack->insert(stack->end(), mParents.begin(), mParents.end());
454 mVisitedState = VisitedState::Ready;
455}
456
457Error CommandGraphNode::visitAndExecute(VkDevice device,
458 Serial serial,
459 RenderPassCache *renderPassCache,
460 CommandBuffer *primaryCommandBuffer)
461{
462 if (mOutsideRenderPassCommands.valid())
463 {
464 mOutsideRenderPassCommands.end();
465 primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
466 }
467
468 if (mInsideRenderPassCommands.valid())
469 {
470 // Pull a compatible RenderPass from the cache.
471 // TODO(jmadill): Insert real ops and layout transitions.
472 RenderPass *renderPass = nullptr;
473 ANGLE_TRY(
474 renderPassCache->getCompatibleRenderPass(device, serial, mRenderPassDesc, &renderPass));
475
476 mInsideRenderPassCommands.end();
477
478 VkRenderPassBeginInfo beginInfo;
479 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
480 beginInfo.pNext = nullptr;
481 beginInfo.renderPass = renderPass->getHandle();
482 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
483 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
484 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
485 beginInfo.renderArea.extent.width = static_cast<uint32_t>(mRenderPassRenderArea.width);
486 beginInfo.renderArea.extent.height = static_cast<uint32_t>(mRenderPassRenderArea.height);
487 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
488 beginInfo.pClearValues = mRenderPassClearValues.data();
489
490 primaryCommandBuffer->beginRenderPass(beginInfo,
491 VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
492 primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
493 primaryCommandBuffer->endRenderPass();
494 }
495
496 mVisitedState = VisitedState::Visited;
497 return NoError();
498}
499
Luc Ferron14f48172018-04-11 08:43:28 -0400500const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
501{
502 return mRenderPassRenderArea;
503}
504
Jamie Madill1f46bc12018-02-20 16:09:43 -0500505// CommandGraph implementation.
Jamie Madill316c6062018-05-29 10:49:45 -0400506CommandGraph::CommandGraph() = default;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500507
508CommandGraph::~CommandGraph()
509{
510 ASSERT(empty());
511}
512
513CommandGraphNode *CommandGraph::allocateNode()
514{
515 // TODO(jmadill): Use a pool allocator for the CPU node allocations.
516 CommandGraphNode *newCommands = new CommandGraphNode();
517 mNodes.emplace_back(newCommands);
518 return newCommands;
519}
520
521Error CommandGraph::submitCommands(VkDevice device,
522 Serial serial,
523 RenderPassCache *renderPassCache,
524 CommandPool *commandPool,
525 CommandBuffer *primaryCommandBufferOut)
526{
527 VkCommandBufferAllocateInfo primaryInfo;
528 primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
529 primaryInfo.pNext = nullptr;
530 primaryInfo.commandPool = commandPool->getHandle();
531 primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
532 primaryInfo.commandBufferCount = 1;
533
534 ANGLE_TRY(primaryCommandBufferOut->init(device, primaryInfo));
535
536 if (mNodes.empty())
537 {
538 return NoError();
539 }
540
541 std::vector<CommandGraphNode *> nodeStack;
542
543 VkCommandBufferBeginInfo beginInfo;
544 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
545 beginInfo.pNext = nullptr;
546 beginInfo.flags = 0;
547 beginInfo.pInheritanceInfo = nullptr;
548
549 ANGLE_TRY(primaryCommandBufferOut->begin(beginInfo));
550
551 for (CommandGraphNode *topLevelNode : mNodes)
552 {
553 // Only process commands that don't have child commands. The others will be pulled in
554 // automatically. Also skip commands that have already been visited.
555 if (topLevelNode->hasChildren() || topLevelNode->visitedState() != VisitedState::Unvisited)
556 continue;
557
558 nodeStack.push_back(topLevelNode);
559
560 while (!nodeStack.empty())
561 {
562 CommandGraphNode *node = nodeStack.back();
563
564 switch (node->visitedState())
565 {
566 case VisitedState::Unvisited:
567 node->visitParents(&nodeStack);
568 break;
569 case VisitedState::Ready:
570 ANGLE_TRY(node->visitAndExecute(device, serial, renderPassCache,
571 primaryCommandBufferOut));
572 nodeStack.pop_back();
573 break;
574 case VisitedState::Visited:
575 nodeStack.pop_back();
576 break;
577 default:
578 UNREACHABLE();
579 break;
580 }
581 }
582 }
583
584 ANGLE_TRY(primaryCommandBufferOut->end());
585
586 // TODO(jmadill): Use pool allocation so we don't need to deallocate command graph.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400587 for (CommandGraphNode *node : mNodes)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500588 {
589 delete node;
590 }
591 mNodes.clear();
592
593 return NoError();
594}
595
596bool CommandGraph::empty() const
597{
598 return mNodes.empty();
599}
600
601} // namespace vk
602} // namespace rx