• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
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 <iostream>
13 
14 #include "libANGLE/renderer/vulkan/ContextVk.h"
15 #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
16 #include "libANGLE/renderer/vulkan/RendererVk.h"
17 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
18 #include "libANGLE/renderer/vulkan/vk_helpers.h"
19 
20 #include "libANGLE/trace.h"
21 
22 namespace rx
23 {
24 namespace vk
25 {
26 namespace
27 {
28 ANGLE_MAYBE_UNUSED
InitAndBeginCommandBuffer(ContextVk * context,const CommandPool & commandPool,const VkCommandBufferInheritanceInfo & inheritanceInfo,VkCommandBufferUsageFlags flags,angle::PoolAllocator * poolAllocator,priv::SecondaryCommandBuffer * commandBuffer)29 angle::Result InitAndBeginCommandBuffer(ContextVk *context,
30                                         const CommandPool &commandPool,
31                                         const VkCommandBufferInheritanceInfo &inheritanceInfo,
32                                         VkCommandBufferUsageFlags flags,
33                                         angle::PoolAllocator *poolAllocator,
34                                         priv::SecondaryCommandBuffer *commandBuffer)
35 {
36     ASSERT(!commandBuffer->valid());
37     commandBuffer->initialize(poolAllocator);
38     return angle::Result::Continue;
39 }
40 
41 ANGLE_MAYBE_UNUSED
InitAndBeginCommandBuffer(vk::Context * context,const CommandPool & commandPool,const VkCommandBufferInheritanceInfo & inheritanceInfo,VkCommandBufferUsageFlags flags,angle::PoolAllocator * poolAllocator,priv::CommandBuffer * commandBuffer)42 angle::Result InitAndBeginCommandBuffer(vk::Context *context,
43                                         const CommandPool &commandPool,
44                                         const VkCommandBufferInheritanceInfo &inheritanceInfo,
45                                         VkCommandBufferUsageFlags flags,
46                                         angle::PoolAllocator *poolAllocator,
47                                         priv::CommandBuffer *commandBuffer)
48 {
49     ASSERT(!commandBuffer->valid());
50     ASSERT(commandPool.valid());
51     VkCommandBufferAllocateInfo createInfo = {};
52     createInfo.sType                       = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
53     createInfo.commandPool                 = commandPool.getHandle();
54     createInfo.level                       = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
55     createInfo.commandBufferCount          = 1;
56 
57     ANGLE_VK_TRY(context, commandBuffer->init(context->getDevice(), createInfo));
58 
59     VkCommandBufferBeginInfo beginInfo = {};
60     beginInfo.sType                    = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
61     beginInfo.flags                    = flags | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
62     beginInfo.pInheritanceInfo         = &inheritanceInfo;
63 
64     ANGLE_VK_TRY(context, commandBuffer->begin(beginInfo));
65     return angle::Result::Continue;
66 }
67 
GetResourceTypeName(CommandGraphResourceType resourceType,CommandGraphNodeFunction function)68 const char *GetResourceTypeName(CommandGraphResourceType resourceType,
69                                 CommandGraphNodeFunction function)
70 {
71     switch (resourceType)
72     {
73         case CommandGraphResourceType::Buffer:
74             return "Buffer";
75         case CommandGraphResourceType::Framebuffer:
76             return "Framebuffer";
77         case CommandGraphResourceType::Image:
78             return "Image";
79         case CommandGraphResourceType::Query:
80             switch (function)
81             {
82                 case CommandGraphNodeFunction::BeginQuery:
83                     return "BeginQuery";
84                 case CommandGraphNodeFunction::EndQuery:
85                     return "EndQuery";
86                 case CommandGraphNodeFunction::WriteTimestamp:
87                     return "WriteTimestamp";
88                 default:
89                     UNREACHABLE();
90                     return "Query";
91             }
92         case CommandGraphResourceType::Dispatcher:
93             return "Dispatcher";
94         case CommandGraphResourceType::EmulatedQuery:
95             switch (function)
96             {
97                 case CommandGraphNodeFunction::BeginTransformFeedbackQuery:
98                     return "BeginTransformFeedbackQuery";
99                 case CommandGraphNodeFunction::EndTransformFeedbackQuery:
100                     return "EndTransformFeedbackQuery";
101                 default:
102                     UNREACHABLE();
103                     return "EmulatedQuery";
104             }
105         case CommandGraphResourceType::FenceSync:
106             switch (function)
107             {
108                 case CommandGraphNodeFunction::SetFenceSync:
109                     return "SetFenceSync";
110                 case CommandGraphNodeFunction::WaitFenceSync:
111                     return "WaitFenceSync";
112                 default:
113                     UNREACHABLE();
114                     return "FenceSync";
115             }
116         case CommandGraphResourceType::GraphBarrier:
117             return "GraphBarrier";
118         case CommandGraphResourceType::DebugMarker:
119             switch (function)
120             {
121                 case CommandGraphNodeFunction::InsertDebugMarker:
122                     return "InsertDebugMarker";
123                 case CommandGraphNodeFunction::PushDebugMarker:
124                     return "PushDebugMarker";
125                 case CommandGraphNodeFunction::PopDebugMarker:
126                     return "PopDebugMarker";
127                 default:
128                     UNREACHABLE();
129                     return "DebugMarker";
130             }
131         case CommandGraphResourceType::HostAvailabilityOperation:
132             switch (function)
133             {
134                 case CommandGraphNodeFunction::HostAvailabilityOperation:
135                     return "HostAvailabilityOperation";
136                 default:
137                     UNREACHABLE();
138                     return "HostAvailabilityOperation";
139             }
140         default:
141             UNREACHABLE();
142             return "";
143     }
144 }
145 
GetLoadOpShorthand(uint32_t loadOp)146 const char *GetLoadOpShorthand(uint32_t loadOp)
147 {
148     switch (loadOp)
149     {
150         case VK_ATTACHMENT_LOAD_OP_CLEAR:
151             return "C";
152         case VK_ATTACHMENT_LOAD_OP_LOAD:
153             return "L";
154         default:
155             return "D";
156     }
157 }
158 
GetStoreOpShorthand(uint32_t storeOp)159 const char *GetStoreOpShorthand(uint32_t storeOp)
160 {
161     switch (storeOp)
162     {
163         case VK_ATTACHMENT_STORE_OP_STORE:
164             return "S";
165         default:
166             return "D";
167     }
168 }
169 
MakeDebugUtilsLabel(GLenum source,const char * marker,VkDebugUtilsLabelEXT * label)170 void MakeDebugUtilsLabel(GLenum source, const char *marker, VkDebugUtilsLabelEXT *label)
171 {
172     static constexpr angle::ColorF kLabelColors[6] = {
173         angle::ColorF(1.0f, 0.5f, 0.5f, 1.0f),  // DEBUG_SOURCE_API
174         angle::ColorF(0.5f, 1.0f, 0.5f, 1.0f),  // DEBUG_SOURCE_WINDOW_SYSTEM
175         angle::ColorF(0.5f, 0.5f, 1.0f, 1.0f),  // DEBUG_SOURCE_SHADER_COMPILER
176         angle::ColorF(0.7f, 0.7f, 0.7f, 1.0f),  // DEBUG_SOURCE_THIRD_PARTY
177         angle::ColorF(0.5f, 0.8f, 0.9f, 1.0f),  // DEBUG_SOURCE_APPLICATION
178         angle::ColorF(0.9f, 0.8f, 0.5f, 1.0f),  // DEBUG_SOURCE_OTHER
179     };
180 
181     int colorIndex = source - GL_DEBUG_SOURCE_API;
182     ASSERT(colorIndex >= 0 && static_cast<size_t>(colorIndex) < ArraySize(kLabelColors));
183 
184     label->sType      = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
185     label->pNext      = nullptr;
186     label->pLabelName = marker;
187     kLabelColors[colorIndex].writeData(label->color);
188 }
189 
190 constexpr VkSubpassContents kRenderPassContents =
191     CommandBuffer::ExecutesInline() ? VK_SUBPASS_CONTENTS_INLINE
192                                     : VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
193 
194 // Helpers to unify executeCommands call based on underlying cmd buffer type
195 ANGLE_MAYBE_UNUSED
ExecuteCommands(PrimaryCommandBuffer * primCmdBuffer,priv::SecondaryCommandBuffer * secCmdBuffer)196 void ExecuteCommands(PrimaryCommandBuffer *primCmdBuffer,
197                      priv::SecondaryCommandBuffer *secCmdBuffer)
198 {
199     secCmdBuffer->executeCommands(primCmdBuffer->getHandle());
200 }
201 
202 ANGLE_MAYBE_UNUSED
ExecuteCommands(PrimaryCommandBuffer * primCmdBuffer,priv::CommandBuffer * secCmdBuffer)203 void ExecuteCommands(PrimaryCommandBuffer *primCmdBuffer, priv::CommandBuffer *secCmdBuffer)
204 {
205     primCmdBuffer->executeCommands(1, secCmdBuffer);
206 }
207 
208 ANGLE_MAYBE_UNUSED
DumpCommands(const priv::SecondaryCommandBuffer & commandBuffer,const char * separator)209 std::string DumpCommands(const priv::SecondaryCommandBuffer &commandBuffer, const char *separator)
210 {
211     return commandBuffer.dumpCommands(separator);
212 }
213 
214 ANGLE_MAYBE_UNUSED
DumpCommands(const priv::CommandBuffer & commandBuffer,const char * separator)215 std::string DumpCommands(const priv::CommandBuffer &commandBuffer, const char *separator)
216 {
217     return "--blob--";
218 }
219 
220 }  // anonymous namespace
221 
222 // CommandGraphResource implementation.
CommandGraphResource(CommandGraphResourceType resourceType)223 CommandGraphResource::CommandGraphResource(CommandGraphResourceType resourceType)
224     : mCurrentWritingNode(nullptr), mResourceType(resourceType)
225 {}
226 
227 CommandGraphResource::~CommandGraphResource() = default;
228 
isResourceInUse(ContextVk * context) const229 bool CommandGraphResource::isResourceInUse(ContextVk *context) const
230 {
231     return context->isSerialInUse(mStoredQueueSerial);
232 }
233 
resetQueueSerial()234 void CommandGraphResource::resetQueueSerial()
235 {
236     mCurrentWritingNode = nullptr;
237     mCurrentReadingNodes.clear();
238     mStoredQueueSerial = Serial();
239 }
240 
recordCommands(ContextVk * context,CommandBuffer ** commandBufferOut)241 angle::Result CommandGraphResource::recordCommands(ContextVk *context,
242                                                    CommandBuffer **commandBufferOut)
243 {
244     updateQueueSerial(context->getCurrentQueueSerial());
245 
246     if (!hasChildlessWritingNode() || hasStartedRenderPass())
247     {
248         startNewCommands(context);
249         return mCurrentWritingNode->beginOutsideRenderPassRecording(
250             context, context->getCommandPool(), commandBufferOut);
251     }
252 
253     CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
254     if (!outsideRenderPassCommands->valid())
255     {
256         ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
257             context, context->getCommandPool(), commandBufferOut));
258     }
259     else
260     {
261         *commandBufferOut = outsideRenderPassCommands;
262     }
263 
264     return angle::Result::Continue;
265 }
266 
beginRenderPass(ContextVk * contextVk,const Framebuffer & framebuffer,const gl::Rectangle & renderArea,const RenderPassDesc & renderPassDesc,const AttachmentOpsArray & renderPassAttachmentOps,const std::vector<VkClearValue> & clearValues,CommandBuffer ** commandBufferOut)267 angle::Result CommandGraphResource::beginRenderPass(
268     ContextVk *contextVk,
269     const Framebuffer &framebuffer,
270     const gl::Rectangle &renderArea,
271     const RenderPassDesc &renderPassDesc,
272     const AttachmentOpsArray &renderPassAttachmentOps,
273     const std::vector<VkClearValue> &clearValues,
274     CommandBuffer **commandBufferOut)
275 {
276     // If a barrier has been inserted in the meantime, stop the command buffer.
277     if (!hasChildlessWritingNode())
278     {
279         startNewCommands(contextVk);
280     }
281 
282     mCurrentWritingNode->storeRenderPassInfo(framebuffer, renderArea, renderPassDesc,
283                                              renderPassAttachmentOps, clearValues);
284 
285     mCurrentWritingNode->setRenderPassOwner(contextVk);
286 
287     return mCurrentWritingNode->beginInsideRenderPassRecording(contextVk, commandBufferOut);
288 }
289 
addWriteDependency(CommandGraphResource * writingResource)290 void CommandGraphResource::addWriteDependency(CommandGraphResource *writingResource)
291 {
292     CommandGraphNode *writingNode = writingResource->mCurrentWritingNode;
293     ASSERT(writingNode);
294 
295     onWriteImpl(writingNode, writingResource->getStoredQueueSerial());
296 }
297 
addReadDependency(CommandGraphResource * readingResource)298 void CommandGraphResource::addReadDependency(CommandGraphResource *readingResource)
299 {
300     updateQueueSerial(readingResource->getStoredQueueSerial());
301 
302     CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
303     ASSERT(readingNode);
304 
305     if (mCurrentWritingNode)
306     {
307         // Ensure 'readingNode' happens after the current writing node.
308         CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
309     }
310 
311     // Add the read node to the list of nodes currently reading this resource.
312     mCurrentReadingNodes.push_back(readingNode);
313 }
314 
finishCurrentCommands(ContextVk * contextVk)315 void CommandGraphResource::finishCurrentCommands(ContextVk *contextVk)
316 {
317     startNewCommands(contextVk);
318 }
319 
startNewCommands(ContextVk * contextVk)320 void CommandGraphResource::startNewCommands(ContextVk *contextVk)
321 {
322     CommandGraphNode *newCommands =
323         contextVk->getCommandGraph()->allocateNode(CommandGraphNodeFunction::Generic);
324     newCommands->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
325     onWriteImpl(newCommands, contextVk->getCurrentQueueSerial());
326 }
327 
onWriteImpl(CommandGraphNode * writingNode,Serial currentSerial)328 void CommandGraphResource::onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial)
329 {
330     updateQueueSerial(currentSerial);
331 
332     // Make sure any open reads and writes finish before we execute 'writingNode'.
333     if (!mCurrentReadingNodes.empty())
334     {
335         CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes.data(),
336                                                        mCurrentReadingNodes.size(), writingNode);
337         mCurrentReadingNodes.clear();
338     }
339 
340     if (mCurrentWritingNode && mCurrentWritingNode != writingNode)
341     {
342         CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, writingNode);
343     }
344 
345     mCurrentWritingNode = writingNode;
346 }
347 
348 // CommandGraphNode implementation.
CommandGraphNode(CommandGraphNodeFunction function,angle::PoolAllocator * poolAllocator)349 CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function,
350                                    angle::PoolAllocator *poolAllocator)
351     : mRenderPassClearValues{},
352       mFunction(function),
353       mPoolAllocator(poolAllocator),
354       mQueryPool(VK_NULL_HANDLE),
355       mQueryIndex(0),
356       mFenceSyncEvent(VK_NULL_HANDLE),
357       mHasChildren(false),
358       mVisitedState(VisitedState::Unvisited),
359       mGlobalMemoryBarrierSrcAccess(0),
360       mGlobalMemoryBarrierDstAccess(0),
361       mGlobalMemoryBarrierStages(0),
362       mRenderPassOwner(nullptr)
363 {}
364 
~CommandGraphNode()365 CommandGraphNode::~CommandGraphNode()
366 {
367     mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
368     // Command buffers are managed by the command pool, so don't need to be freed.
369     mOutsideRenderPassCommands.releaseHandle();
370     mInsideRenderPassCommands.releaseHandle();
371 }
372 
beginOutsideRenderPassRecording(ContextVk * context,const CommandPool & commandPool,CommandBuffer ** commandsOut)373 angle::Result CommandGraphNode::beginOutsideRenderPassRecording(ContextVk *context,
374                                                                 const CommandPool &commandPool,
375                                                                 CommandBuffer **commandsOut)
376 {
377     ASSERT(!mHasChildren);
378 
379     VkCommandBufferInheritanceInfo inheritanceInfo = {};
380     inheritanceInfo.sType       = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
381     inheritanceInfo.renderPass  = VK_NULL_HANDLE;
382     inheritanceInfo.subpass     = 0;
383     inheritanceInfo.framebuffer = VK_NULL_HANDLE;
384     inheritanceInfo.occlusionQueryEnable =
385         CommandBuffer::SupportsQueries(context->getRenderer()->getPhysicalDeviceFeatures());
386     inheritanceInfo.queryFlags         = 0;
387     inheritanceInfo.pipelineStatistics = 0;
388 
389     ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0, mPoolAllocator,
390                                         &mOutsideRenderPassCommands));
391 
392     *commandsOut = &mOutsideRenderPassCommands;
393     return angle::Result::Continue;
394 }
395 
beginInsideRenderPassRecording(ContextVk * context,CommandBuffer ** commandsOut)396 angle::Result CommandGraphNode::beginInsideRenderPassRecording(ContextVk *context,
397                                                                CommandBuffer **commandsOut)
398 {
399     ASSERT(!mHasChildren);
400 
401     // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
402     // TODO(jmadill): Support query for compatible/conformant render pass. http://anglebug.com/2361
403     RenderPass *compatibleRenderPass;
404     ANGLE_TRY(context->getCompatibleRenderPass(mRenderPassDesc, &compatibleRenderPass));
405 
406     VkCommandBufferInheritanceInfo inheritanceInfo = {};
407     inheritanceInfo.sType       = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
408     inheritanceInfo.renderPass  = compatibleRenderPass->getHandle();
409     inheritanceInfo.subpass     = 0;
410     inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
411     inheritanceInfo.occlusionQueryEnable =
412         CommandBuffer::SupportsQueries(context->getRenderer()->getPhysicalDeviceFeatures());
413     inheritanceInfo.queryFlags         = 0;
414     inheritanceInfo.pipelineStatistics = 0;
415 
416     ANGLE_TRY(InitAndBeginCommandBuffer(context, context->getCommandPool(), inheritanceInfo,
417                                         VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT,
418                                         mPoolAllocator, &mInsideRenderPassCommands));
419 
420     *commandsOut = &mInsideRenderPassCommands;
421     return angle::Result::Continue;
422 }
423 
storeRenderPassInfo(const Framebuffer & framebuffer,const gl::Rectangle renderArea,const vk::RenderPassDesc & renderPassDesc,const AttachmentOpsArray & renderPassAttachmentOps,const std::vector<VkClearValue> & clearValues)424 void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
425                                            const gl::Rectangle renderArea,
426                                            const vk::RenderPassDesc &renderPassDesc,
427                                            const AttachmentOpsArray &renderPassAttachmentOps,
428                                            const std::vector<VkClearValue> &clearValues)
429 {
430     mRenderPassDesc          = renderPassDesc;
431     mRenderPassAttachmentOps = renderPassAttachmentOps;
432     mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
433     mRenderPassRenderArea = renderArea;
434     std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
435 }
436 
437 // static
SetHappensBeforeDependencies(CommandGraphNode ** beforeNodes,size_t beforeNodesCount,CommandGraphNode * afterNode)438 void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode **beforeNodes,
439                                                     size_t beforeNodesCount,
440                                                     CommandGraphNode *afterNode)
441 {
442     afterNode->mParents.insert(afterNode->mParents.end(), beforeNodes,
443                                beforeNodes + beforeNodesCount);
444 
445     // TODO(jmadill): is there a faster way to do this?
446     for (size_t i = 0; i < beforeNodesCount; ++i)
447     {
448         beforeNodes[i]->setHasChildren();
449 
450         ASSERT(beforeNodes[i] != afterNode && !beforeNodes[i]->isChildOf(afterNode));
451     }
452 }
453 
SetHappensBeforeDependencies(CommandGraphNode * beforeNode,CommandGraphNode ** afterNodes,size_t afterNodesCount)454 void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode *beforeNode,
455                                                     CommandGraphNode **afterNodes,
456                                                     size_t afterNodesCount)
457 {
458     for (size_t i = 0; i < afterNodesCount; ++i)
459     {
460         SetHappensBeforeDependency(beforeNode, afterNodes[i]);
461     }
462 }
463 
hasParents() const464 bool CommandGraphNode::hasParents() const
465 {
466     return !mParents.empty();
467 }
468 
setQueryPool(const QueryPool * queryPool,uint32_t queryIndex)469 void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIndex)
470 {
471     ASSERT(mFunction == CommandGraphNodeFunction::BeginQuery ||
472            mFunction == CommandGraphNodeFunction::EndQuery ||
473            mFunction == CommandGraphNodeFunction::WriteTimestamp ||
474            mFunction == CommandGraphNodeFunction::BeginTransformFeedbackQuery ||
475            mFunction == CommandGraphNodeFunction::EndTransformFeedbackQuery);
476     mQueryPool  = queryPool->getHandle();
477     mQueryIndex = queryIndex;
478 }
479 
setFenceSync(const vk::Event & event)480 void CommandGraphNode::setFenceSync(const vk::Event &event)
481 {
482     ASSERT(mFunction == CommandGraphNodeFunction::SetFenceSync ||
483            mFunction == CommandGraphNodeFunction::WaitFenceSync);
484     mFenceSyncEvent = event.getHandle();
485 }
486 
setDebugMarker(GLenum source,std::string && marker)487 void CommandGraphNode::setDebugMarker(GLenum source, std::string &&marker)
488 {
489     ASSERT(mFunction == CommandGraphNodeFunction::InsertDebugMarker ||
490            mFunction == CommandGraphNodeFunction::PushDebugMarker);
491     mDebugMarkerSource = source;
492     mDebugMarker       = std::move(marker);
493 }
494 
495 // Do not call this in anything but testing code, since it's slow.
isChildOf(CommandGraphNode * parent)496 bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
497 {
498     std::set<CommandGraphNode *> visitedList;
499     std::vector<CommandGraphNode *> openList;
500     openList.insert(openList.begin(), mParents.begin(), mParents.end());
501     while (!openList.empty())
502     {
503         CommandGraphNode *current = openList.back();
504         openList.pop_back();
505         if (visitedList.count(current) == 0)
506         {
507             if (current == parent)
508             {
509                 return true;
510             }
511             visitedList.insert(current);
512             openList.insert(openList.end(), current->mParents.begin(), current->mParents.end());
513         }
514     }
515 
516     return false;
517 }
518 
visitedState() const519 VisitedState CommandGraphNode::visitedState() const
520 {
521     return mVisitedState;
522 }
523 
visitParents(std::vector<CommandGraphNode * > * stack)524 void CommandGraphNode::visitParents(std::vector<CommandGraphNode *> *stack)
525 {
526     ASSERT(mVisitedState == VisitedState::Unvisited);
527     stack->insert(stack->end(), mParents.begin(), mParents.end());
528     mVisitedState = VisitedState::Ready;
529 }
530 
visitAndExecute(vk::Context * context,Serial serial,RenderPassCache * renderPassCache,PrimaryCommandBuffer * primaryCommandBuffer)531 angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
532                                                 Serial serial,
533                                                 RenderPassCache *renderPassCache,
534                                                 PrimaryCommandBuffer *primaryCommandBuffer)
535 {
536     // Record the deferred pipeline barrier if necessary.
537     ASSERT((mGlobalMemoryBarrierDstAccess == 0) == (mGlobalMemoryBarrierSrcAccess == 0));
538     if (mGlobalMemoryBarrierSrcAccess)
539     {
540         VkMemoryBarrier memoryBarrier = {};
541         memoryBarrier.sType           = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
542         memoryBarrier.srcAccessMask   = mGlobalMemoryBarrierSrcAccess;
543         memoryBarrier.dstAccessMask   = mGlobalMemoryBarrierDstAccess;
544 
545         primaryCommandBuffer->memoryBarrier(mGlobalMemoryBarrierStages, mGlobalMemoryBarrierStages,
546                                             &memoryBarrier);
547     }
548 
549     switch (mFunction)
550     {
551         case CommandGraphNodeFunction::Generic:
552             ASSERT(mQueryPool == VK_NULL_HANDLE && mFenceSyncEvent == VK_NULL_HANDLE);
553 
554             if (mOutsideRenderPassCommands.valid())
555             {
556                 ANGLE_VK_TRY(context, mOutsideRenderPassCommands.end());
557                 ExecuteCommands(primaryCommandBuffer, &mOutsideRenderPassCommands);
558             }
559 
560             if (mInsideRenderPassCommands.valid())
561             {
562                 // Pull a RenderPass from the cache.
563                 // TODO(jmadill): Insert layout transitions.
564                 RenderPass *renderPass = nullptr;
565                 ANGLE_TRY(renderPassCache->getRenderPassWithOps(
566                     context, serial, mRenderPassDesc, mRenderPassAttachmentOps, &renderPass));
567 
568                 ANGLE_VK_TRY(context, mInsideRenderPassCommands.end());
569 
570                 VkRenderPassBeginInfo beginInfo = {};
571                 beginInfo.sType                 = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
572                 beginInfo.renderPass            = renderPass->getHandle();
573                 beginInfo.framebuffer           = mRenderPassFramebuffer.getHandle();
574                 beginInfo.renderArea.offset.x   = static_cast<uint32_t>(mRenderPassRenderArea.x);
575                 beginInfo.renderArea.offset.y   = static_cast<uint32_t>(mRenderPassRenderArea.y);
576                 beginInfo.renderArea.extent.width =
577                     static_cast<uint32_t>(mRenderPassRenderArea.width);
578                 beginInfo.renderArea.extent.height =
579                     static_cast<uint32_t>(mRenderPassRenderArea.height);
580                 beginInfo.clearValueCount =
581                     static_cast<uint32_t>(mRenderPassDesc.attachmentCount());
582                 beginInfo.pClearValues    = mRenderPassClearValues.data();
583 
584                 primaryCommandBuffer->beginRenderPass(beginInfo, kRenderPassContents);
585                 ExecuteCommands(primaryCommandBuffer, &mInsideRenderPassCommands);
586                 primaryCommandBuffer->endRenderPass();
587             }
588             break;
589 
590         case CommandGraphNodeFunction::BeginQuery:
591             ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
592             ASSERT(mQueryPool != VK_NULL_HANDLE);
593 
594             primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
595             primaryCommandBuffer->beginQuery(mQueryPool, mQueryIndex, 0);
596 
597             break;
598 
599         case CommandGraphNodeFunction::EndQuery:
600             ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
601             ASSERT(mQueryPool != VK_NULL_HANDLE);
602 
603             primaryCommandBuffer->endQuery(mQueryPool, mQueryIndex);
604 
605             break;
606 
607         case CommandGraphNodeFunction::WriteTimestamp:
608             ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
609             ASSERT(mQueryPool != VK_NULL_HANDLE);
610 
611             primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
612             primaryCommandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, mQueryPool,
613                                                  mQueryIndex);
614 
615             break;
616 
617         case CommandGraphNodeFunction::BeginTransformFeedbackQuery:
618             // Unless using VK_EXT_transform_feedback (not implemented currently), there's nothing
619             // to do.
620             break;
621 
622         case CommandGraphNodeFunction::EndTransformFeedbackQuery:
623             // Same as BeginTransformFeedbackQuery.
624             break;
625 
626         case CommandGraphNodeFunction::SetFenceSync:
627             ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
628             ASSERT(mFenceSyncEvent != VK_NULL_HANDLE);
629 
630             primaryCommandBuffer->setEvent(mFenceSyncEvent, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
631 
632             break;
633 
634         case CommandGraphNodeFunction::WaitFenceSync:
635             ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
636             ASSERT(mFenceSyncEvent != VK_NULL_HANDLE);
637 
638             // Fence Syncs are purely execution barriers, so there are no memory barriers attached.
639             primaryCommandBuffer->waitEvents(
640                 1, &mFenceSyncEvent, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
641                 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, nullptr, 0, nullptr, 0, nullptr);
642 
643             break;
644 
645         case CommandGraphNodeFunction::GraphBarrier:
646             // Nothing to do.  The memory barrier, if any, is already handled above through global
647             // memory barrier flags.
648             break;
649 
650         case CommandGraphNodeFunction::InsertDebugMarker:
651             ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
652 
653             if (vkCmdInsertDebugUtilsLabelEXT)
654             {
655                 VkDebugUtilsLabelEXT label;
656                 MakeDebugUtilsLabel(mDebugMarkerSource, mDebugMarker.c_str(), &label);
657 
658                 vkCmdInsertDebugUtilsLabelEXT(primaryCommandBuffer->getHandle(), &label);
659             }
660             break;
661 
662         case CommandGraphNodeFunction::PushDebugMarker:
663             ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
664 
665             if (vkCmdBeginDebugUtilsLabelEXT)
666             {
667                 VkDebugUtilsLabelEXT label;
668                 MakeDebugUtilsLabel(mDebugMarkerSource, mDebugMarker.c_str(), &label);
669 
670                 vkCmdBeginDebugUtilsLabelEXT(primaryCommandBuffer->getHandle(), &label);
671             }
672             break;
673 
674         case CommandGraphNodeFunction::PopDebugMarker:
675             ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
676 
677             if (vkCmdEndDebugUtilsLabelEXT)
678             {
679                 vkCmdEndDebugUtilsLabelEXT(primaryCommandBuffer->getHandle());
680             }
681             break;
682 
683         case CommandGraphNodeFunction::HostAvailabilityOperation:
684             // Make sure all writes to host-visible buffers are flushed.  We have no way of knowing
685             // whether any buffer will be mapped for readback in the future, and we can't afford to
686             // flush and wait on a one-pipeline-barrier command buffer on every map().
687             {
688                 VkMemoryBarrier memoryBarrier = {};
689                 memoryBarrier.sType           = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
690                 memoryBarrier.srcAccessMask   = VK_ACCESS_MEMORY_WRITE_BIT;
691                 memoryBarrier.dstAccessMask   = VK_ACCESS_HOST_READ_BIT;
692 
693                 primaryCommandBuffer->memoryBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
694                                                     VK_PIPELINE_STAGE_HOST_BIT, &memoryBarrier);
695             }
696             break;
697 
698         default:
699             UNREACHABLE();
700     }
701 
702     mVisitedState = VisitedState::Visited;
703     return angle::Result::Continue;
704 }
705 
getParentsForDiagnostics() const706 const std::vector<CommandGraphNode *> &CommandGraphNode::getParentsForDiagnostics() const
707 {
708     return mParents;
709 }
710 
setDiagnosticInfo(CommandGraphResourceType resourceType,uintptr_t resourceID)711 void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType,
712                                          uintptr_t resourceID)
713 {
714     mResourceType = resourceType;
715     mResourceID   = resourceID;
716 }
717 
hasDiagnosticID() const718 bool CommandGraphNode::hasDiagnosticID() const
719 {
720     // All nodes have diagnostic IDs to differentiate them except the following select few.
721     return mResourceType != CommandGraphResourceType::HostAvailabilityOperation &&
722            mResourceType != CommandGraphResourceType::GraphBarrier;
723 }
724 
dumpCommandsForDiagnostics(const char * separator) const725 std::string CommandGraphNode::dumpCommandsForDiagnostics(const char *separator) const
726 {
727     std::string result;
728     if (mGlobalMemoryBarrierSrcAccess != 0 || mGlobalMemoryBarrierDstAccess != 0)
729     {
730         result += separator;
731 
732         std::ostringstream out;
733         out << "Memory Barrier Src: 0x" << std::hex << mGlobalMemoryBarrierSrcAccess
734             << " &rarr; Dst: 0x" << std::hex << mGlobalMemoryBarrierDstAccess;
735         result += out.str();
736     }
737     if (mOutsideRenderPassCommands.valid())
738     {
739         result += separator;
740         result += "Outside RP:";
741         result += DumpCommands(mOutsideRenderPassCommands, separator);
742     }
743     if (mInsideRenderPassCommands.valid())
744     {
745         result += separator;
746         result += "Inside RP:";
747 
748         size_t attachmentCount             = mRenderPassDesc.attachmentCount();
749         size_t depthStencilAttachmentCount = mRenderPassDesc.hasDepthStencilAttachment();
750         size_t colorAttachmentCount        = attachmentCount - depthStencilAttachmentCount;
751 
752         std::string loadOps, storeOps;
753 
754         if (colorAttachmentCount > 0)
755         {
756             loadOps += " Color: ";
757             storeOps += " Color: ";
758 
759             for (size_t i = 0; i < colorAttachmentCount; ++i)
760             {
761                 loadOps += GetLoadOpShorthand(mRenderPassAttachmentOps[i].loadOp);
762                 storeOps += GetStoreOpShorthand(mRenderPassAttachmentOps[i].storeOp);
763             }
764         }
765 
766         if (depthStencilAttachmentCount > 0)
767         {
768             ASSERT(depthStencilAttachmentCount == 1);
769 
770             loadOps += " Depth/Stencil: ";
771             storeOps += " Depth/Stencil: ";
772             size_t dsIndex = colorAttachmentCount;
773 
774             loadOps += GetLoadOpShorthand(mRenderPassAttachmentOps[dsIndex].loadOp);
775             loadOps += GetLoadOpShorthand(mRenderPassAttachmentOps[dsIndex].stencilLoadOp);
776 
777             storeOps += GetStoreOpShorthand(mRenderPassAttachmentOps[dsIndex].storeOp);
778             storeOps += GetStoreOpShorthand(mRenderPassAttachmentOps[dsIndex].stencilStoreOp);
779         }
780 
781         if (attachmentCount > 0)
782         {
783             result += " LoadOp: " + loadOps;
784             result += separator;
785             result += "------------ StoreOp: " + storeOps;
786         }
787 
788         result += DumpCommands(mInsideRenderPassCommands, separator);
789     }
790     return result;
791 }
792 
793 // CommandGraph implementation.
CommandGraph(bool enableGraphDiagnostics,angle::PoolAllocator * poolAllocator)794 CommandGraph::CommandGraph(bool enableGraphDiagnostics, angle::PoolAllocator *poolAllocator)
795     : mEnableGraphDiagnostics(enableGraphDiagnostics),
796       mPoolAllocator(poolAllocator),
797       mLastBarrierIndex(kInvalidNodeIndex)
798 {
799     // Push so that allocations made from here will be recycled in clear() below.
800     mPoolAllocator->push();
801 }
802 
~CommandGraph()803 CommandGraph::~CommandGraph()
804 {
805     ASSERT(empty());
806 }
807 
allocateNode(CommandGraphNodeFunction function)808 CommandGraphNode *CommandGraph::allocateNode(CommandGraphNodeFunction function)
809 {
810     // TODO(jmadill): Use a pool allocator for the CPU node allocations.
811     CommandGraphNode *newCommands = new CommandGraphNode(function, mPoolAllocator);
812     mNodes.emplace_back(newCommands);
813     return newCommands;
814 }
815 
allocateBarrierNode(CommandGraphNodeFunction function,CommandGraphResourceType resourceType,uintptr_t resourceID)816 CommandGraphNode *CommandGraph::allocateBarrierNode(CommandGraphNodeFunction function,
817                                                     CommandGraphResourceType resourceType,
818                                                     uintptr_t resourceID)
819 {
820     CommandGraphNode *newNode = allocateNode(function);
821     newNode->setDiagnosticInfo(resourceType, resourceID);
822     setNewBarrier(newNode);
823 
824     return newNode;
825 }
826 
setNewBarrier(CommandGraphNode * newBarrier)827 void CommandGraph::setNewBarrier(CommandGraphNode *newBarrier)
828 {
829     size_t previousBarrierIndex       = 0;
830     CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
831 
832     // Add a dependency from previousBarrier to all nodes in (previousBarrier, newBarrier).
833     if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
834     {
835         size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 2);
836         CommandGraphNode::SetHappensBeforeDependencies(
837             previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
838     }
839 
840     // Add a dependency from all nodes in [previousBarrier, newBarrier) to newBarrier.
841     addDependenciesToNextBarrier(previousBarrierIndex, mNodes.size() - 1, newBarrier);
842 
843     mLastBarrierIndex = mNodes.size() - 1;
844 }
845 
submitCommands(ContextVk * context,Serial serial,RenderPassCache * renderPassCache,PrimaryCommandBuffer * primaryCommandBuffer)846 angle::Result CommandGraph::submitCommands(ContextVk *context,
847                                            Serial serial,
848                                            RenderPassCache *renderPassCache,
849                                            PrimaryCommandBuffer *primaryCommandBuffer)
850 {
851     // There is no point in submitting an empty command buffer, so make sure not to call this
852     // function if there's nothing to do.
853     ASSERT(!mNodes.empty());
854 
855     size_t previousBarrierIndex       = 0;
856     CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
857 
858     // Add a dependency from previousBarrier to all nodes in (previousBarrier, end].
859     if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
860     {
861         size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
862         CommandGraphNode::SetHappensBeforeDependencies(
863             previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
864     }
865 
866     if (mEnableGraphDiagnostics)
867     {
868         dumpGraphDotFile(std::cout);
869     }
870 
871     std::vector<CommandGraphNode *> nodeStack;
872 
873     VkCommandBufferBeginInfo beginInfo = {};
874     beginInfo.sType                    = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
875     beginInfo.flags                    = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
876     beginInfo.pInheritanceInfo         = nullptr;
877 
878     ANGLE_VK_TRY(context, primaryCommandBuffer->begin(beginInfo));
879 
880     ANGLE_TRY(context->traceGpuEvent(primaryCommandBuffer, TRACE_EVENT_PHASE_BEGIN,
881                                      "Primary Command Buffer"));
882 
883     for (CommandGraphNode *topLevelNode : mNodes)
884     {
885         // Only process commands that don't have child commands. The others will be pulled in
886         // automatically. Also skip commands that have already been visited.
887         if (topLevelNode->hasChildren() || topLevelNode->visitedState() != VisitedState::Unvisited)
888             continue;
889 
890         nodeStack.push_back(topLevelNode);
891 
892         while (!nodeStack.empty())
893         {
894             CommandGraphNode *node = nodeStack.back();
895 
896             switch (node->visitedState())
897             {
898                 case VisitedState::Unvisited:
899                     node->visitParents(&nodeStack);
900                     break;
901                 case VisitedState::Ready:
902                     ANGLE_TRY(node->visitAndExecute(context, serial, renderPassCache,
903                                                     primaryCommandBuffer));
904                     nodeStack.pop_back();
905                     break;
906                 case VisitedState::Visited:
907                     nodeStack.pop_back();
908                     break;
909                 default:
910                     UNREACHABLE();
911                     break;
912             }
913         }
914     }
915 
916     ANGLE_TRY(context->traceGpuEvent(primaryCommandBuffer, TRACE_EVENT_PHASE_END,
917                                      "Primary Command Buffer"));
918 
919     ANGLE_VK_TRY(context, primaryCommandBuffer->end());
920 
921     clear();
922 
923     return angle::Result::Continue;
924 }
925 
empty() const926 bool CommandGraph::empty() const
927 {
928     return mNodes.empty();
929 }
930 
clear()931 void CommandGraph::clear()
932 {
933     mLastBarrierIndex = kInvalidNodeIndex;
934     // Release cmd graph pool memory now that cmds are submitted
935     // NOTE: This frees all memory since last push. Right now only the CommandGraph
936     //  will push the allocator (at creation and below). If other people start
937     //  pushing the allocator this (and/or the allocator) will need to be updated.
938     mPoolAllocator->pop();
939     mPoolAllocator->push();
940 
941     // TODO(jmadill): Use pool allocator for performance. http://anglebug.com/2951
942     for (CommandGraphNode *node : mNodes)
943     {
944         delete node;
945     }
946     mNodes.clear();
947 }
948 
beginQuery(const QueryPool * queryPool,uint32_t queryIndex)949 void CommandGraph::beginQuery(const QueryPool *queryPool, uint32_t queryIndex)
950 {
951     CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::BeginQuery,
952                                                     CommandGraphResourceType::Query, 0);
953     newNode->setQueryPool(queryPool, queryIndex);
954 }
955 
endQuery(const QueryPool * queryPool,uint32_t queryIndex)956 void CommandGraph::endQuery(const QueryPool *queryPool, uint32_t queryIndex)
957 {
958     CommandGraphNode *newNode =
959         allocateBarrierNode(CommandGraphNodeFunction::EndQuery, CommandGraphResourceType::Query, 0);
960     newNode->setQueryPool(queryPool, queryIndex);
961 }
962 
writeTimestamp(const QueryPool * queryPool,uint32_t queryIndex)963 void CommandGraph::writeTimestamp(const QueryPool *queryPool, uint32_t queryIndex)
964 {
965     CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::WriteTimestamp,
966                                                     CommandGraphResourceType::Query, 0);
967     newNode->setQueryPool(queryPool, queryIndex);
968 }
969 
beginTransformFeedbackEmulatedQuery()970 void CommandGraph::beginTransformFeedbackEmulatedQuery()
971 {
972     allocateBarrierNode(CommandGraphNodeFunction::BeginTransformFeedbackQuery,
973                         CommandGraphResourceType::EmulatedQuery, 0);
974 }
975 
endTransformFeedbackEmulatedQuery()976 void CommandGraph::endTransformFeedbackEmulatedQuery()
977 {
978     allocateBarrierNode(CommandGraphNodeFunction::EndTransformFeedbackQuery,
979                         CommandGraphResourceType::EmulatedQuery, 0);
980 }
981 
setFenceSync(const vk::Event & event)982 void CommandGraph::setFenceSync(const vk::Event &event)
983 {
984     CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::SetFenceSync,
985                                                     CommandGraphResourceType::FenceSync,
986                                                     reinterpret_cast<uintptr_t>(&event));
987     newNode->setFenceSync(event);
988 }
989 
waitFenceSync(const vk::Event & event)990 void CommandGraph::waitFenceSync(const vk::Event &event)
991 {
992     CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::WaitFenceSync,
993                                                     CommandGraphResourceType::FenceSync,
994                                                     reinterpret_cast<uintptr_t>(&event));
995     newNode->setFenceSync(event);
996 }
997 
memoryBarrier(VkFlags srcAccess,VkFlags dstAccess,VkPipelineStageFlags stages)998 void CommandGraph::memoryBarrier(VkFlags srcAccess, VkFlags dstAccess, VkPipelineStageFlags stages)
999 {
1000     CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::GraphBarrier,
1001                                                     CommandGraphResourceType::GraphBarrier, 0);
1002     newNode->addGlobalMemoryBarrier(srcAccess, dstAccess, stages);
1003 }
1004 
insertDebugMarker(GLenum source,std::string && marker)1005 void CommandGraph::insertDebugMarker(GLenum source, std::string &&marker)
1006 {
1007     CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::InsertDebugMarker,
1008                                                     CommandGraphResourceType::DebugMarker, 0);
1009     newNode->setDebugMarker(source, std::move(marker));
1010 }
1011 
pushDebugMarker(GLenum source,std::string && marker)1012 void CommandGraph::pushDebugMarker(GLenum source, std::string &&marker)
1013 {
1014     CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::PushDebugMarker,
1015                                                     CommandGraphResourceType::DebugMarker, 0);
1016     newNode->setDebugMarker(source, std::move(marker));
1017 }
1018 
popDebugMarker()1019 void CommandGraph::popDebugMarker()
1020 {
1021     allocateBarrierNode(CommandGraphNodeFunction::PopDebugMarker,
1022                         CommandGraphResourceType::DebugMarker, 0);
1023 }
1024 
makeHostVisibleBufferWriteAvailable()1025 void CommandGraph::makeHostVisibleBufferWriteAvailable()
1026 {
1027     allocateBarrierNode(CommandGraphNodeFunction::HostAvailabilityOperation,
1028                         CommandGraphResourceType::HostAvailabilityOperation, 0);
1029 }
1030 
1031 // Dumps the command graph into a dot file that works with graphviz.
dumpGraphDotFile(std::ostream & out) const1032 void CommandGraph::dumpGraphDotFile(std::ostream &out) const
1033 {
1034     // This ID maps a node pointer to a monotonic ID. It allows us to look up parent node IDs.
1035     std::map<const CommandGraphNode *, int> nodeIDMap;
1036     std::map<uintptr_t, int> objectIDMap;
1037     std::map<std::pair<VkQueryPool, uint32_t>, int> queryIDMap;
1038 
1039     // Map nodes to ids.
1040     for (size_t nodeIndex = 0; nodeIndex < mNodes.size(); ++nodeIndex)
1041     {
1042         const CommandGraphNode *node = mNodes[nodeIndex];
1043         nodeIDMap[node]              = static_cast<int>(nodeIndex) + 1;
1044     }
1045 
1046     int bufferIDCounter      = 1;
1047     int framebufferIDCounter = 1;
1048     int imageIDCounter       = 1;
1049     int queryIDCounter       = 1;
1050     int dispatcherIDCounter  = 1;
1051     int fenceIDCounter       = 1;
1052     int xfbIDCounter         = 1;
1053 
1054     out << "digraph {" << std::endl;
1055 
1056     for (const CommandGraphNode *node : mNodes)
1057     {
1058         int nodeID = nodeIDMap[node];
1059 
1060         std::stringstream strstr;
1061         strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics(), node->getFunction());
1062 
1063         if (node->getResourceTypeForDiagnostics() == CommandGraphResourceType::DebugMarker)
1064         {
1065             // For debug markers, use the string from the debug marker itself.
1066             if (node->getFunction() != CommandGraphNodeFunction::PopDebugMarker)
1067             {
1068                 strstr << " " << node->getDebugMarker();
1069             }
1070         }
1071         else if (node->getResourceTypeForDiagnostics() == CommandGraphResourceType::Query)
1072         {
1073             // Special case for queries as they cannot generate a resource ID at creation time that
1074             // would reliably fit in a uintptr_t.
1075             strstr << " ";
1076 
1077             ASSERT(node->getResourceIDForDiagnostics() == 0);
1078 
1079             auto queryID = std::make_pair(node->getQueryPool(), node->getQueryIndex());
1080 
1081             auto it = queryIDMap.find(queryID);
1082             if (it != queryIDMap.end())
1083             {
1084                 strstr << it->second;
1085             }
1086             else
1087             {
1088                 int id = queryIDCounter++;
1089 
1090                 queryIDMap[queryID] = id;
1091                 strstr << id;
1092             }
1093         }
1094         else if (!node->hasDiagnosticID())
1095         {
1096             // Nothing to append for these special nodes.  The name is sufficient.
1097         }
1098         else
1099         {
1100             strstr << " ";
1101 
1102             // Otherwise assign each object an ID, so all the nodes of the same object have the same
1103             // label.
1104             ASSERT(node->getResourceIDForDiagnostics() != 0);
1105             auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
1106             if (it != objectIDMap.end())
1107             {
1108                 strstr << it->second;
1109             }
1110             else
1111             {
1112                 int id = 0;
1113 
1114                 switch (node->getResourceTypeForDiagnostics())
1115                 {
1116                     case CommandGraphResourceType::Buffer:
1117                         id = bufferIDCounter++;
1118                         break;
1119                     case CommandGraphResourceType::Framebuffer:
1120                         id = framebufferIDCounter++;
1121                         break;
1122                     case CommandGraphResourceType::Image:
1123                         id = imageIDCounter++;
1124                         break;
1125                     case CommandGraphResourceType::Dispatcher:
1126                         id = dispatcherIDCounter++;
1127                         break;
1128                     case CommandGraphResourceType::FenceSync:
1129                         id = fenceIDCounter++;
1130                         break;
1131                     case CommandGraphResourceType::EmulatedQuery:
1132                         id = xfbIDCounter++;
1133                         break;
1134                     default:
1135                         UNREACHABLE();
1136                         break;
1137                 }
1138 
1139                 objectIDMap[node->getResourceIDForDiagnostics()] = id;
1140                 strstr << id;
1141             }
1142         }
1143 
1144         const std::string &label = strstr.str();
1145         out << "  " << nodeID << "[label =<" << label << "<BR/><FONT POINT-SIZE=\"10\">Node ID "
1146             << nodeID << node->dumpCommandsForDiagnostics("<BR/>") << "</FONT>>];" << std::endl;
1147     }
1148 
1149     for (const CommandGraphNode *node : mNodes)
1150     {
1151         int nodeID = nodeIDMap[node];
1152 
1153         for (const CommandGraphNode *parent : node->getParentsForDiagnostics())
1154         {
1155             int parentID = nodeIDMap[parent];
1156             out << "  " << parentID << " -> " << nodeID << ";" << std::endl;
1157         }
1158     }
1159 
1160     out << "}" << std::endl;
1161 }
1162 
getLastBarrierNode(size_t * indexOut)1163 CommandGraphNode *CommandGraph::getLastBarrierNode(size_t *indexOut)
1164 {
1165     *indexOut = mLastBarrierIndex == kInvalidNodeIndex ? 0 : mLastBarrierIndex;
1166     return mLastBarrierIndex == kInvalidNodeIndex ? nullptr : mNodes[mLastBarrierIndex];
1167 }
1168 
addDependenciesToNextBarrier(size_t begin,size_t end,CommandGraphNode * nextBarrier)1169 void CommandGraph::addDependenciesToNextBarrier(size_t begin,
1170                                                 size_t end,
1171                                                 CommandGraphNode *nextBarrier)
1172 {
1173     for (size_t i = begin; i < end; ++i)
1174     {
1175         // As a small optimization, only add edges to childless nodes.  The others have an
1176         // indirect dependency.
1177         if (!mNodes[i]->hasChildren())
1178         {
1179             CommandGraphNode::SetHappensBeforeDependency(mNodes[i], nextBarrier);
1180         }
1181     }
1182 }
1183 
1184 }  // namespace vk
1185 }  // namespace rx
1186