blob: eca16932832bef2cb1148d96d0200314d05fdc0e [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 Madill1f46bc12018-02-20 16:09:43 -050036 createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -050037 createInfo.commandPool = commandPool.getHandle();
38 createInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
39 createInfo.commandBufferCount = 1;
40
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 Madill1f46bc12018-02-20 16:09:43 -050044 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -050045 beginInfo.flags = flags | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
46 beginInfo.pInheritanceInfo = &inheritanceInfo;
47
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)
85 : mCurrentWritingNode(nullptr), mResourceType(resourceType)
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
91void CommandGraphResource::updateQueueSerial(Serial queueSerial)
92{
93 ASSERT(queueSerial >= mStoredQueueSerial);
94
95 if (queueSerial > mStoredQueueSerial)
96 {
97 mCurrentWritingNode = nullptr;
98 mCurrentReadingNodes.clear();
99 mStoredQueueSerial = queueSerial;
100 }
101}
102
Jamie Madillc57ee252018-05-30 19:53:48 -0400103bool CommandGraphResource::isResourceInUse(RendererVk *renderer) const
104{
105 return renderer->isSerialInUse(mStoredQueueSerial);
106}
107
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400108bool CommandGraphResource::hasPendingWork(RendererVk *renderer) const
109{
110 // If the renderer has a queue serial higher than the stored one, the command buffers recorded
111 // by this resource have already been submitted, so there is no pending work.
112 return mStoredQueueSerial == renderer->getCurrentQueueSerial();
113}
114
Jamie Madillc57ee252018-05-30 19:53:48 -0400115Serial CommandGraphResource::getStoredQueueSerial() const
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400116{
117 return mStoredQueueSerial;
118}
119
Jamie Madille2d22702018-09-19 08:11:48 -0400120angle::Result CommandGraphResource::recordCommands(Context *context,
121 CommandBuffer **commandBufferOut)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400122{
Jamie Madill21061022018-07-12 23:56:30 -0400123 updateQueueSerial(context->getRenderer()->getCurrentQueueSerial());
Jamie Madill5dca6512018-05-30 10:53:51 -0400124
Jamie Madille2d22702018-09-19 08:11:48 -0400125 if (!hasChildlessWritingNode() || hasStartedRenderPass())
Jamie Madill316c6062018-05-29 10:49:45 -0400126 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400127 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::Generic);
Jamie Madille2d22702018-09-19 08:11:48 -0400128 return mCurrentWritingNode->beginOutsideRenderPassRecording(
129 context, context->getRenderer()->getCommandPool(), commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400130 }
131
132 CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
133 if (!outsideRenderPassCommands->valid())
134 {
135 ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
Jamie Madill21061022018-07-12 23:56:30 -0400136 context, context->getRenderer()->getCommandPool(), commandBufferOut));
Jamie Madill316c6062018-05-29 10:49:45 -0400137 }
138 else
139 {
140 *commandBufferOut = outsideRenderPassCommands;
141 }
142
Jamie Madill21061022018-07-12 23:56:30 -0400143 return angle::Result::Continue();
Jamie Madill316c6062018-05-29 10:49:45 -0400144}
145
Jamie Madill5dca6512018-05-30 10:53:51 -0400146bool CommandGraphResource::appendToStartedRenderPass(RendererVk *renderer,
147 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400148{
Jamie Madill5dca6512018-05-30 10:53:51 -0400149 updateQueueSerial(renderer->getCurrentQueueSerial());
150 if (hasStartedRenderPass())
151 {
152 *commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands();
153 return true;
154 }
155 else
156 {
157 return false;
158 }
Jamie Madill316c6062018-05-29 10:49:45 -0400159}
160
Jamie Madill316c6062018-05-29 10:49:45 -0400161const gl::Rectangle &CommandGraphResource::getRenderPassRenderArea() const
162{
163 ASSERT(hasStartedRenderPass());
164 return mCurrentWritingNode->getRenderPassRenderArea();
165}
166
Jamie Madill21061022018-07-12 23:56:30 -0400167angle::Result CommandGraphResource::beginRenderPass(Context *context,
168 const Framebuffer &framebuffer,
169 const gl::Rectangle &renderArea,
170 const RenderPassDesc &renderPassDesc,
171 const std::vector<VkClearValue> &clearValues,
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400172 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400173{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400174 // If a barrier has been inserted in the meantime, stop the command buffer.
175 if (!hasChildlessWritingNode())
176 {
177 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::Generic);
178 }
179
Jamie Madill316c6062018-05-29 10:49:45 -0400180 // Hard-code RenderPass to clear the first render target to the current clear value.
181 // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
182 mCurrentWritingNode->storeRenderPassInfo(framebuffer, renderArea, renderPassDesc, clearValues);
183
Jamie Madill21061022018-07-12 23:56:30 -0400184 return mCurrentWritingNode->beginInsideRenderPassRecording(context, commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400185}
186
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400187void CommandGraphResource::beginQuery(Context *context,
188 const QueryPool *queryPool,
189 uint32_t queryIndex)
190{
191 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::BeginQuery);
192 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
193}
194
195void CommandGraphResource::endQuery(Context *context,
196 const QueryPool *queryPool,
197 uint32_t queryIndex)
198{
199 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::EndQuery);
200 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
201}
202
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400203void CommandGraphResource::writeTimestamp(Context *context,
204 const QueryPool *queryPool,
205 uint32_t queryIndex)
206{
207 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::WriteTimestamp);
208 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
209}
210
Jamie Madille2d22702018-09-19 08:11:48 -0400211void CommandGraphResource::finishCurrentCommands(RendererVk *renderer)
Jamie Madill316c6062018-05-29 10:49:45 -0400212{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400213 startNewCommands(renderer, CommandGraphNodeFunction::Generic);
214}
215
216void CommandGraphResource::startNewCommands(RendererVk *renderer, CommandGraphNodeFunction function)
217{
218 bool isBarrier = function != CommandGraphNodeFunction::Generic;
219 CommandGraphNode *newCommands = renderer->getCommandGraph()->allocateNode(isBarrier, function);
Jamie Madill0da73fe2018-10-02 09:31:39 -0400220 newCommands->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
Jamie Madill86ce2102018-05-22 11:54:42 -0400221 onWriteImpl(newCommands, renderer->getCurrentQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400222}
223
224void CommandGraphResource::addWriteDependency(CommandGraphResource *writingResource)
225{
226 CommandGraphNode *writingNode = writingResource->mCurrentWritingNode;
227 ASSERT(writingNode);
228
Jamie Madillc57ee252018-05-30 19:53:48 -0400229 onWriteImpl(writingNode, writingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400230}
231
232void CommandGraphResource::onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial)
233{
234 updateQueueSerial(currentSerial);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400235
Jamie Madill9cceac42018-03-31 14:19:16 -0400236 // Make sure any open reads and writes finish before we execute 'writingNode'.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400237 if (!mCurrentReadingNodes.empty())
238 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400239 CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes.data(),
240 mCurrentReadingNodes.size(), writingNode);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400241 mCurrentReadingNodes.clear();
242 }
243
244 if (mCurrentWritingNode && mCurrentWritingNode != writingNode)
245 {
246 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, writingNode);
247 }
248
249 mCurrentWritingNode = writingNode;
250}
251
Jamie Madill316c6062018-05-29 10:49:45 -0400252void CommandGraphResource::addReadDependency(CommandGraphResource *readingResource)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400253{
Jamie Madillc57ee252018-05-30 19:53:48 -0400254 updateQueueSerial(readingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400255
256 CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
257 ASSERT(readingNode);
Jamie Madill9cceac42018-03-31 14:19:16 -0400258
259 if (hasChildlessWritingNode())
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400260 {
Jamie Madill9cceac42018-03-31 14:19:16 -0400261 // Ensure 'readingNode' happens after the current writing node.
262 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
263 }
264
265 // Add the read node to the list of nodes currently reading this resource.
266 mCurrentReadingNodes.push_back(readingNode);
267}
268
Jamie Madill1f46bc12018-02-20 16:09:43 -0500269// CommandGraphNode implementation.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400270CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function)
271 : mRenderPassClearValues{},
272 mFunction(function),
273 mQueryPool(VK_NULL_HANDLE),
274 mQueryIndex(0),
275 mHasChildren(false),
276 mVisitedState(VisitedState::Unvisited)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500277{
278}
279
280CommandGraphNode::~CommandGraphNode()
281{
282 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
283
284 // Command buffers are managed by the command pool, so don't need to be freed.
285 mOutsideRenderPassCommands.releaseHandle();
286 mInsideRenderPassCommands.releaseHandle();
287}
288
289CommandBuffer *CommandGraphNode::getOutsideRenderPassCommands()
290{
291 ASSERT(!mHasChildren);
292 return &mOutsideRenderPassCommands;
293}
294
Jamie Madill21061022018-07-12 23:56:30 -0400295angle::Result CommandGraphNode::beginOutsideRenderPassRecording(Context *context,
296 const CommandPool &commandPool,
297 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500298{
299 ASSERT(!mHasChildren);
300
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400301 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500302 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500303 inheritanceInfo.renderPass = VK_NULL_HANDLE;
304 inheritanceInfo.subpass = 0;
305 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400306 inheritanceInfo.occlusionQueryEnable =
307 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500308 inheritanceInfo.queryFlags = 0;
309 inheritanceInfo.pipelineStatistics = 0;
310
Jamie Madill21061022018-07-12 23:56:30 -0400311 ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500312 &mOutsideRenderPassCommands));
313
314 *commandsOut = &mOutsideRenderPassCommands;
Jamie Madill21061022018-07-12 23:56:30 -0400315 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500316}
317
Jamie Madill21061022018-07-12 23:56:30 -0400318angle::Result CommandGraphNode::beginInsideRenderPassRecording(Context *context,
319 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500320{
321 ASSERT(!mHasChildren);
322
323 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400324 // TODO(jmadill): Support query for compatible/conformant render pass. http://anglebug.com/2361
Jamie Madill1f46bc12018-02-20 16:09:43 -0500325 RenderPass *compatibleRenderPass;
Jamie Madill21061022018-07-12 23:56:30 -0400326 ANGLE_TRY(context->getRenderer()->getCompatibleRenderPass(context, mRenderPassDesc,
327 &compatibleRenderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500328
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400329 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500330 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500331 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
332 inheritanceInfo.subpass = 0;
333 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400334 inheritanceInfo.occlusionQueryEnable =
335 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500336 inheritanceInfo.queryFlags = 0;
337 inheritanceInfo.pipelineStatistics = 0;
338
339 ANGLE_TRY(InitAndBeginCommandBuffer(
Jamie Madill21061022018-07-12 23:56:30 -0400340 context, context->getRenderer()->getCommandPool(), inheritanceInfo,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500341 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
342
343 *commandsOut = &mInsideRenderPassCommands;
Jamie Madill21061022018-07-12 23:56:30 -0400344 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500345}
346
347void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
348 const gl::Rectangle renderArea,
Jamie Madillbcf467f2018-05-23 09:46:00 -0400349 const vk::RenderPassDesc &renderPassDesc,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500350 const std::vector<VkClearValue> &clearValues)
351{
Jamie Madillbcf467f2018-05-23 09:46:00 -0400352 mRenderPassDesc = renderPassDesc;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500353 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
354 mRenderPassRenderArea = renderArea;
355 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
356}
357
Jamie Madill1f46bc12018-02-20 16:09:43 -0500358// static
359void CommandGraphNode::SetHappensBeforeDependency(CommandGraphNode *beforeNode,
360 CommandGraphNode *afterNode)
361{
Jamie Madill9cceac42018-03-31 14:19:16 -0400362 ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500363 afterNode->mParents.emplace_back(beforeNode);
364 beforeNode->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500365}
366
367// static
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400368void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode **beforeNodes,
369 size_t beforeNodesCount,
370 CommandGraphNode *afterNode)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500371{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400372 afterNode->mParents.insert(afterNode->mParents.end(), beforeNodes,
373 beforeNodes + beforeNodesCount);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500374
375 // TODO(jmadill): is there a faster way to do this?
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400376 for (size_t i = 0; i < beforeNodesCount; ++i)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500377 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400378 beforeNodes[i]->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500379
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400380 ASSERT(beforeNodes[i] != afterNode && !beforeNodes[i]->isChildOf(afterNode));
381 }
382}
383
384void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode *beforeNode,
385 CommandGraphNode **afterNodes,
386 size_t afterNodesCount)
387{
388 for (size_t i = 0; i < afterNodesCount; ++i)
389 {
390 SetHappensBeforeDependency(beforeNode, afterNodes[i]);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500391 }
392}
393
394bool CommandGraphNode::hasParents() const
395{
396 return !mParents.empty();
397}
398
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400399void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIndex)
400{
401 ASSERT(mFunction == CommandGraphNodeFunction::BeginQuery ||
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400402 mFunction == CommandGraphNodeFunction::EndQuery ||
403 mFunction == CommandGraphNodeFunction::WriteTimestamp);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400404 mQueryPool = queryPool->getHandle();
405 mQueryIndex = queryIndex;
406}
407
Jamie Madill1f46bc12018-02-20 16:09:43 -0500408void CommandGraphNode::setHasChildren()
409{
410 mHasChildren = true;
411}
412
Jamie Madill1f46bc12018-02-20 16:09:43 -0500413// Do not call this in anything but testing code, since it's slow.
414bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
415{
416 std::set<CommandGraphNode *> visitedList;
417 std::vector<CommandGraphNode *> openList;
418 openList.insert(openList.begin(), mParents.begin(), mParents.end());
419 while (!openList.empty())
420 {
421 CommandGraphNode *current = openList.back();
422 openList.pop_back();
423 if (visitedList.count(current) == 0)
424 {
425 if (current == parent)
426 {
427 return true;
428 }
429 visitedList.insert(current);
430 openList.insert(openList.end(), current->mParents.begin(), current->mParents.end());
431 }
432 }
433
434 return false;
435}
436
437VisitedState CommandGraphNode::visitedState() const
438{
439 return mVisitedState;
440}
441
442void CommandGraphNode::visitParents(std::vector<CommandGraphNode *> *stack)
443{
444 ASSERT(mVisitedState == VisitedState::Unvisited);
445 stack->insert(stack->end(), mParents.begin(), mParents.end());
446 mVisitedState = VisitedState::Ready;
447}
448
Jamie Madill21061022018-07-12 23:56:30 -0400449angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
450 Serial serial,
451 RenderPassCache *renderPassCache,
452 CommandBuffer *primaryCommandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500453{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400454 switch (mFunction)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500455 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400456 case CommandGraphNodeFunction::Generic:
457 ASSERT(mQueryPool == VK_NULL_HANDLE);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500458
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400459 if (mOutsideRenderPassCommands.valid())
460 {
461 ANGLE_TRY(mOutsideRenderPassCommands.end(context));
462 primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
463 }
Jamie Madill1f46bc12018-02-20 16:09:43 -0500464
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400465 if (mInsideRenderPassCommands.valid())
466 {
467 // Pull a compatible RenderPass from the cache.
468 // TODO(jmadill): Insert real ops and layout transitions.
469 RenderPass *renderPass = nullptr;
470 ANGLE_TRY(renderPassCache->getCompatibleRenderPass(context, serial, mRenderPassDesc,
471 &renderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500472
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400473 ANGLE_TRY(mInsideRenderPassCommands.end(context));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500474
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400475 VkRenderPassBeginInfo beginInfo = {};
476 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
477 beginInfo.renderPass = renderPass->getHandle();
478 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
479 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
480 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
481 beginInfo.renderArea.extent.width =
482 static_cast<uint32_t>(mRenderPassRenderArea.width);
483 beginInfo.renderArea.extent.height =
484 static_cast<uint32_t>(mRenderPassRenderArea.height);
485 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
486 beginInfo.pClearValues = mRenderPassClearValues.data();
487
488 primaryCommandBuffer->beginRenderPass(
489 beginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
490 primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
491 primaryCommandBuffer->endRenderPass();
492 }
493 break;
494
495 case CommandGraphNodeFunction::BeginQuery:
496 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
497 ASSERT(mQueryPool != VK_NULL_HANDLE);
498
499 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
500 primaryCommandBuffer->beginQuery(mQueryPool, mQueryIndex, 0);
501
502 break;
503
504 case CommandGraphNodeFunction::EndQuery:
505 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
506 ASSERT(mQueryPool != VK_NULL_HANDLE);
507
508 primaryCommandBuffer->endQuery(mQueryPool, mQueryIndex);
509
510 break;
511
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400512 case CommandGraphNodeFunction::WriteTimestamp:
513 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
514 ASSERT(mQueryPool != VK_NULL_HANDLE);
515
516 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
517 primaryCommandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, mQueryPool,
518 mQueryIndex);
519
520 break;
521
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400522 default:
523 UNREACHABLE();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500524 }
525
526 mVisitedState = VisitedState::Visited;
Jamie Madill21061022018-07-12 23:56:30 -0400527 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500528}
529
Jamie Madill0da73fe2018-10-02 09:31:39 -0400530const std::vector<CommandGraphNode *> &CommandGraphNode::getParentsForDiagnostics() const
531{
532 return mParents;
533}
534
535void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType,
536 uintptr_t resourceID)
537{
538 mResourceType = resourceType;
539 mResourceID = resourceID;
540}
541
Luc Ferron14f48172018-04-11 08:43:28 -0400542const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
543{
544 return mRenderPassRenderArea;
545}
546
Jamie Madill1f46bc12018-02-20 16:09:43 -0500547// CommandGraph implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -0400548CommandGraph::CommandGraph(bool enableGraphDiagnostics)
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400549 : mEnableGraphDiagnostics(enableGraphDiagnostics), mLastBarrierIndex(kInvalidNodeIndex)
Jamie Madill0da73fe2018-10-02 09:31:39 -0400550{
551}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500552
553CommandGraph::~CommandGraph()
554{
555 ASSERT(empty());
556}
557
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400558CommandGraphNode *CommandGraph::allocateNode(bool isBarrier, CommandGraphNodeFunction function)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500559{
560 // TODO(jmadill): Use a pool allocator for the CPU node allocations.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400561 CommandGraphNode *newCommands = new CommandGraphNode(function);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500562 mNodes.emplace_back(newCommands);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400563
564 if (isBarrier)
565 {
566 setNewBarrier(newCommands);
567 }
568
Jamie Madill1f46bc12018-02-20 16:09:43 -0500569 return newCommands;
570}
571
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400572void CommandGraph::setNewBarrier(CommandGraphNode *newBarrier)
573{
574 size_t previousBarrierIndex = 0;
575 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
576
577 // Add a dependency from previousBarrier to all nodes in (previousBarrier, newBarrier].
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
585 // Add a dependency from all nodes in (previousBarrier, newBarrier) to newBarrier.
586 addDependenciesToNextBarrier(previousBarrierIndex + 1, mNodes.size() - 1, newBarrier);
587
588 mLastBarrierIndex = mNodes.size() - 1;
589}
590
Jamie Madill21061022018-07-12 23:56:30 -0400591angle::Result CommandGraph::submitCommands(Context *context,
592 Serial serial,
593 RenderPassCache *renderPassCache,
594 CommandPool *commandPool,
595 CommandBuffer *primaryCommandBufferOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500596{
Shahbaz Youssefi3a482172018-10-11 10:34:44 -0400597 // There is no point in submitting an empty command buffer, so make sure not to call this
598 // function if there's nothing to do.
599 ASSERT(!mNodes.empty());
600
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400601 size_t previousBarrierIndex = 0;
602 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
603
604 // Add a dependency from previousBarrier to all nodes in (previousBarrier, end].
605 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
606 {
607 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
608 CommandGraphNode::SetHappensBeforeDependencies(
609 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
610 }
611
Shahbaz Youssefi3a482172018-10-11 10:34:44 -0400612 mLastBarrierIndex = kInvalidNodeIndex;
613
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400614 VkCommandBufferAllocateInfo primaryInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500615 primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500616 primaryInfo.commandPool = commandPool->getHandle();
617 primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
618 primaryInfo.commandBufferCount = 1;
619
Jamie Madill21061022018-07-12 23:56:30 -0400620 ANGLE_TRY(primaryCommandBufferOut->init(context, primaryInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500621
Jamie Madill0da73fe2018-10-02 09:31:39 -0400622 if (mEnableGraphDiagnostics)
623 {
624 dumpGraphDotFile(std::cout);
625 }
626
Jamie Madill1f46bc12018-02-20 16:09:43 -0500627 std::vector<CommandGraphNode *> nodeStack;
628
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400629 VkCommandBufferBeginInfo beginInfo = {};
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400630 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
631 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
632 beginInfo.pInheritanceInfo = nullptr;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500633
Jamie Madill21061022018-07-12 23:56:30 -0400634 ANGLE_TRY(primaryCommandBufferOut->begin(context, beginInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500635
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400636 ANGLE_TRY(context->getRenderer()->traceGpuEvent(
637 context, primaryCommandBufferOut, TRACE_EVENT_PHASE_BEGIN, "Primary Command Buffer"));
638
Jamie Madill1f46bc12018-02-20 16:09:43 -0500639 for (CommandGraphNode *topLevelNode : mNodes)
640 {
641 // Only process commands that don't have child commands. The others will be pulled in
642 // automatically. Also skip commands that have already been visited.
643 if (topLevelNode->hasChildren() || topLevelNode->visitedState() != VisitedState::Unvisited)
644 continue;
645
646 nodeStack.push_back(topLevelNode);
647
648 while (!nodeStack.empty())
649 {
650 CommandGraphNode *node = nodeStack.back();
651
652 switch (node->visitedState())
653 {
654 case VisitedState::Unvisited:
655 node->visitParents(&nodeStack);
656 break;
657 case VisitedState::Ready:
Jamie Madill21061022018-07-12 23:56:30 -0400658 ANGLE_TRY(node->visitAndExecute(context, serial, renderPassCache,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500659 primaryCommandBufferOut));
660 nodeStack.pop_back();
661 break;
662 case VisitedState::Visited:
663 nodeStack.pop_back();
664 break;
665 default:
666 UNREACHABLE();
667 break;
668 }
669 }
670 }
671
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400672 ANGLE_TRY(context->getRenderer()->traceGpuEvent(
673 context, primaryCommandBufferOut, TRACE_EVENT_PHASE_END, "Primary Command Buffer"));
674
Jamie Madill21061022018-07-12 23:56:30 -0400675 ANGLE_TRY(primaryCommandBufferOut->end(context));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500676
677 // TODO(jmadill): Use pool allocation so we don't need to deallocate command graph.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400678 for (CommandGraphNode *node : mNodes)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500679 {
680 delete node;
681 }
682 mNodes.clear();
683
Jamie Madill21061022018-07-12 23:56:30 -0400684 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500685}
686
687bool CommandGraph::empty() const
688{
689 return mNodes.empty();
690}
691
Jamie Madill0da73fe2018-10-02 09:31:39 -0400692// Dumps the command graph into a dot file that works with graphviz.
693void CommandGraph::dumpGraphDotFile(std::ostream &out) const
694{
695 // This ID maps a node pointer to a monatonic ID. It allows us to look up parent node IDs.
696 std::map<const CommandGraphNode *, int> nodeIDMap;
697 std::map<uintptr_t, int> objectIDMap;
698
699 // Map nodes to ids.
700 for (size_t nodeIndex = 0; nodeIndex < mNodes.size(); ++nodeIndex)
701 {
702 const CommandGraphNode *node = mNodes[nodeIndex];
703 nodeIDMap[node] = static_cast<int>(nodeIndex) + 1;
704 }
705
706 int bufferIDCounter = 1;
707 int framebufferIDCounter = 1;
708 int imageIDCounter = 1;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400709 int queryIDCounter = 1;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400710
711 out << "digraph {" << std::endl;
712
713 for (const CommandGraphNode *node : mNodes)
714 {
715 int nodeID = nodeIDMap[node];
716
717 std::stringstream strstr;
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -0400718 strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics(), node->getFunction());
Jamie Madill0da73fe2018-10-02 09:31:39 -0400719 strstr << " ";
720
721 auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
722 if (it != objectIDMap.end())
723 {
724 strstr << it->second;
725 }
726 else
727 {
728 int id = 0;
729
730 switch (node->getResourceTypeForDiagnostics())
731 {
732 case CommandGraphResourceType::Buffer:
733 id = bufferIDCounter++;
734 break;
735 case CommandGraphResourceType::Framebuffer:
736 id = framebufferIDCounter++;
737 break;
738 case CommandGraphResourceType::Image:
739 id = imageIDCounter++;
740 break;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400741 case CommandGraphResourceType::Query:
742 id = queryIDCounter++;
743 break;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400744 default:
745 UNREACHABLE();
746 break;
747 }
748
749 objectIDMap[node->getResourceIDForDiagnostics()] = id;
750 strstr << id;
751 }
752
753 const std::string &label = strstr.str();
754 out << " " << nodeID << "[label =<" << label << "<BR/> <FONT POINT-SIZE=\"10\">Node ID "
755 << nodeID << "</FONT>>];" << std::endl;
756 }
757
758 for (const CommandGraphNode *node : mNodes)
759 {
760 int nodeID = nodeIDMap[node];
761
762 for (const CommandGraphNode *parent : node->getParentsForDiagnostics())
763 {
764 int parentID = nodeIDMap[parent];
765 out << " " << parentID << " -> " << nodeID << ";" << std::endl;
766 }
767 }
768
769 out << "}" << std::endl;
770}
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400771
772CommandGraphNode *CommandGraph::getLastBarrierNode(size_t *indexOut)
773{
774 *indexOut = mLastBarrierIndex == kInvalidNodeIndex ? 0 : mLastBarrierIndex;
775 return mLastBarrierIndex == kInvalidNodeIndex ? nullptr : mNodes[mLastBarrierIndex];
776}
777
778void CommandGraph::addDependenciesToNextBarrier(size_t begin,
779 size_t end,
780 CommandGraphNode *nextBarrier)
781{
782 for (size_t i = begin; i < end; ++i)
783 {
784 // As a small optimization, only add edges to childless nodes. The others have an
785 // indirect dependency.
786 if (!mNodes[i]->hasChildren())
787 {
788 CommandGraphNode::SetHappensBeforeDependency(mNodes[i], nextBarrier);
789 }
790 }
791}
792
Jamie Madill1f46bc12018-02-20 16:09:43 -0500793} // namespace vk
794} // namespace rx