blob: fa907038c4b56b3ef576abd75f78ccd64ee623e4 [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
19namespace rx
20{
Jamie Madill1f46bc12018-02-20 16:09:43 -050021namespace vk
22{
Jamie Madill1f46bc12018-02-20 16:09:43 -050023namespace
24{
Jamie Madill21061022018-07-12 23:56:30 -040025angle::Result InitAndBeginCommandBuffer(vk::Context *context,
26 const CommandPool &commandPool,
27 const VkCommandBufferInheritanceInfo &inheritanceInfo,
28 VkCommandBufferUsageFlags flags,
29 CommandBuffer *commandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -050030{
31 ASSERT(!commandBuffer->valid());
32
Shahbaz Youssefi06270c92018-10-03 17:00:25 -040033 VkCommandBufferAllocateInfo createInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -050034 createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -050035 createInfo.commandPool = commandPool.getHandle();
36 createInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
37 createInfo.commandBufferCount = 1;
38
Jamie Madill21061022018-07-12 23:56:30 -040039 ANGLE_TRY(commandBuffer->init(context, createInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -050040
Shahbaz Youssefi06270c92018-10-03 17:00:25 -040041 VkCommandBufferBeginInfo beginInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -050042 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -050043 beginInfo.flags = flags | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
44 beginInfo.pInheritanceInfo = &inheritanceInfo;
45
Jamie Madill21061022018-07-12 23:56:30 -040046 ANGLE_TRY(commandBuffer->begin(context, beginInfo));
47 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -050048}
49
Jamie Madill0da73fe2018-10-02 09:31:39 -040050const char *GetResourceTypeName(CommandGraphResourceType resourceType)
51{
52 switch (resourceType)
53 {
54 case CommandGraphResourceType::Buffer:
55 return "Buffer";
56 case CommandGraphResourceType::Framebuffer:
57 return "Framebuffer";
58 case CommandGraphResourceType::Image:
59 return "Image";
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -040060 case CommandGraphResourceType::Query:
61 return "Query";
Jamie Madill0da73fe2018-10-02 09:31:39 -040062 default:
63 UNREACHABLE();
64 return "";
65 }
66}
Jamie Madill1f46bc12018-02-20 16:09:43 -050067} // anonymous namespace
68
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040069// CommandGraphResource implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -040070CommandGraphResource::CommandGraphResource(CommandGraphResourceType resourceType)
71 : mCurrentWritingNode(nullptr), mResourceType(resourceType)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040072{
73}
74
Jamie Madill316c6062018-05-29 10:49:45 -040075CommandGraphResource::~CommandGraphResource() = default;
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040076
77void CommandGraphResource::updateQueueSerial(Serial queueSerial)
78{
79 ASSERT(queueSerial >= mStoredQueueSerial);
80
81 if (queueSerial > mStoredQueueSerial)
82 {
83 mCurrentWritingNode = nullptr;
84 mCurrentReadingNodes.clear();
85 mStoredQueueSerial = queueSerial;
86 }
87}
88
Jamie Madillc57ee252018-05-30 19:53:48 -040089bool CommandGraphResource::isResourceInUse(RendererVk *renderer) const
90{
91 return renderer->isSerialInUse(mStoredQueueSerial);
92}
93
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -040094bool CommandGraphResource::hasPendingWork(RendererVk *renderer) const
95{
96 // If the renderer has a queue serial higher than the stored one, the command buffers recorded
97 // by this resource have already been submitted, so there is no pending work.
98 return mStoredQueueSerial == renderer->getCurrentQueueSerial();
99}
100
Jamie Madillc57ee252018-05-30 19:53:48 -0400101Serial CommandGraphResource::getStoredQueueSerial() const
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400102{
103 return mStoredQueueSerial;
104}
105
Jamie Madille2d22702018-09-19 08:11:48 -0400106angle::Result CommandGraphResource::recordCommands(Context *context,
107 CommandBuffer **commandBufferOut)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400108{
Jamie Madill21061022018-07-12 23:56:30 -0400109 updateQueueSerial(context->getRenderer()->getCurrentQueueSerial());
Jamie Madill5dca6512018-05-30 10:53:51 -0400110
Jamie Madille2d22702018-09-19 08:11:48 -0400111 if (!hasChildlessWritingNode() || hasStartedRenderPass())
Jamie Madill316c6062018-05-29 10:49:45 -0400112 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400113 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::Generic);
Jamie Madille2d22702018-09-19 08:11:48 -0400114 return mCurrentWritingNode->beginOutsideRenderPassRecording(
115 context, context->getRenderer()->getCommandPool(), commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400116 }
117
118 CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
119 if (!outsideRenderPassCommands->valid())
120 {
121 ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
Jamie Madill21061022018-07-12 23:56:30 -0400122 context, context->getRenderer()->getCommandPool(), commandBufferOut));
Jamie Madill316c6062018-05-29 10:49:45 -0400123 }
124 else
125 {
126 *commandBufferOut = outsideRenderPassCommands;
127 }
128
Jamie Madill21061022018-07-12 23:56:30 -0400129 return angle::Result::Continue();
Jamie Madill316c6062018-05-29 10:49:45 -0400130}
131
Jamie Madill5dca6512018-05-30 10:53:51 -0400132bool CommandGraphResource::appendToStartedRenderPass(RendererVk *renderer,
133 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400134{
Jamie Madill5dca6512018-05-30 10:53:51 -0400135 updateQueueSerial(renderer->getCurrentQueueSerial());
136 if (hasStartedRenderPass())
137 {
138 *commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands();
139 return true;
140 }
141 else
142 {
143 return false;
144 }
Jamie Madill316c6062018-05-29 10:49:45 -0400145}
146
Jamie Madill316c6062018-05-29 10:49:45 -0400147const gl::Rectangle &CommandGraphResource::getRenderPassRenderArea() const
148{
149 ASSERT(hasStartedRenderPass());
150 return mCurrentWritingNode->getRenderPassRenderArea();
151}
152
Jamie Madill21061022018-07-12 23:56:30 -0400153angle::Result CommandGraphResource::beginRenderPass(Context *context,
154 const Framebuffer &framebuffer,
155 const gl::Rectangle &renderArea,
156 const RenderPassDesc &renderPassDesc,
157 const std::vector<VkClearValue> &clearValues,
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400158 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400159{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400160 // If a barrier has been inserted in the meantime, stop the command buffer.
161 if (!hasChildlessWritingNode())
162 {
163 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::Generic);
164 }
165
Jamie Madill316c6062018-05-29 10:49:45 -0400166 // Hard-code RenderPass to clear the first render target to the current clear value.
167 // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
168 mCurrentWritingNode->storeRenderPassInfo(framebuffer, renderArea, renderPassDesc, clearValues);
169
Jamie Madill21061022018-07-12 23:56:30 -0400170 return mCurrentWritingNode->beginInsideRenderPassRecording(context, commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400171}
172
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400173void CommandGraphResource::beginQuery(Context *context,
174 const QueryPool *queryPool,
175 uint32_t queryIndex)
176{
177 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::BeginQuery);
178 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
179}
180
181void CommandGraphResource::endQuery(Context *context,
182 const QueryPool *queryPool,
183 uint32_t queryIndex)
184{
185 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::EndQuery);
186 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
187}
188
Jamie Madille2d22702018-09-19 08:11:48 -0400189void CommandGraphResource::finishCurrentCommands(RendererVk *renderer)
Jamie Madill316c6062018-05-29 10:49:45 -0400190{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400191 startNewCommands(renderer, CommandGraphNodeFunction::Generic);
192}
193
194void CommandGraphResource::startNewCommands(RendererVk *renderer, CommandGraphNodeFunction function)
195{
196 bool isBarrier = function != CommandGraphNodeFunction::Generic;
197 CommandGraphNode *newCommands = renderer->getCommandGraph()->allocateNode(isBarrier, function);
Jamie Madill0da73fe2018-10-02 09:31:39 -0400198 newCommands->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
Jamie Madill86ce2102018-05-22 11:54:42 -0400199 onWriteImpl(newCommands, renderer->getCurrentQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400200}
201
202void CommandGraphResource::addWriteDependency(CommandGraphResource *writingResource)
203{
204 CommandGraphNode *writingNode = writingResource->mCurrentWritingNode;
205 ASSERT(writingNode);
206
Jamie Madillc57ee252018-05-30 19:53:48 -0400207 onWriteImpl(writingNode, writingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400208}
209
210void CommandGraphResource::onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial)
211{
212 updateQueueSerial(currentSerial);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400213
Jamie Madill9cceac42018-03-31 14:19:16 -0400214 // Make sure any open reads and writes finish before we execute 'writingNode'.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400215 if (!mCurrentReadingNodes.empty())
216 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400217 CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes.data(),
218 mCurrentReadingNodes.size(), writingNode);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400219 mCurrentReadingNodes.clear();
220 }
221
222 if (mCurrentWritingNode && mCurrentWritingNode != writingNode)
223 {
224 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, writingNode);
225 }
226
227 mCurrentWritingNode = writingNode;
228}
229
Jamie Madill316c6062018-05-29 10:49:45 -0400230void CommandGraphResource::addReadDependency(CommandGraphResource *readingResource)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400231{
Jamie Madillc57ee252018-05-30 19:53:48 -0400232 updateQueueSerial(readingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400233
234 CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
235 ASSERT(readingNode);
Jamie Madill9cceac42018-03-31 14:19:16 -0400236
237 if (hasChildlessWritingNode())
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400238 {
Jamie Madill9cceac42018-03-31 14:19:16 -0400239 // Ensure 'readingNode' happens after the current writing node.
240 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
241 }
242
243 // Add the read node to the list of nodes currently reading this resource.
244 mCurrentReadingNodes.push_back(readingNode);
245}
246
Jamie Madill1f46bc12018-02-20 16:09:43 -0500247// CommandGraphNode implementation.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400248CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function)
249 : mRenderPassClearValues{},
250 mFunction(function),
251 mQueryPool(VK_NULL_HANDLE),
252 mQueryIndex(0),
253 mHasChildren(false),
254 mVisitedState(VisitedState::Unvisited)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500255{
256}
257
258CommandGraphNode::~CommandGraphNode()
259{
260 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
261
262 // Command buffers are managed by the command pool, so don't need to be freed.
263 mOutsideRenderPassCommands.releaseHandle();
264 mInsideRenderPassCommands.releaseHandle();
265}
266
267CommandBuffer *CommandGraphNode::getOutsideRenderPassCommands()
268{
269 ASSERT(!mHasChildren);
270 return &mOutsideRenderPassCommands;
271}
272
Jamie Madill21061022018-07-12 23:56:30 -0400273angle::Result CommandGraphNode::beginOutsideRenderPassRecording(Context *context,
274 const CommandPool &commandPool,
275 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500276{
277 ASSERT(!mHasChildren);
278
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400279 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500280 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500281 inheritanceInfo.renderPass = VK_NULL_HANDLE;
282 inheritanceInfo.subpass = 0;
283 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400284 inheritanceInfo.occlusionQueryEnable =
285 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500286 inheritanceInfo.queryFlags = 0;
287 inheritanceInfo.pipelineStatistics = 0;
288
Jamie Madill21061022018-07-12 23:56:30 -0400289 ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500290 &mOutsideRenderPassCommands));
291
292 *commandsOut = &mOutsideRenderPassCommands;
Jamie Madill21061022018-07-12 23:56:30 -0400293 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500294}
295
Jamie Madill21061022018-07-12 23:56:30 -0400296angle::Result CommandGraphNode::beginInsideRenderPassRecording(Context *context,
297 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500298{
299 ASSERT(!mHasChildren);
300
301 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400302 // TODO(jmadill): Support query for compatible/conformant render pass. http://anglebug.com/2361
Jamie Madill1f46bc12018-02-20 16:09:43 -0500303 RenderPass *compatibleRenderPass;
Jamie Madill21061022018-07-12 23:56:30 -0400304 ANGLE_TRY(context->getRenderer()->getCompatibleRenderPass(context, mRenderPassDesc,
305 &compatibleRenderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500306
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400307 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500308 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500309 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
310 inheritanceInfo.subpass = 0;
311 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400312 inheritanceInfo.occlusionQueryEnable =
313 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500314 inheritanceInfo.queryFlags = 0;
315 inheritanceInfo.pipelineStatistics = 0;
316
317 ANGLE_TRY(InitAndBeginCommandBuffer(
Jamie Madill21061022018-07-12 23:56:30 -0400318 context, context->getRenderer()->getCommandPool(), inheritanceInfo,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500319 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
320
321 *commandsOut = &mInsideRenderPassCommands;
Jamie Madill21061022018-07-12 23:56:30 -0400322 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500323}
324
325void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
326 const gl::Rectangle renderArea,
Jamie Madillbcf467f2018-05-23 09:46:00 -0400327 const vk::RenderPassDesc &renderPassDesc,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500328 const std::vector<VkClearValue> &clearValues)
329{
Jamie Madillbcf467f2018-05-23 09:46:00 -0400330 mRenderPassDesc = renderPassDesc;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500331 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
332 mRenderPassRenderArea = renderArea;
333 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
334}
335
Jamie Madill1f46bc12018-02-20 16:09:43 -0500336// static
337void CommandGraphNode::SetHappensBeforeDependency(CommandGraphNode *beforeNode,
338 CommandGraphNode *afterNode)
339{
Jamie Madill9cceac42018-03-31 14:19:16 -0400340 ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500341 afterNode->mParents.emplace_back(beforeNode);
342 beforeNode->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500343}
344
345// 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 ||
380 mFunction == CommandGraphNodeFunction::EndQuery);
381 mQueryPool = queryPool->getHandle();
382 mQueryIndex = queryIndex;
383}
384
Jamie Madill1f46bc12018-02-20 16:09:43 -0500385void CommandGraphNode::setHasChildren()
386{
387 mHasChildren = true;
388}
389
Jamie Madill1f46bc12018-02-20 16:09:43 -0500390// Do not call this in anything but testing code, since it's slow.
391bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
392{
393 std::set<CommandGraphNode *> visitedList;
394 std::vector<CommandGraphNode *> openList;
395 openList.insert(openList.begin(), mParents.begin(), mParents.end());
396 while (!openList.empty())
397 {
398 CommandGraphNode *current = openList.back();
399 openList.pop_back();
400 if (visitedList.count(current) == 0)
401 {
402 if (current == parent)
403 {
404 return true;
405 }
406 visitedList.insert(current);
407 openList.insert(openList.end(), current->mParents.begin(), current->mParents.end());
408 }
409 }
410
411 return false;
412}
413
414VisitedState CommandGraphNode::visitedState() const
415{
416 return mVisitedState;
417}
418
419void CommandGraphNode::visitParents(std::vector<CommandGraphNode *> *stack)
420{
421 ASSERT(mVisitedState == VisitedState::Unvisited);
422 stack->insert(stack->end(), mParents.begin(), mParents.end());
423 mVisitedState = VisitedState::Ready;
424}
425
Jamie Madill21061022018-07-12 23:56:30 -0400426angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
427 Serial serial,
428 RenderPassCache *renderPassCache,
429 CommandBuffer *primaryCommandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500430{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400431 switch (mFunction)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500432 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400433 case CommandGraphNodeFunction::Generic:
434 ASSERT(mQueryPool == VK_NULL_HANDLE);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500435
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400436 if (mOutsideRenderPassCommands.valid())
437 {
438 ANGLE_TRY(mOutsideRenderPassCommands.end(context));
439 primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
440 }
Jamie Madill1f46bc12018-02-20 16:09:43 -0500441
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400442 if (mInsideRenderPassCommands.valid())
443 {
444 // Pull a compatible RenderPass from the cache.
445 // TODO(jmadill): Insert real ops and layout transitions.
446 RenderPass *renderPass = nullptr;
447 ANGLE_TRY(renderPassCache->getCompatibleRenderPass(context, serial, mRenderPassDesc,
448 &renderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500449
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400450 ANGLE_TRY(mInsideRenderPassCommands.end(context));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500451
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400452 VkRenderPassBeginInfo beginInfo = {};
453 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
454 beginInfo.renderPass = renderPass->getHandle();
455 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
456 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
457 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
458 beginInfo.renderArea.extent.width =
459 static_cast<uint32_t>(mRenderPassRenderArea.width);
460 beginInfo.renderArea.extent.height =
461 static_cast<uint32_t>(mRenderPassRenderArea.height);
462 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
463 beginInfo.pClearValues = mRenderPassClearValues.data();
464
465 primaryCommandBuffer->beginRenderPass(
466 beginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
467 primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
468 primaryCommandBuffer->endRenderPass();
469 }
470 break;
471
472 case CommandGraphNodeFunction::BeginQuery:
473 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
474 ASSERT(mQueryPool != VK_NULL_HANDLE);
475
476 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
477 primaryCommandBuffer->beginQuery(mQueryPool, mQueryIndex, 0);
478
479 break;
480
481 case CommandGraphNodeFunction::EndQuery:
482 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
483 ASSERT(mQueryPool != VK_NULL_HANDLE);
484
485 primaryCommandBuffer->endQuery(mQueryPool, mQueryIndex);
486
487 break;
488
489 default:
490 UNREACHABLE();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500491 }
492
493 mVisitedState = VisitedState::Visited;
Jamie Madill21061022018-07-12 23:56:30 -0400494 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500495}
496
Jamie Madill0da73fe2018-10-02 09:31:39 -0400497const std::vector<CommandGraphNode *> &CommandGraphNode::getParentsForDiagnostics() const
498{
499 return mParents;
500}
501
502void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType,
503 uintptr_t resourceID)
504{
505 mResourceType = resourceType;
506 mResourceID = resourceID;
507}
508
Luc Ferron14f48172018-04-11 08:43:28 -0400509const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
510{
511 return mRenderPassRenderArea;
512}
513
Jamie Madill1f46bc12018-02-20 16:09:43 -0500514// CommandGraph implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -0400515CommandGraph::CommandGraph(bool enableGraphDiagnostics)
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400516 : mEnableGraphDiagnostics(enableGraphDiagnostics), mLastBarrierIndex(kInvalidNodeIndex)
Jamie Madill0da73fe2018-10-02 09:31:39 -0400517{
518}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500519
520CommandGraph::~CommandGraph()
521{
522 ASSERT(empty());
523}
524
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400525CommandGraphNode *CommandGraph::allocateNode(bool isBarrier, CommandGraphNodeFunction function)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500526{
527 // TODO(jmadill): Use a pool allocator for the CPU node allocations.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400528 CommandGraphNode *newCommands = new CommandGraphNode(function);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500529 mNodes.emplace_back(newCommands);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400530
531 if (isBarrier)
532 {
533 setNewBarrier(newCommands);
534 }
535
Jamie Madill1f46bc12018-02-20 16:09:43 -0500536 return newCommands;
537}
538
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400539void CommandGraph::setNewBarrier(CommandGraphNode *newBarrier)
540{
541 size_t previousBarrierIndex = 0;
542 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
543
544 // Add a dependency from previousBarrier to all nodes in (previousBarrier, newBarrier].
545 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
546 {
547 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
548 CommandGraphNode::SetHappensBeforeDependencies(
549 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
550 }
551
552 // Add a dependency from all nodes in (previousBarrier, newBarrier) to newBarrier.
553 addDependenciesToNextBarrier(previousBarrierIndex + 1, mNodes.size() - 1, newBarrier);
554
555 mLastBarrierIndex = mNodes.size() - 1;
556}
557
Jamie Madill21061022018-07-12 23:56:30 -0400558angle::Result CommandGraph::submitCommands(Context *context,
559 Serial serial,
560 RenderPassCache *renderPassCache,
561 CommandPool *commandPool,
562 CommandBuffer *primaryCommandBufferOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500563{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400564 size_t previousBarrierIndex = 0;
565 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
566
567 // Add a dependency from previousBarrier to all nodes in (previousBarrier, end].
568 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
569 {
570 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
571 CommandGraphNode::SetHappensBeforeDependencies(
572 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
573 }
574
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400575 VkCommandBufferAllocateInfo primaryInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500576 primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500577 primaryInfo.commandPool = commandPool->getHandle();
578 primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
579 primaryInfo.commandBufferCount = 1;
580
Jamie Madill21061022018-07-12 23:56:30 -0400581 ANGLE_TRY(primaryCommandBufferOut->init(context, primaryInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500582
583 if (mNodes.empty())
584 {
Jamie Madill21061022018-07-12 23:56:30 -0400585 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500586 }
587
Jamie Madill0da73fe2018-10-02 09:31:39 -0400588 if (mEnableGraphDiagnostics)
589 {
590 dumpGraphDotFile(std::cout);
591 }
592
Jamie Madill1f46bc12018-02-20 16:09:43 -0500593 std::vector<CommandGraphNode *> nodeStack;
594
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400595 VkCommandBufferBeginInfo beginInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500596 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500597 beginInfo.flags = 0;
598 beginInfo.pInheritanceInfo = nullptr;
599
Jamie Madill21061022018-07-12 23:56:30 -0400600 ANGLE_TRY(primaryCommandBufferOut->begin(context, beginInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500601
602 for (CommandGraphNode *topLevelNode : mNodes)
603 {
604 // Only process commands that don't have child commands. The others will be pulled in
605 // automatically. Also skip commands that have already been visited.
606 if (topLevelNode->hasChildren() || topLevelNode->visitedState() != VisitedState::Unvisited)
607 continue;
608
609 nodeStack.push_back(topLevelNode);
610
611 while (!nodeStack.empty())
612 {
613 CommandGraphNode *node = nodeStack.back();
614
615 switch (node->visitedState())
616 {
617 case VisitedState::Unvisited:
618 node->visitParents(&nodeStack);
619 break;
620 case VisitedState::Ready:
Jamie Madill21061022018-07-12 23:56:30 -0400621 ANGLE_TRY(node->visitAndExecute(context, serial, renderPassCache,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500622 primaryCommandBufferOut));
623 nodeStack.pop_back();
624 break;
625 case VisitedState::Visited:
626 nodeStack.pop_back();
627 break;
628 default:
629 UNREACHABLE();
630 break;
631 }
632 }
633 }
634
Jamie Madill21061022018-07-12 23:56:30 -0400635 ANGLE_TRY(primaryCommandBufferOut->end(context));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500636
637 // TODO(jmadill): Use pool allocation so we don't need to deallocate command graph.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400638 for (CommandGraphNode *node : mNodes)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500639 {
640 delete node;
641 }
642 mNodes.clear();
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400643 mLastBarrierIndex = kInvalidNodeIndex;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500644
Jamie Madill21061022018-07-12 23:56:30 -0400645 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500646}
647
648bool CommandGraph::empty() const
649{
650 return mNodes.empty();
651}
652
Jamie Madill0da73fe2018-10-02 09:31:39 -0400653// Dumps the command graph into a dot file that works with graphviz.
654void CommandGraph::dumpGraphDotFile(std::ostream &out) const
655{
656 // This ID maps a node pointer to a monatonic ID. It allows us to look up parent node IDs.
657 std::map<const CommandGraphNode *, int> nodeIDMap;
658 std::map<uintptr_t, int> objectIDMap;
659
660 // Map nodes to ids.
661 for (size_t nodeIndex = 0; nodeIndex < mNodes.size(); ++nodeIndex)
662 {
663 const CommandGraphNode *node = mNodes[nodeIndex];
664 nodeIDMap[node] = static_cast<int>(nodeIndex) + 1;
665 }
666
667 int bufferIDCounter = 1;
668 int framebufferIDCounter = 1;
669 int imageIDCounter = 1;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400670 int queryIDCounter = 1;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400671
672 out << "digraph {" << std::endl;
673
674 for (const CommandGraphNode *node : mNodes)
675 {
676 int nodeID = nodeIDMap[node];
677
678 std::stringstream strstr;
679 strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics());
680 strstr << " ";
681
682 auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
683 if (it != objectIDMap.end())
684 {
685 strstr << it->second;
686 }
687 else
688 {
689 int id = 0;
690
691 switch (node->getResourceTypeForDiagnostics())
692 {
693 case CommandGraphResourceType::Buffer:
694 id = bufferIDCounter++;
695 break;
696 case CommandGraphResourceType::Framebuffer:
697 id = framebufferIDCounter++;
698 break;
699 case CommandGraphResourceType::Image:
700 id = imageIDCounter++;
701 break;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400702 case CommandGraphResourceType::Query:
703 id = queryIDCounter++;
704 break;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400705 default:
706 UNREACHABLE();
707 break;
708 }
709
710 objectIDMap[node->getResourceIDForDiagnostics()] = id;
711 strstr << id;
712 }
713
714 const std::string &label = strstr.str();
715 out << " " << nodeID << "[label =<" << label << "<BR/> <FONT POINT-SIZE=\"10\">Node ID "
716 << nodeID << "</FONT>>];" << std::endl;
717 }
718
719 for (const CommandGraphNode *node : mNodes)
720 {
721 int nodeID = nodeIDMap[node];
722
723 for (const CommandGraphNode *parent : node->getParentsForDiagnostics())
724 {
725 int parentID = nodeIDMap[parent];
726 out << " " << parentID << " -> " << nodeID << ";" << std::endl;
727 }
728 }
729
730 out << "}" << std::endl;
731}
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400732
733CommandGraphNode *CommandGraph::getLastBarrierNode(size_t *indexOut)
734{
735 *indexOut = mLastBarrierIndex == kInvalidNodeIndex ? 0 : mLastBarrierIndex;
736 return mLastBarrierIndex == kInvalidNodeIndex ? nullptr : mNodes[mLastBarrierIndex];
737}
738
739void CommandGraph::addDependenciesToNextBarrier(size_t begin,
740 size_t end,
741 CommandGraphNode *nextBarrier)
742{
743 for (size_t i = begin; i < end; ++i)
744 {
745 // As a small optimization, only add edges to childless nodes. The others have an
746 // indirect dependency.
747 if (!mNodes[i]->hasChildren())
748 {
749 CommandGraphNode::SetHappensBeforeDependency(mNodes[i], nextBarrier);
750 }
751 }
752}
753
Jamie Madill1f46bc12018-02-20 16:09:43 -0500754} // namespace vk
755} // namespace rx