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