blob: adce3e330c58a96aca3b286d080a22ed559ea4b1 [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 Madill85ca1892019-01-16 13:27:15 -050014#include "libANGLE/renderer/vulkan/ContextVk.h"
Jamie Madill1f46bc12018-02-20 16:09:43 -050015#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
16#include "libANGLE/renderer/vulkan/RendererVk.h"
17#include "libANGLE/renderer/vulkan/vk_format_utils.h"
Jamie Madill26084d02018-04-09 13:44:04 -040018#include "libANGLE/renderer/vulkan/vk_helpers.h"
Jamie Madill1f46bc12018-02-20 16:09:43 -050019
Shahbaz Youssefi25224e72018-10-22 11:56:02 -040020#include "third_party/trace_event/trace_event.h"
21
Jamie Madill1f46bc12018-02-20 16:09:43 -050022namespace rx
23{
Jamie Madill1f46bc12018-02-20 16:09:43 -050024namespace vk
25{
Jamie Madill1f46bc12018-02-20 16:09:43 -050026namespace
27{
Jamie Madill21061022018-07-12 23:56:30 -040028angle::Result InitAndBeginCommandBuffer(vk::Context *context,
29 const CommandPool &commandPool,
30 const VkCommandBufferInheritanceInfo &inheritanceInfo,
31 VkCommandBufferUsageFlags flags,
32 CommandBuffer *commandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -050033{
34 ASSERT(!commandBuffer->valid());
35
Shahbaz Youssefi06270c92018-10-03 17:00:25 -040036 VkCommandBufferAllocateInfo createInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -050037 createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
38 createInfo.commandPool = commandPool.getHandle();
39 createInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
40 createInfo.commandBufferCount = 1;
Jamie Madill1f46bc12018-02-20 16:09:43 -050041
Yuly Novikov27780292018-11-09 11:19:49 -050042 ANGLE_VK_TRY(context, commandBuffer->init(context->getDevice(), createInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -050043
Shahbaz Youssefi06270c92018-10-03 17:00:25 -040044 VkCommandBufferBeginInfo beginInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -050045 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
46 beginInfo.flags = flags | VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
47 beginInfo.pInheritanceInfo = &inheritanceInfo;
Jamie Madill1f46bc12018-02-20 16:09:43 -050048
Yuly Novikov27780292018-11-09 11:19:49 -050049 ANGLE_VK_TRY(context, commandBuffer->begin(beginInfo));
Jamie Madill7c985f52018-11-29 18:16:17 -050050 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -050051}
52
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040053const char *GetResourceTypeName(CommandGraphResourceType resourceType,
54 CommandGraphNodeFunction function)
Jamie Madill0da73fe2018-10-02 09:31:39 -040055{
56 switch (resourceType)
57 {
58 case CommandGraphResourceType::Buffer:
59 return "Buffer";
60 case CommandGraphResourceType::Framebuffer:
61 return "Framebuffer";
62 case CommandGraphResourceType::Image:
63 return "Image";
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -040064 case CommandGraphResourceType::Query:
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040065 switch (function)
66 {
67 case CommandGraphNodeFunction::BeginQuery:
68 return "BeginQuery";
69 case CommandGraphNodeFunction::EndQuery:
70 return "EndQuery";
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -040071 case CommandGraphNodeFunction::WriteTimestamp:
72 return "WriteTimestamp";
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -040073 default:
74 UNREACHABLE();
75 return "Query";
76 }
Jamie Madill0da73fe2018-10-02 09:31:39 -040077 default:
78 UNREACHABLE();
79 return "";
80 }
81}
Jamie Madill1f46bc12018-02-20 16:09:43 -050082} // anonymous namespace
83
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040084// CommandGraphResource implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -040085CommandGraphResource::CommandGraphResource(CommandGraphResourceType resourceType)
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -050086 : mCurrentWritingNode(nullptr), mResourceType(resourceType)
Jamie Madillb980c562018-11-27 11:34:27 -050087{}
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040088
Jamie Madill316c6062018-05-29 10:49:45 -040089CommandGraphResource::~CommandGraphResource() = default;
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040090
Jamie Madillc57ee252018-05-30 19:53:48 -040091bool CommandGraphResource::isResourceInUse(RendererVk *renderer) const
92{
93 return renderer->isSerialInUse(mStoredQueueSerial);
94}
95
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -050096angle::Result CommandGraphResource::recordCommands(Context *context,
97 CommandBuffer **commandBufferOut)
Jamie Madill6c7ab7f2018-03-31 14:19:15 -040098{
Jamie Madill21061022018-07-12 23:56:30 -040099 updateQueueSerial(context->getRenderer()->getCurrentQueueSerial());
Jamie Madill5dca6512018-05-30 10:53:51 -0400100
Jamie Madille2d22702018-09-19 08:11:48 -0400101 if (!hasChildlessWritingNode() || hasStartedRenderPass())
Jamie Madill316c6062018-05-29 10:49:45 -0400102 {
Jamie Madill193a2842018-10-30 17:28:41 -0400103 startNewCommands(context->getRenderer());
Jamie Madille2d22702018-09-19 08:11:48 -0400104 return mCurrentWritingNode->beginOutsideRenderPassRecording(
105 context, context->getRenderer()->getCommandPool(), commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400106 }
107
108 CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
109 if (!outsideRenderPassCommands->valid())
110 {
111 ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
Jamie Madill21061022018-07-12 23:56:30 -0400112 context, context->getRenderer()->getCommandPool(), commandBufferOut));
Jamie Madill316c6062018-05-29 10:49:45 -0400113 }
114 else
115 {
116 *commandBufferOut = outsideRenderPassCommands;
117 }
118
Jamie Madill7c985f52018-11-29 18:16:17 -0500119 return angle::Result::Continue;
Jamie Madill316c6062018-05-29 10:49:45 -0400120}
121
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500122const gl::Rectangle &CommandGraphResource::getRenderPassRenderArea() const
Jamie Madill316c6062018-05-29 10:49:45 -0400123{
124 ASSERT(hasStartedRenderPass());
125 return mCurrentWritingNode->getRenderPassRenderArea();
126}
127
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500128angle::Result CommandGraphResource::beginRenderPass(ContextVk *contextVk,
129 const Framebuffer &framebuffer,
130 const gl::Rectangle &renderArea,
131 const RenderPassDesc &renderPassDesc,
132 const std::vector<VkClearValue> &clearValues,
133 CommandBuffer **commandBufferOut)
Jamie Madill316c6062018-05-29 10:49:45 -0400134{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400135 // If a barrier has been inserted in the meantime, stop the command buffer.
136 if (!hasChildlessWritingNode())
137 {
Jamie Madill85ca1892019-01-16 13:27:15 -0500138 startNewCommands(contextVk->getRenderer());
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400139 }
140
Jamie Madill316c6062018-05-29 10:49:45 -0400141 // Hard-code RenderPass to clear the first render target to the current clear value.
142 // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
143 mCurrentWritingNode->storeRenderPassInfo(framebuffer, renderArea, renderPassDesc, clearValues);
144
Jamie Madill85ca1892019-01-16 13:27:15 -0500145 mCurrentWritingNode->setCommandBufferOwner(contextVk);
146
147 return mCurrentWritingNode->beginInsideRenderPassRecording(contextVk, commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400148}
149
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500150void CommandGraphResource::addWriteDependency(CommandGraphResource *writingResource)
Jamie Madill316c6062018-05-29 10:49:45 -0400151{
152 CommandGraphNode *writingNode = writingResource->mCurrentWritingNode;
153 ASSERT(writingNode);
154
Jamie Madillc57ee252018-05-30 19:53:48 -0400155 onWriteImpl(writingNode, writingResource->getStoredQueueSerial());
Jamie Madill316c6062018-05-29 10:49:45 -0400156}
157
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500158void CommandGraphResource::addReadDependency(CommandGraphResource *readingResource)
Jamie Madill193a2842018-10-30 17:28:41 -0400159{
160 updateQueueSerial(readingResource->getStoredQueueSerial());
161
162 CommandGraphNode *readingNode = readingResource->mCurrentWritingNode;
163 ASSERT(readingNode);
164
Shahbaz Youssefib5ba5492019-01-02 15:19:22 -0500165 if (mCurrentWritingNode)
Jamie Madill193a2842018-10-30 17:28:41 -0400166 {
167 // Ensure 'readingNode' happens after the current writing node.
168 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, readingNode);
169 }
170
171 // Add the read node to the list of nodes currently reading this resource.
172 mCurrentReadingNodes.push_back(readingNode);
173}
174
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500175void CommandGraphResource::finishCurrentCommands(RendererVk *renderer)
Jamie Madill193a2842018-10-30 17:28:41 -0400176{
177 startNewCommands(renderer);
178}
179
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500180void CommandGraphResource::startNewCommands(RendererVk *renderer)
Jamie Madill193a2842018-10-30 17:28:41 -0400181{
182 CommandGraphNode *newCommands =
183 renderer->getCommandGraph()->allocateNode(CommandGraphNodeFunction::Generic);
184 newCommands->setDiagnosticInfo(mResourceType, reinterpret_cast<uintptr_t>(this));
185 onWriteImpl(newCommands, renderer->getCurrentQueueSerial());
186}
187
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500188void CommandGraphResource::onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial)
Jamie Madill316c6062018-05-29 10:49:45 -0400189{
190 updateQueueSerial(currentSerial);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400191
Jamie Madill9cceac42018-03-31 14:19:16 -0400192 // Make sure any open reads and writes finish before we execute 'writingNode'.
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400193 if (!mCurrentReadingNodes.empty())
194 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400195 CommandGraphNode::SetHappensBeforeDependencies(mCurrentReadingNodes.data(),
196 mCurrentReadingNodes.size(), writingNode);
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400197 mCurrentReadingNodes.clear();
198 }
199
200 if (mCurrentWritingNode && mCurrentWritingNode != writingNode)
201 {
202 CommandGraphNode::SetHappensBeforeDependency(mCurrentWritingNode, writingNode);
203 }
204
205 mCurrentWritingNode = writingNode;
206}
207
Jamie Madill1f46bc12018-02-20 16:09:43 -0500208// CommandGraphNode implementation.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400209CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function)
210 : mRenderPassClearValues{},
211 mFunction(function),
212 mQueryPool(VK_NULL_HANDLE),
213 mQueryIndex(0),
214 mHasChildren(false),
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500215 mVisitedState(VisitedState::Unvisited),
216 mGlobalMemoryBarrierSrcAccess(0),
Jamie Madill85ca1892019-01-16 13:27:15 -0500217 mGlobalMemoryBarrierDstAccess(0),
218 mCommandBufferOwner(nullptr)
Jamie Madillb980c562018-11-27 11:34:27 -0500219{}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500220
221CommandGraphNode::~CommandGraphNode()
222{
223 mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
224
225 // Command buffers are managed by the command pool, so don't need to be freed.
226 mOutsideRenderPassCommands.releaseHandle();
227 mInsideRenderPassCommands.releaseHandle();
228}
229
230CommandBuffer *CommandGraphNode::getOutsideRenderPassCommands()
231{
232 ASSERT(!mHasChildren);
233 return &mOutsideRenderPassCommands;
234}
235
Jamie Madill21061022018-07-12 23:56:30 -0400236angle::Result CommandGraphNode::beginOutsideRenderPassRecording(Context *context,
237 const CommandPool &commandPool,
238 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500239{
240 ASSERT(!mHasChildren);
241
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400242 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500243 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
244 inheritanceInfo.renderPass = VK_NULL_HANDLE;
245 inheritanceInfo.subpass = 0;
246 inheritanceInfo.framebuffer = VK_NULL_HANDLE;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400247 inheritanceInfo.occlusionQueryEnable =
248 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500249 inheritanceInfo.queryFlags = 0;
250 inheritanceInfo.pipelineStatistics = 0;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500251
Jamie Madill21061022018-07-12 23:56:30 -0400252 ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500253 &mOutsideRenderPassCommands));
254
255 *commandsOut = &mOutsideRenderPassCommands;
Jamie Madill7c985f52018-11-29 18:16:17 -0500256 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500257}
258
Jamie Madill21061022018-07-12 23:56:30 -0400259angle::Result CommandGraphNode::beginInsideRenderPassRecording(Context *context,
260 CommandBuffer **commandsOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500261{
262 ASSERT(!mHasChildren);
263
264 // Get a compatible RenderPass from the cache so we can initialize the inheritance info.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400265 // TODO(jmadill): Support query for compatible/conformant render pass. http://anglebug.com/2361
Jamie Madill1f46bc12018-02-20 16:09:43 -0500266 RenderPass *compatibleRenderPass;
Jamie Madill21061022018-07-12 23:56:30 -0400267 ANGLE_TRY(context->getRenderer()->getCompatibleRenderPass(context, mRenderPassDesc,
268 &compatibleRenderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500269
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400270 VkCommandBufferInheritanceInfo inheritanceInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500271 inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
272 inheritanceInfo.renderPass = compatibleRenderPass->getHandle();
273 inheritanceInfo.subpass = 0;
274 inheritanceInfo.framebuffer = mRenderPassFramebuffer.getHandle();
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400275 inheritanceInfo.occlusionQueryEnable =
276 context->getRenderer()->getPhysicalDeviceFeatures().inheritedQueries;
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500277 inheritanceInfo.queryFlags = 0;
278 inheritanceInfo.pipelineStatistics = 0;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500279
280 ANGLE_TRY(InitAndBeginCommandBuffer(
Jamie Madill21061022018-07-12 23:56:30 -0400281 context, context->getRenderer()->getCommandPool(), inheritanceInfo,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500282 VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
283
284 *commandsOut = &mInsideRenderPassCommands;
Jamie Madill7c985f52018-11-29 18:16:17 -0500285 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500286}
287
288void CommandGraphNode::storeRenderPassInfo(const Framebuffer &framebuffer,
289 const gl::Rectangle renderArea,
Jamie Madillbcf467f2018-05-23 09:46:00 -0400290 const vk::RenderPassDesc &renderPassDesc,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500291 const std::vector<VkClearValue> &clearValues)
292{
Jamie Madillbcf467f2018-05-23 09:46:00 -0400293 mRenderPassDesc = renderPassDesc;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500294 mRenderPassFramebuffer.setHandle(framebuffer.getHandle());
295 mRenderPassRenderArea = renderArea;
296 std::copy(clearValues.begin(), clearValues.end(), mRenderPassClearValues.begin());
297}
298
Jamie Madill1f46bc12018-02-20 16:09:43 -0500299// static
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400300void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode **beforeNodes,
301 size_t beforeNodesCount,
302 CommandGraphNode *afterNode)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500303{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400304 afterNode->mParents.insert(afterNode->mParents.end(), beforeNodes,
305 beforeNodes + beforeNodesCount);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500306
307 // TODO(jmadill): is there a faster way to do this?
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400308 for (size_t i = 0; i < beforeNodesCount; ++i)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500309 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400310 beforeNodes[i]->setHasChildren();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500311
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400312 ASSERT(beforeNodes[i] != afterNode && !beforeNodes[i]->isChildOf(afterNode));
313 }
314}
315
316void CommandGraphNode::SetHappensBeforeDependencies(CommandGraphNode *beforeNode,
317 CommandGraphNode **afterNodes,
318 size_t afterNodesCount)
319{
320 for (size_t i = 0; i < afterNodesCount; ++i)
321 {
322 SetHappensBeforeDependency(beforeNode, afterNodes[i]);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500323 }
324}
325
326bool CommandGraphNode::hasParents() const
327{
328 return !mParents.empty();
329}
330
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400331void CommandGraphNode::setQueryPool(const QueryPool *queryPool, uint32_t queryIndex)
332{
333 ASSERT(mFunction == CommandGraphNodeFunction::BeginQuery ||
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400334 mFunction == CommandGraphNodeFunction::EndQuery ||
335 mFunction == CommandGraphNodeFunction::WriteTimestamp);
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400336 mQueryPool = queryPool->getHandle();
337 mQueryIndex = queryIndex;
338}
339
Jamie Madill1f46bc12018-02-20 16:09:43 -0500340// Do not call this in anything but testing code, since it's slow.
341bool CommandGraphNode::isChildOf(CommandGraphNode *parent)
342{
343 std::set<CommandGraphNode *> visitedList;
344 std::vector<CommandGraphNode *> openList;
345 openList.insert(openList.begin(), mParents.begin(), mParents.end());
346 while (!openList.empty())
347 {
348 CommandGraphNode *current = openList.back();
349 openList.pop_back();
350 if (visitedList.count(current) == 0)
351 {
352 if (current == parent)
353 {
354 return true;
355 }
356 visitedList.insert(current);
357 openList.insert(openList.end(), current->mParents.begin(), current->mParents.end());
358 }
359 }
360
361 return false;
362}
363
364VisitedState CommandGraphNode::visitedState() const
365{
366 return mVisitedState;
367}
368
369void CommandGraphNode::visitParents(std::vector<CommandGraphNode *> *stack)
370{
371 ASSERT(mVisitedState == VisitedState::Unvisited);
372 stack->insert(stack->end(), mParents.begin(), mParents.end());
373 mVisitedState = VisitedState::Ready;
374}
375
Jamie Madill21061022018-07-12 23:56:30 -0400376angle::Result CommandGraphNode::visitAndExecute(vk::Context *context,
377 Serial serial,
378 RenderPassCache *renderPassCache,
379 CommandBuffer *primaryCommandBuffer)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500380{
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400381 switch (mFunction)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500382 {
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400383 case CommandGraphNodeFunction::Generic:
384 ASSERT(mQueryPool == VK_NULL_HANDLE);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500385
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500386 // Record the deferred pipeline barrier if necessary.
387 ASSERT((mGlobalMemoryBarrierDstAccess == 0) == (mGlobalMemoryBarrierSrcAccess == 0));
388 if (mGlobalMemoryBarrierSrcAccess)
389 {
390 VkMemoryBarrier memoryBarrier = {};
391 memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
392 memoryBarrier.srcAccessMask = mGlobalMemoryBarrierSrcAccess;
393 memoryBarrier.dstAccessMask = mGlobalMemoryBarrierDstAccess;
394
Shahbaz Youssefi471358f2018-11-28 15:21:55 -0500395 // Use the all pipe stage to keep the state management simple.
396 primaryCommandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
397 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 1,
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500398 &memoryBarrier, 0, nullptr, 0, nullptr);
399 }
400
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400401 if (mOutsideRenderPassCommands.valid())
402 {
Yuly Novikov27780292018-11-09 11:19:49 -0500403 ANGLE_VK_TRY(context, mOutsideRenderPassCommands.end());
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400404 primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
405 }
Jamie Madill1f46bc12018-02-20 16:09:43 -0500406
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400407 if (mInsideRenderPassCommands.valid())
408 {
409 // Pull a compatible RenderPass from the cache.
410 // TODO(jmadill): Insert real ops and layout transitions.
411 RenderPass *renderPass = nullptr;
412 ANGLE_TRY(renderPassCache->getCompatibleRenderPass(context, serial, mRenderPassDesc,
413 &renderPass));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500414
Yuly Novikov27780292018-11-09 11:19:49 -0500415 ANGLE_VK_TRY(context, mInsideRenderPassCommands.end());
Jamie Madill1f46bc12018-02-20 16:09:43 -0500416
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400417 VkRenderPassBeginInfo beginInfo = {};
418 beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
419 beginInfo.renderPass = renderPass->getHandle();
420 beginInfo.framebuffer = mRenderPassFramebuffer.getHandle();
421 beginInfo.renderArea.offset.x = static_cast<uint32_t>(mRenderPassRenderArea.x);
422 beginInfo.renderArea.offset.y = static_cast<uint32_t>(mRenderPassRenderArea.y);
423 beginInfo.renderArea.extent.width =
424 static_cast<uint32_t>(mRenderPassRenderArea.width);
425 beginInfo.renderArea.extent.height =
426 static_cast<uint32_t>(mRenderPassRenderArea.height);
427 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
428 beginInfo.pClearValues = mRenderPassClearValues.data();
429
430 primaryCommandBuffer->beginRenderPass(
431 beginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
432 primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
433 primaryCommandBuffer->endRenderPass();
434 }
435 break;
436
437 case CommandGraphNodeFunction::BeginQuery:
438 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
439 ASSERT(mQueryPool != VK_NULL_HANDLE);
440
441 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
442 primaryCommandBuffer->beginQuery(mQueryPool, mQueryIndex, 0);
443
444 break;
445
446 case CommandGraphNodeFunction::EndQuery:
447 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
448 ASSERT(mQueryPool != VK_NULL_HANDLE);
449
450 primaryCommandBuffer->endQuery(mQueryPool, mQueryIndex);
451
452 break;
453
Shahbaz Youssefic2b576d2018-10-12 14:45:34 -0400454 case CommandGraphNodeFunction::WriteTimestamp:
455 ASSERT(!mOutsideRenderPassCommands.valid() && !mInsideRenderPassCommands.valid());
456 ASSERT(mQueryPool != VK_NULL_HANDLE);
457
458 primaryCommandBuffer->resetQueryPool(mQueryPool, mQueryIndex, 1);
459 primaryCommandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, mQueryPool,
460 mQueryIndex);
461
462 break;
463
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400464 default:
465 UNREACHABLE();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500466 }
467
468 mVisitedState = VisitedState::Visited;
Jamie Madill7c985f52018-11-29 18:16:17 -0500469 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500470}
471
Jamie Madill0da73fe2018-10-02 09:31:39 -0400472const std::vector<CommandGraphNode *> &CommandGraphNode::getParentsForDiagnostics() const
473{
474 return mParents;
475}
476
477void CommandGraphNode::setDiagnosticInfo(CommandGraphResourceType resourceType,
478 uintptr_t resourceID)
479{
480 mResourceType = resourceType;
481 mResourceID = resourceID;
482}
483
Luc Ferron14f48172018-04-11 08:43:28 -0400484const gl::Rectangle &CommandGraphNode::getRenderPassRenderArea() const
485{
486 return mRenderPassRenderArea;
487}
488
Jamie Madill1f46bc12018-02-20 16:09:43 -0500489// CommandGraph implementation.
Jamie Madill0da73fe2018-10-02 09:31:39 -0400490CommandGraph::CommandGraph(bool enableGraphDiagnostics)
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400491 : mEnableGraphDiagnostics(enableGraphDiagnostics), mLastBarrierIndex(kInvalidNodeIndex)
Jamie Madillb980c562018-11-27 11:34:27 -0500492{}
Jamie Madill1f46bc12018-02-20 16:09:43 -0500493
494CommandGraph::~CommandGraph()
495{
496 ASSERT(empty());
497}
498
Jamie Madill193a2842018-10-30 17:28:41 -0400499CommandGraphNode *CommandGraph::allocateNode(CommandGraphNodeFunction function)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500500{
501 // TODO(jmadill): Use a pool allocator for the CPU node allocations.
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400502 CommandGraphNode *newCommands = new CommandGraphNode(function);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500503 mNodes.emplace_back(newCommands);
504 return newCommands;
505}
506
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500507CommandGraphNode *CommandGraph::allocateBarrierNode(CommandGraphResourceType resourceType,
508 CommandGraphNodeFunction function)
509{
510 CommandGraphNode *newNode = allocateNode(function);
511 newNode->setDiagnosticInfo(resourceType, 0);
512 setNewBarrier(newNode);
513
514 return newNode;
515}
516
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400517void CommandGraph::setNewBarrier(CommandGraphNode *newBarrier)
518{
519 size_t previousBarrierIndex = 0;
520 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
521
522 // Add a dependency from previousBarrier to all nodes in (previousBarrier, newBarrier].
523 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
524 {
525 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
526 CommandGraphNode::SetHappensBeforeDependencies(
527 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
528 }
529
530 // Add a dependency from all nodes in (previousBarrier, newBarrier) to newBarrier.
531 addDependenciesToNextBarrier(previousBarrierIndex + 1, mNodes.size() - 1, newBarrier);
532
533 mLastBarrierIndex = mNodes.size() - 1;
534}
535
Jamie Madill21061022018-07-12 23:56:30 -0400536angle::Result CommandGraph::submitCommands(Context *context,
537 Serial serial,
538 RenderPassCache *renderPassCache,
539 CommandPool *commandPool,
540 CommandBuffer *primaryCommandBufferOut)
Jamie Madill1f46bc12018-02-20 16:09:43 -0500541{
Shahbaz Youssefi3a482172018-10-11 10:34:44 -0400542 // There is no point in submitting an empty command buffer, so make sure not to call this
543 // function if there's nothing to do.
544 ASSERT(!mNodes.empty());
545
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400546 size_t previousBarrierIndex = 0;
547 CommandGraphNode *previousBarrier = getLastBarrierNode(&previousBarrierIndex);
548
549 // Add a dependency from previousBarrier to all nodes in (previousBarrier, end].
550 if (previousBarrier && previousBarrierIndex + 1 < mNodes.size())
551 {
552 size_t afterNodesCount = mNodes.size() - (previousBarrierIndex + 1);
553 CommandGraphNode::SetHappensBeforeDependencies(
554 previousBarrier, &mNodes[previousBarrierIndex + 1], afterNodesCount);
555 }
556
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400557 VkCommandBufferAllocateInfo primaryInfo = {};
Jamie Madill03d1a5e2018-11-12 11:34:24 -0500558 primaryInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
559 primaryInfo.commandPool = commandPool->getHandle();
560 primaryInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
561 primaryInfo.commandBufferCount = 1;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500562
Yuly Novikov27780292018-11-09 11:19:49 -0500563 ANGLE_VK_TRY(context, primaryCommandBufferOut->init(context->getDevice(), primaryInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500564
Jamie Madill0da73fe2018-10-02 09:31:39 -0400565 if (mEnableGraphDiagnostics)
566 {
567 dumpGraphDotFile(std::cout);
568 }
569
Jamie Madill1f46bc12018-02-20 16:09:43 -0500570 std::vector<CommandGraphNode *> nodeStack;
571
Shahbaz Youssefi06270c92018-10-03 17:00:25 -0400572 VkCommandBufferBeginInfo beginInfo = {};
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400573 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
574 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
575 beginInfo.pInheritanceInfo = nullptr;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500576
Yuly Novikov27780292018-11-09 11:19:49 -0500577 ANGLE_VK_TRY(context, primaryCommandBufferOut->begin(beginInfo));
Jamie Madill1f46bc12018-02-20 16:09:43 -0500578
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400579 ANGLE_TRY(context->getRenderer()->traceGpuEvent(
580 context, primaryCommandBufferOut, TRACE_EVENT_PHASE_BEGIN, "Primary Command Buffer"));
581
Jamie Madill1f46bc12018-02-20 16:09:43 -0500582 for (CommandGraphNode *topLevelNode : mNodes)
583 {
584 // Only process commands that don't have child commands. The others will be pulled in
585 // automatically. Also skip commands that have already been visited.
586 if (topLevelNode->hasChildren() || topLevelNode->visitedState() != VisitedState::Unvisited)
587 continue;
588
589 nodeStack.push_back(topLevelNode);
590
591 while (!nodeStack.empty())
592 {
593 CommandGraphNode *node = nodeStack.back();
594
595 switch (node->visitedState())
596 {
597 case VisitedState::Unvisited:
598 node->visitParents(&nodeStack);
599 break;
600 case VisitedState::Ready:
Jamie Madill21061022018-07-12 23:56:30 -0400601 ANGLE_TRY(node->visitAndExecute(context, serial, renderPassCache,
Jamie Madill1f46bc12018-02-20 16:09:43 -0500602 primaryCommandBufferOut));
603 nodeStack.pop_back();
604 break;
605 case VisitedState::Visited:
606 nodeStack.pop_back();
607 break;
608 default:
609 UNREACHABLE();
610 break;
611 }
612 }
613 }
614
Shahbaz Youssefi25224e72018-10-22 11:56:02 -0400615 ANGLE_TRY(context->getRenderer()->traceGpuEvent(
616 context, primaryCommandBufferOut, TRACE_EVENT_PHASE_END, "Primary Command Buffer"));
617
Yuly Novikov27780292018-11-09 11:19:49 -0500618 ANGLE_VK_TRY(context, primaryCommandBufferOut->end());
Jamie Madill1f46bc12018-02-20 16:09:43 -0500619
Yuly Novikovb56ddbb2018-11-02 16:53:18 -0400620 clear();
Jamie Madill1f46bc12018-02-20 16:09:43 -0500621
Jamie Madill7c985f52018-11-29 18:16:17 -0500622 return angle::Result::Continue;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500623}
624
625bool CommandGraph::empty() const
626{
627 return mNodes.empty();
628}
629
Yuly Novikovb56ddbb2018-11-02 16:53:18 -0400630void CommandGraph::clear()
631{
632 mLastBarrierIndex = kInvalidNodeIndex;
633
634 // TODO(jmadill): Use pool allocator for performance. http://anglebug.com/2951
635 for (CommandGraphNode *node : mNodes)
636 {
637 delete node;
638 }
639 mNodes.clear();
640}
641
Shahbaz Youssefic81e7bf2019-01-18 15:35:55 -0500642void CommandGraph::beginQuery(const QueryPool *queryPool, uint32_t queryIndex)
643{
644 CommandGraphNode *newNode =
645 allocateBarrierNode(CommandGraphResourceType::Query, CommandGraphNodeFunction::BeginQuery);
646 newNode->setQueryPool(queryPool, queryIndex);
647}
648
649void CommandGraph::endQuery(const QueryPool *queryPool, uint32_t queryIndex)
650{
651 CommandGraphNode *newNode =
652 allocateBarrierNode(CommandGraphResourceType::Query, CommandGraphNodeFunction::EndQuery);
653 newNode->setQueryPool(queryPool, queryIndex);
654}
655
656void CommandGraph::writeTimestamp(const QueryPool *queryPool, uint32_t queryIndex)
657{
658 CommandGraphNode *newNode = allocateBarrierNode(CommandGraphResourceType::Query,
659 CommandGraphNodeFunction::WriteTimestamp);
660 newNode->setQueryPool(queryPool, queryIndex);
661}
662
Jamie Madill0da73fe2018-10-02 09:31:39 -0400663// Dumps the command graph into a dot file that works with graphviz.
664void CommandGraph::dumpGraphDotFile(std::ostream &out) const
665{
666 // This ID maps a node pointer to a monatonic ID. It allows us to look up parent node IDs.
667 std::map<const CommandGraphNode *, int> nodeIDMap;
668 std::map<uintptr_t, int> objectIDMap;
669
670 // Map nodes to ids.
671 for (size_t nodeIndex = 0; nodeIndex < mNodes.size(); ++nodeIndex)
672 {
673 const CommandGraphNode *node = mNodes[nodeIndex];
674 nodeIDMap[node] = static_cast<int>(nodeIndex) + 1;
675 }
676
677 int bufferIDCounter = 1;
678 int framebufferIDCounter = 1;
679 int imageIDCounter = 1;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400680 int queryIDCounter = 1;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400681
682 out << "digraph {" << std::endl;
683
684 for (const CommandGraphNode *node : mNodes)
685 {
686 int nodeID = nodeIDMap[node];
687
688 std::stringstream strstr;
Shahbaz Youssefi6eba3c62018-10-11 14:00:08 -0400689 strstr << GetResourceTypeName(node->getResourceTypeForDiagnostics(), node->getFunction());
Jamie Madill0da73fe2018-10-02 09:31:39 -0400690 strstr << " ";
691
692 auto it = objectIDMap.find(node->getResourceIDForDiagnostics());
693 if (it != objectIDMap.end())
694 {
695 strstr << it->second;
696 }
697 else
698 {
699 int id = 0;
700
701 switch (node->getResourceTypeForDiagnostics())
702 {
703 case CommandGraphResourceType::Buffer:
704 id = bufferIDCounter++;
705 break;
706 case CommandGraphResourceType::Framebuffer:
707 id = framebufferIDCounter++;
708 break;
709 case CommandGraphResourceType::Image:
710 id = imageIDCounter++;
711 break;
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400712 case CommandGraphResourceType::Query:
713 id = queryIDCounter++;
714 break;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400715 default:
716 UNREACHABLE();
717 break;
718 }
719
720 objectIDMap[node->getResourceIDForDiagnostics()] = id;
721 strstr << id;
722 }
723
724 const std::string &label = strstr.str();
725 out << " " << nodeID << "[label =<" << label << "<BR/> <FONT POINT-SIZE=\"10\">Node ID "
726 << nodeID << "</FONT>>];" << std::endl;
727 }
728
729 for (const CommandGraphNode *node : mNodes)
730 {
731 int nodeID = nodeIDMap[node];
732
733 for (const CommandGraphNode *parent : node->getParentsForDiagnostics())
734 {
735 int parentID = nodeIDMap[parent];
736 out << " " << parentID << " -> " << nodeID << ";" << std::endl;
737 }
738 }
739
740 out << "}" << std::endl;
741}
Shahbaz Youssefi563fbaa2018-10-02 11:22:01 -0400742
743CommandGraphNode *CommandGraph::getLastBarrierNode(size_t *indexOut)
744{
745 *indexOut = mLastBarrierIndex == kInvalidNodeIndex ? 0 : mLastBarrierIndex;
746 return mLastBarrierIndex == kInvalidNodeIndex ? nullptr : mNodes[mLastBarrierIndex];
747}
748
749void CommandGraph::addDependenciesToNextBarrier(size_t begin,
750 size_t end,
751 CommandGraphNode *nextBarrier)
752{
753 for (size_t i = begin; i < end; ++i)
754 {
755 // As a small optimization, only add edges to childless nodes. The others have an
756 // indirect dependency.
757 if (!mNodes[i]->hasChildren())
758 {
759 CommandGraphNode::SetHappensBeforeDependency(mNodes[i], nextBarrier);
760 }
761 }
762}
763
Jamie Madill1f46bc12018-02-20 16:09:43 -0500764} // namespace vk
765} // namespace rx