blob: 6dfdefddbe693c93acae96ba7addd3b04faa8d42 [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
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040050const char *GetResourceTypeName(CommandGraphResourceType resourceType,
51 CommandGraphNodeFunction function)
Jamie Madill0da73fe2018-10-02 09:31:39 -040052{
53 switch (resourceType)
54 {
55 case CommandGraphResourceType::Buffer:
56 return "Buffer";
57 case CommandGraphResourceType::Framebuffer:
58 return "Framebuffer";
59 case CommandGraphResourceType::Image:
60 return "Image";
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -040061 case CommandGraphResourceType::Query:
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040062 switch (function)
63 {
64 case CommandGraphNodeFunction::BeginQuery:
65 return "BeginQuery";
66 case CommandGraphNodeFunction::EndQuery:
67 return "EndQuery";
68 default:
69 UNREACHABLE();
70 return "Query";
71 }
Jamie Madill0da73fe2018-10-02 09:31:39 -040072 default:
73 UNREACHABLE();
74 return "";
75 }
76}
Jamie Madill1f46bc12018-02-20 16:09:43 -050077} // anonymous namespace
78
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040079// CommandGraphResource implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -040080CommandGraphResource::CommandGraphResource(CommandGraphResourceType resourceType)
81 : mCurrentWritingNode(nullptr), mResourceType(resourceType)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040082{
83}
84
Jamie Madill316c6062018-05-29 10:49:45 -040085CommandGraphResource::~CommandGraphResource() = default;
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040086
87void CommandGraphResource::updateQueueSerial(Serial queueSerial)
88{
89 ASSERT(queueSerial >= mStoredQueueSerial);
90
91 if (queueSerial > mStoredQueueSerial)
92 {
93 mCurrentWritingNode = nullptr;
94 mCurrentReadingNodes.clear();
95 mStoredQueueSerial = queueSerial;
96 }
97}
98
Jamie Madillc57ee252018-05-30 19:53:48 -040099bool CommandGraphResource::isResourceInUse(RendererVk *renderer) const
100{
101 return renderer->isSerialInUse(mStoredQueueSerial);
102}
103
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400104bool CommandGraphResource::hasPendingWork(RendererVk *renderer) const
105{
106 // If the renderer has a queue serial higher than the stored one, the command buffers recorded
107 // by this resource have already been submitted, so there is no pending work.
108 return mStoredQueueSerial == renderer->getCurrentQueueSerial();
109}
110
Jamie Madillc57ee252018-05-30 19:53:48 -0400111Serial CommandGraphResource::getStoredQueueSerial() const
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400112{
113 return mStoredQueueSerial;
114}
115
Jamie Madille2d22702018-09-19 08:11:48 -0400116angle::Result CommandGraphResource::recordCommands(Context *context,
117 CommandBuffer **commandBufferOut)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400118{
Jamie Madill21061022018-07-12 23:56:30 -0400119 updateQueueSerial(context->getRenderer()->getCurrentQueueSerial());
Jamie Madill5dca6512018-05-30 10:53:51 -0400120
Jamie Madille2d22702018-09-19 08:11:48 -0400121 if (!hasChildlessWritingNode() || hasStartedRenderPass())
Jamie Madill316c6062018-05-29 10:49:45 -0400122 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400123 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::Generic);
Jamie Madille2d22702018-09-19 08:11:48 -0400124 return mCurrentWritingNode->beginOutsideRenderPassRecording(
125 context, context->getRenderer()->getCommandPool(), commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400126 }
127
128 CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
129 if (!outsideRenderPassCommands->valid())
130 {
131 ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
Jamie Madill21061022018-07-12 23:56:30 -0400132 context, context->getRenderer()->getCommandPool(), commandBufferOut));
Jamie Madill316c6062018-05-29 10:49:45 -0400133 }
134 else
135 {
136 *commandBufferOut = outsideRenderPassCommands;
137 }
138
Jamie Madill21061022018-07-12 23:56:30 -0400139 return angle::Result::Continue();
Jamie Madill316c6062018-05-29 10:49:45 -0400140}
141
Jamie Madill5dca6512018-05-30 10:53:51 -0400142bool CommandGraphResource::appendToStartedRenderPass(RendererVk *renderer,
143 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400144{
Jamie Madill5dca6512018-05-30 10:53:51 -0400145 updateQueueSerial(renderer->getCurrentQueueSerial());
146 if (hasStartedRenderPass())
147 {
148 *commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands();
149 return true;
150 }
151 else
152 {
153 return false;
154 }
Jamie Madill316c6062018-05-29 10:49:45 -0400155}
156
Jamie Madill316c6062018-05-29 10:49:45 -0400157const gl::Rectangle &CommandGraphResource::getRenderPassRenderArea() const
158{
159 ASSERT(hasStartedRenderPass());
160 return mCurrentWritingNode->getRenderPassRenderArea();
161}
162
Jamie Madill21061022018-07-12 23:56:30 -0400163angle::Result CommandGraphResource::beginRenderPass(Context *context,
164 const Framebuffer &framebuffer,
165 const gl::Rectangle &renderArea,
166 const RenderPassDesc &renderPassDesc,
167 const std::vector<VkClearValue> &clearValues,
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400168 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400169{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400170 // If a barrier has been inserted in the meantime, stop the command buffer.
171 if (!hasChildlessWritingNode())
172 {
173 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::Generic);
174 }
175
Jamie Madill316c6062018-05-29 10:49:45 -0400176 // Hard-code RenderPass to clear the first render target to the current clear value.
177 // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
178 mCurrentWritingNode->storeRenderPassInfo(framebuffer, renderArea, renderPassDesc, clearValues);
179
Jamie Madill21061022018-07-12 23:56:30 -0400180 return mCurrentWritingNode->beginInsideRenderPassRecording(context, commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400181}
182
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400183void CommandGraphResource::beginQuery(Context *context,
184 const QueryPool *queryPool,
185 uint32_t queryIndex)
186{
187 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::BeginQuery);
188 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
189}
190
191void CommandGraphResource::endQuery(Context *context,
192 const QueryPool *queryPool,
193 uint32_t queryIndex)
194{
195 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::EndQuery);
196 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
197}
198
Jamie Madille2d22702018-09-19 08:11:48 -0400199void CommandGraphResource::finishCurrentCommands(RendererVk *renderer)
Jamie Madill316c6062018-05-29 10:49:45 -0400200{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400201 startNewCommands(renderer, CommandGraphNodeFunction::Generic);
202}
203
204void CommandGraphResource::startNewCommands(RendererVk *renderer, CommandGraphNodeFunction function)
205{
206 bool isBarrier = function != CommandGraphNodeFunction::Generic;
207 CommandGraphNode *newCommands = renderer->getCommandGraph()->allocateNode(isBarrier, function);
Jamie Madill0da73fe2018-10-02 09:31:39 -0400208 newCommands->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
Jamie Madill86ce2102018-05-22 11:54:42 -0400209 onWriteImpl(newCommands, renderer->getCurrentQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400210}
211
212void CommandGraphResource::addWriteDependency(CommandGraphResource *writingResource)
213{
214 CommandGraphNode *writingNode = writingResource->mCurrentWritingNode;
215 ASSERT(writingNode);
216
Jamie Madillc57ee252018-05-30 19:53:48 -0400217 onWriteImpl(writingNode, writingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400218}
219
220void CommandGraphResource::onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial)
221{
222 updateQueueSerial(currentSerial);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400223
Jamie Madill9cceac42018-03-31 14:19:16 -0400224 // Make sure any open reads and writes finish before we execute 'writingNode'.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400225 if (!mCurrentReadingNodes.empty())
226 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400227 CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes.data(),
228 mCurrentReadingNodes.size(), writingNode);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400229 mCurrentReadingNodes.clear();
230 }
231
232 if (mCurrentWritingNode && mCurrentWritingNode != writingNode)
233 {
234 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, writingNode);
235 }
236
237 mCurrentWritingNode = writingNode;
238}
239
Jamie Madill316c6062018-05-29 10:49:45 -0400240void CommandGraphResource::addReadDependency(CommandGraphResource *readingResource)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400241{
Jamie Madillc57ee252018-05-30 19:53:48 -0400242 updateQueueSerial(readingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400243
244 CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
245 ASSERT(readingNode);
Jamie Madill9cceac42018-03-31 14:19:16 -0400246
247 if (hasChildlessWritingNode())
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400248 {
Jamie Madill9cceac42018-03-31 14:19:16 -0400249 // Ensure 'readingNode' happens after the current writing node.
250 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
251 }
252
253 // Add the read node to the list of nodes currently reading this resource.
254 mCurrentReadingNodes.push_back(readingNode);
255}
256
Jamie Madill1f46bc12018-02-20 16:09:43 -0500257// CommandGraphNode implementation.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400258CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function)
259 : mRenderPassClearValues{},
260 mFunction(function),
261 mQueryPool(VK_NULL_HANDLE),
262 mQueryIndex(0),
263 mHasChildren(false),
264 mVisitedState(VisitedState::Unvisited)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500265{
266}
267
268CommandGraphNode::~CommandGraphNode()
269{
270 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
271
272 // Command buffers are managed by the command pool, so don't need to be freed.
273 mOutsideRenderPassCommands.releaseHandle();
274 mInsideRenderPassCommands.releaseHandle();
275}
276
277CommandBuffer *CommandGraphNode::getOutsideRenderPassCommands()
278{
279 ASSERT(!mHasChildren);
280 return &mOutsideRenderPassCommands;
281}
282
Jamie Madill21061022018-07-12 23:56:30 -0400283angle::Result CommandGraphNode::beginOutsideRenderPassRecording(Context *context,
284 const CommandPool &commandPool,
285 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500286{
287 ASSERT(!mHasChildren);
288
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400289 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500290 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500291 inheritanceInfo.renderPass = VK_NULL_HANDLE;
292 inheritanceInfo.subpass = 0;
293 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400294 inheritanceInfo.occlusionQueryEnable =
295 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500296 inheritanceInfo.queryFlags = 0;
297 inheritanceInfo.pipelineStatistics = 0;
298
Jamie Madill21061022018-07-12 23:56:30 -0400299 ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500300 &mOutsideRenderPassCommands));
301
302 *commandsOut = &mOutsideRenderPassCommands;
Jamie Madill21061022018-07-12 23:56:30 -0400303 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500304}
305
Jamie Madill21061022018-07-12 23:56:30 -0400306angle::Result CommandGraphNode::beginInsideRenderPassRecording(Context *context,
307 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500308{
309 ASSERT(!mHasChildren);
310
311 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400312 // TODO(jmadill): Support query for compatible/conformant render pass. http://anglebug.com/2361
Jamie Madill1f46bc12018-02-20 16:09:43 -0500313 RenderPass *compatibleRenderPass;
Jamie Madill21061022018-07-12 23:56:30 -0400314 ANGLE_TRY(context->getRenderer()->getCompatibleRenderPass(context, mRenderPassDesc,
315 &compatibleRenderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500316
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400317 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500318 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500319 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
320 inheritanceInfo.subpass = 0;
321 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400322 inheritanceInfo.occlusionQueryEnable =
323 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500324 inheritanceInfo.queryFlags = 0;
325 inheritanceInfo.pipelineStatistics = 0;
326
327 ANGLE_TRY(InitAndBeginCommandBuffer(
Jamie Madill21061022018-07-12 23:56:30 -0400328 context, context->getRenderer()->getCommandPool(), inheritanceInfo,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500329 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
330
331 *commandsOut = &mInsideRenderPassCommands;
Jamie Madill21061022018-07-12 23:56:30 -0400332 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500333}
334
335void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
336 const gl::Rectangle renderArea,
Jamie Madillbcf467f2018-05-23 09:46:00 -0400337 const vk::RenderPassDesc &renderPassDesc,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500338 const std::vector<VkClearValue> &clearValues)
339{
Jamie Madillbcf467f2018-05-23 09:46:00 -0400340 mRenderPassDesc = renderPassDesc;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500341 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
342 mRenderPassRenderArea = renderArea;
343 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
344}
345
Jamie Madill1f46bc12018-02-20 16:09:43 -0500346// static
347void CommandGraphNode::SetHappensBeforeDependency(CommandGraphNode *beforeNode,
348 CommandGraphNode *afterNode)
349{
Jamie Madill9cceac42018-03-31 14:19:16 -0400350 ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500351 afterNode->mParents.emplace_back(beforeNode);
352 beforeNode->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500353}
354
355// static
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400356void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode **beforeNodes,
357 size_t beforeNodesCount,
358 CommandGraphNode *afterNode)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500359{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400360 afterNode->mParents.insert(afterNode->mParents.end(), beforeNodes,
361 beforeNodes + beforeNodesCount);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500362
363 // TODO(jmadill): is there a faster way to do this?
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400364 for (size_t i = 0; i < beforeNodesCount; ++i)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500365 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400366 beforeNodes[i]->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500367
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400368 ASSERT(beforeNodes[i] != afterNode && !beforeNodes[i]->isChildOf(afterNode));
369 }
370}
371
372void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode *beforeNode,
373 CommandGraphNode **afterNodes,
374 size_t afterNodesCount)
375{
376 for (size_t i = 0; i < afterNodesCount; ++i)
377 {
378 SetHappensBeforeDependency(beforeNode, afterNodes[i]);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500379 }
380}
381
382bool CommandGraphNode::hasParents() const
383{
384 return !mParents.empty();
385}
386
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400387void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIndex)
388{
389 ASSERT(mFunction == CommandGraphNodeFunction::BeginQuery ||
390 mFunction == CommandGraphNodeFunction::EndQuery);
391 mQueryPool = queryPool->getHandle();
392 mQueryIndex = queryIndex;
393}
394
Jamie Madill1f46bc12018-02-20 16:09:43 -0500395void CommandGraphNode::setHasChildren()
396{
397 mHasChildren = true;
398}
399
Jamie Madill1f46bc12018-02-20 16:09:43 -0500400// Do not call this in anything but testing code, since it's slow.
401bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
402{
403 std::set<CommandGraphNode *> visitedList;
404 std::vector<CommandGraphNode *> openList;
405 openList.insert(openList.begin(), mParents.begin(), mParents.end());
406 while (!openList.empty())
407 {
408 CommandGraphNode *current = openList.back();
409 openList.pop_back();
410 if (visitedList.count(current) == 0)
411 {
412 if (current == parent)
413 {
414 return true;
415 }
416 visitedList.insert(current);
417 openList.insert(openList.end(), current->mParents.begin(), current->mParents.end());
418 }
419 }
420
421 return false;
422}
423
424VisitedState CommandGraphNode::visitedState() const
425{
426 return mVisitedState;
427}
428
429void CommandGraphNode::visitParents(std::vector<CommandGraphNode *> *stack)
430{
431 ASSERT(mVisitedState == VisitedState::Unvisited);
432 stack->insert(stack->end(), mParents.begin(), mParents.end());
433 mVisitedState = VisitedState::Ready;
434}
435
Jamie Madill21061022018-07-12 23:56:30 -0400436angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
437 Serial serial,
438 RenderPassCache *renderPassCache,
439 CommandBuffer *primaryCommandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500440{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400441 switch (mFunction)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500442 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400443 case CommandGraphNodeFunction::Generic:
444 ASSERT(mQueryPool == VK_NULL_HANDLE);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500445
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400446 if (mOutsideRenderPassCommands.valid())
447 {
448 ANGLE_TRY(mOutsideRenderPassCommands.end(context));
449 primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
450 }
Jamie Madill1f46bc12018-02-20 16:09:43 -0500451
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400452 if (mInsideRenderPassCommands.valid())
453 {
454 // Pull a compatible RenderPass from the cache.
455 // TODO(jmadill): Insert real ops and layout transitions.
456 RenderPass *renderPass = nullptr;
457 ANGLE_TRY(renderPassCache->getCompatibleRenderPass(context, serial, mRenderPassDesc,
458 &renderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500459
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400460 ANGLE_TRY(mInsideRenderPassCommands.end(context));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500461
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400462 VkRenderPassBeginInfo beginInfo = {};
463 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
464 beginInfo.renderPass = renderPass->getHandle();
465 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
466 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
467 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
468 beginInfo.renderArea.extent.width =
469 static_cast<uint32_t>(mRenderPassRenderArea.width);
470 beginInfo.renderArea.extent.height =
471 static_cast<uint32_t>(mRenderPassRenderArea.height);
472 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
473 beginInfo.pClearValues = mRenderPassClearValues.data();
474
475 primaryCommandBuffer->beginRenderPass(
476 beginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
477 primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
478 primaryCommandBuffer->endRenderPass();
479 }
480 break;
481
482 case CommandGraphNodeFunction::BeginQuery:
483 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
484 ASSERT(mQueryPool != VK_NULL_HANDLE);
485
486 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
487 primaryCommandBuffer->beginQuery(mQueryPool, mQueryIndex, 0);
488
489 break;
490
491 case CommandGraphNodeFunction::EndQuery:
492 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
493 ASSERT(mQueryPool != VK_NULL_HANDLE);
494
495 primaryCommandBuffer->endQuery(mQueryPool, mQueryIndex);
496
497 break;
498
499 default:
500 UNREACHABLE();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500501 }
502
503 mVisitedState = VisitedState::Visited;
Jamie Madill21061022018-07-12 23:56:30 -0400504 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500505}
506
Jamie Madill0da73fe2018-10-02 09:31:39 -0400507const std::vector<CommandGraphNode *> &CommandGraphNode::getParentsForDiagnostics() const
508{
509 return mParents;
510}
511
512void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType,
513 uintptr_t resourceID)
514{
515 mResourceType = resourceType;
516 mResourceID = resourceID;
517}
518
Luc Ferron14f48172018-04-11 08:43:28 -0400519const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
520{
521 return mRenderPassRenderArea;
522}
523
Jamie Madill1f46bc12018-02-20 16:09:43 -0500524// CommandGraph implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -0400525CommandGraph::CommandGraph(bool enableGraphDiagnostics)
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400526 : mEnableGraphDiagnostics(enableGraphDiagnostics), mLastBarrierIndex(kInvalidNodeIndex)
Jamie Madill0da73fe2018-10-02 09:31:39 -0400527{
528}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500529
530CommandGraph::~CommandGraph()
531{
532 ASSERT(empty());
533}
534
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400535CommandGraphNode *CommandGraph::allocateNode(bool isBarrier, CommandGraphNodeFunction function)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500536{
537 // TODO(jmadill): Use a pool allocator for the CPU node allocations.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400538 CommandGraphNode *newCommands = new CommandGraphNode(function);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500539 mNodes.emplace_back(newCommands);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400540
541 if (isBarrier)
542 {
543 setNewBarrier(newCommands);
544 }
545
Jamie Madill1f46bc12018-02-20 16:09:43 -0500546 return newCommands;
547}
548
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400549void CommandGraph::setNewBarrier(CommandGraphNode *newBarrier)
550{
551 size_t previousBarrierIndex = 0;
552 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
553
554 // Add a dependency from previousBarrier to all nodes in (previousBarrier, newBarrier].
555 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
556 {
557 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
558 CommandGraphNode::SetHappensBeforeDependencies(
559 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
560 }
561
562 // Add a dependency from all nodes in (previousBarrier, newBarrier) to newBarrier.
563 addDependenciesToNextBarrier(previousBarrierIndex + 1, mNodes.size() - 1, newBarrier);
564
565 mLastBarrierIndex = mNodes.size() - 1;
566}
567
Jamie Madill21061022018-07-12 23:56:30 -0400568angle::Result CommandGraph::submitCommands(Context *context,
569 Serial serial,
570 RenderPassCache *renderPassCache,
571 CommandPool *commandPool,
572 CommandBuffer *primaryCommandBufferOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500573{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400574 size_t previousBarrierIndex = 0;
575 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
576
577 // Add a dependency from previousBarrier to all nodes in (previousBarrier, end].
578 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
579 {
580 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
581 CommandGraphNode::SetHappensBeforeDependencies(
582 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
583 }
584
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400585 VkCommandBufferAllocateInfo primaryInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500586 primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500587 primaryInfo.commandPool = commandPool->getHandle();
588 primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
589 primaryInfo.commandBufferCount = 1;
590
Jamie Madill21061022018-07-12 23:56:30 -0400591 ANGLE_TRY(primaryCommandBufferOut->init(context, primaryInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500592
593 if (mNodes.empty())
594 {
Jamie Madill21061022018-07-12 23:56:30 -0400595 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500596 }
597
Jamie Madill0da73fe2018-10-02 09:31:39 -0400598 if (mEnableGraphDiagnostics)
599 {
600 dumpGraphDotFile(std::cout);
601 }
602
Jamie Madill1f46bc12018-02-20 16:09:43 -0500603 std::vector<CommandGraphNode *> nodeStack;
604
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400605 VkCommandBufferBeginInfo beginInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500606 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500607 beginInfo.flags = 0;
608 beginInfo.pInheritanceInfo = nullptr;
609
Jamie Madill21061022018-07-12 23:56:30 -0400610 ANGLE_TRY(primaryCommandBufferOut->begin(context, beginInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500611
612 for (CommandGraphNode *topLevelNode : mNodes)
613 {
614 // Only process commands that don't have child commands. The others will be pulled in
615 // automatically. Also skip commands that have already been visited.
616 if (topLevelNode->hasChildren() || topLevelNode->visitedState() != VisitedState::Unvisited)
617 continue;
618
619 nodeStack.push_back(topLevelNode);
620
621 while (!nodeStack.empty())
622 {
623 CommandGraphNode *node = nodeStack.back();
624
625 switch (node->visitedState())
626 {
627 case VisitedState::Unvisited:
628 node->visitParents(&nodeStack);
629 break;
630 case VisitedState::Ready:
Jamie Madill21061022018-07-12 23:56:30 -0400631 ANGLE_TRY(node->visitAndExecute(context, serial, renderPassCache,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500632 primaryCommandBufferOut));
633 nodeStack.pop_back();
634 break;
635 case VisitedState::Visited:
636 nodeStack.pop_back();
637 break;
638 default:
639 UNREACHABLE();
640 break;
641 }
642 }
643 }
644
Jamie Madill21061022018-07-12 23:56:30 -0400645 ANGLE_TRY(primaryCommandBufferOut->end(context));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500646
647 // TODO(jmadill): Use pool allocation so we don't need to deallocate command graph.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400648 for (CommandGraphNode *node : mNodes)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500649 {
650 delete node;
651 }
652 mNodes.clear();
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400653 mLastBarrierIndex = kInvalidNodeIndex;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500654
Jamie Madill21061022018-07-12 23:56:30 -0400655 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500656}
657
658bool CommandGraph::empty() const
659{
660 return mNodes.empty();
661}
662
Jamie Madill0da73fe2018-10-02 09:31:39 -0400663// Dumps the command graph into a dot file that works with graphviz.
664void CommandGraph::dumpGraphDotFile(std::ostream &out) const
665{
666 // This ID maps a node pointer to a monatonic ID. It allows us to look up parent node IDs.
667 std::map<const CommandGraphNode *, int> nodeIDMap;
668 std::map<uintptr_t, int> objectIDMap;
669
670 // Map nodes to ids.
671 for (size_t nodeIndex = 0; nodeIndex < mNodes.size(); ++nodeIndex)
672 {
673 const CommandGraphNode *node = mNodes[nodeIndex];
674 nodeIDMap[node] = static_cast<int>(nodeIndex) + 1;
675 }
676
677 int bufferIDCounter = 1;
678 int framebufferIDCounter = 1;
679 int imageIDCounter = 1;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400680 int queryIDCounter = 1;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400681
682 out << "digraph {" << std::endl;
683
684 for (const CommandGraphNode *node : mNodes)
685 {
686 int nodeID = nodeIDMap[node];
687
688 std::stringstream strstr;
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -0400689 strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics(), node->getFunction());
Jamie Madill0da73fe2018-10-02 09:31:39 -0400690 strstr << " ";
691
692 auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
693 if (it != objectIDMap.end())
694 {
695 strstr << it->second;
696 }
697 else
698 {
699 int id = 0;
700
701 switch (node->getResourceTypeForDiagnostics())
702 {
703 case CommandGraphResourceType::Buffer:
704 id = bufferIDCounter++;
705 break;
706 case CommandGraphResourceType::Framebuffer:
707 id = framebufferIDCounter++;
708 break;
709 case CommandGraphResourceType::Image:
710 id = imageIDCounter++;
711 break;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400712 case CommandGraphResourceType::Query:
713 id = queryIDCounter++;
714 break;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400715 default:
716 UNREACHABLE();
717 break;
718 }
719
720 objectIDMap[node->getResourceIDForDiagnostics()] = id;
721 strstr << id;
722 }
723
724 const std::string &label = strstr.str();
725 out << " " << nodeID << "[label =<" << label << "<BR/> <FONT POINT-SIZE=\"10\">Node ID "
726 << nodeID << "</FONT>>];" << std::endl;
727 }
728
729 for (const CommandGraphNode *node : mNodes)
730 {
731 int nodeID = nodeIDMap[node];
732
733 for (const CommandGraphNode *parent : node->getParentsForDiagnostics())
734 {
735 int parentID = nodeIDMap[parent];
736 out << " " << parentID << " -> " << nodeID << ";" << std::endl;
737 }
738 }
739
740 out << "}" << std::endl;
741}
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400742
743CommandGraphNode *CommandGraph::getLastBarrierNode(size_t *indexOut)
744{
745 *indexOut = mLastBarrierIndex == kInvalidNodeIndex ? 0 : mLastBarrierIndex;
746 return mLastBarrierIndex == kInvalidNodeIndex ? nullptr : mNodes[mLastBarrierIndex];
747}
748
749void CommandGraph::addDependenciesToNextBarrier(size_t begin,
750 size_t end,
751 CommandGraphNode *nextBarrier)
752{
753 for (size_t i = begin; i < end; ++i)
754 {
755 // As a small optimization, only add edges to childless nodes. The others have an
756 // indirect dependency.
757 if (!mNodes[i]->hasChildren())
758 {
759 CommandGraphNode::SetHappensBeforeDependency(mNodes[i], nextBarrier);
760 }
761 }
762}
763
Jamie Madill1f46bc12018-02-20 16:09:43 -0500764} // namespace vk
765} // namespace rx