blob: 4fb85c661361b8d4fdf7bfb35f7dfd3c846207f6 [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{
Tobin Ehlis134425c2019-03-15 17:02:17 -060028ANGLE_MAYBE_UNUSED
Jamie Madill21061022018-07-12 23:56:30 -040029angle::Result InitAndBeginCommandBuffer(vk::Context *context,
30 const CommandPool &commandPool,
31 const VkCommandBufferInheritanceInfo &inheritanceInfo,
32 VkCommandBufferUsageFlags flags,
Tobin Ehlis134425c2019-03-15 17:02:17 -060033 angle::PoolAllocator *poolAllocator,
34 SecondaryCommandBuffer *commandBuffer)
35{
36 ASSERT(!commandBuffer->valid());
37 commandBuffer->initialize(poolAllocator);
38 return angle::Result::Continue;
39}
40
41ANGLE_MAYBE_UNUSED
42angle::Result InitAndBeginCommandBuffer(vk::Context *context,
43 const CommandPool &commandPool,
44 const VkCommandBufferInheritanceInfo &inheritanceInfo,
45 VkCommandBufferUsageFlags flags,
46 angle::PoolAllocator *poolAllocator,
Jamie Madill21061022018-07-12 23:56:30 -040047 CommandBuffer *commandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -050048{
49 ASSERT(!commandBuffer->valid());
Shahbaz Youssefi06270c92018-10-03 17:00:25 -040050 VkCommandBufferAllocateInfo createInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -050051 createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
52 createInfo.commandPool = commandPool.getHandle();
53 createInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
54 createInfo.commandBufferCount = 1;
Jamie Madill1f46bc12018-02-20 16:09:43 -050055
Yuly Novikov27780292018-11-09 11:19:49 -050056 ANGLE_VK_TRY(context, commandBuffer->init(context->getDevice(), createInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -050057
Shahbaz Youssefi06270c92018-10-03 17:00:25 -040058 VkCommandBufferBeginInfo beginInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -050059 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
60 beginInfo.flags = flags | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
61 beginInfo.pInheritanceInfo = &inheritanceInfo;
Jamie Madill1f46bc12018-02-20 16:09:43 -050062
Yuly Novikov27780292018-11-09 11:19:49 -050063 ANGLE_VK_TRY(context, commandBuffer->begin(beginInfo));
Jamie Madill7c985f52018-11-29 18:16:17 -050064 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -050065}
66
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040067const char *GetResourceTypeName(CommandGraphResourceType resourceType,
68 CommandGraphNodeFunction function)
Jamie Madill0da73fe2018-10-02 09:31:39 -040069{
70 switch (resourceType)
71 {
72 case CommandGraphResourceType::Buffer:
73 return "Buffer";
74 case CommandGraphResourceType::Framebuffer:
75 return "Framebuffer";
76 case CommandGraphResourceType::Image:
77 return "Image";
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -040078 case CommandGraphResourceType::Query:
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040079 switch (function)
80 {
81 case CommandGraphNodeFunction::BeginQuery:
82 return "BeginQuery";
83 case CommandGraphNodeFunction::EndQuery:
84 return "EndQuery";
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -040085 case CommandGraphNodeFunction::WriteTimestamp:
86 return "WriteTimestamp";
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040087 default:
88 UNREACHABLE();
89 return "Query";
90 }
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -050091 case CommandGraphResourceType::FenceSync:
92 switch (function)
93 {
94 case CommandGraphNodeFunction::SetFenceSync:
95 return "SetFenceSync";
96 case CommandGraphNodeFunction::WaitFenceSync:
97 return "WaitFenceSync";
98 default:
99 UNREACHABLE();
100 return "FenceSync";
101 }
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000102 case CommandGraphResourceType::DebugMarker:
103 switch (function)
104 {
105 case CommandGraphNodeFunction::InsertDebugMarker:
106 return "InsertDebugMarker";
107 case CommandGraphNodeFunction::PushDebugMarker:
108 return "PushDebugMarker";
109 case CommandGraphNodeFunction::PopDebugMarker:
110 return "PopDebugMarker";
111 default:
112 UNREACHABLE();
113 return "DebugMarker";
114 }
Jamie Madill0da73fe2018-10-02 09:31:39 -0400115 default:
116 UNREACHABLE();
117 return "";
118 }
119}
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000120
121void MakeDebugUtilsLabel(GLenum source, const char *marker, VkDebugUtilsLabelEXT *label)
122{
123 static constexpr angle::ColorF kLabelColors[6] = {
124 angle::ColorF(1.0f, 0.5f, 0.5f, 1.0f), // DEBUG_SOURCE_API
125 angle::ColorF(0.5f, 1.0f, 0.5f, 1.0f), // DEBUG_SOURCE_WINDOW_SYSTEM
126 angle::ColorF(0.5f, 0.5f, 1.0f, 1.0f), // DEBUG_SOURCE_SHADER_COMPILER
127 angle::ColorF(0.7f, 0.7f, 0.7f, 1.0f), // DEBUG_SOURCE_THIRD_PARTY
128 angle::ColorF(0.5f, 0.8f, 0.9f, 1.0f), // DEBUG_SOURCE_APPLICATION
129 angle::ColorF(0.9f, 0.8f, 0.5f, 1.0f), // DEBUG_SOURCE_OTHER
130 };
131
132 int colorIndex = source - GL_DEBUG_SOURCE_API;
133 ASSERT(colorIndex >= 0 && static_cast<size_t>(colorIndex) < ArraySize(kLabelColors));
134
135 label->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
136 label->pNext = nullptr;
137 label->pLabelName = marker;
138 kLabelColors[colorIndex].writeData(label->color);
139}
140
Tobin Ehlis134425c2019-03-15 17:02:17 -0600141#if ANGLE_USE_CUSTOM_VULKAN_CMD_BUFFERS
142static constexpr VkSubpassContents kRenderPassContents = VK_SUBPASS_CONTENTS_INLINE;
143#else
144static constexpr VkSubpassContents kRenderPassContents =
145 VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
146#endif
147
148// Helpers to unify executeCommands call based on underlying cmd buffer type
149ANGLE_MAYBE_UNUSED
150void ExecuteCommands(CommandBuffer *primCmdBuffer, SecondaryCommandBuffer *secCmdBuffer)
151{
152 secCmdBuffer->executeCommands(primCmdBuffer->getHandle());
153}
154
155ANGLE_MAYBE_UNUSED
156void ExecuteCommands(CommandBuffer *primCmdBuffer, CommandBuffer *secCmdBuffer)
157{
158 primCmdBuffer->executeCommands(1, secCmdBuffer);
159}
160
Jamie Madill1f46bc12018-02-20 16:09:43 -0500161} // anonymous namespace
162
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400163// CommandGraphResource implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -0400164CommandGraphResource::CommandGraphResource(CommandGraphResourceType resourceType)
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500165 : mCurrentWritingNode(nullptr), mResourceType(resourceType)
Jamie Madillb980c562018-11-27 11:34:27 -0500166{}
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400167
Jamie Madill316c6062018-05-29 10:49:45 -0400168CommandGraphResource::~CommandGraphResource() = default;
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400169
Jamie Madillc57ee252018-05-30 19:53:48 -0400170bool CommandGraphResource::isResourceInUse(RendererVk *renderer) const
171{
172 return renderer->isSerialInUse(mStoredQueueSerial);
173}
174
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500175angle::Result CommandGraphResource::recordCommands(Context *context,
Tobin Ehlis134425c2019-03-15 17:02:17 -0600176 CommandBufferT **commandBufferOut)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400177{
Jamie Madill21061022018-07-12 23:56:30 -0400178 updateQueueSerial(context->getRenderer()->getCurrentQueueSerial());
Jamie Madill5dca6512018-05-30 10:53:51 -0400179
Jamie Madille2d22702018-09-19 08:11:48 -0400180 if (!hasChildlessWritingNode() || hasStartedRenderPass())
Jamie Madill316c6062018-05-29 10:49:45 -0400181 {
Jamie Madill193a2842018-10-30 17:28:41 -0400182 startNewCommands(context->getRenderer());
Jamie Madille2d22702018-09-19 08:11:48 -0400183 return mCurrentWritingNode->beginOutsideRenderPassRecording(
184 context, context->getRenderer()->getCommandPool(), commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400185 }
186
Tobin Ehlis134425c2019-03-15 17:02:17 -0600187 CommandBufferT *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
Jamie Madill316c6062018-05-29 10:49:45 -0400188 if (!outsideRenderPassCommands->valid())
189 {
190 ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
Jamie Madill21061022018-07-12 23:56:30 -0400191 context, context->getRenderer()->getCommandPool(), commandBufferOut));
Jamie Madill316c6062018-05-29 10:49:45 -0400192 }
193 else
194 {
195 *commandBufferOut = outsideRenderPassCommands;
196 }
197
Jamie Madill7c985f52018-11-29 18:16:17 -0500198 return angle::Result::Continue;
Jamie Madill316c6062018-05-29 10:49:45 -0400199}
200
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500201const gl::Rectangle &CommandGraphResource::getRenderPassRenderArea() const
Jamie Madill316c6062018-05-29 10:49:45 -0400202{
203 ASSERT(hasStartedRenderPass());
204 return mCurrentWritingNode->getRenderPassRenderArea();
205}
206
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500207angle::Result CommandGraphResource::beginRenderPass(ContextVk *contextVk,
208 const Framebuffer &framebuffer,
209 const gl::Rectangle &renderArea,
210 const RenderPassDesc &renderPassDesc,
211 const std::vector<VkClearValue> &clearValues,
Tobin Ehlis134425c2019-03-15 17:02:17 -0600212 CommandBufferT **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400213{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400214 // If a barrier has been inserted in the meantime, stop the command buffer.
215 if (!hasChildlessWritingNode())
216 {
Jamie Madill85ca1892019-01-16 13:27:15 -0500217 startNewCommands(contextVk->getRenderer());
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400218 }
219
Jamie Madill316c6062018-05-29 10:49:45 -0400220 // Hard-code RenderPass to clear the first render target to the current clear value.
221 // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
222 mCurrentWritingNode->storeRenderPassInfo(framebuffer, renderArea, renderPassDesc, clearValues);
223
Jamie Madill85ca1892019-01-16 13:27:15 -0500224 mCurrentWritingNode->setCommandBufferOwner(contextVk);
225
226 return mCurrentWritingNode->beginInsideRenderPassRecording(contextVk, commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400227}
228
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500229void CommandGraphResource::addWriteDependency(CommandGraphResource *writingResource)
Jamie Madill316c6062018-05-29 10:49:45 -0400230{
231 CommandGraphNode *writingNode = writingResource->mCurrentWritingNode;
232 ASSERT(writingNode);
233
Jamie Madillc57ee252018-05-30 19:53:48 -0400234 onWriteImpl(writingNode, writingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400235}
236
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500237void CommandGraphResource::addReadDependency(CommandGraphResource *readingResource)
Jamie Madill193a2842018-10-30 17:28:41 -0400238{
239 updateQueueSerial(readingResource->getStoredQueueSerial());
240
241 CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
242 ASSERT(readingNode);
243
Shahbaz Youssefib5ba5492019-01-02 15:19:22 -0500244 if (mCurrentWritingNode)
Jamie Madill193a2842018-10-30 17:28:41 -0400245 {
246 // Ensure 'readingNode' happens after the current writing node.
247 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
248 }
249
250 // Add the read node to the list of nodes currently reading this resource.
251 mCurrentReadingNodes.push_back(readingNode);
252}
253
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500254void CommandGraphResource::finishCurrentCommands(RendererVk *renderer)
Jamie Madill193a2842018-10-30 17:28:41 -0400255{
256 startNewCommands(renderer);
257}
258
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500259void CommandGraphResource::startNewCommands(RendererVk *renderer)
Jamie Madill193a2842018-10-30 17:28:41 -0400260{
261 CommandGraphNode *newCommands =
262 renderer->getCommandGraph()->allocateNode(CommandGraphNodeFunction::Generic);
263 newCommands->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
264 onWriteImpl(newCommands, renderer->getCurrentQueueSerial());
265}
266
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500267void CommandGraphResource::onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial)
Jamie Madill316c6062018-05-29 10:49:45 -0400268{
269 updateQueueSerial(currentSerial);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400270
Jamie Madill9cceac42018-03-31 14:19:16 -0400271 // Make sure any open reads and writes finish before we execute 'writingNode'.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400272 if (!mCurrentReadingNodes.empty())
273 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400274 CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes.data(),
275 mCurrentReadingNodes.size(), writingNode);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400276 mCurrentReadingNodes.clear();
277 }
278
279 if (mCurrentWritingNode && mCurrentWritingNode != writingNode)
280 {
281 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, writingNode);
282 }
283
284 mCurrentWritingNode = writingNode;
285}
286
Jamie Madill1f46bc12018-02-20 16:09:43 -0500287// CommandGraphNode implementation.
Tobin Ehlis134425c2019-03-15 17:02:17 -0600288CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function,
289 angle::PoolAllocator *poolAllocator)
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400290 : mRenderPassClearValues{},
291 mFunction(function),
Tobin Ehlis134425c2019-03-15 17:02:17 -0600292 mPoolAllocator(poolAllocator),
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400293 mQueryPool(VK_NULL_HANDLE),
294 mQueryIndex(0),
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500295 mFenceSyncEvent(VK_NULL_HANDLE),
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400296 mHasChildren(false),
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500297 mVisitedState(VisitedState::Unvisited),
298 mGlobalMemoryBarrierSrcAccess(0),
Jamie Madill85ca1892019-01-16 13:27:15 -0500299 mGlobalMemoryBarrierDstAccess(0),
300 mCommandBufferOwner(nullptr)
Jamie Madillb980c562018-11-27 11:34:27 -0500301{}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500302
303CommandGraphNode::~CommandGraphNode()
304{
305 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
306
307 // Command buffers are managed by the command pool, so don't need to be freed.
308 mOutsideRenderPassCommands.releaseHandle();
309 mInsideRenderPassCommands.releaseHandle();
310}
311
Jamie Madill21061022018-07-12 23:56:30 -0400312angle::Result CommandGraphNode::beginOutsideRenderPassRecording(Context *context,
313 const CommandPool &commandPool,
Tobin Ehlis134425c2019-03-15 17:02:17 -0600314 CommandBufferT **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500315{
316 ASSERT(!mHasChildren);
317
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400318 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500319 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
320 inheritanceInfo.renderPass = VK_NULL_HANDLE;
321 inheritanceInfo.subpass = 0;
322 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400323 inheritanceInfo.occlusionQueryEnable =
324 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500325 inheritanceInfo.queryFlags = 0;
326 inheritanceInfo.pipelineStatistics = 0;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500327
Tobin Ehlis134425c2019-03-15 17:02:17 -0600328 ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0, mPoolAllocator,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500329 &mOutsideRenderPassCommands));
330
331 *commandsOut = &mOutsideRenderPassCommands;
Jamie Madill7c985f52018-11-29 18:16:17 -0500332 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500333}
334
Jamie Madill21061022018-07-12 23:56:30 -0400335angle::Result CommandGraphNode::beginInsideRenderPassRecording(Context *context,
Tobin Ehlis134425c2019-03-15 17:02:17 -0600336 CommandBufferT **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500337{
338 ASSERT(!mHasChildren);
339
340 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400341 // TODO(jmadill): Support query for compatible/conformant render pass. http://anglebug.com/2361
Jamie Madill1f46bc12018-02-20 16:09:43 -0500342 RenderPass *compatibleRenderPass;
Jamie Madill21061022018-07-12 23:56:30 -0400343 ANGLE_TRY(context->getRenderer()->getCompatibleRenderPass(context, mRenderPassDesc,
344 &compatibleRenderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500345
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400346 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500347 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
348 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
349 inheritanceInfo.subpass = 0;
350 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400351 inheritanceInfo.occlusionQueryEnable =
352 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500353 inheritanceInfo.queryFlags = 0;
354 inheritanceInfo.pipelineStatistics = 0;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500355
Tobin Ehlis134425c2019-03-15 17:02:17 -0600356 ANGLE_TRY(InitAndBeginCommandBuffer(context, context->getRenderer()->getCommandPool(),
357 inheritanceInfo,
358 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT,
359 mPoolAllocator, &mInsideRenderPassCommands));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500360
361 *commandsOut = &mInsideRenderPassCommands;
Jamie Madill7c985f52018-11-29 18:16:17 -0500362 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500363}
364
365void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
366 const gl::Rectangle renderArea,
Jamie Madillbcf467f2018-05-23 09:46:00 -0400367 const vk::RenderPassDesc &renderPassDesc,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500368 const std::vector<VkClearValue> &clearValues)
369{
Jamie Madillbcf467f2018-05-23 09:46:00 -0400370 mRenderPassDesc = renderPassDesc;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500371 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
372 mRenderPassRenderArea = renderArea;
373 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
374}
375
Jamie Madill1f46bc12018-02-20 16:09:43 -0500376// static
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400377void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode **beforeNodes,
378 size_t beforeNodesCount,
379 CommandGraphNode *afterNode)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500380{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400381 afterNode->mParents.insert(afterNode->mParents.end(), beforeNodes,
382 beforeNodes + beforeNodesCount);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500383
384 // TODO(jmadill): is there a faster way to do this?
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400385 for (size_t i = 0; i < beforeNodesCount; ++i)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500386 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400387 beforeNodes[i]->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500388
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400389 ASSERT(beforeNodes[i] != afterNode && !beforeNodes[i]->isChildOf(afterNode));
390 }
391}
392
393void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode *beforeNode,
394 CommandGraphNode **afterNodes,
395 size_t afterNodesCount)
396{
397 for (size_t i = 0; i < afterNodesCount; ++i)
398 {
399 SetHappensBeforeDependency(beforeNode, afterNodes[i]);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500400 }
401}
402
403bool CommandGraphNode::hasParents() const
404{
405 return !mParents.empty();
406}
407
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400408void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIndex)
409{
410 ASSERT(mFunction == CommandGraphNodeFunction::BeginQuery ||
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400411 mFunction == CommandGraphNodeFunction::EndQuery ||
412 mFunction == CommandGraphNodeFunction::WriteTimestamp);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400413 mQueryPool = queryPool->getHandle();
414 mQueryIndex = queryIndex;
415}
416
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500417void CommandGraphNode::setFenceSync(const vk::Event &event)
418{
419 ASSERT(mFunction == CommandGraphNodeFunction::SetFenceSync ||
420 mFunction == CommandGraphNodeFunction::WaitFenceSync);
421 mFenceSyncEvent = event.getHandle();
422}
423
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000424void CommandGraphNode::setDebugMarker(GLenum source, std::string &&marker)
425{
426 ASSERT(mFunction == CommandGraphNodeFunction::InsertDebugMarker ||
427 mFunction == CommandGraphNodeFunction::PushDebugMarker);
428 mDebugMarkerSource = source;
429 mDebugMarker = std::move(marker);
430}
431
Jamie Madill1f46bc12018-02-20 16:09:43 -0500432// Do not call this in anything but testing code, since it's slow.
433bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
434{
435 std::set<CommandGraphNode *> visitedList;
436 std::vector<CommandGraphNode *> openList;
437 openList.insert(openList.begin(), mParents.begin(), mParents.end());
438 while (!openList.empty())
439 {
440 CommandGraphNode *current = openList.back();
441 openList.pop_back();
442 if (visitedList.count(current) == 0)
443 {
444 if (current == parent)
445 {
446 return true;
447 }
448 visitedList.insert(current);
449 openList.insert(openList.end(), current->mParents.begin(), current->mParents.end());
450 }
451 }
452
453 return false;
454}
455
456VisitedState CommandGraphNode::visitedState() const
457{
458 return mVisitedState;
459}
460
461void CommandGraphNode::visitParents(std::vector<CommandGraphNode *> *stack)
462{
463 ASSERT(mVisitedState == VisitedState::Unvisited);
464 stack->insert(stack->end(), mParents.begin(), mParents.end());
465 mVisitedState = VisitedState::Ready;
466}
467
Jamie Madill21061022018-07-12 23:56:30 -0400468angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
469 Serial serial,
470 RenderPassCache *renderPassCache,
471 CommandBuffer *primaryCommandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500472{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400473 switch (mFunction)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500474 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400475 case CommandGraphNodeFunction::Generic:
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500476 ASSERT(mQueryPool == VK_NULL_HANDLE && mFenceSyncEvent == VK_NULL_HANDLE);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500477
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500478 // Record the deferred pipeline barrier if necessary.
479 ASSERT((mGlobalMemoryBarrierDstAccess == 0) == (mGlobalMemoryBarrierSrcAccess == 0));
480 if (mGlobalMemoryBarrierSrcAccess)
481 {
482 VkMemoryBarrier memoryBarrier = {};
483 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
484 memoryBarrier.srcAccessMask = mGlobalMemoryBarrierSrcAccess;
485 memoryBarrier.dstAccessMask = mGlobalMemoryBarrierDstAccess;
486
Shahbaz Youssefi471358f2018-11-28 15:21:55 -0500487 // Use the all pipe stage to keep the state management simple.
488 primaryCommandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
489 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1,
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500490 &memoryBarrier, 0, nullptr, 0, nullptr);
491 }
492
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400493 if (mOutsideRenderPassCommands.valid())
494 {
Yuly Novikov27780292018-11-09 11:19:49 -0500495 ANGLE_VK_TRY(context, mOutsideRenderPassCommands.end());
Tobin Ehlis134425c2019-03-15 17:02:17 -0600496 ExecuteCommands(primaryCommandBuffer, &mOutsideRenderPassCommands);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400497 }
Jamie Madill1f46bc12018-02-20 16:09:43 -0500498
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400499 if (mInsideRenderPassCommands.valid())
500 {
501 // Pull a compatible RenderPass from the cache.
502 // TODO(jmadill): Insert real ops and layout transitions.
503 RenderPass *renderPass = nullptr;
504 ANGLE_TRY(renderPassCache->getCompatibleRenderPass(context, serial, mRenderPassDesc,
505 &renderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500506
Yuly Novikov27780292018-11-09 11:19:49 -0500507 ANGLE_VK_TRY(context, mInsideRenderPassCommands.end());
Jamie Madill1f46bc12018-02-20 16:09:43 -0500508
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400509 VkRenderPassBeginInfo beginInfo = {};
510 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
511 beginInfo.renderPass = renderPass->getHandle();
512 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
513 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
514 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
515 beginInfo.renderArea.extent.width =
516 static_cast<uint32_t>(mRenderPassRenderArea.width);
517 beginInfo.renderArea.extent.height =
518 static_cast<uint32_t>(mRenderPassRenderArea.height);
519 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
520 beginInfo.pClearValues = mRenderPassClearValues.data();
521
Tobin Ehlis134425c2019-03-15 17:02:17 -0600522 primaryCommandBuffer->beginRenderPass(beginInfo, kRenderPassContents);
523 ExecuteCommands(primaryCommandBuffer, &mInsideRenderPassCommands);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400524 primaryCommandBuffer->endRenderPass();
525 }
526 break;
527
528 case CommandGraphNodeFunction::BeginQuery:
529 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
530 ASSERT(mQueryPool != VK_NULL_HANDLE);
531
532 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
533 primaryCommandBuffer->beginQuery(mQueryPool, mQueryIndex, 0);
534
535 break;
536
537 case CommandGraphNodeFunction::EndQuery:
538 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
539 ASSERT(mQueryPool != VK_NULL_HANDLE);
540
541 primaryCommandBuffer->endQuery(mQueryPool, mQueryIndex);
542
543 break;
544
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400545 case CommandGraphNodeFunction::WriteTimestamp:
546 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
547 ASSERT(mQueryPool != VK_NULL_HANDLE);
548
549 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
550 primaryCommandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, mQueryPool,
551 mQueryIndex);
552
553 break;
554
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500555 case CommandGraphNodeFunction::SetFenceSync:
556 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
557 ASSERT(mFenceSyncEvent != VK_NULL_HANDLE);
558
559 primaryCommandBuffer->setEvent(mFenceSyncEvent, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
560
561 break;
562
563 case CommandGraphNodeFunction::WaitFenceSync:
564 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
565 ASSERT(mFenceSyncEvent != VK_NULL_HANDLE);
566
567 // Fence Syncs are purely execution barriers, so there are no memory barriers attached.
568 primaryCommandBuffer->waitEvents(
569 1, &mFenceSyncEvent, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
570 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, nullptr, 0, nullptr, 0, nullptr);
571
572 break;
573
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000574 case CommandGraphNodeFunction::InsertDebugMarker:
575 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
576
577 if (vkCmdInsertDebugUtilsLabelEXT)
578 {
579 VkDebugUtilsLabelEXT label;
580 MakeDebugUtilsLabel(mDebugMarkerSource, mDebugMarker.c_str(), &label);
581
582 vkCmdInsertDebugUtilsLabelEXT(primaryCommandBuffer->getHandle(), &label);
583 }
584 break;
585
586 case CommandGraphNodeFunction::PushDebugMarker:
587 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
588
589 if (vkCmdBeginDebugUtilsLabelEXT)
590 {
591 VkDebugUtilsLabelEXT label;
592 MakeDebugUtilsLabel(mDebugMarkerSource, mDebugMarker.c_str(), &label);
593
594 vkCmdBeginDebugUtilsLabelEXT(primaryCommandBuffer->getHandle(), &label);
595 }
596 break;
597
598 case CommandGraphNodeFunction::PopDebugMarker:
599 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
600
601 if (vkCmdEndDebugUtilsLabelEXT)
602 {
603 vkCmdEndDebugUtilsLabelEXT(primaryCommandBuffer->getHandle());
604 }
605 break;
606
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400607 default:
608 UNREACHABLE();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500609 }
610
611 mVisitedState = VisitedState::Visited;
Jamie Madill7c985f52018-11-29 18:16:17 -0500612 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500613}
614
Jamie Madill0da73fe2018-10-02 09:31:39 -0400615const std::vector<CommandGraphNode *> &CommandGraphNode::getParentsForDiagnostics() const
616{
617 return mParents;
618}
619
620void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType,
621 uintptr_t resourceID)
622{
623 mResourceType = resourceType;
624 mResourceID = resourceID;
625}
626
Luc Ferron14f48172018-04-11 08:43:28 -0400627const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
628{
629 return mRenderPassRenderArea;
630}
631
Jamie Madill1f46bc12018-02-20 16:09:43 -0500632// CommandGraph implementation.
Tobin Ehlis134425c2019-03-15 17:02:17 -0600633CommandGraph::CommandGraph(bool enableGraphDiagnostics, angle::PoolAllocator *poolAllocator)
634 : mEnableGraphDiagnostics(enableGraphDiagnostics),
635 mPoolAllocator(poolAllocator),
636 mLastBarrierIndex(kInvalidNodeIndex)
Jamie Madillb980c562018-11-27 11:34:27 -0500637{}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500638
639CommandGraph::~CommandGraph()
640{
641 ASSERT(empty());
642}
643
Jamie Madill193a2842018-10-30 17:28:41 -0400644CommandGraphNode *CommandGraph::allocateNode(CommandGraphNodeFunction function)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500645{
646 // TODO(jmadill): Use a pool allocator for the CPU node allocations.
Tobin Ehlis134425c2019-03-15 17:02:17 -0600647 CommandGraphNode *newCommands = new CommandGraphNode(function, mPoolAllocator);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500648 mNodes.emplace_back(newCommands);
649 return newCommands;
650}
651
Shahbaz Youssefide52ca32019-03-13 14:23:30 -0400652CommandGraphNode *CommandGraph::allocateBarrierNode(CommandGraphNodeFunction function,
653 CommandGraphResourceType resourceType,
654 uintptr_t resourceID)
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500655{
656 CommandGraphNode *newNode = allocateNode(function);
Shahbaz Youssefide52ca32019-03-13 14:23:30 -0400657 newNode->setDiagnosticInfo(resourceType, resourceID);
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500658 setNewBarrier(newNode);
659
660 return newNode;
661}
662
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400663void CommandGraph::setNewBarrier(CommandGraphNode *newBarrier)
664{
665 size_t previousBarrierIndex = 0;
666 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
667
Shahbaz Youssefi2fb65632019-03-13 15:29:13 -0400668 // Add a dependency from previousBarrier to all nodes in (previousBarrier, newBarrier).
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400669 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
670 {
Shahbaz Youssefi2fb65632019-03-13 15:29:13 -0400671 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 2);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400672 CommandGraphNode::SetHappensBeforeDependencies(
673 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
674 }
675
Shahbaz Youssefi2fb65632019-03-13 15:29:13 -0400676 // Add a dependency from all nodes in [previousBarrier, newBarrier) to newBarrier.
677 addDependenciesToNextBarrier(previousBarrierIndex, mNodes.size() - 1, newBarrier);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400678
679 mLastBarrierIndex = mNodes.size() - 1;
680}
681
Jamie Madill21061022018-07-12 23:56:30 -0400682angle::Result CommandGraph::submitCommands(Context *context,
683 Serial serial,
684 RenderPassCache *renderPassCache,
685 CommandPool *commandPool,
686 CommandBuffer *primaryCommandBufferOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500687{
Shahbaz Youssefi3a482172018-10-11 10:34:44 -0400688 // There is no point in submitting an empty command buffer, so make sure not to call this
689 // function if there's nothing to do.
690 ASSERT(!mNodes.empty());
691
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400692 size_t previousBarrierIndex = 0;
693 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
694
695 // Add a dependency from previousBarrier to all nodes in (previousBarrier, end].
696 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
697 {
698 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
699 CommandGraphNode::SetHappensBeforeDependencies(
700 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
701 }
702
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400703 VkCommandBufferAllocateInfo primaryInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500704 primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
705 primaryInfo.commandPool = commandPool->getHandle();
706 primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
707 primaryInfo.commandBufferCount = 1;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500708
Yuly Novikov27780292018-11-09 11:19:49 -0500709 ANGLE_VK_TRY(context, primaryCommandBufferOut->init(context->getDevice(), primaryInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500710
Jamie Madill0da73fe2018-10-02 09:31:39 -0400711 if (mEnableGraphDiagnostics)
712 {
713 dumpGraphDotFile(std::cout);
714 }
715
Jamie Madill1f46bc12018-02-20 16:09:43 -0500716 std::vector<CommandGraphNode *> nodeStack;
717
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400718 VkCommandBufferBeginInfo beginInfo = {};
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400719 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
720 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
721 beginInfo.pInheritanceInfo = nullptr;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500722
Yuly Novikov27780292018-11-09 11:19:49 -0500723 ANGLE_VK_TRY(context, primaryCommandBufferOut->begin(beginInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500724
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400725 ANGLE_TRY(context->getRenderer()->traceGpuEvent(
726 context, primaryCommandBufferOut, TRACE_EVENT_PHASE_BEGIN, "Primary Command Buffer"));
727
Jamie Madill1f46bc12018-02-20 16:09:43 -0500728 for (CommandGraphNode *topLevelNode : mNodes)
729 {
730 // Only process commands that don't have child commands. The others will be pulled in
731 // automatically. Also skip commands that have already been visited.
732 if (topLevelNode->hasChildren() || topLevelNode->visitedState() != VisitedState::Unvisited)
733 continue;
734
735 nodeStack.push_back(topLevelNode);
736
737 while (!nodeStack.empty())
738 {
739 CommandGraphNode *node = nodeStack.back();
740
741 switch (node->visitedState())
742 {
743 case VisitedState::Unvisited:
744 node->visitParents(&nodeStack);
745 break;
746 case VisitedState::Ready:
Jamie Madill21061022018-07-12 23:56:30 -0400747 ANGLE_TRY(node->visitAndExecute(context, serial, renderPassCache,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500748 primaryCommandBufferOut));
749 nodeStack.pop_back();
750 break;
751 case VisitedState::Visited:
752 nodeStack.pop_back();
753 break;
754 default:
755 UNREACHABLE();
756 break;
757 }
758 }
759 }
760
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400761 ANGLE_TRY(context->getRenderer()->traceGpuEvent(
762 context, primaryCommandBufferOut, TRACE_EVENT_PHASE_END, "Primary Command Buffer"));
763
Yuly Novikov27780292018-11-09 11:19:49 -0500764 ANGLE_VK_TRY(context, primaryCommandBufferOut->end());
Jamie Madill1f46bc12018-02-20 16:09:43 -0500765
Yuly Novikovb56ddbb2018-11-02 16:53:18 -0400766 clear();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500767
Jamie Madill7c985f52018-11-29 18:16:17 -0500768 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500769}
770
771bool CommandGraph::empty() const
772{
773 return mNodes.empty();
774}
775
Yuly Novikovb56ddbb2018-11-02 16:53:18 -0400776void CommandGraph::clear()
777{
778 mLastBarrierIndex = kInvalidNodeIndex;
779
780 // TODO(jmadill): Use pool allocator for performance. http://anglebug.com/2951
781 for (CommandGraphNode *node : mNodes)
782 {
783 delete node;
784 }
785 mNodes.clear();
786}
787
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500788void CommandGraph::beginQuery(const QueryPool *queryPool, uint32_t queryIndex)
789{
Shahbaz Youssefide52ca32019-03-13 14:23:30 -0400790 CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::BeginQuery,
791 CommandGraphResourceType::Query, 0);
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500792 newNode->setQueryPool(queryPool, queryIndex);
793}
794
795void CommandGraph::endQuery(const QueryPool *queryPool, uint32_t queryIndex)
796{
797 CommandGraphNode *newNode =
Shahbaz Youssefide52ca32019-03-13 14:23:30 -0400798 allocateBarrierNode(CommandGraphNodeFunction::EndQuery, CommandGraphResourceType::Query, 0);
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500799 newNode->setQueryPool(queryPool, queryIndex);
800}
801
802void CommandGraph::writeTimestamp(const QueryPool *queryPool, uint32_t queryIndex)
803{
Shahbaz Youssefide52ca32019-03-13 14:23:30 -0400804 CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::WriteTimestamp,
805 CommandGraphResourceType::Query, 0);
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500806 newNode->setQueryPool(queryPool, queryIndex);
807}
808
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500809void CommandGraph::setFenceSync(const vk::Event &event)
810{
Shahbaz Youssefide52ca32019-03-13 14:23:30 -0400811 CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::SetFenceSync,
812 CommandGraphResourceType::FenceSync,
813 reinterpret_cast<uintptr_t>(&event));
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500814 newNode->setFenceSync(event);
815}
816
817void CommandGraph::waitFenceSync(const vk::Event &event)
818{
Shahbaz Youssefide52ca32019-03-13 14:23:30 -0400819 CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::WaitFenceSync,
820 CommandGraphResourceType::FenceSync,
821 reinterpret_cast<uintptr_t>(&event));
Shahbaz Youssefi82fddcb2019-01-18 14:27:43 -0500822 newNode->setFenceSync(event);
823}
824
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000825void CommandGraph::insertDebugMarker(GLenum source, std::string &&marker)
826{
Shahbaz Youssefide52ca32019-03-13 14:23:30 -0400827 CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::InsertDebugMarker,
828 CommandGraphResourceType::DebugMarker, 0);
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000829 newNode->setDebugMarker(source, std::move(marker));
830}
831
832void CommandGraph::pushDebugMarker(GLenum source, std::string &&marker)
833{
Shahbaz Youssefide52ca32019-03-13 14:23:30 -0400834 CommandGraphNode *newNode = allocateBarrierNode(CommandGraphNodeFunction::PushDebugMarker,
835 CommandGraphResourceType::DebugMarker, 0);
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000836 newNode->setDebugMarker(source, std::move(marker));
837}
838
839void CommandGraph::popDebugMarker()
840{
Shahbaz Youssefide52ca32019-03-13 14:23:30 -0400841 allocateBarrierNode(CommandGraphNodeFunction::PopDebugMarker,
842 CommandGraphResourceType::DebugMarker, 0);
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000843}
844
Jamie Madill0da73fe2018-10-02 09:31:39 -0400845// Dumps the command graph into a dot file that works with graphviz.
846void CommandGraph::dumpGraphDotFile(std::ostream &out) const
847{
Shahbaz Youssefide52ca32019-03-13 14:23:30 -0400848 // This ID maps a node pointer to a monotonic ID. It allows us to look up parent node IDs.
Jamie Madill0da73fe2018-10-02 09:31:39 -0400849 std::map<const CommandGraphNode *, int> nodeIDMap;
850 std::map<uintptr_t, int> objectIDMap;
Shahbaz Youssefide52ca32019-03-13 14:23:30 -0400851 std::map<std::pair<VkQueryPool, uint32_t>, int> queryIDMap;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400852
853 // Map nodes to ids.
854 for (size_t nodeIndex = 0; nodeIndex < mNodes.size(); ++nodeIndex)
855 {
856 const CommandGraphNode *node = mNodes[nodeIndex];
857 nodeIDMap[node] = static_cast<int>(nodeIndex) + 1;
858 }
859
860 int bufferIDCounter = 1;
861 int framebufferIDCounter = 1;
862 int imageIDCounter = 1;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400863 int queryIDCounter = 1;
Shahbaz Youssefide52ca32019-03-13 14:23:30 -0400864 int fenceIDCounter = 1;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400865
866 out << "digraph {" << std::endl;
867
868 for (const CommandGraphNode *node : mNodes)
869 {
870 int nodeID = nodeIDMap[node];
871
872 std::stringstream strstr;
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -0400873 strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics(), node->getFunction());
Jamie Madill0da73fe2018-10-02 09:31:39 -0400874
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000875 if (node->getResourceTypeForDiagnostics() == CommandGraphResourceType::DebugMarker)
Jamie Madill0da73fe2018-10-02 09:31:39 -0400876 {
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000877 // For debug markers, use the string from the debug marker itself.
878 if (node->getFunction() != CommandGraphNodeFunction::PopDebugMarker)
879 {
880 strstr << " " << node->getDebugMarker();
881 }
Jamie Madill0da73fe2018-10-02 09:31:39 -0400882 }
Shahbaz Youssefide52ca32019-03-13 14:23:30 -0400883 else if (node->getResourceTypeForDiagnostics() == CommandGraphResourceType::Query)
884 {
885 // Special case for queries as they cannot generate a resource ID at creation time that
886 // would reliably fit in a uintptr_t.
887 strstr << " ";
888
889 ASSERT(node->getResourceIDForDiagnostics() == 0);
890
891 auto queryID = std::make_pair(node->getQueryPool(), node->getQueryIndex());
892
893 auto it = queryIDMap.find(queryID);
894 if (it != queryIDMap.end())
895 {
896 strstr << it->second;
897 }
898 else
899 {
900 int id = queryIDCounter++;
901
902 queryIDMap[queryID] = id;
903 strstr << id;
904 }
905 }
Jamie Madill0da73fe2018-10-02 09:31:39 -0400906 else
907 {
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000908 strstr << " ";
Jamie Madill0da73fe2018-10-02 09:31:39 -0400909
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000910 // Otherwise assign each object an ID, so all the nodes of the same object have the same
911 // label.
912 ASSERT(node->getResourceIDForDiagnostics() != 0);
913 auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
914 if (it != objectIDMap.end())
Jamie Madill0da73fe2018-10-02 09:31:39 -0400915 {
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000916 strstr << it->second;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400917 }
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000918 else
919 {
920 int id = 0;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400921
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000922 switch (node->getResourceTypeForDiagnostics())
923 {
924 case CommandGraphResourceType::Buffer:
925 id = bufferIDCounter++;
926 break;
927 case CommandGraphResourceType::Framebuffer:
928 id = framebufferIDCounter++;
929 break;
930 case CommandGraphResourceType::Image:
931 id = imageIDCounter++;
932 break;
Shahbaz Youssefide52ca32019-03-13 14:23:30 -0400933 case CommandGraphResourceType::FenceSync:
934 id = fenceIDCounter++;
Shahbaz Youssefi4d153382019-02-26 15:08:11 +0000935 break;
936 default:
937 UNREACHABLE();
938 break;
939 }
940
941 objectIDMap[node->getResourceIDForDiagnostics()] = id;
942 strstr << id;
943 }
Jamie Madill0da73fe2018-10-02 09:31:39 -0400944 }
945
946 const std::string &label = strstr.str();
947 out << " " << nodeID << "[label =<" << label << "<BR/> <FONT POINT-SIZE=\"10\">Node ID "
948 << nodeID << "</FONT>>];" << std::endl;
949 }
950
951 for (const CommandGraphNode *node : mNodes)
952 {
953 int nodeID = nodeIDMap[node];
954
955 for (const CommandGraphNode *parent : node->getParentsForDiagnostics())
956 {
957 int parentID = nodeIDMap[parent];
958 out << " " << parentID << " -> " << nodeID << ";" << std::endl;
959 }
960 }
961
962 out << "}" << std::endl;
963}
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400964
965CommandGraphNode *CommandGraph::getLastBarrierNode(size_t *indexOut)
966{
967 *indexOut = mLastBarrierIndex == kInvalidNodeIndex ? 0 : mLastBarrierIndex;
968 return mLastBarrierIndex == kInvalidNodeIndex ? nullptr : mNodes[mLastBarrierIndex];
969}
970
971void CommandGraph::addDependenciesToNextBarrier(size_t begin,
972 size_t end,
973 CommandGraphNode *nextBarrier)
974{
975 for (size_t i = begin; i < end; ++i)
976 {
977 // As a small optimization, only add edges to childless nodes. The others have an
978 // indirect dependency.
979 if (!mNodes[i]->hasChildren())
980 {
981 CommandGraphNode::SetHappensBeforeDependency(mNodes[i], nextBarrier);
982 }
983 }
984}
985
Jamie Madill1f46bc12018-02-20 16:09:43 -0500986} // namespace vk
987} // namespace rx