blob: 3c95e7fbf9bab626ad1142213f06ea572f07fcf3 [file] [log] [blame]
Jamie Madill1f46bc12018-02-20 16:09:43 -05001//
2// Copyright 2017 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6// CommandGraph:
7// Deferred work constructed by GL calls, that will later be flushed to Vulkan.
8//
9
10#include "libANGLE/renderer/vulkan/CommandGraph.h"
11
Jamie Madill0da73fe2018-10-02 09:31:39 -040012#include <iostream>
13
Jamie Madill1f46bc12018-02-20 16:09:43 -050014#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
15#include "libANGLE/renderer/vulkan/RendererVk.h"
16#include "libANGLE/renderer/vulkan/vk_format_utils.h"
Jamie Madill26084d02018-04-09 13:44:04 -040017#include "libANGLE/renderer/vulkan/vk_helpers.h"
Jamie Madill1f46bc12018-02-20 16:09:43 -050018
Shahbaz Youssefi25224e72018-10-22 11:56:02 -040019#include "third_party/trace_event/trace_event.h"
20
Jamie Madill1f46bc12018-02-20 16:09:43 -050021namespace rx
22{
Jamie Madill1f46bc12018-02-20 16:09:43 -050023namespace vk
24{
Jamie Madill1f46bc12018-02-20 16:09:43 -050025namespace
26{
Jamie Madill21061022018-07-12 23:56:30 -040027angle::Result InitAndBeginCommandBuffer(vk::Context *context,
28 const CommandPool &commandPool,
29 const VkCommandBufferInheritanceInfo &inheritanceInfo,
30 VkCommandBufferUsageFlags flags,
31 CommandBuffer *commandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -050032{
33 ASSERT(!commandBuffer->valid());
34
Shahbaz Youssefi06270c92018-10-03 17:00:25 -040035 VkCommandBufferAllocateInfo createInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -050036 createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
37 createInfo.commandPool = commandPool.getHandle();
38 createInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
39 createInfo.commandBufferCount = 1;
Jamie Madill1f46bc12018-02-20 16:09:43 -050040
Yuly Novikov27780292018-11-09 11:19:49 -050041 ANGLE_VK_TRY(context, commandBuffer->init(context->getDevice(), createInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -050042
Shahbaz Youssefi06270c92018-10-03 17:00:25 -040043 VkCommandBufferBeginInfo beginInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -050044 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
45 beginInfo.flags = flags | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
46 beginInfo.pInheritanceInfo = &inheritanceInfo;
Jamie Madill1f46bc12018-02-20 16:09:43 -050047
Yuly Novikov27780292018-11-09 11:19:49 -050048 ANGLE_VK_TRY(context, commandBuffer->begin(beginInfo));
Jamie Madill21061022018-07-12 23:56:30 -040049 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -050050}
51
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040052const char *GetResourceTypeName(CommandGraphResourceType resourceType,
53 CommandGraphNodeFunction function)
Jamie Madill0da73fe2018-10-02 09:31:39 -040054{
55 switch (resourceType)
56 {
57 case CommandGraphResourceType::Buffer:
58 return "Buffer";
59 case CommandGraphResourceType::Framebuffer:
60 return "Framebuffer";
61 case CommandGraphResourceType::Image:
62 return "Image";
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -040063 case CommandGraphResourceType::Query:
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040064 switch (function)
65 {
66 case CommandGraphNodeFunction::BeginQuery:
67 return "BeginQuery";
68 case CommandGraphNodeFunction::EndQuery:
69 return "EndQuery";
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -040070 case CommandGraphNodeFunction::WriteTimestamp:
71 return "WriteTimestamp";
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040072 default:
73 UNREACHABLE();
74 return "Query";
75 }
Jamie Madill0da73fe2018-10-02 09:31:39 -040076 default:
77 UNREACHABLE();
78 return "";
79 }
80}
Jamie Madill1f46bc12018-02-20 16:09:43 -050081} // anonymous namespace
82
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040083// CommandGraphResource implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -040084CommandGraphResource::CommandGraphResource(CommandGraphResourceType resourceType)
Jamie Madill193a2842018-10-30 17:28:41 -040085 : mResourceType(resourceType), mCurrentWritingNode(nullptr)
Jamie Madillb980c562018-11-27 11:34:27 -050086{}
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040087
Jamie Madill316c6062018-05-29 10:49:45 -040088CommandGraphResource::~CommandGraphResource() = default;
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040089
Jamie Madillc57ee252018-05-30 19:53:48 -040090bool CommandGraphResource::isResourceInUse(RendererVk *renderer) const
91{
92 return renderer->isSerialInUse(mStoredQueueSerial);
93}
94
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -040095bool CommandGraphResource::hasPendingWork(RendererVk *renderer) const
96{
97 // If the renderer has a queue serial higher than the stored one, the command buffers recorded
98 // by this resource have already been submitted, so there is no pending work.
99 return mStoredQueueSerial == renderer->getCurrentQueueSerial();
100}
101
Jamie Madillc57ee252018-05-30 19:53:48 -0400102Serial CommandGraphResource::getStoredQueueSerial() const
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400103{
104 return mStoredQueueSerial;
105}
106
Jamie Madill193a2842018-10-30 17:28:41 -0400107// RecordableGraphResource implementation.
108RecordableGraphResource::RecordableGraphResource(CommandGraphResourceType resourceType)
109 : CommandGraphResource(resourceType)
Jamie Madillb980c562018-11-27 11:34:27 -0500110{}
Jamie Madill193a2842018-10-30 17:28:41 -0400111
112RecordableGraphResource::~RecordableGraphResource() = default;
113
114void RecordableGraphResource::updateQueueSerial(Serial queueSerial)
115{
116 ASSERT(queueSerial >= mStoredQueueSerial);
117
118 if (queueSerial > mStoredQueueSerial)
119 {
120 mCurrentWritingNode = nullptr;
121 mCurrentReadingNodes.clear();
122 mStoredQueueSerial = queueSerial;
123 }
124}
125
126angle::Result RecordableGraphResource::recordCommands(Context *context,
127 CommandBuffer **commandBufferOut)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400128{
Jamie Madill21061022018-07-12 23:56:30 -0400129 updateQueueSerial(context->getRenderer()->getCurrentQueueSerial());
Jamie Madill5dca6512018-05-30 10:53:51 -0400130
Jamie Madille2d22702018-09-19 08:11:48 -0400131 if (!hasChildlessWritingNode() || hasStartedRenderPass())
Jamie Madill316c6062018-05-29 10:49:45 -0400132 {
Jamie Madill193a2842018-10-30 17:28:41 -0400133 startNewCommands(context->getRenderer());
Jamie Madille2d22702018-09-19 08:11:48 -0400134 return mCurrentWritingNode->beginOutsideRenderPassRecording(
135 context, context->getRenderer()->getCommandPool(), commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400136 }
137
138 CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
139 if (!outsideRenderPassCommands->valid())
140 {
141 ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
Jamie Madill21061022018-07-12 23:56:30 -0400142 context, context->getRenderer()->getCommandPool(), commandBufferOut));
Jamie Madill316c6062018-05-29 10:49:45 -0400143 }
144 else
145 {
146 *commandBufferOut = outsideRenderPassCommands;
147 }
148
Jamie Madill21061022018-07-12 23:56:30 -0400149 return angle::Result::Continue();
Jamie Madill316c6062018-05-29 10:49:45 -0400150}
151
Jamie Madill193a2842018-10-30 17:28:41 -0400152bool RecordableGraphResource::appendToStartedRenderPass(RendererVk *renderer,
153 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400154{
Jamie Madill5dca6512018-05-30 10:53:51 -0400155 updateQueueSerial(renderer->getCurrentQueueSerial());
156 if (hasStartedRenderPass())
157 {
158 *commandBufferOut = mCurrentWritingNode->getInsideRenderPassCommands();
159 return true;
160 }
161 else
162 {
163 return false;
164 }
Jamie Madill316c6062018-05-29 10:49:45 -0400165}
166
Jamie Madill193a2842018-10-30 17:28:41 -0400167const gl::Rectangle &RecordableGraphResource::getRenderPassRenderArea() const
Jamie Madill316c6062018-05-29 10:49:45 -0400168{
169 ASSERT(hasStartedRenderPass());
170 return mCurrentWritingNode->getRenderPassRenderArea();
171}
172
Jamie Madill193a2842018-10-30 17:28:41 -0400173angle::Result RecordableGraphResource::beginRenderPass(Context *context,
174 const Framebuffer &framebuffer,
175 const gl::Rectangle &renderArea,
176 const RenderPassDesc &renderPassDesc,
177 const std::vector<VkClearValue> &clearValues,
178 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400179{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400180 // If a barrier has been inserted in the meantime, stop the command buffer.
181 if (!hasChildlessWritingNode())
182 {
Jamie Madill193a2842018-10-30 17:28:41 -0400183 startNewCommands(context->getRenderer());
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400184 }
185
Jamie Madill316c6062018-05-29 10:49:45 -0400186 // Hard-code RenderPass to clear the first render target to the current clear value.
187 // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
188 mCurrentWritingNode->storeRenderPassInfo(framebuffer, renderArea, renderPassDesc, clearValues);
189
Jamie Madill21061022018-07-12 23:56:30 -0400190 return mCurrentWritingNode->beginInsideRenderPassRecording(context, commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400191}
192
Jamie Madill193a2842018-10-30 17:28:41 -0400193void RecordableGraphResource::addWriteDependency(RecordableGraphResource *writingResource)
Jamie Madill316c6062018-05-29 10:49:45 -0400194{
195 CommandGraphNode *writingNode = writingResource->mCurrentWritingNode;
196 ASSERT(writingNode);
197
Jamie Madillc57ee252018-05-30 19:53:48 -0400198 onWriteImpl(writingNode, writingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400199}
200
Jamie Madill193a2842018-10-30 17:28:41 -0400201void RecordableGraphResource::addReadDependency(RecordableGraphResource *readingResource)
202{
203 updateQueueSerial(readingResource->getStoredQueueSerial());
204
205 CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
206 ASSERT(readingNode);
207
208 if (hasChildlessWritingNode())
209 {
210 // Ensure 'readingNode' happens after the current writing node.
211 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
212 }
213
214 // Add the read node to the list of nodes currently reading this resource.
215 mCurrentReadingNodes.push_back(readingNode);
216}
217
218void RecordableGraphResource::finishCurrentCommands(RendererVk *renderer)
219{
220 startNewCommands(renderer);
221}
222
223void RecordableGraphResource::startNewCommands(RendererVk *renderer)
224{
225 CommandGraphNode *newCommands =
226 renderer->getCommandGraph()->allocateNode(CommandGraphNodeFunction::Generic);
227 newCommands->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
228 onWriteImpl(newCommands, renderer->getCurrentQueueSerial());
229}
230
231void RecordableGraphResource::onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial)
Jamie Madill316c6062018-05-29 10:49:45 -0400232{
233 updateQueueSerial(currentSerial);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400234
Jamie Madill9cceac42018-03-31 14:19:16 -0400235 // Make sure any open reads and writes finish before we execute 'writingNode'.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400236 if (!mCurrentReadingNodes.empty())
237 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400238 CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes.data(),
239 mCurrentReadingNodes.size(), writingNode);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400240 mCurrentReadingNodes.clear();
241 }
242
243 if (mCurrentWritingNode && mCurrentWritingNode != writingNode)
244 {
245 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, writingNode);
246 }
247
248 mCurrentWritingNode = writingNode;
249}
250
Jamie Madill193a2842018-10-30 17:28:41 -0400251// QueryGraphResource implementation.
Jamie Madillb980c562018-11-27 11:34:27 -0500252QueryGraphResource::QueryGraphResource() : CommandGraphResource(CommandGraphResourceType::Query) {}
Jamie Madill316c6062018-05-29 10:49:45 -0400253
Jamie Madill193a2842018-10-30 17:28:41 -0400254QueryGraphResource::~QueryGraphResource() = default;
Jamie Madill9cceac42018-03-31 14:19:16 -0400255
Jamie Madill193a2842018-10-30 17:28:41 -0400256void QueryGraphResource::beginQuery(Context *context,
257 const QueryPool *queryPool,
258 uint32_t queryIndex)
259{
260 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::BeginQuery);
261 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
262}
Jamie Madill9cceac42018-03-31 14:19:16 -0400263
Jamie Madill193a2842018-10-30 17:28:41 -0400264void QueryGraphResource::endQuery(Context *context, const QueryPool *queryPool, uint32_t queryIndex)
265{
266 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::EndQuery);
267 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
268}
269
270void QueryGraphResource::writeTimestamp(Context *context,
271 const QueryPool *queryPool,
272 uint32_t queryIndex)
273{
274 startNewCommands(context->getRenderer(), CommandGraphNodeFunction::WriteTimestamp);
275 mCurrentWritingNode->setQueryPool(queryPool, queryIndex);
276}
277
278void QueryGraphResource::startNewCommands(RendererVk *renderer, CommandGraphNodeFunction function)
279{
280 CommandGraph *commandGraph = renderer->getCommandGraph();
281 CommandGraphNode *newNode = commandGraph->allocateNode(function);
282 newNode->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
283 commandGraph->setNewBarrier(newNode);
284
285 mStoredQueueSerial = renderer->getCurrentQueueSerial();
286 mCurrentWritingNode = newNode;
Jamie Madill9cceac42018-03-31 14:19:16 -0400287}
288
Jamie Madill1f46bc12018-02-20 16:09:43 -0500289// CommandGraphNode implementation.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400290CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function)
291 : mRenderPassClearValues{},
292 mFunction(function),
293 mQueryPool(VK_NULL_HANDLE),
294 mQueryIndex(0),
295 mHasChildren(false),
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500296 mVisitedState(VisitedState::Unvisited),
297 mGlobalMemoryBarrierSrcAccess(0),
298 mGlobalMemoryBarrierDstAccess(0)
Jamie Madillb980c562018-11-27 11:34:27 -0500299{}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500300
301CommandGraphNode::~CommandGraphNode()
302{
303 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
304
305 // Command buffers are managed by the command pool, so don't need to be freed.
306 mOutsideRenderPassCommands.releaseHandle();
307 mInsideRenderPassCommands.releaseHandle();
308}
309
310CommandBuffer *CommandGraphNode::getOutsideRenderPassCommands()
311{
312 ASSERT(!mHasChildren);
313 return &mOutsideRenderPassCommands;
314}
315
Jamie Madill21061022018-07-12 23:56:30 -0400316angle::Result CommandGraphNode::beginOutsideRenderPassRecording(Context *context,
317 const CommandPool &commandPool,
318 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500319{
320 ASSERT(!mHasChildren);
321
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400322 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500323 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
324 inheritanceInfo.renderPass = VK_NULL_HANDLE;
325 inheritanceInfo.subpass = 0;
326 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400327 inheritanceInfo.occlusionQueryEnable =
328 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500329 inheritanceInfo.queryFlags = 0;
330 inheritanceInfo.pipelineStatistics = 0;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500331
Jamie Madill21061022018-07-12 23:56:30 -0400332 ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500333 &mOutsideRenderPassCommands));
334
335 *commandsOut = &mOutsideRenderPassCommands;
Jamie Madill21061022018-07-12 23:56:30 -0400336 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500337}
338
Jamie Madill21061022018-07-12 23:56:30 -0400339angle::Result CommandGraphNode::beginInsideRenderPassRecording(Context *context,
340 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500341{
342 ASSERT(!mHasChildren);
343
344 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400345 // TODO(jmadill): Support query for compatible/conformant render pass. http://anglebug.com/2361
Jamie Madill1f46bc12018-02-20 16:09:43 -0500346 RenderPass *compatibleRenderPass;
Jamie Madill21061022018-07-12 23:56:30 -0400347 ANGLE_TRY(context->getRenderer()->getCompatibleRenderPass(context, mRenderPassDesc,
348 &compatibleRenderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500349
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400350 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500351 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
352 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
353 inheritanceInfo.subpass = 0;
354 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400355 inheritanceInfo.occlusionQueryEnable =
356 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500357 inheritanceInfo.queryFlags = 0;
358 inheritanceInfo.pipelineStatistics = 0;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500359
360 ANGLE_TRY(InitAndBeginCommandBuffer(
Jamie Madill21061022018-07-12 23:56:30 -0400361 context, context->getRenderer()->getCommandPool(), inheritanceInfo,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500362 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
363
364 *commandsOut = &mInsideRenderPassCommands;
Jamie Madill21061022018-07-12 23:56:30 -0400365 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500366}
367
368void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
369 const gl::Rectangle renderArea,
Jamie Madillbcf467f2018-05-23 09:46:00 -0400370 const vk::RenderPassDesc &renderPassDesc,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500371 const std::vector<VkClearValue> &clearValues)
372{
Jamie Madillbcf467f2018-05-23 09:46:00 -0400373 mRenderPassDesc = renderPassDesc;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500374 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
375 mRenderPassRenderArea = renderArea;
376 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
377}
378
Jamie Madill1f46bc12018-02-20 16:09:43 -0500379// static
380void CommandGraphNode::SetHappensBeforeDependency(CommandGraphNode *beforeNode,
381 CommandGraphNode *afterNode)
382{
Jamie Madill9cceac42018-03-31 14:19:16 -0400383 ASSERT(beforeNode != afterNode && !beforeNode->isChildOf(afterNode));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500384 afterNode->mParents.emplace_back(beforeNode);
385 beforeNode->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500386}
387
388// static
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400389void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode **beforeNodes,
390 size_t beforeNodesCount,
391 CommandGraphNode *afterNode)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500392{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400393 afterNode->mParents.insert(afterNode->mParents.end(), beforeNodes,
394 beforeNodes + beforeNodesCount);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500395
396 // TODO(jmadill): is there a faster way to do this?
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400397 for (size_t i = 0; i < beforeNodesCount; ++i)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500398 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400399 beforeNodes[i]->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500400
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400401 ASSERT(beforeNodes[i] != afterNode && !beforeNodes[i]->isChildOf(afterNode));
402 }
403}
404
405void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode *beforeNode,
406 CommandGraphNode **afterNodes,
407 size_t afterNodesCount)
408{
409 for (size_t i = 0; i < afterNodesCount; ++i)
410 {
411 SetHappensBeforeDependency(beforeNode, afterNodes[i]);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500412 }
413}
414
415bool CommandGraphNode::hasParents() const
416{
417 return !mParents.empty();
418}
419
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400420void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIndex)
421{
422 ASSERT(mFunction == CommandGraphNodeFunction::BeginQuery ||
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400423 mFunction == CommandGraphNodeFunction::EndQuery ||
424 mFunction == CommandGraphNodeFunction::WriteTimestamp);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400425 mQueryPool = queryPool->getHandle();
426 mQueryIndex = queryIndex;
427}
428
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500429void CommandGraphNode::addGlobalMemoryBarrier(VkFlags srcAccess, VkFlags dstAccess)
430{
431 mGlobalMemoryBarrierSrcAccess |= srcAccess;
432 mGlobalMemoryBarrierDstAccess |= dstAccess;
433}
434
Jamie Madill1f46bc12018-02-20 16:09:43 -0500435void CommandGraphNode::setHasChildren()
436{
437 mHasChildren = true;
438}
439
Jamie Madill1f46bc12018-02-20 16:09:43 -0500440// Do not call this in anything but testing code, since it's slow.
441bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
442{
443 std::set<CommandGraphNode *> visitedList;
444 std::vector<CommandGraphNode *> openList;
445 openList.insert(openList.begin(), mParents.begin(), mParents.end());
446 while (!openList.empty())
447 {
448 CommandGraphNode *current = openList.back();
449 openList.pop_back();
450 if (visitedList.count(current) == 0)
451 {
452 if (current == parent)
453 {
454 return true;
455 }
456 visitedList.insert(current);
457 openList.insert(openList.end(), current->mParents.begin(), current->mParents.end());
458 }
459 }
460
461 return false;
462}
463
464VisitedState CommandGraphNode::visitedState() const
465{
466 return mVisitedState;
467}
468
469void CommandGraphNode::visitParents(std::vector<CommandGraphNode *> *stack)
470{
471 ASSERT(mVisitedState == VisitedState::Unvisited);
472 stack->insert(stack->end(), mParents.begin(), mParents.end());
473 mVisitedState = VisitedState::Ready;
474}
475
Jamie Madill21061022018-07-12 23:56:30 -0400476angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
477 Serial serial,
478 RenderPassCache *renderPassCache,
479 CommandBuffer *primaryCommandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500480{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400481 switch (mFunction)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500482 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400483 case CommandGraphNodeFunction::Generic:
484 ASSERT(mQueryPool == VK_NULL_HANDLE);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500485
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500486 // Record the deferred pipeline barrier if necessary.
487 ASSERT((mGlobalMemoryBarrierDstAccess == 0) == (mGlobalMemoryBarrierSrcAccess == 0));
488 if (mGlobalMemoryBarrierSrcAccess)
489 {
490 VkMemoryBarrier memoryBarrier = {};
491 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
492 memoryBarrier.srcAccessMask = mGlobalMemoryBarrierSrcAccess;
493 memoryBarrier.dstAccessMask = mGlobalMemoryBarrierDstAccess;
494
Shahbaz Youssefi471358f2018-11-28 15:21:55 -0500495 // Use the all pipe stage to keep the state management simple.
496 primaryCommandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
497 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1,
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500498 &memoryBarrier, 0, nullptr, 0, nullptr);
499 }
500
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400501 if (mOutsideRenderPassCommands.valid())
502 {
Yuly Novikov27780292018-11-09 11:19:49 -0500503 ANGLE_VK_TRY(context, mOutsideRenderPassCommands.end());
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400504 primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
505 }
Jamie Madill1f46bc12018-02-20 16:09:43 -0500506
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400507 if (mInsideRenderPassCommands.valid())
508 {
509 // Pull a compatible RenderPass from the cache.
510 // TODO(jmadill): Insert real ops and layout transitions.
511 RenderPass *renderPass = nullptr;
512 ANGLE_TRY(renderPassCache->getCompatibleRenderPass(context, serial, mRenderPassDesc,
513 &renderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500514
Yuly Novikov27780292018-11-09 11:19:49 -0500515 ANGLE_VK_TRY(context, mInsideRenderPassCommands.end());
Jamie Madill1f46bc12018-02-20 16:09:43 -0500516
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400517 VkRenderPassBeginInfo beginInfo = {};
518 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
519 beginInfo.renderPass = renderPass->getHandle();
520 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
521 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
522 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
523 beginInfo.renderArea.extent.width =
524 static_cast<uint32_t>(mRenderPassRenderArea.width);
525 beginInfo.renderArea.extent.height =
526 static_cast<uint32_t>(mRenderPassRenderArea.height);
527 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
528 beginInfo.pClearValues = mRenderPassClearValues.data();
529
530 primaryCommandBuffer->beginRenderPass(
531 beginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
532 primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
533 primaryCommandBuffer->endRenderPass();
534 }
535 break;
536
537 case CommandGraphNodeFunction::BeginQuery:
538 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
539 ASSERT(mQueryPool != VK_NULL_HANDLE);
540
541 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
542 primaryCommandBuffer->beginQuery(mQueryPool, mQueryIndex, 0);
543
544 break;
545
546 case CommandGraphNodeFunction::EndQuery:
547 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
548 ASSERT(mQueryPool != VK_NULL_HANDLE);
549
550 primaryCommandBuffer->endQuery(mQueryPool, mQueryIndex);
551
552 break;
553
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400554 case CommandGraphNodeFunction::WriteTimestamp:
555 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
556 ASSERT(mQueryPool != VK_NULL_HANDLE);
557
558 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
559 primaryCommandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, mQueryPool,
560 mQueryIndex);
561
562 break;
563
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400564 default:
565 UNREACHABLE();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500566 }
567
568 mVisitedState = VisitedState::Visited;
Jamie Madill21061022018-07-12 23:56:30 -0400569 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500570}
571
Jamie Madill0da73fe2018-10-02 09:31:39 -0400572const std::vector<CommandGraphNode *> &CommandGraphNode::getParentsForDiagnostics() const
573{
574 return mParents;
575}
576
577void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType,
578 uintptr_t resourceID)
579{
580 mResourceType = resourceType;
581 mResourceID = resourceID;
582}
583
Luc Ferron14f48172018-04-11 08:43:28 -0400584const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
585{
586 return mRenderPassRenderArea;
587}
588
Jamie Madill1f46bc12018-02-20 16:09:43 -0500589// CommandGraph implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -0400590CommandGraph::CommandGraph(bool enableGraphDiagnostics)
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400591 : mEnableGraphDiagnostics(enableGraphDiagnostics), mLastBarrierIndex(kInvalidNodeIndex)
Jamie Madillb980c562018-11-27 11:34:27 -0500592{}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500593
594CommandGraph::~CommandGraph()
595{
596 ASSERT(empty());
597}
598
Jamie Madill193a2842018-10-30 17:28:41 -0400599CommandGraphNode *CommandGraph::allocateNode(CommandGraphNodeFunction function)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500600{
601 // TODO(jmadill): Use a pool allocator for the CPU node allocations.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400602 CommandGraphNode *newCommands = new CommandGraphNode(function);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500603 mNodes.emplace_back(newCommands);
604 return newCommands;
605}
606
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400607void CommandGraph::setNewBarrier(CommandGraphNode *newBarrier)
608{
609 size_t previousBarrierIndex = 0;
610 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
611
612 // Add a dependency from previousBarrier to all nodes in (previousBarrier, newBarrier].
613 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
614 {
615 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
616 CommandGraphNode::SetHappensBeforeDependencies(
617 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
618 }
619
620 // Add a dependency from all nodes in (previousBarrier, newBarrier) to newBarrier.
621 addDependenciesToNextBarrier(previousBarrierIndex + 1, mNodes.size() - 1, newBarrier);
622
623 mLastBarrierIndex = mNodes.size() - 1;
624}
625
Jamie Madill21061022018-07-12 23:56:30 -0400626angle::Result CommandGraph::submitCommands(Context *context,
627 Serial serial,
628 RenderPassCache *renderPassCache,
629 CommandPool *commandPool,
630 CommandBuffer *primaryCommandBufferOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500631{
Shahbaz Youssefi3a482172018-10-11 10:34:44 -0400632 // There is no point in submitting an empty command buffer, so make sure not to call this
633 // function if there's nothing to do.
634 ASSERT(!mNodes.empty());
635
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400636 size_t previousBarrierIndex = 0;
637 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
638
639 // Add a dependency from previousBarrier to all nodes in (previousBarrier, end].
640 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
641 {
642 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
643 CommandGraphNode::SetHappensBeforeDependencies(
644 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
645 }
646
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400647 VkCommandBufferAllocateInfo primaryInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500648 primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
649 primaryInfo.commandPool = commandPool->getHandle();
650 primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
651 primaryInfo.commandBufferCount = 1;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500652
Yuly Novikov27780292018-11-09 11:19:49 -0500653 ANGLE_VK_TRY(context, primaryCommandBufferOut->init(context->getDevice(), primaryInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500654
Jamie Madill0da73fe2018-10-02 09:31:39 -0400655 if (mEnableGraphDiagnostics)
656 {
657 dumpGraphDotFile(std::cout);
658 }
659
Jamie Madill1f46bc12018-02-20 16:09:43 -0500660 std::vector<CommandGraphNode *> nodeStack;
661
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400662 VkCommandBufferBeginInfo beginInfo = {};
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400663 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
664 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
665 beginInfo.pInheritanceInfo = nullptr;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500666
Yuly Novikov27780292018-11-09 11:19:49 -0500667 ANGLE_VK_TRY(context, primaryCommandBufferOut->begin(beginInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500668
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400669 ANGLE_TRY(context->getRenderer()->traceGpuEvent(
670 context, primaryCommandBufferOut, TRACE_EVENT_PHASE_BEGIN, "Primary Command Buffer"));
671
Jamie Madill1f46bc12018-02-20 16:09:43 -0500672 for (CommandGraphNode *topLevelNode : mNodes)
673 {
674 // Only process commands that don't have child commands. The others will be pulled in
675 // automatically. Also skip commands that have already been visited.
676 if (topLevelNode->hasChildren() || topLevelNode->visitedState() != VisitedState::Unvisited)
677 continue;
678
679 nodeStack.push_back(topLevelNode);
680
681 while (!nodeStack.empty())
682 {
683 CommandGraphNode *node = nodeStack.back();
684
685 switch (node->visitedState())
686 {
687 case VisitedState::Unvisited:
688 node->visitParents(&nodeStack);
689 break;
690 case VisitedState::Ready:
Jamie Madill21061022018-07-12 23:56:30 -0400691 ANGLE_TRY(node->visitAndExecute(context, serial, renderPassCache,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500692 primaryCommandBufferOut));
693 nodeStack.pop_back();
694 break;
695 case VisitedState::Visited:
696 nodeStack.pop_back();
697 break;
698 default:
699 UNREACHABLE();
700 break;
701 }
702 }
703 }
704
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400705 ANGLE_TRY(context->getRenderer()->traceGpuEvent(
706 context, primaryCommandBufferOut, TRACE_EVENT_PHASE_END, "Primary Command Buffer"));
707
Yuly Novikov27780292018-11-09 11:19:49 -0500708 ANGLE_VK_TRY(context, primaryCommandBufferOut->end());
Jamie Madill1f46bc12018-02-20 16:09:43 -0500709
Yuly Novikovb56ddbb2018-11-02 16:53:18 -0400710 clear();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500711
Jamie Madill21061022018-07-12 23:56:30 -0400712 return angle::Result::Continue();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500713}
714
715bool CommandGraph::empty() const
716{
717 return mNodes.empty();
718}
719
Yuly Novikovb56ddbb2018-11-02 16:53:18 -0400720void CommandGraph::clear()
721{
722 mLastBarrierIndex = kInvalidNodeIndex;
723
724 // TODO(jmadill): Use pool allocator for performance. http://anglebug.com/2951
725 for (CommandGraphNode *node : mNodes)
726 {
727 delete node;
728 }
729 mNodes.clear();
730}
731
Jamie Madill0da73fe2018-10-02 09:31:39 -0400732// Dumps the command graph into a dot file that works with graphviz.
733void CommandGraph::dumpGraphDotFile(std::ostream &out) const
734{
735 // This ID maps a node pointer to a monatonic ID. It allows us to look up parent node IDs.
736 std::map<const CommandGraphNode *, int> nodeIDMap;
737 std::map<uintptr_t, int> objectIDMap;
738
739 // Map nodes to ids.
740 for (size_t nodeIndex = 0; nodeIndex < mNodes.size(); ++nodeIndex)
741 {
742 const CommandGraphNode *node = mNodes[nodeIndex];
743 nodeIDMap[node] = static_cast<int>(nodeIndex) + 1;
744 }
745
746 int bufferIDCounter = 1;
747 int framebufferIDCounter = 1;
748 int imageIDCounter = 1;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400749 int queryIDCounter = 1;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400750
751 out << "digraph {" << std::endl;
752
753 for (const CommandGraphNode *node : mNodes)
754 {
755 int nodeID = nodeIDMap[node];
756
757 std::stringstream strstr;
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -0400758 strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics(), node->getFunction());
Jamie Madill0da73fe2018-10-02 09:31:39 -0400759 strstr << " ";
760
761 auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
762 if (it != objectIDMap.end())
763 {
764 strstr << it->second;
765 }
766 else
767 {
768 int id = 0;
769
770 switch (node->getResourceTypeForDiagnostics())
771 {
772 case CommandGraphResourceType::Buffer:
773 id = bufferIDCounter++;
774 break;
775 case CommandGraphResourceType::Framebuffer:
776 id = framebufferIDCounter++;
777 break;
778 case CommandGraphResourceType::Image:
779 id = imageIDCounter++;
780 break;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400781 case CommandGraphResourceType::Query:
782 id = queryIDCounter++;
783 break;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400784 default:
785 UNREACHABLE();
786 break;
787 }
788
789 objectIDMap[node->getResourceIDForDiagnostics()] = id;
790 strstr << id;
791 }
792
793 const std::string &label = strstr.str();
794 out << " " << nodeID << "[label =<" << label << "<BR/> <FONT POINT-SIZE=\"10\">Node ID "
795 << nodeID << "</FONT>>];" << std::endl;
796 }
797
798 for (const CommandGraphNode *node : mNodes)
799 {
800 int nodeID = nodeIDMap[node];
801
802 for (const CommandGraphNode *parent : node->getParentsForDiagnostics())
803 {
804 int parentID = nodeIDMap[parent];
805 out << " " << parentID << " -> " << nodeID << ";" << std::endl;
806 }
807 }
808
809 out << "}" << std::endl;
810}
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400811
812CommandGraphNode *CommandGraph::getLastBarrierNode(size_t *indexOut)
813{
814 *indexOut = mLastBarrierIndex == kInvalidNodeIndex ? 0 : mLastBarrierIndex;
815 return mLastBarrierIndex == kInvalidNodeIndex ? nullptr : mNodes[mLastBarrierIndex];
816}
817
818void CommandGraph::addDependenciesToNextBarrier(size_t begin,
819 size_t end,
820 CommandGraphNode *nextBarrier)
821{
822 for (size_t i = begin; i < end; ++i)
823 {
824 // As a small optimization, only add edges to childless nodes. The others have an
825 // indirect dependency.
826 if (!mNodes[i]->hasChildren())
827 {
828 CommandGraphNode::SetHappensBeforeDependency(mNodes[i], nextBarrier);
829 }
830 }
831}
832
Jamie Madill1f46bc12018-02-20 16:09:43 -0500833} // namespace vk
834} // namespace rx