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