blob: 894f6ae89927f00957546d65ab300552986c0f9b [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#ifndef LIBANGLE_RENDERER_VULKAN_COMMAND_GRAPH_H_
11#define LIBANGLE_RENDERER_VULKAN_COMMAND_GRAPH_H_
12
13#include "libANGLE/renderer/vulkan/vk_cache_utils.h"
14
15namespace rx
16{
17
18namespace vk
19{
Jamie Madill3d61ac22018-08-28 16:58:55 -040020enum class VisitedState
21{
22 Unvisited,
23 Ready,
24 Visited,
25};
26
Jamie Madill0da73fe2018-10-02 09:31:39 -040027enum class CommandGraphResourceType
28{
29 Buffer,
30 Framebuffer,
31 Image,
32};
33
Jamie Madill3d61ac22018-08-28 16:58:55 -040034// Only used internally in the command graph. Kept in the header for better inlining performance.
35class CommandGraphNode final : angle::NonCopyable
36{
37 public:
38 CommandGraphNode();
39 ~CommandGraphNode();
40
41 // Immutable queries for when we're walking the commands tree.
42 CommandBuffer *getOutsideRenderPassCommands();
43
44 CommandBuffer *getInsideRenderPassCommands()
45 {
46 ASSERT(!mHasChildren);
47 return &mInsideRenderPassCommands;
48 }
49
50 // For outside the render pass (copies, transitions, etc).
51 angle::Result beginOutsideRenderPassRecording(Context *context,
52 const CommandPool &commandPool,
53 CommandBuffer **commandsOut);
54
55 // For rendering commands (draws).
56 angle::Result beginInsideRenderPassRecording(Context *context, CommandBuffer **commandsOut);
57
58 // storeRenderPassInfo and append*RenderTarget store info relevant to the RenderPass.
59 void storeRenderPassInfo(const Framebuffer &framebuffer,
60 const gl::Rectangle renderArea,
61 const vk::RenderPassDesc &renderPassDesc,
62 const std::vector<VkClearValue> &clearValues);
63
64 // Dependency commands order node execution in the command graph.
65 // Once a node has commands that must happen after it, recording is stopped and the node is
66 // frozen forever.
67 static void SetHappensBeforeDependency(CommandGraphNode *beforeNode,
68 CommandGraphNode *afterNode);
69 static void SetHappensBeforeDependencies(const std::vector<CommandGraphNode *> &beforeNodes,
70 CommandGraphNode *afterNode);
71 bool hasParents() const;
72 bool hasChildren() const { return mHasChildren; }
73
74 // Commands for traversing the node on a flush operation.
75 VisitedState visitedState() const;
76 void visitParents(std::vector<CommandGraphNode *> *stack);
77 angle::Result visitAndExecute(Context *context,
78 Serial serial,
79 RenderPassCache *renderPassCache,
80 CommandBuffer *primaryCommandBuffer);
81
Jamie Madill0da73fe2018-10-02 09:31:39 -040082 // Only used in the command graph diagnostics.
83 const std::vector<CommandGraphNode *> &getParentsForDiagnostics() const;
84 void setDiagnosticInfo(CommandGraphResourceType resourceType, uintptr_t resourceID);
85
86 CommandGraphResourceType getResourceTypeForDiagnostics() const { return mResourceType; }
87 uintptr_t getResourceIDForDiagnostics() const { return mResourceID; }
88
Jamie Madill3d61ac22018-08-28 16:58:55 -040089 const gl::Rectangle &getRenderPassRenderArea() const;
90
91 private:
92 void setHasChildren();
93
94 // Used for testing only.
95 bool isChildOf(CommandGraphNode *parent);
96
97 // Only used if we need a RenderPass for these commands.
98 RenderPassDesc mRenderPassDesc;
99 Framebuffer mRenderPassFramebuffer;
100 gl::Rectangle mRenderPassRenderArea;
101 gl::AttachmentArray<VkClearValue> mRenderPassClearValues;
102
103 // Keep a separate buffers for commands inside and outside a RenderPass.
104 // TODO(jmadill): We might not need inside and outside RenderPass commands separate.
105 CommandBuffer mOutsideRenderPassCommands;
106 CommandBuffer mInsideRenderPassCommands;
107
108 // Parents are commands that must be submitted before 'this' CommandNode can be submitted.
109 std::vector<CommandGraphNode *> mParents;
110
111 // If this is true, other commands exist that must be submitted after 'this' command.
112 bool mHasChildren;
113
114 // Used when traversing the dependency graph.
115 VisitedState mVisitedState;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400116
117 // Additional diagnostic information.
118 CommandGraphResourceType mResourceType;
119 uintptr_t mResourceID;
Jamie Madill3d61ac22018-08-28 16:58:55 -0400120};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500121
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400122// This is a helper class for back-end objects used in Vk command buffers. It records a serial
123// at command recording times indicating an order in the queue. We use Fences to detect when
124// commands finish, and then release any unreferenced and deleted resources based on the stored
125// queue serial in a special 'garbage' queue. Resources also track current read and write
126// dependencies. Only one command buffer node can be writing to the Resource at a time, but many
127// can be reading from it. Together the dependencies will form a command graph at submission time.
Jamie Madill0da73fe2018-10-02 09:31:39 -0400128class CommandGraphResource : angle::NonCopyable
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400129{
130 public:
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400131 virtual ~CommandGraphResource();
132
Jamie Madillc57ee252018-05-30 19:53:48 -0400133 // Returns true if the resource is in use by the renderer.
134 bool isResourceInUse(RendererVk *renderer) const;
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400135
Jamie Madilld014c9e2018-05-18 15:15:59 -0400136 // Sets up dependency relations. 'this' resource is the resource being written to.
137 void addWriteDependency(CommandGraphResource *writingResource);
138
139 // Sets up dependency relations. 'this' resource is the resource being read.
140 void addReadDependency(CommandGraphResource *readingResource);
141
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400142 // Allocates a write node via getNewWriteNode and returns a started command buffer.
143 // The started command buffer will render outside of a RenderPass.
Jamie Madille2d22702018-09-19 08:11:48 -0400144 // Will append to an existing command buffer/graph node if possible.
145 angle::Result recordCommands(Context *context, CommandBuffer **commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400146
147 // Begins a command buffer on the current graph node for in-RenderPass rendering.
148 // Currently only called from FramebufferVk::getCommandBufferForDraw.
Jamie Madill21061022018-07-12 23:56:30 -0400149 angle::Result beginRenderPass(Context *context,
150 const Framebuffer &framebuffer,
151 const gl::Rectangle &renderArea,
152 const RenderPassDesc &renderPassDesc,
153 const std::vector<VkClearValue> &clearValues,
154 CommandBuffer **commandBufferOut) const;
Jamie Madill316c6062018-05-29 10:49:45 -0400155
Jamie Madill5dca6512018-05-30 10:53:51 -0400156 // Checks if we're in a RenderPass, returning true if so. Updates serial internally.
157 // Returns the started command buffer in commandBufferOut.
158 bool appendToStartedRenderPass(RendererVk *renderer, CommandBuffer **commandBufferOut);
Jamie Madill316c6062018-05-29 10:49:45 -0400159
160 // Accessor for RenderPass RenderArea.
161 const gl::Rectangle &getRenderPassRenderArea() const;
162
163 // Called when 'this' object changes, but we'd like to start a new command buffer later.
Jamie Madille2d22702018-09-19 08:11:48 -0400164 void finishCurrentCommands(RendererVk *renderer);
Jamie Madill316c6062018-05-29 10:49:45 -0400165
Jamie Madill2d03ff42018-09-27 15:04:26 -0400166 protected:
Jamie Madill0da73fe2018-10-02 09:31:39 -0400167 explicit CommandGraphResource(CommandGraphResourceType resourceType);
168
Jamie Madillc57ee252018-05-30 19:53:48 -0400169 // Get the current queue serial for this resource. Only used to release resources.
170 Serial getStoredQueueSerial() const;
171
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400172 private:
Jamie Madill316c6062018-05-29 10:49:45 -0400173 void onWriteImpl(CommandGraphNode *writingNode, Serial currentSerial);
174
175 // Returns true if this node has a current writing node with no children.
Jamie Madill3d61ac22018-08-28 16:58:55 -0400176 bool hasChildlessWritingNode() const
177 {
178 return (mCurrentWritingNode != nullptr && !mCurrentWritingNode->hasChildren());
179 }
Jamie Madill316c6062018-05-29 10:49:45 -0400180
Jamie Madill5dca6512018-05-30 10:53:51 -0400181 // Checks if we're in a RenderPass without children.
Jamie Madill3d61ac22018-08-28 16:58:55 -0400182 bool hasStartedRenderPass() const
183 {
184 return hasChildlessWritingNode() &&
185 mCurrentWritingNode->getInsideRenderPassCommands()->valid();
186 }
Jamie Madill5dca6512018-05-30 10:53:51 -0400187
188 // Updates the in-use serial tracked for this resource. Will clear dependencies if the resource
189 // was not used in this set of command nodes.
190 void updateQueueSerial(Serial queueSerial);
191
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400192 Serial mStoredQueueSerial;
193 std::vector<CommandGraphNode *> mCurrentReadingNodes;
194 CommandGraphNode *mCurrentWritingNode;
Jamie Madill0da73fe2018-10-02 09:31:39 -0400195
196 // Additional diagnostic information.
197 CommandGraphResourceType mResourceType;
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400198};
199
Jamie Madill1f46bc12018-02-20 16:09:43 -0500200// Translating OpenGL commands into Vulkan and submitting them immediately loses out on some
201// of the powerful flexiblity Vulkan offers in RenderPasses. Load/Store ops can automatically
202// clear RenderPass attachments, or preserve the contents. RenderPass automatic layout transitions
203// can improve certain performance cases. Also, we can remove redundant RenderPass Begin and Ends
204// when processing interleaved draw operations on independent Framebuffers.
205//
206// ANGLE's CommandGraph (and CommandGraphNode) attempt to solve these problems using deferred
207// command submission. We also sometimes call this command re-ordering. A brief summary:
208//
209// During GL command processing, we record Vulkan commands into secondary command buffers, which
210// are stored in CommandGraphNodes, and these nodes are chained together via dependencies to
211// for a directed acyclic CommandGraph. When we need to submit the CommandGraph, say during a
212// SwapBuffers or ReadPixels call, we begin a primary Vulkan CommandBuffer, and walk the
213// CommandGraph, starting at the most senior nodes, recording secondary CommandBuffers inside
Jamie Madill6c7ab7f2018-03-31 14:19:15 -0400214// and outside RenderPasses as necessary, filled with the right load/store operations. Once
Jamie Madill1f46bc12018-02-20 16:09:43 -0500215// the primary CommandBuffer has recorded all of the secondary CommandBuffers from all the open
216// CommandGraphNodes, we submit the primary CommandBuffer to the VkQueue on the device.
Jamie Madilla5e06072018-05-18 14:36:05 -0400217//
Jamie Madill1f46bc12018-02-20 16:09:43 -0500218// The Command Graph consists of an array of open Command Graph Nodes. It supports allocating new
219// nodes for the graph, which are linked via dependency relation calls in CommandGraphNode, and
220// also submitting the whole command graph via submitCommands.
221class CommandGraph final : angle::NonCopyable
222{
223 public:
Jamie Madill0da73fe2018-10-02 09:31:39 -0400224 explicit CommandGraph(bool enableGraphDiagnostics);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500225 ~CommandGraph();
226
227 // Allocates a new CommandGraphNode and adds it to the list of current open nodes. No ordering
228 // relations exist in the node by default. Call CommandGraphNode::SetHappensBeforeDependency
229 // to set up dependency relations.
230 CommandGraphNode *allocateNode();
231
Jamie Madill21061022018-07-12 23:56:30 -0400232 angle::Result submitCommands(Context *context,
233 Serial serial,
234 RenderPassCache *renderPassCache,
235 CommandPool *commandPool,
236 CommandBuffer *primaryCommandBufferOut);
Jamie Madill1f46bc12018-02-20 16:09:43 -0500237 bool empty() const;
238
239 private:
Jamie Madill0da73fe2018-10-02 09:31:39 -0400240 void dumpGraphDotFile(std::ostream &out) const;
Jamie Madill1f46bc12018-02-20 16:09:43 -0500241
Jamie Madill0da73fe2018-10-02 09:31:39 -0400242 std::vector<CommandGraphNode *> mNodes;
243 bool mEnableGraphDiagnostics;
244};
Jamie Madill1f46bc12018-02-20 16:09:43 -0500245} // namespace vk
246} // namespace rx
247
248#endif // LIBANGLE_RENDERER_VULKAN_COMMAND_GRAPH_H_