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 namespace rx
16 {
17 namespace vk
18 {
19 // Tracks how a resource is used by ANGLE and by a VkQueue. The reference count indicates the number
20 // of times a resource is retained by ANGLE. The serial indicates the most recent use of a resource
21 // in the VkQueue. The reference count and serial together can determine if a resource is currently
22 // in use.
23 struct ResourceUse
24 {
25     ResourceUse() = default;
26 
27     // The number of times a resource is retained by ANGLE.
28     uint32_t counter = 0;
29 
30     // The most recent time of use in a VkQueue.
31     Serial serial;
32 };
33 
34 class SharedResourceUse final : angle::NonCopyable
35 {
36   public:
SharedResourceUse()37     SharedResourceUse() : mUse(nullptr) {}
~SharedResourceUse()38     ~SharedResourceUse() { ASSERT(!valid()); }
SharedResourceUse(SharedResourceUse && rhs)39     SharedResourceUse(SharedResourceUse &&rhs) : mUse(rhs.mUse) { rhs.mUse = nullptr; }
40     SharedResourceUse &operator=(SharedResourceUse &&rhs)
41     {
42         std::swap(mUse, rhs.mUse);
43         return *this;
44     }
45 
valid()46     ANGLE_INLINE bool valid() const { return mUse != nullptr; }
47 
init()48     void init()
49     {
50         ASSERT(!mUse);
51         mUse = new ResourceUse;
52         mUse->counter++;
53     }
54 
55     // Specifically for use with command buffers that are used as one-offs.
updateSerialOneOff(Serial serial)56     void updateSerialOneOff(Serial serial) { mUse->serial = serial; }
57 
release()58     ANGLE_INLINE void release()
59     {
60         ASSERT(valid());
61         ASSERT(mUse->counter > 0);
62         if (--mUse->counter == 0)
63         {
64             delete mUse;
65         }
66         mUse = nullptr;
67     }
68 
releaseAndUpdateSerial(Serial serial)69     ANGLE_INLINE void releaseAndUpdateSerial(Serial serial)
70     {
71         ASSERT(valid());
72         ASSERT(mUse->counter > 0);
73         ASSERT(mUse->serial <= serial);
74         mUse->serial = serial;
75         release();
76     }
77 
set(const SharedResourceUse & rhs)78     ANGLE_INLINE void set(const SharedResourceUse &rhs)
79     {
80         ASSERT(rhs.valid());
81         ASSERT(!valid());
82         ASSERT(rhs.mUse->counter < std::numeric_limits<uint32_t>::max());
83         mUse = rhs.mUse;
84         mUse->counter++;
85     }
86 
87     // The base counter value for a live resource is "1". Any value greater than one indicates
88     // the resource is in use by a command buffer.
usedInRecordedCommands()89     ANGLE_INLINE bool usedInRecordedCommands() const
90     {
91         ASSERT(valid());
92         return mUse->counter > 1;
93     }
94 
usedInRunningCommands(Serial lastCompletedSerial)95     ANGLE_INLINE bool usedInRunningCommands(Serial lastCompletedSerial) const
96     {
97         ASSERT(valid());
98         return mUse->serial > lastCompletedSerial;
99     }
100 
isCurrentlyInUse(Serial lastCompletedSerial)101     ANGLE_INLINE bool isCurrentlyInUse(Serial lastCompletedSerial) const
102     {
103         return usedInRecordedCommands() || usedInRunningCommands(lastCompletedSerial);
104     }
105 
getSerial()106     ANGLE_INLINE Serial getSerial() const
107     {
108         ASSERT(valid());
109         return mUse->serial;
110     }
111 
112   private:
113     ResourceUse *mUse;
114 };
115 
116 class SharedGarbage
117 {
118   public:
119     SharedGarbage();
120     SharedGarbage(SharedGarbage &&other);
121     SharedGarbage(SharedResourceUse &&use, std::vector<GarbageObject> &&garbage);
122     ~SharedGarbage();
123     SharedGarbage &operator=(SharedGarbage &&rhs);
124 
125     bool destroyIfComplete(RendererVk *renderer, Serial completedSerial);
126 
127   private:
128     SharedResourceUse mLifetime;
129     std::vector<GarbageObject> mGarbage;
130 };
131 
132 using SharedGarbageList = std::vector<SharedGarbage>;
133 
134 // Mixin to abstract away the resource use tracking.
135 class ResourceUseList final : angle::NonCopyable
136 {
137   public:
138     ResourceUseList();
139     ResourceUseList(ResourceUseList &&other);
140     virtual ~ResourceUseList();
141     ResourceUseList &operator=(ResourceUseList &&rhs);
142 
143     void add(const SharedResourceUse &resourceUse);
144 
145     void releaseResourceUses();
146     void releaseResourceUsesAndUpdateSerials(Serial serial);
147 
empty()148     bool empty() { return mResourceUses.empty(); }
149 
150   private:
151     std::vector<SharedResourceUse> mResourceUses;
152 };
153 
add(const SharedResourceUse & resourceUse)154 ANGLE_INLINE void ResourceUseList::add(const SharedResourceUse &resourceUse)
155 {
156     SharedResourceUse newUse;
157     newUse.set(resourceUse);
158     mResourceUses.emplace_back(std::move(newUse));
159 }
160 
161 // This is a helper class for back-end objects used in Vk command buffers. They keep a record
162 // of their use in ANGLE and VkQueues via SharedResourceUse.
163 class Resource : angle::NonCopyable
164 {
165   public:
166     virtual ~Resource();
167 
168     // Returns true if the resource is used by ANGLE in an unflushed command buffer.
usedInRecordedCommands()169     bool usedInRecordedCommands() const { return mUse.usedInRecordedCommands(); }
170 
171     // Determine if the driver has finished execution with this resource.
usedInRunningCommands(Serial lastCompletedSerial)172     bool usedInRunningCommands(Serial lastCompletedSerial) const
173     {
174         return mUse.usedInRunningCommands(lastCompletedSerial);
175     }
176 
177     // Returns true if the resource is in use by ANGLE or the driver.
isCurrentlyInUse(Serial lastCompletedSerial)178     bool isCurrentlyInUse(Serial lastCompletedSerial) const
179     {
180         return mUse.isCurrentlyInUse(lastCompletedSerial);
181     }
182 
183     // Ensures the driver is caught up to this resource and it is only in use by ANGLE.
184     angle::Result finishRunningCommands(ContextVk *contextVk);
185 
186     // Complete all recorded and in-flight commands involving this resource
187     angle::Result waitForIdle(ContextVk *contextVk, const char *debugMessage);
188 
189     // Adds the resource to a resource use list.
190     void retain(ResourceUseList *resourceUseList) const;
191 
192   protected:
193     Resource();
194     Resource(Resource &&other);
195 
196     // Current resource lifetime.
197     SharedResourceUse mUse;
198 };
199 
retain(ResourceUseList * resourceUseList)200 ANGLE_INLINE void Resource::retain(ResourceUseList *resourceUseList) const
201 {
202     // Store reference in resource list.
203     resourceUseList->add(mUse);
204 }
205 
206 }  // namespace vk
207 }  // namespace rx
208 
209 #endif  // LIBANGLE_RENDERER_VULKAN_RESOURCEVK_H_
210