• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
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 // ResourceVk:
7 //    Resource lifetime tracking in the Vulkan back-end.
8 //
9 
10 #ifndef LIBANGLE_RENDERER_VULKAN_RESOURCEVK_H_
11 #define LIBANGLE_RENDERER_VULKAN_RESOURCEVK_H_
12 
13 #include "libANGLE/HandleAllocator.h"
14 #include "libANGLE/renderer/vulkan/vk_utils.h"
15 
16 #include <queue>
17 
18 namespace rx
19 {
20 namespace vk
21 {
22 // We expect almost all reasonable usage case should have at most 4 current contexts now. When
23 // exceeded, it should still work, but storage will grow.
24 static constexpr size_t kMaxFastQueueSerials = 4;
25 // Serials is an array of queue serials, which when paired with the index of the serials in the
26 // array result in QueueSerials. The array may expand if needed. Since it owned by Resource object
27 // which is protected by shared lock, it is safe to reallocate storage if needed. When it passes to
28 // renderer at garbage collection time, we will make a copy. The array size is expected to be small.
29 // But in future if we run into situation that array size is too big, we can change to packed array
30 // of QueueSerials.
31 using Serials = angle::FastVector<Serial, kMaxFastQueueSerials>;
32 
33 // Tracks how a resource is used by ANGLE and by a VkQueue. The serial indicates the most recent use
34 // of a resource in the VkQueue. We use the monotonically incrementing serial number to determine if
35 // a resource is currently in use.
36 class ResourceUse final
37 {
38   public:
39     ResourceUse()  = default;
40     ~ResourceUse() = default;
41 
ResourceUse(const QueueSerial & queueSerial)42     ResourceUse(const QueueSerial &queueSerial) { setQueueSerial(queueSerial); }
ResourceUse(const Serials & otherSerials)43     ResourceUse(const Serials &otherSerials) { mSerials = otherSerials; }
44 
45     // Copy constructor
ResourceUse(const ResourceUse & other)46     ResourceUse(const ResourceUse &other) : mSerials(other.mSerials) {}
47     ResourceUse &operator=(const ResourceUse &other)
48     {
49         mSerials = other.mSerials;
50         return *this;
51     }
52 
53     // Move constructor
ResourceUse(ResourceUse && other)54     ResourceUse(ResourceUse &&other) : mSerials(other.mSerials) { other.mSerials.clear(); }
55     ResourceUse &operator=(ResourceUse &&other)
56     {
57         mSerials = other.mSerials;
58         other.mSerials.clear();
59         return *this;
60     }
61 
valid()62     bool valid() const { return mSerials.size() > 0; }
63 
reset()64     void reset() { mSerials.clear(); }
65 
getSerials()66     const Serials &getSerials() const { return mSerials; }
67 
setSerial(SerialIndex index,Serial serial)68     void setSerial(SerialIndex index, Serial serial)
69     {
70         ASSERT(index != kInvalidQueueSerialIndex);
71         if (ANGLE_UNLIKELY(mSerials.size() <= index))
72         {
73             mSerials.resize(index + 1, kZeroSerial);
74         }
75         ASSERT(mSerials[index] <= serial);
76         mSerials[index] = serial;
77     }
78 
setQueueSerial(const QueueSerial & queueSerial)79     void setQueueSerial(const QueueSerial &queueSerial)
80     {
81         setSerial(queueSerial.getIndex(), queueSerial.getSerial());
82     }
83 
84     // Returns true if there is at least one serial is greater than
85     bool operator>(const AtomicQueueSerialFixedArray &serials) const
86     {
87         ASSERT(mSerials.size() <= serials.size());
88         for (SerialIndex i = 0; i < mSerials.size(); ++i)
89         {
90             if (mSerials[i] > serials[i])
91             {
92                 return true;
93             }
94         }
95         return false;
96     }
97 
98     // Returns true if it contains a serial that is greater than
99     bool operator>(const QueueSerial &queuSerial) const
100     {
101         return mSerials.size() > queuSerial.getIndex() &&
102                mSerials[queuSerial.getIndex()] > queuSerial.getSerial();
103     }
104 
105     // Returns true if all serials are less than or equal
106     bool operator<=(const AtomicQueueSerialFixedArray &serials) const
107     {
108         ASSERT(mSerials.size() <= serials.size());
109         for (SerialIndex i = 0; i < mSerials.size(); ++i)
110         {
111             if (mSerials[i] > serials[i])
112             {
113                 return false;
114             }
115         }
116         return true;
117     }
118 
usedByCommandBuffer(const QueueSerial & commandBufferQueueSerial)119     bool usedByCommandBuffer(const QueueSerial &commandBufferQueueSerial) const
120     {
121         ASSERT(commandBufferQueueSerial.valid());
122         // Return true if we have the exact queue serial in the array.
123         return mSerials.size() > commandBufferQueueSerial.getIndex() &&
124                mSerials[commandBufferQueueSerial.getIndex()] ==
125                    commandBufferQueueSerial.getSerial();
126     }
127 
128     // Merge other's serials into this object.
merge(const ResourceUse & other)129     void merge(const ResourceUse &other)
130     {
131         if (mSerials.size() < other.mSerials.size())
132         {
133             mSerials.resize(other.mSerials.size(), kZeroSerial);
134         }
135 
136         for (SerialIndex i = 0; i < other.mSerials.size(); ++i)
137         {
138             if (mSerials[i] < other.mSerials[i])
139             {
140                 mSerials[i] = other.mSerials[i];
141             }
142         }
143     }
144 
145   private:
146     // The most recent time of use in a VkQueue.
147     Serials mSerials;
148 };
149 std::ostream &operator<<(std::ostream &os, const ResourceUse &use);
150 
151 class SharedGarbage
152 {
153   public:
154     SharedGarbage();
155     SharedGarbage(SharedGarbage &&other);
156     SharedGarbage(const ResourceUse &use, GarbageList &&garbage);
157     ~SharedGarbage();
158     SharedGarbage &operator=(SharedGarbage &&rhs);
159 
160     bool destroyIfComplete(RendererVk *renderer);
161     bool hasResourceUseSubmitted(RendererVk *renderer) const;
162 
163   private:
164     ResourceUse mLifetime;
165     GarbageList mGarbage;
166 };
167 
168 using SharedGarbageList = std::queue<SharedGarbage>;
169 
170 // This is a helper class for back-end objects used in Vk command buffers. They keep a record
171 // of their use in ANGLE and VkQueues via ResourceUse.
172 class Resource : angle::NonCopyable
173 {
174   public:
~Resource()175     virtual ~Resource() {}
176 
177     // Complete all recorded and in-flight commands involving this resource
178     angle::Result waitForIdle(ContextVk *contextVk,
179                               const char *debugMessage,
180                               RenderPassClosureReason reason);
181 
setSerial(SerialIndex index,Serial serial)182     void setSerial(SerialIndex index, Serial serial) { mUse.setSerial(index, serial); }
183 
setQueueSerial(const QueueSerial & queueSerial)184     void setQueueSerial(const QueueSerial &queueSerial)
185     {
186         mUse.setSerial(queueSerial.getIndex(), queueSerial.getSerial());
187     }
188 
mergeResourceUse(const ResourceUse & use)189     void mergeResourceUse(const ResourceUse &use) { mUse.merge(use); }
190 
191     // Check if this resource is used by a command buffer.
usedByCommandBuffer(const QueueSerial & commandBufferQueueSerial)192     bool usedByCommandBuffer(const QueueSerial &commandBufferQueueSerial) const
193     {
194         return mUse.usedByCommandBuffer(commandBufferQueueSerial);
195     }
196 
getResourceUse()197     const ResourceUse &getResourceUse() const { return mUse; }
198 
199   protected:
Resource()200     Resource() {}
Resource(Resource && other)201     Resource(Resource &&other) : Resource() { mUse = std::move(other.mUse); }
202     Resource &operator=(Resource &&rhs)
203     {
204         std::swap(mUse, rhs.mUse);
205         return *this;
206     }
207 
208     // Current resource lifetime.
209     ResourceUse mUse;
210 };
211 
212 // Similar to |Resource| above, this tracks object usage. This includes additional granularity to
213 // track whether an object is used for read-only or read/write access.
214 class ReadWriteResource : public Resource
215 {
216   public:
~ReadWriteResource()217     virtual ~ReadWriteResource() override {}
218 
219     // Complete all recorded and in-flight commands involving this resource
waitForIdle(ContextVk * contextVk,const char * debugMessage,RenderPassClosureReason reason)220     angle::Result waitForIdle(ContextVk *contextVk,
221                               const char *debugMessage,
222                               RenderPassClosureReason reason)
223     {
224         return Resource::waitForIdle(contextVk, debugMessage, reason);
225     }
226 
setWriteQueueSerial(const QueueSerial & writeQueueSerial)227     void setWriteQueueSerial(const QueueSerial &writeQueueSerial)
228     {
229         mUse.setQueueSerial(writeQueueSerial);
230         mWriteUse.setQueueSerial(writeQueueSerial);
231     }
232 
233     // Check if this resource is used by a command buffer.
usedByCommandBuffer(const QueueSerial & commandBufferQueueSerial)234     bool usedByCommandBuffer(const QueueSerial &commandBufferQueueSerial) const
235     {
236         return mUse.usedByCommandBuffer(commandBufferQueueSerial);
237     }
writtenByCommandBuffer(const QueueSerial & commandBufferQueueSerial)238     bool writtenByCommandBuffer(const QueueSerial &commandBufferQueueSerial) const
239     {
240         return mWriteUse.usedByCommandBuffer(commandBufferQueueSerial);
241     }
242 
getWriteResourceUse()243     const ResourceUse &getWriteResourceUse() const { return mWriteUse; }
244 
245   protected:
ReadWriteResource()246     ReadWriteResource() {}
ReadWriteResource(ReadWriteResource && other)247     ReadWriteResource(ReadWriteResource &&other) { *this = std::move(other); }
248     ReadWriteResource &operator=(ReadWriteResource &&other)
249     {
250         Resource::operator=(std::move(other));
251         mWriteUse = std::move(other.mWriteUse);
252         return *this;
253     }
254 
255     // Track write use of the object. Only updated for setWriteQueueSerial().
256     ResourceUse mWriteUse;
257 };
258 
259 // Adds "void release(RendererVk *)" method for collecting garbage.
260 // Enables RendererScoped<> for classes that support DeviceScoped<>.
261 template <class T>
262 class ReleasableResource final : public Resource
263 {
264   public:
265     // Calls collectGarbage() on the object.
266     void release(RendererVk *renderer);
267 
get()268     const T &get() const { return mObject; }
get()269     T &get() { return mObject; }
270 
271   private:
272     T mObject;
273 };
274 }  // namespace vk
275 }  // namespace rx
276 
277 #endif  // LIBANGLE_RENDERER_VULKAN_RESOURCEVK_H_
278