blob: bc9363c3296ab99a0a7df9b52079544c7aab5908 [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 Madill1f46bc12018-02-20 16:09:43 -050014#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
15#include "libANGLE/renderer/vulkan/RendererVk.h"
16#include "libANGLE/renderer/vulkan/vk_format_utils.h"
Jamie Madill26084d02018-04-09 13:44:04 -040017#include "libANGLE/renderer/vulkan/vk_helpers.h"
Jamie Madill1f46bc12018-02-20 16:09:43 -050018
Shahbaz Youssefi25224e72018-10-22 11:56:02 -040019#include "third_party/trace_event/trace_event.h"
20
Jamie Madill1f46bc12018-02-20 16:09:43 -050021namespace rx
22{
Jamie Madill1f46bc12018-02-20 16:09:43 -050023namespace vk
24{
Jamie Madill1f46bc12018-02-20 16:09:43 -050025namespace
26{
Jamie Madill21061022018-07-12 23:56:30 -040027angle::Result InitAndBeginCommandBuffer(vk::Context *context,
28 const CommandPool &commandPool,
29 const VkCommandBufferInheritanceInfo &inheritanceInfo,
30 VkCommandBufferUsageFlags flags,
31 CommandBuffer *commandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -050032{
33 ASSERT(!commandBuffer->valid());
34
Shahbaz Youssefi06270c92018-10-03 17:00:25 -040035 VkCommandBufferAllocateInfo createInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -050036 createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
37 createInfo.commandPool = commandPool.getHandle();
38 createInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
39 createInfo.commandBufferCount = 1;
Jamie Madill1f46bc12018-02-20 16:09:43 -050040
Jamie Madill21061022018-07-12 23:56:30 -040041 ANGLE_TRY(commandBuffer->init(context, createInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -050042
Shahbaz Youssefi06270c92018-10-03 17:00:25 -040043 VkCommandBufferBeginInfo beginInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -050044 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
45 beginInfo.flags = flags | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
46 beginInfo.pInheritanceInfo = &inheritanceInfo;
Jamie Madill1f46bc12018-02-20 16:09:43 -050047
Jamie Madill21061022018-07-12 23:56:30 -040048 ANGLE_TRY(commandBuffer->begin(context, beginInfo));
49 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -050050}
51
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040052const char *GetResourceTypeName(CommandGraphResourceType resourceType,
53 CommandGraphNodeFunction function)
Jamie Madill0da73fe2018-10-02 09:31:39 -040054{
55 switch (resourceType)
56 {
57 case CommandGraphResourceType::Buffer:
58 return "Buffer";
59 case CommandGraphResourceType::Framebuffer:
60 return "Framebuffer";
61 case CommandGraphResourceType::Image:
62 return "Image";
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -040063 case CommandGraphResourceType::Query:
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040064 switch (function)
65 {
66 case CommandGraphNodeFunction::BeginQuery:
67 return "BeginQuery";
68 case CommandGraphNodeFunction::EndQuery:
69 return "EndQuery";
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -040070 case CommandGraphNodeFunction::WriteTimestamp:
71 return "WriteTimestamp";
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040072 default:
73 UNREACHABLE();
74 return "Query";
75 }
Jamie Madill0da73fe2018-10-02 09:31:39 -040076 default:
77 UNREACHABLE();
78 return "";
79 }
80}
Jamie Madill1f46bc12018-02-20 16:09:43 -050081} // anonymous namespace
82
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040083// CommandGraphResource implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -040084CommandGraphResource::CommandGraphResource(CommandGraphResourceType resourceType)
Jamie Madill193a2842018-10-30 17:28:41 -040085 : mResourceType(resourceType), mCurrentWritingNode(nullptr)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040086{
87}
88
Jamie Madill316c6062018-05-29 10:49:45 -040089CommandGraphResource::~CommandGraphResource() = default;
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040090
Jamie Madillc57ee252018-05-30 19:53:48 -040091bool CommandGraphResource::isResourceInUse(RendererVk *renderer) const
92{
93 return renderer->isSerialInUse(mStoredQueueSerial);
94}
95
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -040096bool CommandGraphResource::hasPendingWork(RendererVk *renderer) const
97{
98 // If the renderer has a queue serial higher than the stored one, the command buffers recorded
99 // by this resource have already been submitted, so there is no pending work.
100 return mStoredQueueSerial == renderer->getCurrentQueueSerial();
101}
102
Jamie Madillc57ee252018-05-30 19:53:48 -0400103Serial CommandGraphResource::getStoredQueueSerial() const
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400104{
105 return mStoredQueueSerial;
106}
107
Jamie Madill193a2842018-10-30 17:28:41 -0400108// RecordableGraphResource implementation.
109RecordableGraphResource::RecordableGraphResource(CommandGraphResourceType resourceType)
110 : CommandGraphResource(resourceType)
111{
112}
113
114RecordableGraphResource::~RecordableGraphResource() = default;
115
116void RecordableGraphResource::updateQueueSerial(Serial queueSerial)
117{
118 ASSERT(queueSerial >= mStoredQueueSerial);
119
120 if (queueSerial > mStoredQueueSerial)
121 {
122 mCurrentWritingNode = nullptr;
123 mCurrentReadingNodes.clear();
124 mStoredQueueSerial = queueSerial;
125 }
126}
127
128angle::Result RecordableGraphResource::recordCommands(Context *context,
129 CommandBuffer **commandBufferOut)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400130{
Jamie Madill21061022018-07-12 23:56:30 -0400131 updateQueueSerial(context->getRenderer()->getCurrentQueueSerial());
Jamie Madill5dca6512018-05-30 10:53:51 -0400132
Jamie Madille2d22702018-09-19 08:11:48 -0400133 if (!hasChildlessWritingNode() || hasStartedRenderPass())
Jamie Madill316c6062018-05-29 10:49:45 -0400134 {
Jamie Madill193a2842018-10-30 17:28:41 -0400135 startNewCommands(context->getRenderer());
Jamie Madille2d22702018-09-19 08:11:48 -0400136 return mCurrentWritingNode->beginOutsideRenderPassRecording(
137 context, context->getRenderer()->getCommandPool(), commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400138 }
139
140 CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
141 if (!outsideRenderPassCommands->valid())
142 {
143 ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
Jamie Madill21061022018-07-12 23:56:30 -0400144 context, context->getRenderer()->getCommandPool(), commandBufferOut));
Jamie Madill316c6062018-05-29 10:49:45 -0400145 }
146 else
147 {
148 *commandBufferOut = outsideRenderPassCommands;
149 }
150
Jamie Madill21061022018-07-12 23:56:30 -0400151 return angle::Result::Continue();
Jamie Madill316c6062018-05-29 10:49:45 -0400152}
153
Jamie Madill193a2842018-10-30 17:28:41 -0400154bool RecordableGraphResource::appendToStartedRenderPass(RendererVk *renderer,
155 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400156{
Jamie Madill5dca6512018-05-30 10:53:51 -0400157 updateQueueSerial(renderer->getCurrentQueueSerial());
158 if (hasStartedRenderPass())
159 {
160 *commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands();
161 return true;
162 }
163 else
164 {
165 return false;
166 }
Jamie Madill316c6062018-05-29 10:49:45 -0400167}
168
Jamie Madill193a2842018-10-30 17:28:41 -0400169const gl::Rectangle &RecordableGraphResource::getRenderPassRenderArea() const
Jamie Madill316c6062018-05-29 10:49:45 -0400170{
171 ASSERT(hasStartedRenderPass());
172 return mCurrentWritingNode->getRenderPassRenderArea();
173}
174
Jamie Madill193a2842018-10-30 17:28:41 -0400175angle::Result RecordableGraphResource::beginRenderPass(Context *context,
176 const Framebuffer &framebuffer,
177 const gl::Rectangle &renderArea,
178 const RenderPassDesc &renderPassDesc,
179 const std::vector<VkClearValue> &clearValues,
180 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400181{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400182 // If a barrier has been inserted in the meantime, stop the command buffer.
183 if (!hasChildlessWritingNode())
184 {
Jamie Madill193a2842018-10-30 17:28:41 -0400185 startNewCommands(context->getRenderer());
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400186 }
187
Jamie Madill316c6062018-05-29 10:49:45 -0400188 // Hard-code RenderPass to clear the first render target to the current clear value.
189 // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
190 mCurrentWritingNode->storeRenderPassInfo(framebuffer, renderArea, renderPassDesc, clearValues);
191
Jamie Madill21061022018-07-12 23:56:30 -0400192 return mCurrentWritingNode->beginInsideRenderPassRecording(context, commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400193}
194
Jamie Madill193a2842018-10-30 17:28:41 -0400195void RecordableGraphResource::addWriteDependency(RecordableGraphResource *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
Jamie Madill193a2842018-10-30 17:28:41 -0400203void RecordableGraphResource::addReadDependency(RecordableGraphResource *readingResource)
204{
205 updateQueueSerial(readingResource->getStoredQueueSerial());
206
207 CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
208 ASSERT(readingNode);
209
210 if (hasChildlessWritingNode())
211 {
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
220void RecordableGraphResource::finishCurrentCommands(RendererVk *renderer)
221{
222 startNewCommands(renderer);
223}
224
225void RecordableGraphResource::startNewCommands(RendererVk *renderer)
226{
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
233void RecordableGraphResource::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 Madill193a2842018-10-30 17:28:41 -0400253// QueryGraphResource implementation.
254QueryGraphResource::QueryGraphResource() : CommandGraphResource(CommandGraphResourceType::Query)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400255{
Jamie Madill193a2842018-10-30 17:28:41 -0400256}
Jamie Madill316c6062018-05-29 10:49:45 -0400257
Jamie Madill193a2842018-10-30 17:28:41 -0400258QueryGraphResource::~QueryGraphResource() = default;
Jamie Madill9cceac42018-03-31 14:19:16 -0400259
Jamie Madill193a2842018-10-30 17:28:41 -0400260void QueryGraphResource::beginQuery(Context *context,
261 const QueryPool *queryPool,
262 uint32_t queryIndex)
263{
264 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::BeginQuery);
265 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
266}
Jamie Madill9cceac42018-03-31 14:19:16 -0400267
Jamie Madill193a2842018-10-30 17:28:41 -0400268void QueryGraphResource::endQuery(Context *context, const QueryPool *queryPool, uint32_t queryIndex)
269{
270 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::EndQuery);
271 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
272}
273
274void QueryGraphResource::writeTimestamp(Context *context,
275 const QueryPool *queryPool,
276 uint32_t queryIndex)
277{
278 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::WriteTimestamp);
279 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
280}
281
282void QueryGraphResource::startNewCommands(RendererVk *renderer, CommandGraphNodeFunction function)
283{
284 CommandGraph *commandGraph = renderer->getCommandGraph();
285 CommandGraphNode *newNode = commandGraph->allocateNode(function);
286 newNode->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
287 commandGraph->setNewBarrier(newNode);
288
289 mStoredQueueSerial = renderer->getCurrentQueueSerial();
290 mCurrentWritingNode = newNode;
Jamie Madill9cceac42018-03-31 14:19:16 -0400291}
292
Jamie Madill1f46bc12018-02-20 16:09:43 -0500293// CommandGraphNode implementation.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400294CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function)
295 : mRenderPassClearValues{},
296 mFunction(function),
297 mQueryPool(VK_NULL_HANDLE),
298 mQueryIndex(0),
299 mHasChildren(false),
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500300 mVisitedState(VisitedState::Unvisited),
301 mGlobalMemoryBarrierSrcAccess(0),
302 mGlobalMemoryBarrierDstAccess(0)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500303{
304}
305
306CommandGraphNode::~CommandGraphNode()
307{
308 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
309
310 // Command buffers are managed by the command pool, so don't need to be freed.
311 mOutsideRenderPassCommands.releaseHandle();
312 mInsideRenderPassCommands.releaseHandle();
313}
314
315CommandBuffer *CommandGraphNode::getOutsideRenderPassCommands()
316{
317 ASSERT(!mHasChildren);
318 return &mOutsideRenderPassCommands;
319}
320
Jamie Madill21061022018-07-12 23:56:30 -0400321angle::Result CommandGraphNode::beginOutsideRenderPassRecording(Context *context,
322 const CommandPool &commandPool,
323 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500324{
325 ASSERT(!mHasChildren);
326
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400327 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500328 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
329 inheritanceInfo.renderPass = VK_NULL_HANDLE;
330 inheritanceInfo.subpass = 0;
331 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400332 inheritanceInfo.occlusionQueryEnable =
333 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500334 inheritanceInfo.queryFlags = 0;
335 inheritanceInfo.pipelineStatistics = 0;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500336
Jamie Madill21061022018-07-12 23:56:30 -0400337 ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500338 &mOutsideRenderPassCommands));
339
340 *commandsOut = &mOutsideRenderPassCommands;
Jamie Madill21061022018-07-12 23:56:30 -0400341 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500342}
343
Jamie Madill21061022018-07-12 23:56:30 -0400344angle::Result CommandGraphNode::beginInsideRenderPassRecording(Context *context,
345 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500346{
347 ASSERT(!mHasChildren);
348
349 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400350 // TODO(jmadill): Support query for compatible/conformant render pass. http://anglebug.com/2361
Jamie Madill1f46bc12018-02-20 16:09:43 -0500351 RenderPass *compatibleRenderPass;
Jamie Madill21061022018-07-12 23:56:30 -0400352 ANGLE_TRY(context->getRenderer()->getCompatibleRenderPass(context, mRenderPassDesc,
353 &compatibleRenderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500354
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400355 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500356 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
357 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
358 inheritanceInfo.subpass = 0;
359 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400360 inheritanceInfo.occlusionQueryEnable =
361 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500362 inheritanceInfo.queryFlags = 0;
363 inheritanceInfo.pipelineStatistics = 0;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500364
365 ANGLE_TRY(InitAndBeginCommandBuffer(
Jamie Madill21061022018-07-12 23:56:30 -0400366 context, context->getRenderer()->getCommandPool(), inheritanceInfo,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500367 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
368
369 *commandsOut = &mInsideRenderPassCommands;
Jamie Madill21061022018-07-12 23:56:30 -0400370 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500371}
372
373void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
374 const gl::Rectangle renderArea,
Jamie Madillbcf467f2018-05-23 09:46:00 -0400375 const vk::RenderPassDesc &renderPassDesc,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500376 const std::vector<VkClearValue> &clearValues)
377{
Jamie Madillbcf467f2018-05-23 09:46:00 -0400378 mRenderPassDesc = renderPassDesc;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500379 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
380 mRenderPassRenderArea = renderArea;
381 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
382}
383
Jamie Madill1f46bc12018-02-20 16:09:43 -0500384// static
385void CommandGraphNode::SetHappensBeforeDependency(CommandGraphNode *beforeNode,
386 CommandGraphNode *afterNode)
387{
Jamie Madill9cceac42018-03-31 14:19:16 -0400388 ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500389 afterNode->mParents.emplace_back(beforeNode);
390 beforeNode->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500391}
392
393// static
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400394void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode **beforeNodes,
395 size_t beforeNodesCount,
396 CommandGraphNode *afterNode)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500397{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400398 afterNode->mParents.insert(afterNode->mParents.end(), beforeNodes,
399 beforeNodes + beforeNodesCount);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500400
401 // TODO(jmadill): is there a faster way to do this?
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400402 for (size_t i = 0; i < beforeNodesCount; ++i)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500403 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400404 beforeNodes[i]->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500405
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400406 ASSERT(beforeNodes[i] != afterNode && !beforeNodes[i]->isChildOf(afterNode));
407 }
408}
409
410void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode *beforeNode,
411 CommandGraphNode **afterNodes,
412 size_t afterNodesCount)
413{
414 for (size_t i = 0; i < afterNodesCount; ++i)
415 {
416 SetHappensBeforeDependency(beforeNode, afterNodes[i]);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500417 }
418}
419
420bool CommandGraphNode::hasParents() const
421{
422 return !mParents.empty();
423}
424
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400425void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIndex)
426{
427 ASSERT(mFunction == CommandGraphNodeFunction::BeginQuery ||
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400428 mFunction == CommandGraphNodeFunction::EndQuery ||
429 mFunction == CommandGraphNodeFunction::WriteTimestamp);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400430 mQueryPool = queryPool->getHandle();
431 mQueryIndex = queryIndex;
432}
433
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500434void CommandGraphNode::addGlobalMemoryBarrier(VkFlags srcAccess, VkFlags dstAccess)
435{
436 mGlobalMemoryBarrierSrcAccess |= srcAccess;
437 mGlobalMemoryBarrierDstAccess |= dstAccess;
438}
439
Jamie Madill1f46bc12018-02-20 16:09:43 -0500440void CommandGraphNode::setHasChildren()
441{
442 mHasChildren = true;
443}
444
Jamie Madill1f46bc12018-02-20 16:09:43 -0500445// Do not call this in anything but testing code, since it's slow.
446bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
447{
448 std::set<CommandGraphNode *> visitedList;
449 std::vector<CommandGraphNode *> openList;
450 openList.insert(openList.begin(), mParents.begin(), mParents.end());
451 while (!openList.empty())
452 {
453 CommandGraphNode *current = openList.back();
454 openList.pop_back();
455 if (visitedList.count(current) == 0)
456 {
457 if (current == parent)
458 {
459 return true;
460 }
461 visitedList.insert(current);
462 openList.insert(openList.end(), current->mParents.begin(), current->mParents.end());
463 }
464 }
465
466 return false;
467}
468
469VisitedState CommandGraphNode::visitedState() const
470{
471 return mVisitedState;
472}
473
474void CommandGraphNode::visitParents(std::vector<CommandGraphNode *> *stack)
475{
476 ASSERT(mVisitedState == VisitedState::Unvisited);
477 stack->insert(stack->end(), mParents.begin(), mParents.end());
478 mVisitedState = VisitedState::Ready;
479}
480
Jamie Madill21061022018-07-12 23:56:30 -0400481angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
482 Serial serial,
483 RenderPassCache *renderPassCache,
484 CommandBuffer *primaryCommandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500485{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400486 switch (mFunction)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500487 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400488 case CommandGraphNodeFunction::Generic:
489 ASSERT(mQueryPool == VK_NULL_HANDLE);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500490
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500491 // Record the deferred pipeline barrier if necessary.
492 ASSERT((mGlobalMemoryBarrierDstAccess == 0) == (mGlobalMemoryBarrierSrcAccess == 0));
493 if (mGlobalMemoryBarrierSrcAccess)
494 {
495 VkMemoryBarrier memoryBarrier = {};
496 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
497 memoryBarrier.srcAccessMask = mGlobalMemoryBarrierSrcAccess;
498 memoryBarrier.dstAccessMask = mGlobalMemoryBarrierDstAccess;
499
500 // Use the top of pipe stage to keep the state management simple.
501 primaryCommandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
502 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 1,
503 &memoryBarrier, 0, nullptr, 0, nullptr);
504 }
505
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400506 if (mOutsideRenderPassCommands.valid())
507 {
508 ANGLE_TRY(mOutsideRenderPassCommands.end(context));
509 primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
510 }
Jamie Madill1f46bc12018-02-20 16:09:43 -0500511
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400512 if (mInsideRenderPassCommands.valid())
513 {
514 // Pull a compatible RenderPass from the cache.
515 // TODO(jmadill): Insert real ops and layout transitions.
516 RenderPass *renderPass = nullptr;
517 ANGLE_TRY(renderPassCache->getCompatibleRenderPass(context, serial, mRenderPassDesc,
518 &renderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500519
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400520 ANGLE_TRY(mInsideRenderPassCommands.end(context));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500521
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400522 VkRenderPassBeginInfo beginInfo = {};
523 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
524 beginInfo.renderPass = renderPass->getHandle();
525 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
526 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
527 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
528 beginInfo.renderArea.extent.width =
529 static_cast<uint32_t>(mRenderPassRenderArea.width);
530 beginInfo.renderArea.extent.height =
531 static_cast<uint32_t>(mRenderPassRenderArea.height);
532 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
533 beginInfo.pClearValues = mRenderPassClearValues.data();
534
535 primaryCommandBuffer->beginRenderPass(
536 beginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
537 primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
538 primaryCommandBuffer->endRenderPass();
539 }
540 break;
541
542 case CommandGraphNodeFunction::BeginQuery:
543 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
544 ASSERT(mQueryPool != VK_NULL_HANDLE);
545
546 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
547 primaryCommandBuffer->beginQuery(mQueryPool, mQueryIndex, 0);
548
549 break;
550
551 case CommandGraphNodeFunction::EndQuery:
552 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
553 ASSERT(mQueryPool != VK_NULL_HANDLE);
554
555 primaryCommandBuffer->endQuery(mQueryPool, mQueryIndex);
556
557 break;
558
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400559 case CommandGraphNodeFunction::WriteTimestamp:
560 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
561 ASSERT(mQueryPool != VK_NULL_HANDLE);
562
563 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
564 primaryCommandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, mQueryPool,
565 mQueryIndex);
566
567 break;
568
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400569 default:
570 UNREACHABLE();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500571 }
572
573 mVisitedState = VisitedState::Visited;
Jamie Madill21061022018-07-12 23:56:30 -0400574 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500575}
576
Jamie Madill0da73fe2018-10-02 09:31:39 -0400577const std::vector<CommandGraphNode *> &CommandGraphNode::getParentsForDiagnostics() const
578{
579 return mParents;
580}
581
582void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType,
583 uintptr_t resourceID)
584{
585 mResourceType = resourceType;
586 mResourceID = resourceID;
587}
588
Luc Ferron14f48172018-04-11 08:43:28 -0400589const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
590{
591 return mRenderPassRenderArea;
592}
593
Jamie Madill1f46bc12018-02-20 16:09:43 -0500594// CommandGraph implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -0400595CommandGraph::CommandGraph(bool enableGraphDiagnostics)
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400596 : mEnableGraphDiagnostics(enableGraphDiagnostics), mLastBarrierIndex(kInvalidNodeIndex)
Jamie Madill0da73fe2018-10-02 09:31:39 -0400597{
598}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500599
600CommandGraph::~CommandGraph()
601{
602 ASSERT(empty());
603}
604
Jamie Madill193a2842018-10-30 17:28:41 -0400605CommandGraphNode *CommandGraph::allocateNode(CommandGraphNodeFunction function)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500606{
607 // TODO(jmadill): Use a pool allocator for the CPU node allocations.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400608 CommandGraphNode *newCommands = new CommandGraphNode(function);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500609 mNodes.emplace_back(newCommands);
610 return newCommands;
611}
612
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400613void CommandGraph::setNewBarrier(CommandGraphNode *newBarrier)
614{
615 size_t previousBarrierIndex = 0;
616 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
617
618 // Add a dependency from previousBarrier to all nodes in (previousBarrier, newBarrier].
619 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
620 {
621 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
622 CommandGraphNode::SetHappensBeforeDependencies(
623 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
624 }
625
626 // Add a dependency from all nodes in (previousBarrier, newBarrier) to newBarrier.
627 addDependenciesToNextBarrier(previousBarrierIndex + 1, mNodes.size() - 1, newBarrier);
628
629 mLastBarrierIndex = mNodes.size() - 1;
630}
631
Jamie Madill21061022018-07-12 23:56:30 -0400632angle::Result CommandGraph::submitCommands(Context *context,
633 Serial serial,
634 RenderPassCache *renderPassCache,
635 CommandPool *commandPool,
636 CommandBuffer *primaryCommandBufferOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500637{
Shahbaz Youssefi3a482172018-10-11 10:34:44 -0400638 // There is no point in submitting an empty command buffer, so make sure not to call this
639 // function if there's nothing to do.
640 ASSERT(!mNodes.empty());
641
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400642 size_t previousBarrierIndex = 0;
643 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
644
645 // Add a dependency from previousBarrier to all nodes in (previousBarrier, end].
646 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
647 {
648 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
649 CommandGraphNode::SetHappensBeforeDependencies(
650 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
651 }
652
Shahbaz Youssefi3a482172018-10-11 10:34:44 -0400653 mLastBarrierIndex = kInvalidNodeIndex;
654
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400655 VkCommandBufferAllocateInfo primaryInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500656 primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
657 primaryInfo.commandPool = commandPool->getHandle();
658 primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
659 primaryInfo.commandBufferCount = 1;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500660
Jamie Madill21061022018-07-12 23:56:30 -0400661 ANGLE_TRY(primaryCommandBufferOut->init(context, primaryInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500662
Jamie Madill0da73fe2018-10-02 09:31:39 -0400663 if (mEnableGraphDiagnostics)
664 {
665 dumpGraphDotFile(std::cout);
666 }
667
Jamie Madill1f46bc12018-02-20 16:09:43 -0500668 std::vector<CommandGraphNode *> nodeStack;
669
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400670 VkCommandBufferBeginInfo beginInfo = {};
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400671 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
672 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
673 beginInfo.pInheritanceInfo = nullptr;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500674
Jamie Madill21061022018-07-12 23:56:30 -0400675 ANGLE_TRY(primaryCommandBufferOut->begin(context, beginInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500676
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400677 ANGLE_TRY(context->getRenderer()->traceGpuEvent(
678 context, primaryCommandBufferOut, TRACE_EVENT_PHASE_BEGIN, "Primary Command Buffer"));
679
Jamie Madill1f46bc12018-02-20 16:09:43 -0500680 for (CommandGraphNode *topLevelNode : mNodes)
681 {
682 // Only process commands that don't have child commands. The others will be pulled in
683 // automatically. Also skip commands that have already been visited.
684 if (topLevelNode->hasChildren() || topLevelNode->visitedState() != VisitedState::Unvisited)
685 continue;
686
687 nodeStack.push_back(topLevelNode);
688
689 while (!nodeStack.empty())
690 {
691 CommandGraphNode *node = nodeStack.back();
692
693 switch (node->visitedState())
694 {
695 case VisitedState::Unvisited:
696 node->visitParents(&nodeStack);
697 break;
698 case VisitedState::Ready:
Jamie Madill21061022018-07-12 23:56:30 -0400699 ANGLE_TRY(node->visitAndExecute(context, serial, renderPassCache,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500700 primaryCommandBufferOut));
701 nodeStack.pop_back();
702 break;
703 case VisitedState::Visited:
704 nodeStack.pop_back();
705 break;
706 default:
707 UNREACHABLE();
708 break;
709 }
710 }
711 }
712
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400713 ANGLE_TRY(context->getRenderer()->traceGpuEvent(
714 context, primaryCommandBufferOut, TRACE_EVENT_PHASE_END, "Primary Command Buffer"));
715
Jamie Madill21061022018-07-12 23:56:30 -0400716 ANGLE_TRY(primaryCommandBufferOut->end(context));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500717
718 // TODO(jmadill): Use pool allocation so we don't need to deallocate command graph.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400719 for (CommandGraphNode *node : mNodes)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500720 {
721 delete node;
722 }
723 mNodes.clear();
724
Jamie Madill21061022018-07-12 23:56:30 -0400725 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500726}
727
728bool CommandGraph::empty() const
729{
730 return mNodes.empty();
731}
732
Jamie Madill0da73fe2018-10-02 09:31:39 -0400733// Dumps the command graph into a dot file that works with graphviz.
734void CommandGraph::dumpGraphDotFile(std::ostream &out) const
735{
736 // This ID maps a node pointer to a monatonic ID. It allows us to look up parent node IDs.
737 std::map<const CommandGraphNode *, int> nodeIDMap;
738 std::map<uintptr_t, int> objectIDMap;
739
740 // Map nodes to ids.
741 for (size_t nodeIndex = 0; nodeIndex < mNodes.size(); ++nodeIndex)
742 {
743 const CommandGraphNode *node = mNodes[nodeIndex];
744 nodeIDMap[node] = static_cast<int>(nodeIndex) + 1;
745 }
746
747 int bufferIDCounter = 1;
748 int framebufferIDCounter = 1;
749 int imageIDCounter = 1;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400750 int queryIDCounter = 1;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400751
752 out << "digraph {" << std::endl;
753
754 for (const CommandGraphNode *node : mNodes)
755 {
756 int nodeID = nodeIDMap[node];
757
758 std::stringstream strstr;
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -0400759 strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics(), node->getFunction());
Jamie Madill0da73fe2018-10-02 09:31:39 -0400760 strstr << " ";
761
762 auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
763 if (it != objectIDMap.end())
764 {
765 strstr << it->second;
766 }
767 else
768 {
769 int id = 0;
770
771 switch (node->getResourceTypeForDiagnostics())
772 {
773 case CommandGraphResourceType::Buffer:
774 id = bufferIDCounter++;
775 break;
776 case CommandGraphResourceType::Framebuffer:
777 id = framebufferIDCounter++;
778 break;
779 case CommandGraphResourceType::Image:
780 id = imageIDCounter++;
781 break;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400782 case CommandGraphResourceType::Query:
783 id = queryIDCounter++;
784 break;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400785 default:
786 UNREACHABLE();
787 break;
788 }
789
790 objectIDMap[node->getResourceIDForDiagnostics()] = id;
791 strstr << id;
792 }
793
794 const std::string &label = strstr.str();
795 out << " " << nodeID << "[label =<" << label << "<BR/> <FONT POINT-SIZE=\"10\">Node ID "
796 << nodeID << "</FONT>>];" << std::endl;
797 }
798
799 for (const CommandGraphNode *node : mNodes)
800 {
801 int nodeID = nodeIDMap[node];
802
803 for (const CommandGraphNode *parent : node->getParentsForDiagnostics())
804 {
805 int parentID = nodeIDMap[parent];
806 out << " " << parentID << " -> " << nodeID << ";" << std::endl;
807 }
808 }
809
810 out << "}" << std::endl;
811}
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400812
813CommandGraphNode *CommandGraph::getLastBarrierNode(size_t *indexOut)
814{
815 *indexOut = mLastBarrierIndex == kInvalidNodeIndex ? 0 : mLastBarrierIndex;
816 return mLastBarrierIndex == kInvalidNodeIndex ? nullptr : mNodes[mLastBarrierIndex];
817}
818
819void CommandGraph::addDependenciesToNextBarrier(size_t begin,
820 size_t end,
821 CommandGraphNode *nextBarrier)
822{
823 for (size_t i = begin; i < end; ++i)
824 {
825 // As a small optimization, only add edges to childless nodes. The others have an
826 // indirect dependency.
827 if (!mNodes[i]->hasChildren())
828 {
829 CommandGraphNode::SetHappensBeforeDependency(mNodes[i], nextBarrier);
830 }
831 }
832}
833
Jamie Madill1f46bc12018-02-20 16:09:43 -0500834} // namespace vk
835} // namespace rx