• 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/renderer/vulkan/vk_utils.h"
14 
15 #include <queue>
16 
17 namespace rx
18 {
19 namespace vk
20 {
21 // Tracks how a resource is used by ANGLE and by a VkQueue. The reference count indicates the number
22 // of times a resource is retained by ANGLE. The serial indicates the most recent use of a resource
23 // in the VkQueue. The reference count and serial together can determine if a resource is currently
24 // in use.
25 struct ResourceUse
26 {
27     ResourceUse() = default;
28 
29     // The number of times a resource is retained by ANGLE.
30     uint32_t counter = 0;
31 
32     // The most recent time of use in a VkQueue.
33     Serial serial;
34 };
35 
36 class SharedResourceUse final : angle::NonCopyable
37 {
38   public:
SharedResourceUse()39     SharedResourceUse() : mUse(nullptr) {}
~SharedResourceUse()40     ~SharedResourceUse() { ASSERT(!valid()); }
SharedResourceUse(SharedResourceUse && rhs)41     SharedResourceUse(SharedResourceUse &&rhs) : mUse(rhs.mUse) { rhs.mUse = nullptr; }
42     SharedResourceUse &operator=(SharedResourceUse &&rhs)
43     {
44         std::swap(mUse, rhs.mUse);
45         return *this;
46     }
47 
valid()48     ANGLE_INLINE bool valid() const { return mUse != nullptr; }
49 
init()50     void init()
51     {
52         ASSERT(!mUse);
53         mUse = new ResourceUse;
54         mUse->counter++;
55     }
56 
57     // Specifically for use with command buffers that are used as one-offs.
updateSerialOneOff(Serial serial)58     void updateSerialOneOff(Serial serial) { mUse->serial = serial; }
59 
release()60     ANGLE_INLINE void release()
61     {
62         ASSERT(valid());
63         ASSERT(mUse->counter > 0);
64         if (--mUse->counter == 0)
65         {
66             delete mUse;
67         }
68         mUse = nullptr;
69     }
70 
releaseAndUpdateSerial(Serial serial)71     ANGLE_INLINE void releaseAndUpdateSerial(Serial serial)
72     {
73         ASSERT(valid());
74         ASSERT(mUse->counter > 0);
75         ASSERT(mUse->serial <= serial);
76         mUse->serial = serial;
77         release();
78     }
79 
set(const SharedResourceUse & rhs)80     ANGLE_INLINE void set(const SharedResourceUse &rhs)
81     {
82         ASSERT(rhs.valid());
83         ASSERT(!valid());
84         ASSERT(rhs.mUse->counter < std::numeric_limits<uint32_t>::max());
85         mUse = rhs.mUse;
86         mUse->counter++;
87     }
88 
89     // The base counter value for a live resource is "1". Any value greater than one indicates
90     // the resource is in use by a command buffer.
usedInRecordedCommands()91     ANGLE_INLINE bool usedInRecordedCommands() const
92     {
93         ASSERT(valid());
94         return mUse->counter > 1;
95     }
96 
usedInRunningCommands(Serial lastCompletedSerial)97     ANGLE_INLINE bool usedInRunningCommands(Serial lastCompletedSerial) const
98     {
99         ASSERT(valid());
100         return mUse->serial > lastCompletedSerial;
101     }
102 
isCurrentlyInUse(Serial lastCompletedSerial)103     ANGLE_INLINE bool isCurrentlyInUse(Serial lastCompletedSerial) const
104     {
105         return usedInRecordedCommands() || usedInRunningCommands(lastCompletedSerial);
106     }
107 
getSerial()108     ANGLE_INLINE Serial getSerial() const
109     {
110         ASSERT(valid());
111         return mUse->serial;
112     }
113 
114   private:
115     ResourceUse *mUse;
116 };
117 
118 class SharedBufferSuballocationGarbage
119 {
120   public:
121     SharedBufferSuballocationGarbage() = default;
SharedBufferSuballocationGarbage(SharedBufferSuballocationGarbage && other)122     SharedBufferSuballocationGarbage(SharedBufferSuballocationGarbage &&other)
123         : mLifetime(std::move(other.mLifetime)),
124           mSuballocation(std::move(other.mSuballocation)),
125           mBuffer(std::move(other.mBuffer))
126     {}
SharedBufferSuballocationGarbage(SharedResourceUse && use,BufferSuballocation && suballocation,Buffer && buffer)127     SharedBufferSuballocationGarbage(SharedResourceUse &&use,
128                                      BufferSuballocation &&suballocation,
129                                      Buffer &&buffer)
130         : mLifetime(std::move(use)),
131           mSuballocation(std::move(suballocation)),
132           mBuffer(std::move(buffer))
133     {}
134     ~SharedBufferSuballocationGarbage() = default;
135 
136     bool destroyIfComplete(RendererVk *renderer, Serial completedSerial);
usedInRecordedCommands()137     bool usedInRecordedCommands() const { return mLifetime.usedInRecordedCommands(); }
138 
139   private:
140     SharedResourceUse mLifetime;
141     BufferSuballocation mSuballocation;
142     Buffer mBuffer;
143 };
144 using SharedBufferSuballocationGarbageList = std::queue<SharedBufferSuballocationGarbage>;
145 
146 class SharedGarbage
147 {
148   public:
149     SharedGarbage();
150     SharedGarbage(SharedGarbage &&other);
151     SharedGarbage(SharedResourceUse &&use, std::vector<GarbageObject> &&garbage);
152     ~SharedGarbage();
153     SharedGarbage &operator=(SharedGarbage &&rhs);
154 
155     bool destroyIfComplete(RendererVk *renderer, Serial completedSerial);
usedInRecordedCommands()156     bool usedInRecordedCommands() const { return mLifetime.usedInRecordedCommands(); }
157 
158   private:
159     SharedResourceUse mLifetime;
160     std::vector<GarbageObject> mGarbage;
161 };
162 
163 using SharedGarbageList = std::queue<SharedGarbage>;
164 
165 // Mixin to abstract away the resource use tracking.
166 class ResourceUseList final : angle::NonCopyable
167 {
168   public:
169     ResourceUseList();
170     ResourceUseList(ResourceUseList &&other);
171     virtual ~ResourceUseList();
172     ResourceUseList &operator=(ResourceUseList &&rhs);
173 
174     void add(const SharedResourceUse &resourceUse);
175 
176     void releaseResourceUses();
177     void releaseResourceUsesAndUpdateSerials(Serial serial);
178 
empty()179     bool empty() { return mResourceUses.empty(); }
180 
181   private:
182     std::vector<SharedResourceUse> mResourceUses;
183 };
184 
add(const SharedResourceUse & resourceUse)185 ANGLE_INLINE void ResourceUseList::add(const SharedResourceUse &resourceUse)
186 {
187     SharedResourceUse newUse;
188     newUse.set(resourceUse);
189     mResourceUses.emplace_back(std::move(newUse));
190 }
191 
192 // This is a helper class for back-end objects used in Vk command buffers. They keep a record
193 // of their use in ANGLE and VkQueues via SharedResourceUse.
194 class Resource : angle::NonCopyable
195 {
196   public:
197     virtual ~Resource();
198 
199     // Returns true if the resource is used by ANGLE in an unflushed command buffer.
usedInRecordedCommands()200     bool usedInRecordedCommands() const { return mUse.usedInRecordedCommands(); }
201 
202     // Determine if the driver has finished execution with this resource.
usedInRunningCommands(Serial lastCompletedSerial)203     bool usedInRunningCommands(Serial lastCompletedSerial) const
204     {
205         return mUse.usedInRunningCommands(lastCompletedSerial);
206     }
207 
208     // Returns true if the resource is in use by ANGLE or the driver.
isCurrentlyInUse(Serial lastCompletedSerial)209     bool isCurrentlyInUse(Serial lastCompletedSerial) const
210     {
211         return mUse.isCurrentlyInUse(lastCompletedSerial);
212     }
213 
214     // Ensures the driver is caught up to this resource and it is only in use by ANGLE.
215     angle::Result finishRunningCommands(ContextVk *contextVk);
216 
217     // Complete all recorded and in-flight commands involving this resource
218     angle::Result waitForIdle(ContextVk *contextVk,
219                               const char *debugMessage,
220                               RenderPassClosureReason reason);
221 
222     // Adds the resource to a resource use list.
223     void retain(ResourceUseList *resourceUseList) const;
224 
225   protected:
226     Resource();
227     Resource(Resource &&other);
228     Resource &operator=(Resource &&rhs);
229 
230     // Current resource lifetime.
231     SharedResourceUse mUse;
232 };
233 
retain(ResourceUseList * resourceUseList)234 ANGLE_INLINE void Resource::retain(ResourceUseList *resourceUseList) const
235 {
236     // Store reference in resource list.
237     resourceUseList->add(mUse);
238 }
239 
240 // Similar to |Resource| above, this tracks object usage. This includes additional granularity to
241 // track whether an object is used for read-only or read/write access.
242 class ReadWriteResource : public angle::NonCopyable
243 {
244   public:
245     virtual ~ReadWriteResource();
246 
247     // Returns true if the resource is used by ANGLE in an unflushed command buffer.
usedInRecordedCommands()248     bool usedInRecordedCommands() const { return mReadOnlyUse.usedInRecordedCommands(); }
249 
250     // Determine if the driver has finished execution with this resource.
usedInRunningCommands(Serial lastCompletedSerial)251     bool usedInRunningCommands(Serial lastCompletedSerial) const
252     {
253         return mReadOnlyUse.usedInRunningCommands(lastCompletedSerial);
254     }
255 
256     // Returns true if the resource is in use by ANGLE or the driver.
isCurrentlyInUse(Serial lastCompletedSerial)257     bool isCurrentlyInUse(Serial lastCompletedSerial) const
258     {
259         return mReadOnlyUse.isCurrentlyInUse(lastCompletedSerial);
260     }
isCurrentlyInUseForWrite(Serial lastCompletedSerial)261     bool isCurrentlyInUseForWrite(Serial lastCompletedSerial) const
262     {
263         return mReadWriteUse.isCurrentlyInUse(lastCompletedSerial);
264     }
265 
266     // Ensures the driver is caught up to this resource and it is only in use by ANGLE.
267     angle::Result finishRunningCommands(ContextVk *contextVk);
268 
269     // Ensures the GPU write commands is completed.
270     angle::Result finishGPUWriteCommands(ContextVk *contextVk);
271 
272     // Complete all recorded and in-flight commands involving this resource
273     angle::Result waitForIdle(ContextVk *contextVk,
274                               const char *debugMessage,
275                               RenderPassClosureReason reason);
276 
277     // Adds the resource to a resource use list.
278     void retainReadOnly(ResourceUseList *resourceUseList) const;
279     void retainReadWrite(ResourceUseList *resourceUseList) const;
280 
281   protected:
282     ReadWriteResource();
283     ReadWriteResource(ReadWriteResource &&other);
284     ReadWriteResource &operator=(ReadWriteResource &&other);
285 
286     // Track any use of the object. Always updated on every retain call.
287     SharedResourceUse mReadOnlyUse;
288     // Track read/write use of the object. Only updated for retainReadWrite().
289     SharedResourceUse mReadWriteUse;
290 };
291 
retainReadOnly(ResourceUseList * resourceUseList)292 ANGLE_INLINE void ReadWriteResource::retainReadOnly(ResourceUseList *resourceUseList) const
293 {
294     // Store reference in resource list.
295     resourceUseList->add(mReadOnlyUse);
296 }
297 
retainReadWrite(ResourceUseList * resourceUseList)298 ANGLE_INLINE void ReadWriteResource::retainReadWrite(ResourceUseList *resourceUseList) const
299 {
300     // Store reference in resource list.
301     resourceUseList->add(mReadOnlyUse);
302     resourceUseList->add(mReadWriteUse);
303 }
304 
305 }  // namespace vk
306 }  // namespace rx
307 
308 #endif  // LIBANGLE_RENDERER_VULKAN_RESOURCEVK_H_
309