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