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 << " → 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