blob: 84b3c31f33a0d6a69643d6a8e8b68b2cde5a6055 [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
Shahbaz Youssefi06270c92018-10-03 17:00:25 -040033 VkCommandBufferAllocateInfo createInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -050034 createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -050035 createInfo.commandPool = commandPool.getHandle();
36 createInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
37 createInfo.commandBufferCount = 1;
38
Jamie Madill21061022018-07-12 23:56:30 -040039 ANGLE_TRY(commandBuffer->init(context, createInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -050040
Shahbaz Youssefi06270c92018-10-03 17:00:25 -040041 VkCommandBufferBeginInfo beginInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -050042 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -050043 beginInfo.flags = flags | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
44 beginInfo.pInheritanceInfo = &inheritanceInfo;
45
Jamie Madill21061022018-07-12 23:56:30 -040046 ANGLE_TRY(commandBuffer->begin(context, beginInfo));
47 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -050048}
49
Jamie Madill0da73fe2018-10-02 09:31:39 -040050const char *GetResourceTypeName(CommandGraphResourceType resourceType)
51{
52 switch (resourceType)
53 {
54 case CommandGraphResourceType::Buffer:
55 return "Buffer";
56 case CommandGraphResourceType::Framebuffer:
57 return "Framebuffer";
58 case CommandGraphResourceType::Image:
59 return "Image";
60 default:
61 UNREACHABLE();
62 return "";
63 }
64}
Jamie Madill1f46bc12018-02-20 16:09:43 -050065} // anonymous namespace
66
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040067// CommandGraphResource implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -040068CommandGraphResource::CommandGraphResource(CommandGraphResourceType resourceType)
69 : mCurrentWritingNode(nullptr), mResourceType(resourceType)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040070{
71}
72
Jamie Madill316c6062018-05-29 10:49:45 -040073CommandGraphResource::~CommandGraphResource() = default;
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040074
75void CommandGraphResource::updateQueueSerial(Serial queueSerial)
76{
77 ASSERT(queueSerial >= mStoredQueueSerial);
78
79 if (queueSerial > mStoredQueueSerial)
80 {
81 mCurrentWritingNode = nullptr;
82 mCurrentReadingNodes.clear();
83 mStoredQueueSerial = queueSerial;
84 }
85}
86
Jamie Madillc57ee252018-05-30 19:53:48 -040087bool CommandGraphResource::isResourceInUse(RendererVk *renderer) const
88{
89 return renderer->isSerialInUse(mStoredQueueSerial);
90}
91
92Serial CommandGraphResource::getStoredQueueSerial() const
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040093{
94 return mStoredQueueSerial;
95}
96
Jamie Madille2d22702018-09-19 08:11:48 -040097angle::Result CommandGraphResource::recordCommands(Context *context,
98 CommandBuffer **commandBufferOut)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040099{
Jamie Madill21061022018-07-12 23:56:30 -0400100 updateQueueSerial(context->getRenderer()->getCurrentQueueSerial());
Jamie Madill5dca6512018-05-30 10:53:51 -0400101
Jamie Madille2d22702018-09-19 08:11:48 -0400102 if (!hasChildlessWritingNode() || hasStartedRenderPass())
Jamie Madill316c6062018-05-29 10:49:45 -0400103 {
Jamie Madille2d22702018-09-19 08:11:48 -0400104 finishCurrentCommands(context->getRenderer());
105 return mCurrentWritingNode->beginOutsideRenderPassRecording(
106 context, context->getRenderer()->getCommandPool(), commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400107 }
108
109 CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
110 if (!outsideRenderPassCommands->valid())
111 {
112 ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
Jamie Madill21061022018-07-12 23:56:30 -0400113 context, context->getRenderer()->getCommandPool(), commandBufferOut));
Jamie Madill316c6062018-05-29 10:49:45 -0400114 }
115 else
116 {
117 *commandBufferOut = outsideRenderPassCommands;
118 }
119
Jamie Madill21061022018-07-12 23:56:30 -0400120 return angle::Result::Continue();
Jamie Madill316c6062018-05-29 10:49:45 -0400121}
122
Jamie Madill5dca6512018-05-30 10:53:51 -0400123bool CommandGraphResource::appendToStartedRenderPass(RendererVk *renderer,
124 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400125{
Jamie Madill5dca6512018-05-30 10:53:51 -0400126 updateQueueSerial(renderer->getCurrentQueueSerial());
127 if (hasStartedRenderPass())
128 {
129 *commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands();
130 return true;
131 }
132 else
133 {
134 return false;
135 }
Jamie Madill316c6062018-05-29 10:49:45 -0400136}
137
Jamie Madill316c6062018-05-29 10:49:45 -0400138const gl::Rectangle &CommandGraphResource::getRenderPassRenderArea() const
139{
140 ASSERT(hasStartedRenderPass());
141 return mCurrentWritingNode->getRenderPassRenderArea();
142}
143
Jamie Madill21061022018-07-12 23:56:30 -0400144angle::Result CommandGraphResource::beginRenderPass(Context *context,
145 const Framebuffer &framebuffer,
146 const gl::Rectangle &renderArea,
147 const RenderPassDesc &renderPassDesc,
148 const std::vector<VkClearValue> &clearValues,
149 CommandBuffer **commandBufferOut) const
Jamie Madill316c6062018-05-29 10:49:45 -0400150{
151 // Hard-code RenderPass to clear the first render target to the current clear value.
152 // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
153 mCurrentWritingNode->storeRenderPassInfo(framebuffer, renderArea, renderPassDesc, clearValues);
154
Jamie Madill21061022018-07-12 23:56:30 -0400155 return mCurrentWritingNode->beginInsideRenderPassRecording(context, commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400156}
157
Jamie Madille2d22702018-09-19 08:11:48 -0400158void CommandGraphResource::finishCurrentCommands(RendererVk *renderer)
Jamie Madill316c6062018-05-29 10:49:45 -0400159{
Jamie Madill86ce2102018-05-22 11:54:42 -0400160 CommandGraphNode *newCommands = renderer->getCommandGraph()->allocateNode();
Jamie Madill0da73fe2018-10-02 09:31:39 -0400161 newCommands->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
Jamie Madill86ce2102018-05-22 11:54:42 -0400162 onWriteImpl(newCommands, renderer->getCurrentQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400163}
164
165void CommandGraphResource::addWriteDependency(CommandGraphResource *writingResource)
166{
167 CommandGraphNode *writingNode = writingResource->mCurrentWritingNode;
168 ASSERT(writingNode);
169
Jamie Madillc57ee252018-05-30 19:53:48 -0400170 onWriteImpl(writingNode, writingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400171}
172
173void CommandGraphResource::onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial)
174{
175 updateQueueSerial(currentSerial);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400176
Jamie Madill9cceac42018-03-31 14:19:16 -0400177 // Make sure any open reads and writes finish before we execute 'writingNode'.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400178 if (!mCurrentReadingNodes.empty())
179 {
180 CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes, writingNode);
181 mCurrentReadingNodes.clear();
182 }
183
184 if (mCurrentWritingNode && mCurrentWritingNode != writingNode)
185 {
186 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, writingNode);
187 }
188
189 mCurrentWritingNode = writingNode;
190}
191
Jamie Madill316c6062018-05-29 10:49:45 -0400192void CommandGraphResource::addReadDependency(CommandGraphResource *readingResource)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400193{
Jamie Madillc57ee252018-05-30 19:53:48 -0400194 updateQueueSerial(readingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400195
196 CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
197 ASSERT(readingNode);
Jamie Madill9cceac42018-03-31 14:19:16 -0400198
199 if (hasChildlessWritingNode())
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400200 {
Jamie Madill9cceac42018-03-31 14:19:16 -0400201 // Ensure 'readingNode' happens after the current writing node.
202 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
203 }
204
205 // Add the read node to the list of nodes currently reading this resource.
206 mCurrentReadingNodes.push_back(readingNode);
207}
208
Jamie Madill1f46bc12018-02-20 16:09:43 -0500209// CommandGraphNode implementation.
Jamie Madill316c6062018-05-29 10:49:45 -0400210CommandGraphNode::CommandGraphNode()
211 : mRenderPassClearValues{}, mHasChildren(false), mVisitedState(VisitedState::Unvisited)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500212{
213}
214
215CommandGraphNode::~CommandGraphNode()
216{
217 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
218
219 // Command buffers are managed by the command pool, so don't need to be freed.
220 mOutsideRenderPassCommands.releaseHandle();
221 mInsideRenderPassCommands.releaseHandle();
222}
223
224CommandBuffer *CommandGraphNode::getOutsideRenderPassCommands()
225{
226 ASSERT(!mHasChildren);
227 return &mOutsideRenderPassCommands;
228}
229
Jamie Madill21061022018-07-12 23:56:30 -0400230angle::Result CommandGraphNode::beginOutsideRenderPassRecording(Context *context,
231 const CommandPool &commandPool,
232 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500233{
234 ASSERT(!mHasChildren);
235
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400236 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500237 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500238 inheritanceInfo.renderPass = VK_NULL_HANDLE;
239 inheritanceInfo.subpass = 0;
240 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
241 inheritanceInfo.occlusionQueryEnable = VK_FALSE;
242 inheritanceInfo.queryFlags = 0;
243 inheritanceInfo.pipelineStatistics = 0;
244
Jamie Madill21061022018-07-12 23:56:30 -0400245 ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500246 &mOutsideRenderPassCommands));
247
248 *commandsOut = &mOutsideRenderPassCommands;
Jamie Madill21061022018-07-12 23:56:30 -0400249 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500250}
251
Jamie Madill21061022018-07-12 23:56:30 -0400252angle::Result CommandGraphNode::beginInsideRenderPassRecording(Context *context,
253 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500254{
255 ASSERT(!mHasChildren);
256
257 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
258 // TODO(jmadill): Support query for compatible/conformant render pass. htto://anglebug.com/2361
259 RenderPass *compatibleRenderPass;
Jamie Madill21061022018-07-12 23:56:30 -0400260 ANGLE_TRY(context->getRenderer()->getCompatibleRenderPass(context, mRenderPassDesc,
261 &compatibleRenderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500262
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400263 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500264 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500265 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
266 inheritanceInfo.subpass = 0;
267 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
268 inheritanceInfo.occlusionQueryEnable = VK_FALSE;
269 inheritanceInfo.queryFlags = 0;
270 inheritanceInfo.pipelineStatistics = 0;
271
272 ANGLE_TRY(InitAndBeginCommandBuffer(
Jamie Madill21061022018-07-12 23:56:30 -0400273 context, context->getRenderer()->getCommandPool(), inheritanceInfo,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500274 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
275
276 *commandsOut = &mInsideRenderPassCommands;
Jamie Madill21061022018-07-12 23:56:30 -0400277 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500278}
279
280void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
281 const gl::Rectangle renderArea,
Jamie Madillbcf467f2018-05-23 09:46:00 -0400282 const vk::RenderPassDesc &renderPassDesc,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500283 const std::vector<VkClearValue> &clearValues)
284{
Jamie Madillbcf467f2018-05-23 09:46:00 -0400285 mRenderPassDesc = renderPassDesc;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500286 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
287 mRenderPassRenderArea = renderArea;
288 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
289}
290
Jamie Madill1f46bc12018-02-20 16:09:43 -0500291// static
292void CommandGraphNode::SetHappensBeforeDependency(CommandGraphNode *beforeNode,
293 CommandGraphNode *afterNode)
294{
Jamie Madill9cceac42018-03-31 14:19:16 -0400295 ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500296 afterNode->mParents.emplace_back(beforeNode);
297 beforeNode->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500298}
299
300// static
301void CommandGraphNode::SetHappensBeforeDependencies(
302 const std::vector<CommandGraphNode *> &beforeNodes,
303 CommandGraphNode *afterNode)
304{
305 afterNode->mParents.insert(afterNode->mParents.end(), beforeNodes.begin(), beforeNodes.end());
306
307 // TODO(jmadill): is there a faster way to do this?
308 for (CommandGraphNode *beforeNode : beforeNodes)
309 {
310 beforeNode->setHasChildren();
311
312 ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
313 }
314}
315
316bool CommandGraphNode::hasParents() const
317{
318 return !mParents.empty();
319}
320
321void CommandGraphNode::setHasChildren()
322{
323 mHasChildren = true;
324}
325
Jamie Madill1f46bc12018-02-20 16:09:43 -0500326// Do not call this in anything but testing code, since it's slow.
327bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
328{
329 std::set<CommandGraphNode *> visitedList;
330 std::vector<CommandGraphNode *> openList;
331 openList.insert(openList.begin(), mParents.begin(), mParents.end());
332 while (!openList.empty())
333 {
334 CommandGraphNode *current = openList.back();
335 openList.pop_back();
336 if (visitedList.count(current) == 0)
337 {
338 if (current == parent)
339 {
340 return true;
341 }
342 visitedList.insert(current);
343 openList.insert(openList.end(), current->mParents.begin(), current->mParents.end());
344 }
345 }
346
347 return false;
348}
349
350VisitedState CommandGraphNode::visitedState() const
351{
352 return mVisitedState;
353}
354
355void CommandGraphNode::visitParents(std::vector<CommandGraphNode *> *stack)
356{
357 ASSERT(mVisitedState == VisitedState::Unvisited);
358 stack->insert(stack->end(), mParents.begin(), mParents.end());
359 mVisitedState = VisitedState::Ready;
360}
361
Jamie Madill21061022018-07-12 23:56:30 -0400362angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
363 Serial serial,
364 RenderPassCache *renderPassCache,
365 CommandBuffer *primaryCommandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500366{
367 if (mOutsideRenderPassCommands.valid())
368 {
Jamie Madill21061022018-07-12 23:56:30 -0400369 ANGLE_TRY(mOutsideRenderPassCommands.end(context));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500370 primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
371 }
372
373 if (mInsideRenderPassCommands.valid())
374 {
375 // Pull a compatible RenderPass from the cache.
376 // TODO(jmadill): Insert real ops and layout transitions.
377 RenderPass *renderPass = nullptr;
Jamie Madill21061022018-07-12 23:56:30 -0400378 ANGLE_TRY(renderPassCache->getCompatibleRenderPass(context, serial, mRenderPassDesc,
379 &renderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500380
Jamie Madill21061022018-07-12 23:56:30 -0400381 ANGLE_TRY(mInsideRenderPassCommands.end(context));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500382
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400383 VkRenderPassBeginInfo beginInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500384 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500385 beginInfo.renderPass = renderPass->getHandle();
386 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
387 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
388 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
389 beginInfo.renderArea.extent.width = static_cast<uint32_t>(mRenderPassRenderArea.width);
390 beginInfo.renderArea.extent.height = static_cast<uint32_t>(mRenderPassRenderArea.height);
391 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
392 beginInfo.pClearValues = mRenderPassClearValues.data();
393
394 primaryCommandBuffer->beginRenderPass(beginInfo,
395 VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
396 primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
397 primaryCommandBuffer->endRenderPass();
398 }
399
400 mVisitedState = VisitedState::Visited;
Jamie Madill21061022018-07-12 23:56:30 -0400401 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500402}
403
Jamie Madill0da73fe2018-10-02 09:31:39 -0400404const std::vector<CommandGraphNode *> &CommandGraphNode::getParentsForDiagnostics() const
405{
406 return mParents;
407}
408
409void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType,
410 uintptr_t resourceID)
411{
412 mResourceType = resourceType;
413 mResourceID = resourceID;
414}
415
Luc Ferron14f48172018-04-11 08:43:28 -0400416const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
417{
418 return mRenderPassRenderArea;
419}
420
Jamie Madill1f46bc12018-02-20 16:09:43 -0500421// CommandGraph implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -0400422CommandGraph::CommandGraph(bool enableGraphDiagnostics)
423 : mEnableGraphDiagnostics(enableGraphDiagnostics)
424{
425}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500426
427CommandGraph::~CommandGraph()
428{
429 ASSERT(empty());
430}
431
432CommandGraphNode *CommandGraph::allocateNode()
433{
434 // TODO(jmadill): Use a pool allocator for the CPU node allocations.
435 CommandGraphNode *newCommands = new CommandGraphNode();
436 mNodes.emplace_back(newCommands);
437 return newCommands;
438}
439
Jamie Madill21061022018-07-12 23:56:30 -0400440angle::Result CommandGraph::submitCommands(Context *context,
441 Serial serial,
442 RenderPassCache *renderPassCache,
443 CommandPool *commandPool,
444 CommandBuffer *primaryCommandBufferOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500445{
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400446 VkCommandBufferAllocateInfo primaryInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500447 primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500448 primaryInfo.commandPool = commandPool->getHandle();
449 primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
450 primaryInfo.commandBufferCount = 1;
451
Jamie Madill21061022018-07-12 23:56:30 -0400452 ANGLE_TRY(primaryCommandBufferOut->init(context, primaryInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500453
454 if (mNodes.empty())
455 {
Jamie Madill21061022018-07-12 23:56:30 -0400456 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500457 }
458
Jamie Madill0da73fe2018-10-02 09:31:39 -0400459 if (mEnableGraphDiagnostics)
460 {
461 dumpGraphDotFile(std::cout);
462 }
463
Jamie Madill1f46bc12018-02-20 16:09:43 -0500464 std::vector<CommandGraphNode *> nodeStack;
465
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400466 VkCommandBufferBeginInfo beginInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500467 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500468 beginInfo.flags = 0;
469 beginInfo.pInheritanceInfo = nullptr;
470
Jamie Madill21061022018-07-12 23:56:30 -0400471 ANGLE_TRY(primaryCommandBufferOut->begin(context, beginInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500472
473 for (CommandGraphNode *topLevelNode : mNodes)
474 {
475 // Only process commands that don't have child commands. The others will be pulled in
476 // automatically. Also skip commands that have already been visited.
477 if (topLevelNode->hasChildren() || topLevelNode->visitedState() != VisitedState::Unvisited)
478 continue;
479
480 nodeStack.push_back(topLevelNode);
481
482 while (!nodeStack.empty())
483 {
484 CommandGraphNode *node = nodeStack.back();
485
486 switch (node->visitedState())
487 {
488 case VisitedState::Unvisited:
489 node->visitParents(&nodeStack);
490 break;
491 case VisitedState::Ready:
Jamie Madill21061022018-07-12 23:56:30 -0400492 ANGLE_TRY(node->visitAndExecute(context, serial, renderPassCache,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500493 primaryCommandBufferOut));
494 nodeStack.pop_back();
495 break;
496 case VisitedState::Visited:
497 nodeStack.pop_back();
498 break;
499 default:
500 UNREACHABLE();
501 break;
502 }
503 }
504 }
505
Jamie Madill21061022018-07-12 23:56:30 -0400506 ANGLE_TRY(primaryCommandBufferOut->end(context));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500507
508 // TODO(jmadill): Use pool allocation so we don't need to deallocate command graph.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400509 for (CommandGraphNode *node : mNodes)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500510 {
511 delete node;
512 }
513 mNodes.clear();
514
Jamie Madill21061022018-07-12 23:56:30 -0400515 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500516}
517
518bool CommandGraph::empty() const
519{
520 return mNodes.empty();
521}
522
Jamie Madill0da73fe2018-10-02 09:31:39 -0400523// Dumps the command graph into a dot file that works with graphviz.
524void CommandGraph::dumpGraphDotFile(std::ostream &out) const
525{
526 // This ID maps a node pointer to a monatonic ID. It allows us to look up parent node IDs.
527 std::map<const CommandGraphNode *, int> nodeIDMap;
528 std::map<uintptr_t, int> objectIDMap;
529
530 // Map nodes to ids.
531 for (size_t nodeIndex = 0; nodeIndex < mNodes.size(); ++nodeIndex)
532 {
533 const CommandGraphNode *node = mNodes[nodeIndex];
534 nodeIDMap[node] = static_cast<int>(nodeIndex) + 1;
535 }
536
537 int bufferIDCounter = 1;
538 int framebufferIDCounter = 1;
539 int imageIDCounter = 1;
540
541 out << "digraph {" << std::endl;
542
543 for (const CommandGraphNode *node : mNodes)
544 {
545 int nodeID = nodeIDMap[node];
546
547 std::stringstream strstr;
548 strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics());
549 strstr << " ";
550
551 auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
552 if (it != objectIDMap.end())
553 {
554 strstr << it->second;
555 }
556 else
557 {
558 int id = 0;
559
560 switch (node->getResourceTypeForDiagnostics())
561 {
562 case CommandGraphResourceType::Buffer:
563 id = bufferIDCounter++;
564 break;
565 case CommandGraphResourceType::Framebuffer:
566 id = framebufferIDCounter++;
567 break;
568 case CommandGraphResourceType::Image:
569 id = imageIDCounter++;
570 break;
571 default:
572 UNREACHABLE();
573 break;
574 }
575
576 objectIDMap[node->getResourceIDForDiagnostics()] = id;
577 strstr << id;
578 }
579
580 const std::string &label = strstr.str();
581 out << " " << nodeID << "[label =<" << label << "<BR/> <FONT POINT-SIZE=\"10\">Node ID "
582 << nodeID << "</FONT>>];" << std::endl;
583 }
584
585 for (const CommandGraphNode *node : mNodes)
586 {
587 int nodeID = nodeIDMap[node];
588
589 for (const CommandGraphNode *parent : node->getParentsForDiagnostics())
590 {
591 int parentID = nodeIDMap[parent];
592 out << " " << parentID << " -> " << nodeID << ";" << std::endl;
593 }
594 }
595
596 out << "}" << std::endl;
597}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500598} // namespace vk
599} // namespace rx