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