blob: 6cadc029bafc7360599c4fbfe98357c6b497da39 [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";
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -040068 case CommandGraphNodeFunction::WriteTimestamp:
69 return "WriteTimestamp";
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040070 default:
71 UNREACHABLE();
72 return "Query";
73 }
Jamie Madill0da73fe2018-10-02 09:31:39 -040074 default:
75 UNREACHABLE();
76 return "";
77 }
78}
Jamie Madill1f46bc12018-02-20 16:09:43 -050079} // anonymous namespace
80
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040081// CommandGraphResource implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -040082CommandGraphResource::CommandGraphResource(CommandGraphResourceType resourceType)
83 : mCurrentWritingNode(nullptr), mResourceType(resourceType)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040084{
85}
86
Jamie Madill316c6062018-05-29 10:49:45 -040087CommandGraphResource::~CommandGraphResource() = default;
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040088
89void CommandGraphResource::updateQueueSerial(Serial queueSerial)
90{
91 ASSERT(queueSerial >= mStoredQueueSerial);
92
93 if (queueSerial > mStoredQueueSerial)
94 {
95 mCurrentWritingNode = nullptr;
96 mCurrentReadingNodes.clear();
97 mStoredQueueSerial = queueSerial;
98 }
99}
100
Jamie Madillc57ee252018-05-30 19:53:48 -0400101bool CommandGraphResource::isResourceInUse(RendererVk *renderer) const
102{
103 return renderer->isSerialInUse(mStoredQueueSerial);
104}
105
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400106bool CommandGraphResource::hasPendingWork(RendererVk *renderer) const
107{
108 // If the renderer has a queue serial higher than the stored one, the command buffers recorded
109 // by this resource have already been submitted, so there is no pending work.
110 return mStoredQueueSerial == renderer->getCurrentQueueSerial();
111}
112
Jamie Madillc57ee252018-05-30 19:53:48 -0400113Serial CommandGraphResource::getStoredQueueSerial() const
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400114{
115 return mStoredQueueSerial;
116}
117
Jamie Madille2d22702018-09-19 08:11:48 -0400118angle::Result CommandGraphResource::recordCommands(Context *context,
119 CommandBuffer **commandBufferOut)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400120{
Jamie Madill21061022018-07-12 23:56:30 -0400121 updateQueueSerial(context->getRenderer()->getCurrentQueueSerial());
Jamie Madill5dca6512018-05-30 10:53:51 -0400122
Jamie Madille2d22702018-09-19 08:11:48 -0400123 if (!hasChildlessWritingNode() || hasStartedRenderPass())
Jamie Madill316c6062018-05-29 10:49:45 -0400124 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400125 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::Generic);
Jamie Madille2d22702018-09-19 08:11:48 -0400126 return mCurrentWritingNode->beginOutsideRenderPassRecording(
127 context, context->getRenderer()->getCommandPool(), commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400128 }
129
130 CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
131 if (!outsideRenderPassCommands->valid())
132 {
133 ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
Jamie Madill21061022018-07-12 23:56:30 -0400134 context, context->getRenderer()->getCommandPool(), commandBufferOut));
Jamie Madill316c6062018-05-29 10:49:45 -0400135 }
136 else
137 {
138 *commandBufferOut = outsideRenderPassCommands;
139 }
140
Jamie Madill21061022018-07-12 23:56:30 -0400141 return angle::Result::Continue();
Jamie Madill316c6062018-05-29 10:49:45 -0400142}
143
Jamie Madill5dca6512018-05-30 10:53:51 -0400144bool CommandGraphResource::appendToStartedRenderPass(RendererVk *renderer,
145 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400146{
Jamie Madill5dca6512018-05-30 10:53:51 -0400147 updateQueueSerial(renderer->getCurrentQueueSerial());
148 if (hasStartedRenderPass())
149 {
150 *commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands();
151 return true;
152 }
153 else
154 {
155 return false;
156 }
Jamie Madill316c6062018-05-29 10:49:45 -0400157}
158
Jamie Madill316c6062018-05-29 10:49:45 -0400159const gl::Rectangle &CommandGraphResource::getRenderPassRenderArea() const
160{
161 ASSERT(hasStartedRenderPass());
162 return mCurrentWritingNode->getRenderPassRenderArea();
163}
164
Jamie Madill21061022018-07-12 23:56:30 -0400165angle::Result CommandGraphResource::beginRenderPass(Context *context,
166 const Framebuffer &framebuffer,
167 const gl::Rectangle &renderArea,
168 const RenderPassDesc &renderPassDesc,
169 const std::vector<VkClearValue> &clearValues,
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400170 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400171{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400172 // If a barrier has been inserted in the meantime, stop the command buffer.
173 if (!hasChildlessWritingNode())
174 {
175 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::Generic);
176 }
177
Jamie Madill316c6062018-05-29 10:49:45 -0400178 // Hard-code RenderPass to clear the first render target to the current clear value.
179 // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
180 mCurrentWritingNode->storeRenderPassInfo(framebuffer, renderArea, renderPassDesc, clearValues);
181
Jamie Madill21061022018-07-12 23:56:30 -0400182 return mCurrentWritingNode->beginInsideRenderPassRecording(context, commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400183}
184
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400185void CommandGraphResource::beginQuery(Context *context,
186 const QueryPool *queryPool,
187 uint32_t queryIndex)
188{
189 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::BeginQuery);
190 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
191}
192
193void CommandGraphResource::endQuery(Context *context,
194 const QueryPool *queryPool,
195 uint32_t queryIndex)
196{
197 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::EndQuery);
198 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
199}
200
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400201void CommandGraphResource::writeTimestamp(Context *context,
202 const QueryPool *queryPool,
203 uint32_t queryIndex)
204{
205 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::WriteTimestamp);
206 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
207}
208
Jamie Madille2d22702018-09-19 08:11:48 -0400209void CommandGraphResource::finishCurrentCommands(RendererVk *renderer)
Jamie Madill316c6062018-05-29 10:49:45 -0400210{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400211 startNewCommands(renderer, CommandGraphNodeFunction::Generic);
212}
213
214void CommandGraphResource::startNewCommands(RendererVk *renderer, CommandGraphNodeFunction function)
215{
216 bool isBarrier = function != CommandGraphNodeFunction::Generic;
217 CommandGraphNode *newCommands = renderer->getCommandGraph()->allocateNode(isBarrier, function);
Jamie Madill0da73fe2018-10-02 09:31:39 -0400218 newCommands->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
Jamie Madill86ce2102018-05-22 11:54:42 -0400219 onWriteImpl(newCommands, renderer->getCurrentQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400220}
221
222void CommandGraphResource::addWriteDependency(CommandGraphResource *writingResource)
223{
224 CommandGraphNode *writingNode = writingResource->mCurrentWritingNode;
225 ASSERT(writingNode);
226
Jamie Madillc57ee252018-05-30 19:53:48 -0400227 onWriteImpl(writingNode, writingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400228}
229
230void CommandGraphResource::onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial)
231{
232 updateQueueSerial(currentSerial);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400233
Jamie Madill9cceac42018-03-31 14:19:16 -0400234 // Make sure any open reads and writes finish before we execute 'writingNode'.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400235 if (!mCurrentReadingNodes.empty())
236 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400237 CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes.data(),
238 mCurrentReadingNodes.size(), writingNode);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400239 mCurrentReadingNodes.clear();
240 }
241
242 if (mCurrentWritingNode && mCurrentWritingNode != writingNode)
243 {
244 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, writingNode);
245 }
246
247 mCurrentWritingNode = writingNode;
248}
249
Jamie Madill316c6062018-05-29 10:49:45 -0400250void CommandGraphResource::addReadDependency(CommandGraphResource *readingResource)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400251{
Jamie Madillc57ee252018-05-30 19:53:48 -0400252 updateQueueSerial(readingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400253
254 CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
255 ASSERT(readingNode);
Jamie Madill9cceac42018-03-31 14:19:16 -0400256
257 if (hasChildlessWritingNode())
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400258 {
Jamie Madill9cceac42018-03-31 14:19:16 -0400259 // Ensure 'readingNode' happens after the current writing node.
260 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
261 }
262
263 // Add the read node to the list of nodes currently reading this resource.
264 mCurrentReadingNodes.push_back(readingNode);
265}
266
Jamie Madill1f46bc12018-02-20 16:09:43 -0500267// CommandGraphNode implementation.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400268CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function)
269 : mRenderPassClearValues{},
270 mFunction(function),
271 mQueryPool(VK_NULL_HANDLE),
272 mQueryIndex(0),
273 mHasChildren(false),
274 mVisitedState(VisitedState::Unvisited)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500275{
276}
277
278CommandGraphNode::~CommandGraphNode()
279{
280 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
281
282 // Command buffers are managed by the command pool, so don't need to be freed.
283 mOutsideRenderPassCommands.releaseHandle();
284 mInsideRenderPassCommands.releaseHandle();
285}
286
287CommandBuffer *CommandGraphNode::getOutsideRenderPassCommands()
288{
289 ASSERT(!mHasChildren);
290 return &mOutsideRenderPassCommands;
291}
292
Jamie Madill21061022018-07-12 23:56:30 -0400293angle::Result CommandGraphNode::beginOutsideRenderPassRecording(Context *context,
294 const CommandPool &commandPool,
295 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500296{
297 ASSERT(!mHasChildren);
298
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400299 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500300 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500301 inheritanceInfo.renderPass = VK_NULL_HANDLE;
302 inheritanceInfo.subpass = 0;
303 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400304 inheritanceInfo.occlusionQueryEnable =
305 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500306 inheritanceInfo.queryFlags = 0;
307 inheritanceInfo.pipelineStatistics = 0;
308
Jamie Madill21061022018-07-12 23:56:30 -0400309 ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500310 &mOutsideRenderPassCommands));
311
312 *commandsOut = &mOutsideRenderPassCommands;
Jamie Madill21061022018-07-12 23:56:30 -0400313 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500314}
315
Jamie Madill21061022018-07-12 23:56:30 -0400316angle::Result CommandGraphNode::beginInsideRenderPassRecording(Context *context,
317 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500318{
319 ASSERT(!mHasChildren);
320
321 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400322 // TODO(jmadill): Support query for compatible/conformant render pass. http://anglebug.com/2361
Jamie Madill1f46bc12018-02-20 16:09:43 -0500323 RenderPass *compatibleRenderPass;
Jamie Madill21061022018-07-12 23:56:30 -0400324 ANGLE_TRY(context->getRenderer()->getCompatibleRenderPass(context, mRenderPassDesc,
325 &compatibleRenderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500326
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400327 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500328 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500329 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
330 inheritanceInfo.subpass = 0;
331 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400332 inheritanceInfo.occlusionQueryEnable =
333 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500334 inheritanceInfo.queryFlags = 0;
335 inheritanceInfo.pipelineStatistics = 0;
336
337 ANGLE_TRY(InitAndBeginCommandBuffer(
Jamie Madill21061022018-07-12 23:56:30 -0400338 context, context->getRenderer()->getCommandPool(), inheritanceInfo,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500339 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
340
341 *commandsOut = &mInsideRenderPassCommands;
Jamie Madill21061022018-07-12 23:56:30 -0400342 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500343}
344
345void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
346 const gl::Rectangle renderArea,
Jamie Madillbcf467f2018-05-23 09:46:00 -0400347 const vk::RenderPassDesc &renderPassDesc,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500348 const std::vector<VkClearValue> &clearValues)
349{
Jamie Madillbcf467f2018-05-23 09:46:00 -0400350 mRenderPassDesc = renderPassDesc;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500351 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
352 mRenderPassRenderArea = renderArea;
353 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
354}
355
Jamie Madill1f46bc12018-02-20 16:09:43 -0500356// static
357void CommandGraphNode::SetHappensBeforeDependency(CommandGraphNode *beforeNode,
358 CommandGraphNode *afterNode)
359{
Jamie Madill9cceac42018-03-31 14:19:16 -0400360 ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500361 afterNode->mParents.emplace_back(beforeNode);
362 beforeNode->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500363}
364
365// static
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400366void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode **beforeNodes,
367 size_t beforeNodesCount,
368 CommandGraphNode *afterNode)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500369{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400370 afterNode->mParents.insert(afterNode->mParents.end(), beforeNodes,
371 beforeNodes + beforeNodesCount);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500372
373 // TODO(jmadill): is there a faster way to do this?
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400374 for (size_t i = 0; i < beforeNodesCount; ++i)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500375 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400376 beforeNodes[i]->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500377
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400378 ASSERT(beforeNodes[i] != afterNode && !beforeNodes[i]->isChildOf(afterNode));
379 }
380}
381
382void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode *beforeNode,
383 CommandGraphNode **afterNodes,
384 size_t afterNodesCount)
385{
386 for (size_t i = 0; i < afterNodesCount; ++i)
387 {
388 SetHappensBeforeDependency(beforeNode, afterNodes[i]);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500389 }
390}
391
392bool CommandGraphNode::hasParents() const
393{
394 return !mParents.empty();
395}
396
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400397void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIndex)
398{
399 ASSERT(mFunction == CommandGraphNodeFunction::BeginQuery ||
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400400 mFunction == CommandGraphNodeFunction::EndQuery ||
401 mFunction == CommandGraphNodeFunction::WriteTimestamp);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400402 mQueryPool = queryPool->getHandle();
403 mQueryIndex = queryIndex;
404}
405
Jamie Madill1f46bc12018-02-20 16:09:43 -0500406void CommandGraphNode::setHasChildren()
407{
408 mHasChildren = true;
409}
410
Jamie Madill1f46bc12018-02-20 16:09:43 -0500411// Do not call this in anything but testing code, since it's slow.
412bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
413{
414 std::set<CommandGraphNode *> visitedList;
415 std::vector<CommandGraphNode *> openList;
416 openList.insert(openList.begin(), mParents.begin(), mParents.end());
417 while (!openList.empty())
418 {
419 CommandGraphNode *current = openList.back();
420 openList.pop_back();
421 if (visitedList.count(current) == 0)
422 {
423 if (current == parent)
424 {
425 return true;
426 }
427 visitedList.insert(current);
428 openList.insert(openList.end(), current->mParents.begin(), current->mParents.end());
429 }
430 }
431
432 return false;
433}
434
435VisitedState CommandGraphNode::visitedState() const
436{
437 return mVisitedState;
438}
439
440void CommandGraphNode::visitParents(std::vector<CommandGraphNode *> *stack)
441{
442 ASSERT(mVisitedState == VisitedState::Unvisited);
443 stack->insert(stack->end(), mParents.begin(), mParents.end());
444 mVisitedState = VisitedState::Ready;
445}
446
Jamie Madill21061022018-07-12 23:56:30 -0400447angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
448 Serial serial,
449 RenderPassCache *renderPassCache,
450 CommandBuffer *primaryCommandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500451{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400452 switch (mFunction)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500453 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400454 case CommandGraphNodeFunction::Generic:
455 ASSERT(mQueryPool == VK_NULL_HANDLE);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500456
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400457 if (mOutsideRenderPassCommands.valid())
458 {
459 ANGLE_TRY(mOutsideRenderPassCommands.end(context));
460 primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
461 }
Jamie Madill1f46bc12018-02-20 16:09:43 -0500462
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400463 if (mInsideRenderPassCommands.valid())
464 {
465 // Pull a compatible RenderPass from the cache.
466 // TODO(jmadill): Insert real ops and layout transitions.
467 RenderPass *renderPass = nullptr;
468 ANGLE_TRY(renderPassCache->getCompatibleRenderPass(context, serial, mRenderPassDesc,
469 &renderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500470
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400471 ANGLE_TRY(mInsideRenderPassCommands.end(context));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500472
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400473 VkRenderPassBeginInfo beginInfo = {};
474 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
475 beginInfo.renderPass = renderPass->getHandle();
476 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
477 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
478 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
479 beginInfo.renderArea.extent.width =
480 static_cast<uint32_t>(mRenderPassRenderArea.width);
481 beginInfo.renderArea.extent.height =
482 static_cast<uint32_t>(mRenderPassRenderArea.height);
483 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
484 beginInfo.pClearValues = mRenderPassClearValues.data();
485
486 primaryCommandBuffer->beginRenderPass(
487 beginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
488 primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
489 primaryCommandBuffer->endRenderPass();
490 }
491 break;
492
493 case CommandGraphNodeFunction::BeginQuery:
494 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
495 ASSERT(mQueryPool != VK_NULL_HANDLE);
496
497 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
498 primaryCommandBuffer->beginQuery(mQueryPool, mQueryIndex, 0);
499
500 break;
501
502 case CommandGraphNodeFunction::EndQuery:
503 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
504 ASSERT(mQueryPool != VK_NULL_HANDLE);
505
506 primaryCommandBuffer->endQuery(mQueryPool, mQueryIndex);
507
508 break;
509
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400510 case CommandGraphNodeFunction::WriteTimestamp:
511 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
512 ASSERT(mQueryPool != VK_NULL_HANDLE);
513
514 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
515 primaryCommandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, mQueryPool,
516 mQueryIndex);
517
518 break;
519
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400520 default:
521 UNREACHABLE();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500522 }
523
524 mVisitedState = VisitedState::Visited;
Jamie Madill21061022018-07-12 23:56:30 -0400525 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500526}
527
Jamie Madill0da73fe2018-10-02 09:31:39 -0400528const std::vector<CommandGraphNode *> &CommandGraphNode::getParentsForDiagnostics() const
529{
530 return mParents;
531}
532
533void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType,
534 uintptr_t resourceID)
535{
536 mResourceType = resourceType;
537 mResourceID = resourceID;
538}
539
Luc Ferron14f48172018-04-11 08:43:28 -0400540const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
541{
542 return mRenderPassRenderArea;
543}
544
Jamie Madill1f46bc12018-02-20 16:09:43 -0500545// CommandGraph implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -0400546CommandGraph::CommandGraph(bool enableGraphDiagnostics)
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400547 : mEnableGraphDiagnostics(enableGraphDiagnostics), mLastBarrierIndex(kInvalidNodeIndex)
Jamie Madill0da73fe2018-10-02 09:31:39 -0400548{
549}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500550
551CommandGraph::~CommandGraph()
552{
553 ASSERT(empty());
554}
555
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400556CommandGraphNode *CommandGraph::allocateNode(bool isBarrier, CommandGraphNodeFunction function)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500557{
558 // TODO(jmadill): Use a pool allocator for the CPU node allocations.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400559 CommandGraphNode *newCommands = new CommandGraphNode(function);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500560 mNodes.emplace_back(newCommands);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400561
562 if (isBarrier)
563 {
564 setNewBarrier(newCommands);
565 }
566
Jamie Madill1f46bc12018-02-20 16:09:43 -0500567 return newCommands;
568}
569
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400570void CommandGraph::setNewBarrier(CommandGraphNode *newBarrier)
571{
572 size_t previousBarrierIndex = 0;
573 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
574
575 // Add a dependency from previousBarrier to all nodes in (previousBarrier, newBarrier].
576 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
577 {
578 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
579 CommandGraphNode::SetHappensBeforeDependencies(
580 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
581 }
582
583 // Add a dependency from all nodes in (previousBarrier, newBarrier) to newBarrier.
584 addDependenciesToNextBarrier(previousBarrierIndex + 1, mNodes.size() - 1, newBarrier);
585
586 mLastBarrierIndex = mNodes.size() - 1;
587}
588
Jamie Madill21061022018-07-12 23:56:30 -0400589angle::Result CommandGraph::submitCommands(Context *context,
590 Serial serial,
591 RenderPassCache *renderPassCache,
592 CommandPool *commandPool,
593 CommandBuffer *primaryCommandBufferOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500594{
Shahbaz Youssefi3a482172018-10-11 10:34:44 -0400595 // There is no point in submitting an empty command buffer, so make sure not to call this
596 // function if there's nothing to do.
597 ASSERT(!mNodes.empty());
598
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400599 size_t previousBarrierIndex = 0;
600 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
601
602 // Add a dependency from previousBarrier to all nodes in (previousBarrier, end].
603 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
604 {
605 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
606 CommandGraphNode::SetHappensBeforeDependencies(
607 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
608 }
609
Shahbaz Youssefi3a482172018-10-11 10:34:44 -0400610 mLastBarrierIndex = kInvalidNodeIndex;
611
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400612 VkCommandBufferAllocateInfo primaryInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500613 primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500614 primaryInfo.commandPool = commandPool->getHandle();
615 primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
616 primaryInfo.commandBufferCount = 1;
617
Jamie Madill21061022018-07-12 23:56:30 -0400618 ANGLE_TRY(primaryCommandBufferOut->init(context, primaryInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500619
Jamie Madill0da73fe2018-10-02 09:31:39 -0400620 if (mEnableGraphDiagnostics)
621 {
622 dumpGraphDotFile(std::cout);
623 }
624
Jamie Madill1f46bc12018-02-20 16:09:43 -0500625 std::vector<CommandGraphNode *> nodeStack;
626
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400627 VkCommandBufferBeginInfo beginInfo = {};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500628 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500629 beginInfo.flags = 0;
630 beginInfo.pInheritanceInfo = nullptr;
631
Jamie Madill21061022018-07-12 23:56:30 -0400632 ANGLE_TRY(primaryCommandBufferOut->begin(context, beginInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500633
634 for (CommandGraphNode *topLevelNode : mNodes)
635 {
636 // Only process commands that don't have child commands. The others will be pulled in
637 // automatically. Also skip commands that have already been visited.
638 if (topLevelNode->hasChildren() || topLevelNode->visitedState() != VisitedState::Unvisited)
639 continue;
640
641 nodeStack.push_back(topLevelNode);
642
643 while (!nodeStack.empty())
644 {
645 CommandGraphNode *node = nodeStack.back();
646
647 switch (node->visitedState())
648 {
649 case VisitedState::Unvisited:
650 node->visitParents(&nodeStack);
651 break;
652 case VisitedState::Ready:
Jamie Madill21061022018-07-12 23:56:30 -0400653 ANGLE_TRY(node->visitAndExecute(context, serial, renderPassCache,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500654 primaryCommandBufferOut));
655 nodeStack.pop_back();
656 break;
657 case VisitedState::Visited:
658 nodeStack.pop_back();
659 break;
660 default:
661 UNREACHABLE();
662 break;
663 }
664 }
665 }
666
Jamie Madill21061022018-07-12 23:56:30 -0400667 ANGLE_TRY(primaryCommandBufferOut->end(context));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500668
669 // TODO(jmadill): Use pool allocation so we don't need to deallocate command graph.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400670 for (CommandGraphNode *node : mNodes)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500671 {
672 delete node;
673 }
674 mNodes.clear();
675
Jamie Madill21061022018-07-12 23:56:30 -0400676 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500677}
678
679bool CommandGraph::empty() const
680{
681 return mNodes.empty();
682}
683
Jamie Madill0da73fe2018-10-02 09:31:39 -0400684// Dumps the command graph into a dot file that works with graphviz.
685void CommandGraph::dumpGraphDotFile(std::ostream &out) const
686{
687 // This ID maps a node pointer to a monatonic ID. It allows us to look up parent node IDs.
688 std::map<const CommandGraphNode *, int> nodeIDMap;
689 std::map<uintptr_t, int> objectIDMap;
690
691 // Map nodes to ids.
692 for (size_t nodeIndex = 0; nodeIndex < mNodes.size(); ++nodeIndex)
693 {
694 const CommandGraphNode *node = mNodes[nodeIndex];
695 nodeIDMap[node] = static_cast<int>(nodeIndex) + 1;
696 }
697
698 int bufferIDCounter = 1;
699 int framebufferIDCounter = 1;
700 int imageIDCounter = 1;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400701 int queryIDCounter = 1;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400702
703 out << "digraph {" << std::endl;
704
705 for (const CommandGraphNode *node : mNodes)
706 {
707 int nodeID = nodeIDMap[node];
708
709 std::stringstream strstr;
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -0400710 strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics(), node->getFunction());
Jamie Madill0da73fe2018-10-02 09:31:39 -0400711 strstr << " ";
712
713 auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
714 if (it != objectIDMap.end())
715 {
716 strstr << it->second;
717 }
718 else
719 {
720 int id = 0;
721
722 switch (node->getResourceTypeForDiagnostics())
723 {
724 case CommandGraphResourceType::Buffer:
725 id = bufferIDCounter++;
726 break;
727 case CommandGraphResourceType::Framebuffer:
728 id = framebufferIDCounter++;
729 break;
730 case CommandGraphResourceType::Image:
731 id = imageIDCounter++;
732 break;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400733 case CommandGraphResourceType::Query:
734 id = queryIDCounter++;
735 break;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400736 default:
737 UNREACHABLE();
738 break;
739 }
740
741 objectIDMap[node->getResourceIDForDiagnostics()] = id;
742 strstr << id;
743 }
744
745 const std::string &label = strstr.str();
746 out << " " << nodeID << "[label =<" << label << "<BR/> <FONT POINT-SIZE=\"10\">Node ID "
747 << nodeID << "</FONT>>];" << std::endl;
748 }
749
750 for (const CommandGraphNode *node : mNodes)
751 {
752 int nodeID = nodeIDMap[node];
753
754 for (const CommandGraphNode *parent : node->getParentsForDiagnostics())
755 {
756 int parentID = nodeIDMap[parent];
757 out << " " << parentID << " -> " << nodeID << ";" << std::endl;
758 }
759 }
760
761 out << "}" << std::endl;
762}
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400763
764CommandGraphNode *CommandGraph::getLastBarrierNode(size_t *indexOut)
765{
766 *indexOut = mLastBarrierIndex == kInvalidNodeIndex ? 0 : mLastBarrierIndex;
767 return mLastBarrierIndex == kInvalidNodeIndex ? nullptr : mNodes[mLastBarrierIndex];
768}
769
770void CommandGraph::addDependenciesToNextBarrier(size_t begin,
771 size_t end,
772 CommandGraphNode *nextBarrier)
773{
774 for (size_t i = begin; i < end; ++i)
775 {
776 // As a small optimization, only add edges to childless nodes. The others have an
777 // indirect dependency.
778 if (!mNodes[i]->hasChildren())
779 {
780 CommandGraphNode::SetHappensBeforeDependency(mNodes[i], nextBarrier);
781 }
782 }
783}
784
Jamie Madill1f46bc12018-02-20 16:09:43 -0500785} // namespace vk
786} // namespace rx