blob: 5f6892b3d4129c5984ffeba60c163427e677bb8b [file] [log] [blame]
Jamie Madill1f46bc12018-02-20 16:09:43 -05001//
2// Copyright 2017 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6// CommandGraph:
7// Deferred work constructed by GL calls, that will later be flushed to Vulkan.
8//
9
10#include "libANGLE/renderer/vulkan/CommandGraph.h"
11
Jamie Madill0da73fe2018-10-02 09:31:39 -040012#include <iostream>
13
Jamie Madill85ca1892019-01-16 13:27:15 -050014#include "libANGLE/renderer/vulkan/ContextVk.h"
Jamie Madill1f46bc12018-02-20 16:09:43 -050015#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
16#include "libANGLE/renderer/vulkan/RendererVk.h"
17#include "libANGLE/renderer/vulkan/vk_format_utils.h"
Jamie Madill26084d02018-04-09 13:44:04 -040018#include "libANGLE/renderer/vulkan/vk_helpers.h"
Jamie Madill1f46bc12018-02-20 16:09:43 -050019
Shahbaz Youssefi25224e72018-10-22 11:56:02 -040020#include "third_party/trace_event/trace_event.h"
21
Jamie Madill1f46bc12018-02-20 16:09:43 -050022namespace rx
23{
Jamie Madill1f46bc12018-02-20 16:09:43 -050024namespace vk
25{
Jamie Madill1f46bc12018-02-20 16:09:43 -050026namespace
27{
Jamie Madill21061022018-07-12 23:56:30 -040028angle::Result InitAndBeginCommandBuffer(vk::Context *context,
29 const CommandPool &commandPool,
30 const VkCommandBufferInheritanceInfo &inheritanceInfo,
31 VkCommandBufferUsageFlags flags,
32 CommandBuffer *commandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -050033{
34 ASSERT(!commandBuffer->valid());
35
Shahbaz Youssefi06270c92018-10-03 17:00:25 -040036 VkCommandBufferAllocateInfo createInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -050037 createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
38 createInfo.commandPool = commandPool.getHandle();
39 createInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
40 createInfo.commandBufferCount = 1;
Jamie Madill1f46bc12018-02-20 16:09:43 -050041
Yuly Novikov27780292018-11-09 11:19:49 -050042 ANGLE_VK_TRY(context, commandBuffer->init(context->getDevice(), createInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -050043
Shahbaz Youssefi06270c92018-10-03 17:00:25 -040044 VkCommandBufferBeginInfo beginInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -050045 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
46 beginInfo.flags = flags | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
47 beginInfo.pInheritanceInfo = &inheritanceInfo;
Jamie Madill1f46bc12018-02-20 16:09:43 -050048
Yuly Novikov27780292018-11-09 11:19:49 -050049 ANGLE_VK_TRY(context, commandBuffer->begin(beginInfo));
Jamie Madill7c985f52018-11-29 18:16:17 -050050 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -050051}
52
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040053const char *GetResourceTypeName(CommandGraphResourceType resourceType,
54 CommandGraphNodeFunction function)
Jamie Madill0da73fe2018-10-02 09:31:39 -040055{
56 switch (resourceType)
57 {
58 case CommandGraphResourceType::Buffer:
59 return "Buffer";
60 case CommandGraphResourceType::Framebuffer:
61 return "Framebuffer";
62 case CommandGraphResourceType::Image:
63 return "Image";
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -040064 case CommandGraphResourceType::Query:
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040065 switch (function)
66 {
67 case CommandGraphNodeFunction::BeginQuery:
68 return "BeginQuery";
69 case CommandGraphNodeFunction::EndQuery:
70 return "EndQuery";
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -040071 case CommandGraphNodeFunction::WriteTimestamp:
72 return "WriteTimestamp";
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040073 default:
74 UNREACHABLE();
75 return "Query";
76 }
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -050077 case CommandGraphResourceType::FenceSync:
78 switch (function)
79 {
80 case CommandGraphNodeFunction::SetFenceSync:
81 return "SetFenceSync";
82 case CommandGraphNodeFunction::WaitFenceSync:
83 return "WaitFenceSync";
84 default:
85 UNREACHABLE();
86 return "FenceSync";
87 }
Shahbaz Youssefi4d153382019-02-26 15:08:11 +000088 case CommandGraphResourceType::DebugMarker:
89 switch (function)
90 {
91 case CommandGraphNodeFunction::InsertDebugMarker:
92 return "InsertDebugMarker";
93 case CommandGraphNodeFunction::PushDebugMarker:
94 return "PushDebugMarker";
95 case CommandGraphNodeFunction::PopDebugMarker:
96 return "PopDebugMarker";
97 default:
98 UNREACHABLE();
99 return "DebugMarker";
100 }
Jamie Madill0da73fe2018-10-02 09:31:39 -0400101 default:
102 UNREACHABLE();
103 return "";
104 }
105}
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000106
107void MakeDebugUtilsLabel(GLenum source, const char *marker, VkDebugUtilsLabelEXT *label)
108{
109 static constexpr angle::ColorF kLabelColors[6] = {
110 angle::ColorF(1.0f, 0.5f, 0.5f, 1.0f), // DEBUG_SOURCE_API
111 angle::ColorF(0.5f, 1.0f, 0.5f, 1.0f), // DEBUG_SOURCE_WINDOW_SYSTEM
112 angle::ColorF(0.5f, 0.5f, 1.0f, 1.0f), // DEBUG_SOURCE_SHADER_COMPILER
113 angle::ColorF(0.7f, 0.7f, 0.7f, 1.0f), // DEBUG_SOURCE_THIRD_PARTY
114 angle::ColorF(0.5f, 0.8f, 0.9f, 1.0f), // DEBUG_SOURCE_APPLICATION
115 angle::ColorF(0.9f, 0.8f, 0.5f, 1.0f), // DEBUG_SOURCE_OTHER
116 };
117
118 int colorIndex = source - GL_DEBUG_SOURCE_API;
119 ASSERT(colorIndex >= 0 && static_cast<size_t>(colorIndex) < ArraySize(kLabelColors));
120
121 label->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
122 label->pNext = nullptr;
123 label->pLabelName = marker;
124 kLabelColors[colorIndex].writeData(label->color);
125}
126
Jamie Madill1f46bc12018-02-20 16:09:43 -0500127} // anonymous namespace
128
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400129// CommandGraphResource implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -0400130CommandGraphResource::CommandGraphResource(CommandGraphResourceType resourceType)
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500131 : mCurrentWritingNode(nullptr), mResourceType(resourceType)
Jamie Madillb980c562018-11-27 11:34:27 -0500132{}
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400133
Jamie Madill316c6062018-05-29 10:49:45 -0400134CommandGraphResource::~CommandGraphResource() = default;
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400135
Jamie Madillc57ee252018-05-30 19:53:48 -0400136bool CommandGraphResource::isResourceInUse(RendererVk *renderer) const
137{
138 return renderer->isSerialInUse(mStoredQueueSerial);
139}
140
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500141angle::Result CommandGraphResource::recordCommands(Context *context,
142 CommandBuffer **commandBufferOut)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400143{
Jamie Madill21061022018-07-12 23:56:30 -0400144 updateQueueSerial(context->getRenderer()->getCurrentQueueSerial());
Jamie Madill5dca6512018-05-30 10:53:51 -0400145
Jamie Madille2d22702018-09-19 08:11:48 -0400146 if (!hasChildlessWritingNode() || hasStartedRenderPass())
Jamie Madill316c6062018-05-29 10:49:45 -0400147 {
Jamie Madill193a2842018-10-30 17:28:41 -0400148 startNewCommands(context->getRenderer());
Jamie Madille2d22702018-09-19 08:11:48 -0400149 return mCurrentWritingNode->beginOutsideRenderPassRecording(
150 context, context->getRenderer()->getCommandPool(), commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400151 }
152
153 CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
154 if (!outsideRenderPassCommands->valid())
155 {
156 ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
Jamie Madill21061022018-07-12 23:56:30 -0400157 context, context->getRenderer()->getCommandPool(), commandBufferOut));
Jamie Madill316c6062018-05-29 10:49:45 -0400158 }
159 else
160 {
161 *commandBufferOut = outsideRenderPassCommands;
162 }
163
Jamie Madill7c985f52018-11-29 18:16:17 -0500164 return angle::Result::Continue;
Jamie Madill316c6062018-05-29 10:49:45 -0400165}
166
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500167const gl::Rectangle &CommandGraphResource::getRenderPassRenderArea() const
Jamie Madill316c6062018-05-29 10:49:45 -0400168{
169 ASSERT(hasStartedRenderPass());
170 return mCurrentWritingNode->getRenderPassRenderArea();
171}
172
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500173angle::Result CommandGraphResource::beginRenderPass(ContextVk *contextVk,
174 const Framebuffer &framebuffer,
175 const gl::Rectangle &renderArea,
176 const RenderPassDesc &renderPassDesc,
177 const std::vector<VkClearValue> &clearValues,
178 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400179{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400180 // If a barrier has been inserted in the meantime, stop the command buffer.
181 if (!hasChildlessWritingNode())
182 {
Jamie Madill85ca1892019-01-16 13:27:15 -0500183 startNewCommands(contextVk->getRenderer());
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400184 }
185
Jamie Madill316c6062018-05-29 10:49:45 -0400186 // Hard-code RenderPass to clear the first render target to the current clear value.
187 // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
188 mCurrentWritingNode->storeRenderPassInfo(framebuffer, renderArea, renderPassDesc, clearValues);
189
Jamie Madill85ca1892019-01-16 13:27:15 -0500190 mCurrentWritingNode->setCommandBufferOwner(contextVk);
191
192 return mCurrentWritingNode->beginInsideRenderPassRecording(contextVk, commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400193}
194
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500195void CommandGraphResource::addWriteDependency(CommandGraphResource *writingResource)
Jamie Madill316c6062018-05-29 10:49:45 -0400196{
197 CommandGraphNode *writingNode = writingResource->mCurrentWritingNode;
198 ASSERT(writingNode);
199
Jamie Madillc57ee252018-05-30 19:53:48 -0400200 onWriteImpl(writingNode, writingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400201}
202
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500203void CommandGraphResource::addReadDependency(CommandGraphResource *readingResource)
Jamie Madill193a2842018-10-30 17:28:41 -0400204{
205 updateQueueSerial(readingResource->getStoredQueueSerial());
206
207 CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
208 ASSERT(readingNode);
209
Shahbaz Youssefib5ba5492019-01-02 15:19:22 -0500210 if (mCurrentWritingNode)
Jamie Madill193a2842018-10-30 17:28:41 -0400211 {
212 // Ensure 'readingNode' happens after the current writing node.
213 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
214 }
215
216 // Add the read node to the list of nodes currently reading this resource.
217 mCurrentReadingNodes.push_back(readingNode);
218}
219
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500220void CommandGraphResource::finishCurrentCommands(RendererVk *renderer)
Jamie Madill193a2842018-10-30 17:28:41 -0400221{
222 startNewCommands(renderer);
223}
224
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500225void CommandGraphResource::startNewCommands(RendererVk *renderer)
Jamie Madill193a2842018-10-30 17:28:41 -0400226{
227 CommandGraphNode *newCommands =
228 renderer->getCommandGraph()->allocateNode(CommandGraphNodeFunction::Generic);
229 newCommands->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
230 onWriteImpl(newCommands, renderer->getCurrentQueueSerial());
231}
232
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500233void CommandGraphResource::onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial)
Jamie Madill316c6062018-05-29 10:49:45 -0400234{
235 updateQueueSerial(currentSerial);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400236
Jamie Madill9cceac42018-03-31 14:19:16 -0400237 // Make sure any open reads and writes finish before we execute 'writingNode'.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400238 if (!mCurrentReadingNodes.empty())
239 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400240 CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes.data(),
241 mCurrentReadingNodes.size(), writingNode);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400242 mCurrentReadingNodes.clear();
243 }
244
245 if (mCurrentWritingNode && mCurrentWritingNode != writingNode)
246 {
247 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, writingNode);
248 }
249
250 mCurrentWritingNode = writingNode;
251}
252
Jamie Madill1f46bc12018-02-20 16:09:43 -0500253// CommandGraphNode implementation.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400254CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function)
255 : mRenderPassClearValues{},
256 mFunction(function),
257 mQueryPool(VK_NULL_HANDLE),
258 mQueryIndex(0),
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500259 mFenceSyncEvent(VK_NULL_HANDLE),
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400260 mHasChildren(false),
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500261 mVisitedState(VisitedState::Unvisited),
262 mGlobalMemoryBarrierSrcAccess(0),
Jamie Madill85ca1892019-01-16 13:27:15 -0500263 mGlobalMemoryBarrierDstAccess(0),
264 mCommandBufferOwner(nullptr)
Jamie Madillb980c562018-11-27 11:34:27 -0500265{}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500266
267CommandGraphNode::~CommandGraphNode()
268{
269 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
270
271 // Command buffers are managed by the command pool, so don't need to be freed.
272 mOutsideRenderPassCommands.releaseHandle();
273 mInsideRenderPassCommands.releaseHandle();
274}
275
276CommandBuffer *CommandGraphNode::getOutsideRenderPassCommands()
277{
278 ASSERT(!mHasChildren);
279 return &mOutsideRenderPassCommands;
280}
281
Jamie Madill21061022018-07-12 23:56:30 -0400282angle::Result CommandGraphNode::beginOutsideRenderPassRecording(Context *context,
283 const CommandPool &commandPool,
284 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500285{
286 ASSERT(!mHasChildren);
287
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400288 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500289 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
290 inheritanceInfo.renderPass = VK_NULL_HANDLE;
291 inheritanceInfo.subpass = 0;
292 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400293 inheritanceInfo.occlusionQueryEnable =
294 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500295 inheritanceInfo.queryFlags = 0;
296 inheritanceInfo.pipelineStatistics = 0;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500297
Jamie Madill21061022018-07-12 23:56:30 -0400298 ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500299 &mOutsideRenderPassCommands));
300
301 *commandsOut = &mOutsideRenderPassCommands;
Jamie Madill7c985f52018-11-29 18:16:17 -0500302 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500303}
304
Jamie Madill21061022018-07-12 23:56:30 -0400305angle::Result CommandGraphNode::beginInsideRenderPassRecording(Context *context,
306 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500307{
308 ASSERT(!mHasChildren);
309
310 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400311 // TODO(jmadill): Support query for compatible/conformant render pass. http://anglebug.com/2361
Jamie Madill1f46bc12018-02-20 16:09:43 -0500312 RenderPass *compatibleRenderPass;
Jamie Madill21061022018-07-12 23:56:30 -0400313 ANGLE_TRY(context->getRenderer()->getCompatibleRenderPass(context, mRenderPassDesc,
314 &compatibleRenderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500315
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400316 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500317 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
318 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
319 inheritanceInfo.subpass = 0;
320 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400321 inheritanceInfo.occlusionQueryEnable =
322 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500323 inheritanceInfo.queryFlags = 0;
324 inheritanceInfo.pipelineStatistics = 0;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500325
326 ANGLE_TRY(InitAndBeginCommandBuffer(
Jamie Madill21061022018-07-12 23:56:30 -0400327 context, context->getRenderer()->getCommandPool(), inheritanceInfo,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500328 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
329
330 *commandsOut = &mInsideRenderPassCommands;
Jamie Madill7c985f52018-11-29 18:16:17 -0500331 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500332}
333
334void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
335 const gl::Rectangle renderArea,
Jamie Madillbcf467f2018-05-23 09:46:00 -0400336 const vk::RenderPassDesc &renderPassDesc,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500337 const std::vector<VkClearValue> &clearValues)
338{
Jamie Madillbcf467f2018-05-23 09:46:00 -0400339 mRenderPassDesc = renderPassDesc;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500340 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
341 mRenderPassRenderArea = renderArea;
342 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
343}
344
Jamie Madill1f46bc12018-02-20 16:09:43 -0500345// static
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400346void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode **beforeNodes,
347 size_t beforeNodesCount,
348 CommandGraphNode *afterNode)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500349{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400350 afterNode->mParents.insert(afterNode->mParents.end(), beforeNodes,
351 beforeNodes + beforeNodesCount);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500352
353 // TODO(jmadill): is there a faster way to do this?
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400354 for (size_t i = 0; i < beforeNodesCount; ++i)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500355 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400356 beforeNodes[i]->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500357
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400358 ASSERT(beforeNodes[i] != afterNode && !beforeNodes[i]->isChildOf(afterNode));
359 }
360}
361
362void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode *beforeNode,
363 CommandGraphNode **afterNodes,
364 size_t afterNodesCount)
365{
366 for (size_t i = 0; i < afterNodesCount; ++i)
367 {
368 SetHappensBeforeDependency(beforeNode, afterNodes[i]);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500369 }
370}
371
372bool CommandGraphNode::hasParents() const
373{
374 return !mParents.empty();
375}
376
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400377void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIndex)
378{
379 ASSERT(mFunction == CommandGraphNodeFunction::BeginQuery ||
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400380 mFunction == CommandGraphNodeFunction::EndQuery ||
381 mFunction == CommandGraphNodeFunction::WriteTimestamp);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400382 mQueryPool = queryPool->getHandle();
383 mQueryIndex = queryIndex;
384}
385
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500386void CommandGraphNode::setFenceSync(const vk::Event &event)
387{
388 ASSERT(mFunction == CommandGraphNodeFunction::SetFenceSync ||
389 mFunction == CommandGraphNodeFunction::WaitFenceSync);
390 mFenceSyncEvent = event.getHandle();
391}
392
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000393void CommandGraphNode::setDebugMarker(GLenum source, std::string &&marker)
394{
395 ASSERT(mFunction == CommandGraphNodeFunction::InsertDebugMarker ||
396 mFunction == CommandGraphNodeFunction::PushDebugMarker);
397 mDebugMarkerSource = source;
398 mDebugMarker = std::move(marker);
399}
400
Jamie Madill1f46bc12018-02-20 16:09:43 -0500401// Do not call this in anything but testing code, since it's slow.
402bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
403{
404 std::set<CommandGraphNode *> visitedList;
405 std::vector<CommandGraphNode *> openList;
406 openList.insert(openList.begin(), mParents.begin(), mParents.end());
407 while (!openList.empty())
408 {
409 CommandGraphNode *current = openList.back();
410 openList.pop_back();
411 if (visitedList.count(current) == 0)
412 {
413 if (current == parent)
414 {
415 return true;
416 }
417 visitedList.insert(current);
418 openList.insert(openList.end(), current->mParents.begin(), current->mParents.end());
419 }
420 }
421
422 return false;
423}
424
425VisitedState CommandGraphNode::visitedState() const
426{
427 return mVisitedState;
428}
429
430void CommandGraphNode::visitParents(std::vector<CommandGraphNode *> *stack)
431{
432 ASSERT(mVisitedState == VisitedState::Unvisited);
433 stack->insert(stack->end(), mParents.begin(), mParents.end());
434 mVisitedState = VisitedState::Ready;
435}
436
Jamie Madill21061022018-07-12 23:56:30 -0400437angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
438 Serial serial,
439 RenderPassCache *renderPassCache,
440 CommandBuffer *primaryCommandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500441{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400442 switch (mFunction)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500443 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400444 case CommandGraphNodeFunction::Generic:
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500445 ASSERT(mQueryPool == VK_NULL_HANDLE && mFenceSyncEvent == VK_NULL_HANDLE);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500446
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500447 // Record the deferred pipeline barrier if necessary.
448 ASSERT((mGlobalMemoryBarrierDstAccess == 0) == (mGlobalMemoryBarrierSrcAccess == 0));
449 if (mGlobalMemoryBarrierSrcAccess)
450 {
451 VkMemoryBarrier memoryBarrier = {};
452 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
453 memoryBarrier.srcAccessMask = mGlobalMemoryBarrierSrcAccess;
454 memoryBarrier.dstAccessMask = mGlobalMemoryBarrierDstAccess;
455
Shahbaz Youssefi471358f2018-11-28 15:21:55 -0500456 // Use the all pipe stage to keep the state management simple.
457 primaryCommandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
458 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1,
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500459 &memoryBarrier, 0, nullptr, 0, nullptr);
460 }
461
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400462 if (mOutsideRenderPassCommands.valid())
463 {
Yuly Novikov27780292018-11-09 11:19:49 -0500464 ANGLE_VK_TRY(context, mOutsideRenderPassCommands.end());
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400465 primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
466 }
Jamie Madill1f46bc12018-02-20 16:09:43 -0500467
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400468 if (mInsideRenderPassCommands.valid())
469 {
470 // Pull a compatible RenderPass from the cache.
471 // TODO(jmadill): Insert real ops and layout transitions.
472 RenderPass *renderPass = nullptr;
473 ANGLE_TRY(renderPassCache->getCompatibleRenderPass(context, serial, mRenderPassDesc,
474 &renderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500475
Yuly Novikov27780292018-11-09 11:19:49 -0500476 ANGLE_VK_TRY(context, mInsideRenderPassCommands.end());
Jamie Madill1f46bc12018-02-20 16:09:43 -0500477
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400478 VkRenderPassBeginInfo beginInfo = {};
479 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
480 beginInfo.renderPass = renderPass->getHandle();
481 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
482 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
483 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
484 beginInfo.renderArea.extent.width =
485 static_cast<uint32_t>(mRenderPassRenderArea.width);
486 beginInfo.renderArea.extent.height =
487 static_cast<uint32_t>(mRenderPassRenderArea.height);
488 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
489 beginInfo.pClearValues = mRenderPassClearValues.data();
490
491 primaryCommandBuffer->beginRenderPass(
492 beginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
493 primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
494 primaryCommandBuffer->endRenderPass();
495 }
496 break;
497
498 case CommandGraphNodeFunction::BeginQuery:
499 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
500 ASSERT(mQueryPool != VK_NULL_HANDLE);
501
502 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
503 primaryCommandBuffer->beginQuery(mQueryPool, mQueryIndex, 0);
504
505 break;
506
507 case CommandGraphNodeFunction::EndQuery:
508 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
509 ASSERT(mQueryPool != VK_NULL_HANDLE);
510
511 primaryCommandBuffer->endQuery(mQueryPool, mQueryIndex);
512
513 break;
514
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400515 case CommandGraphNodeFunction::WriteTimestamp:
516 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
517 ASSERT(mQueryPool != VK_NULL_HANDLE);
518
519 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
520 primaryCommandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, mQueryPool,
521 mQueryIndex);
522
523 break;
524
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500525 case CommandGraphNodeFunction::SetFenceSync:
526 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
527 ASSERT(mFenceSyncEvent != VK_NULL_HANDLE);
528
529 primaryCommandBuffer->setEvent(mFenceSyncEvent, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
530
531 break;
532
533 case CommandGraphNodeFunction::WaitFenceSync:
534 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
535 ASSERT(mFenceSyncEvent != VK_NULL_HANDLE);
536
537 // Fence Syncs are purely execution barriers, so there are no memory barriers attached.
538 primaryCommandBuffer->waitEvents(
539 1, &mFenceSyncEvent, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
540 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, nullptr, 0, nullptr, 0, nullptr);
541
542 break;
543
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000544 case CommandGraphNodeFunction::InsertDebugMarker:
545 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
546
547 if (vkCmdInsertDebugUtilsLabelEXT)
548 {
549 VkDebugUtilsLabelEXT label;
550 MakeDebugUtilsLabel(mDebugMarkerSource, mDebugMarker.c_str(), &label);
551
552 vkCmdInsertDebugUtilsLabelEXT(primaryCommandBuffer->getHandle(), &label);
553 }
554 break;
555
556 case CommandGraphNodeFunction::PushDebugMarker:
557 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
558
559 if (vkCmdBeginDebugUtilsLabelEXT)
560 {
561 VkDebugUtilsLabelEXT label;
562 MakeDebugUtilsLabel(mDebugMarkerSource, mDebugMarker.c_str(), &label);
563
564 vkCmdBeginDebugUtilsLabelEXT(primaryCommandBuffer->getHandle(), &label);
565 }
566 break;
567
568 case CommandGraphNodeFunction::PopDebugMarker:
569 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
570
571 if (vkCmdEndDebugUtilsLabelEXT)
572 {
573 vkCmdEndDebugUtilsLabelEXT(primaryCommandBuffer->getHandle());
574 }
575 break;
576
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400577 default:
578 UNREACHABLE();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500579 }
580
581 mVisitedState = VisitedState::Visited;
Jamie Madill7c985f52018-11-29 18:16:17 -0500582 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500583}
584
Jamie Madill0da73fe2018-10-02 09:31:39 -0400585const std::vector<CommandGraphNode *> &CommandGraphNode::getParentsForDiagnostics() const
586{
587 return mParents;
588}
589
590void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType,
591 uintptr_t resourceID)
592{
593 mResourceType = resourceType;
594 mResourceID = resourceID;
595}
596
Luc Ferron14f48172018-04-11 08:43:28 -0400597const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
598{
599 return mRenderPassRenderArea;
600}
601
Jamie Madill1f46bc12018-02-20 16:09:43 -0500602// CommandGraph implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -0400603CommandGraph::CommandGraph(bool enableGraphDiagnostics)
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400604 : mEnableGraphDiagnostics(enableGraphDiagnostics), mLastBarrierIndex(kInvalidNodeIndex)
Jamie Madillb980c562018-11-27 11:34:27 -0500605{}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500606
607CommandGraph::~CommandGraph()
608{
609 ASSERT(empty());
610}
611
Jamie Madill193a2842018-10-30 17:28:41 -0400612CommandGraphNode *CommandGraph::allocateNode(CommandGraphNodeFunction function)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500613{
614 // TODO(jmadill): Use a pool allocator for the CPU node allocations.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400615 CommandGraphNode *newCommands = new CommandGraphNode(function);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500616 mNodes.emplace_back(newCommands);
617 return newCommands;
618}
619
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500620CommandGraphNode *CommandGraph::allocateBarrierNode(CommandGraphResourceType resourceType,
621 CommandGraphNodeFunction function)
622{
623 CommandGraphNode *newNode = allocateNode(function);
624 newNode->setDiagnosticInfo(resourceType, 0);
625 setNewBarrier(newNode);
626
627 return newNode;
628}
629
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400630void CommandGraph::setNewBarrier(CommandGraphNode *newBarrier)
631{
632 size_t previousBarrierIndex = 0;
633 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
634
635 // Add a dependency from previousBarrier to all nodes in (previousBarrier, newBarrier].
636 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
637 {
638 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
639 CommandGraphNode::SetHappensBeforeDependencies(
640 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
641 }
642
643 // Add a dependency from all nodes in (previousBarrier, newBarrier) to newBarrier.
644 addDependenciesToNextBarrier(previousBarrierIndex + 1, mNodes.size() - 1, newBarrier);
645
646 mLastBarrierIndex = mNodes.size() - 1;
647}
648
Jamie Madill21061022018-07-12 23:56:30 -0400649angle::Result CommandGraph::submitCommands(Context *context,
650 Serial serial,
651 RenderPassCache *renderPassCache,
652 CommandPool *commandPool,
653 CommandBuffer *primaryCommandBufferOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500654{
Shahbaz Youssefi3a482172018-10-11 10:34:44 -0400655 // There is no point in submitting an empty command buffer, so make sure not to call this
656 // function if there's nothing to do.
657 ASSERT(!mNodes.empty());
658
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400659 size_t previousBarrierIndex = 0;
660 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
661
662 // Add a dependency from previousBarrier to all nodes in (previousBarrier, end].
663 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
664 {
665 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
666 CommandGraphNode::SetHappensBeforeDependencies(
667 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
668 }
669
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400670 VkCommandBufferAllocateInfo primaryInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500671 primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
672 primaryInfo.commandPool = commandPool->getHandle();
673 primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
674 primaryInfo.commandBufferCount = 1;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500675
Yuly Novikov27780292018-11-09 11:19:49 -0500676 ANGLE_VK_TRY(context, primaryCommandBufferOut->init(context->getDevice(), primaryInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500677
Jamie Madill0da73fe2018-10-02 09:31:39 -0400678 if (mEnableGraphDiagnostics)
679 {
680 dumpGraphDotFile(std::cout);
681 }
682
Jamie Madill1f46bc12018-02-20 16:09:43 -0500683 std::vector<CommandGraphNode *> nodeStack;
684
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400685 VkCommandBufferBeginInfo beginInfo = {};
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400686 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
687 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
688 beginInfo.pInheritanceInfo = nullptr;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500689
Yuly Novikov27780292018-11-09 11:19:49 -0500690 ANGLE_VK_TRY(context, primaryCommandBufferOut->begin(beginInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500691
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400692 ANGLE_TRY(context->getRenderer()->traceGpuEvent(
693 context, primaryCommandBufferOut, TRACE_EVENT_PHASE_BEGIN, "Primary Command Buffer"));
694
Jamie Madill1f46bc12018-02-20 16:09:43 -0500695 for (CommandGraphNode *topLevelNode : mNodes)
696 {
697 // Only process commands that don't have child commands. The others will be pulled in
698 // automatically. Also skip commands that have already been visited.
699 if (topLevelNode->hasChildren() || topLevelNode->visitedState() != VisitedState::Unvisited)
700 continue;
701
702 nodeStack.push_back(topLevelNode);
703
704 while (!nodeStack.empty())
705 {
706 CommandGraphNode *node = nodeStack.back();
707
708 switch (node->visitedState())
709 {
710 case VisitedState::Unvisited:
711 node->visitParents(&nodeStack);
712 break;
713 case VisitedState::Ready:
Jamie Madill21061022018-07-12 23:56:30 -0400714 ANGLE_TRY(node->visitAndExecute(context, serial, renderPassCache,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500715 primaryCommandBufferOut));
716 nodeStack.pop_back();
717 break;
718 case VisitedState::Visited:
719 nodeStack.pop_back();
720 break;
721 default:
722 UNREACHABLE();
723 break;
724 }
725 }
726 }
727
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400728 ANGLE_TRY(context->getRenderer()->traceGpuEvent(
729 context, primaryCommandBufferOut, TRACE_EVENT_PHASE_END, "Primary Command Buffer"));
730
Yuly Novikov27780292018-11-09 11:19:49 -0500731 ANGLE_VK_TRY(context, primaryCommandBufferOut->end());
Jamie Madill1f46bc12018-02-20 16:09:43 -0500732
Yuly Novikovb56ddbb2018-11-02 16:53:18 -0400733 clear();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500734
Jamie Madill7c985f52018-11-29 18:16:17 -0500735 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500736}
737
738bool CommandGraph::empty() const
739{
740 return mNodes.empty();
741}
742
Yuly Novikovb56ddbb2018-11-02 16:53:18 -0400743void CommandGraph::clear()
744{
745 mLastBarrierIndex = kInvalidNodeIndex;
746
747 // TODO(jmadill): Use pool allocator for performance. http://anglebug.com/2951
748 for (CommandGraphNode *node : mNodes)
749 {
750 delete node;
751 }
752 mNodes.clear();
753}
754
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500755void CommandGraph::beginQuery(const QueryPool *queryPool, uint32_t queryIndex)
756{
757 CommandGraphNode *newNode =
758 allocateBarrierNode(CommandGraphResourceType::Query, CommandGraphNodeFunction::BeginQuery);
759 newNode->setQueryPool(queryPool, queryIndex);
760}
761
762void CommandGraph::endQuery(const QueryPool *queryPool, uint32_t queryIndex)
763{
764 CommandGraphNode *newNode =
765 allocateBarrierNode(CommandGraphResourceType::Query, CommandGraphNodeFunction::EndQuery);
766 newNode->setQueryPool(queryPool, queryIndex);
767}
768
769void CommandGraph::writeTimestamp(const QueryPool *queryPool, uint32_t queryIndex)
770{
771 CommandGraphNode *newNode = allocateBarrierNode(CommandGraphResourceType::Query,
772 CommandGraphNodeFunction::WriteTimestamp);
773 newNode->setQueryPool(queryPool, queryIndex);
774}
775
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500776void CommandGraph::setFenceSync(const vk::Event &event)
777{
778 CommandGraphNode *newNode = allocateBarrierNode(CommandGraphResourceType::FenceSync,
779 CommandGraphNodeFunction::SetFenceSync);
780 newNode->setFenceSync(event);
781}
782
783void CommandGraph::waitFenceSync(const vk::Event &event)
784{
785 CommandGraphNode *newNode = allocateBarrierNode(CommandGraphResourceType::FenceSync,
786 CommandGraphNodeFunction::WaitFenceSync);
787 newNode->setFenceSync(event);
788}
789
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000790void CommandGraph::insertDebugMarker(GLenum source, std::string &&marker)
791{
792 CommandGraphNode *newNode = allocateBarrierNode(CommandGraphResourceType::DebugMarker,
793 CommandGraphNodeFunction::InsertDebugMarker);
794 newNode->setDebugMarker(source, std::move(marker));
795}
796
797void CommandGraph::pushDebugMarker(GLenum source, std::string &&marker)
798{
799 CommandGraphNode *newNode = allocateBarrierNode(CommandGraphResourceType::DebugMarker,
800 CommandGraphNodeFunction::PushDebugMarker);
801 newNode->setDebugMarker(source, std::move(marker));
802}
803
804void CommandGraph::popDebugMarker()
805{
806 allocateBarrierNode(CommandGraphResourceType::DebugMarker,
807 CommandGraphNodeFunction::PopDebugMarker);
808}
809
Jamie Madill0da73fe2018-10-02 09:31:39 -0400810// Dumps the command graph into a dot file that works with graphviz.
811void CommandGraph::dumpGraphDotFile(std::ostream &out) const
812{
813 // This ID maps a node pointer to a monatonic ID. It allows us to look up parent node IDs.
814 std::map<const CommandGraphNode *, int> nodeIDMap;
815 std::map<uintptr_t, int> objectIDMap;
816
817 // Map nodes to ids.
818 for (size_t nodeIndex = 0; nodeIndex < mNodes.size(); ++nodeIndex)
819 {
820 const CommandGraphNode *node = mNodes[nodeIndex];
821 nodeIDMap[node] = static_cast<int>(nodeIndex) + 1;
822 }
823
824 int bufferIDCounter = 1;
825 int framebufferIDCounter = 1;
826 int imageIDCounter = 1;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400827 int queryIDCounter = 1;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400828
829 out << "digraph {" << std::endl;
830
831 for (const CommandGraphNode *node : mNodes)
832 {
833 int nodeID = nodeIDMap[node];
834
835 std::stringstream strstr;
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -0400836 strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics(), node->getFunction());
Jamie Madill0da73fe2018-10-02 09:31:39 -0400837
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000838 if (node->getResourceTypeForDiagnostics() == CommandGraphResourceType::DebugMarker)
Jamie Madill0da73fe2018-10-02 09:31:39 -0400839 {
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000840 // For debug markers, use the string from the debug marker itself.
841 if (node->getFunction() != CommandGraphNodeFunction::PopDebugMarker)
842 {
843 strstr << " " << node->getDebugMarker();
844 }
Jamie Madill0da73fe2018-10-02 09:31:39 -0400845 }
846 else
847 {
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000848 strstr << " ";
Jamie Madill0da73fe2018-10-02 09:31:39 -0400849
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000850 // Otherwise assign each object an ID, so all the nodes of the same object have the same
851 // label.
852 ASSERT(node->getResourceIDForDiagnostics() != 0);
853 auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
854 if (it != objectIDMap.end())
Jamie Madill0da73fe2018-10-02 09:31:39 -0400855 {
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000856 strstr << it->second;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400857 }
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000858 else
859 {
860 int id = 0;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400861
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000862 switch (node->getResourceTypeForDiagnostics())
863 {
864 case CommandGraphResourceType::Buffer:
865 id = bufferIDCounter++;
866 break;
867 case CommandGraphResourceType::Framebuffer:
868 id = framebufferIDCounter++;
869 break;
870 case CommandGraphResourceType::Image:
871 id = imageIDCounter++;
872 break;
873 case CommandGraphResourceType::Query:
874 id = queryIDCounter++;
875 break;
876 default:
877 UNREACHABLE();
878 break;
879 }
880
881 objectIDMap[node->getResourceIDForDiagnostics()] = id;
882 strstr << id;
883 }
Jamie Madill0da73fe2018-10-02 09:31:39 -0400884 }
885
886 const std::string &label = strstr.str();
887 out << " " << nodeID << "[label =<" << label << "<BR/> <FONT POINT-SIZE=\"10\">Node ID "
888 << nodeID << "</FONT>>];" << std::endl;
889 }
890
891 for (const CommandGraphNode *node : mNodes)
892 {
893 int nodeID = nodeIDMap[node];
894
895 for (const CommandGraphNode *parent : node->getParentsForDiagnostics())
896 {
897 int parentID = nodeIDMap[parent];
898 out << " " << parentID << " -> " << nodeID << ";" << std::endl;
899 }
900 }
901
902 out << "}" << std::endl;
903}
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400904
905CommandGraphNode *CommandGraph::getLastBarrierNode(size_t *indexOut)
906{
907 *indexOut = mLastBarrierIndex == kInvalidNodeIndex ? 0 : mLastBarrierIndex;
908 return mLastBarrierIndex == kInvalidNodeIndex ? nullptr : mNodes[mLastBarrierIndex];
909}
910
911void CommandGraph::addDependenciesToNextBarrier(size_t begin,
912 size_t end,
913 CommandGraphNode *nextBarrier)
914{
915 for (size_t i = begin; i < end; ++i)
916 {
917 // As a small optimization, only add edges to childless nodes. The others have an
918 // indirect dependency.
919 if (!mNodes[i]->hasChildren())
920 {
921 CommandGraphNode::SetHappensBeforeDependency(mNodes[i], nextBarrier);
922 }
923 }
924}
925
Jamie Madill1f46bc12018-02-20 16:09:43 -0500926} // namespace vk
927} // namespace rx