xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/serial_utils.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2019 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 // serial_utils:
7 //   Utilities for generating unique IDs for resources in ANGLE.
8 //
9 
10 #ifndef LIBANGLE_RENDERER_SERIAL_UTILS_H_
11 #define LIBANGLE_RENDERER_SERIAL_UTILS_H_
12 
13 #include <array>
14 #include <atomic>
15 #include <limits>
16 
17 #include "common/angleutils.h"
18 #include "common/debug.h"
19 
20 namespace rx
21 {
22 class ResourceSerial
23 {
24   public:
ResourceSerial()25     constexpr ResourceSerial() : mValue(kDirty) {}
ResourceSerial(uintptr_t value)26     explicit constexpr ResourceSerial(uintptr_t value) : mValue(value) {}
27     constexpr bool operator==(ResourceSerial other) const { return mValue == other.mValue; }
28     constexpr bool operator!=(ResourceSerial other) const { return mValue != other.mValue; }
29 
dirty()30     void dirty() { mValue = kDirty; }
clear()31     void clear() { mValue = kEmpty; }
32 
valid()33     constexpr bool valid() const { return mValue != kEmpty && mValue != kDirty; }
empty()34     constexpr bool empty() const { return mValue == kEmpty; }
35 
36   private:
37     constexpr static uintptr_t kDirty = std::numeric_limits<uintptr_t>::max();
38     constexpr static uintptr_t kEmpty = 0;
39 
40     uintptr_t mValue;
41 };
42 
43 // Class UniqueSerial defines unique serial number for object identification. It has only
44 // equal/unequal comparison but no greater/smaller comparison. The default constructor creates an
45 // invalid value.
46 class UniqueSerial final
47 {
48   public:
UniqueSerial()49     constexpr UniqueSerial() : mValue(kInvalid) {}
50     constexpr UniqueSerial(const UniqueSerial &other)  = default;
51     UniqueSerial &operator=(const UniqueSerial &other) = default;
52 
53     constexpr bool operator==(const UniqueSerial &other) const
54     {
55         return mValue != kInvalid && mValue == other.mValue;
56     }
57     constexpr bool operator!=(const UniqueSerial &other) const
58     {
59         return mValue == kInvalid || mValue != other.mValue;
60     }
61 
62     // Useful for serialization.
getValue()63     constexpr uint64_t getValue() const { return mValue; }
valid()64     constexpr bool valid() const { return mValue != kInvalid; }
65 
66   private:
67     friend class UniqueSerialFactory;
UniqueSerial(uint64_t value)68     constexpr explicit UniqueSerial(uint64_t value) : mValue(value) {}
69     uint64_t mValue;
70     static constexpr uint64_t kInvalid = 0;
71 };
72 
73 class UniqueSerialFactory final : angle::NonCopyable
74 {
75   public:
UniqueSerialFactory()76     UniqueSerialFactory() : mSerial(1) {}
77 
generate()78     UniqueSerial generate()
79     {
80         uint64_t current = mSerial++;
81         ASSERT(mSerial > current);  // Integer overflow
82         return UniqueSerial(current);
83     }
84 
85   private:
86     uint64_t mSerial;
87 };
88 
89 // Class Serial defines a monotonically increasing serial number that indicates the timeline of
90 // execution.
91 class Serial final
92 {
93   public:
Serial()94     constexpr Serial() : mValue(0) {}
95     constexpr Serial(const Serial &other)  = default;
96     Serial &operator=(const Serial &other) = default;
97 
Infinite()98     static constexpr Serial Infinite() { return Serial(std::numeric_limits<uint64_t>::max()); }
99 
100     constexpr bool operator==(const Serial &other) const { return mValue == other.mValue; }
101     constexpr bool operator!=(const Serial &other) const { return mValue != other.mValue; }
102     constexpr bool operator>(const Serial &other) const { return mValue > other.mValue; }
103     constexpr bool operator>=(const Serial &other) const { return mValue >= other.mValue; }
104     constexpr bool operator<(const Serial &other) const { return mValue < other.mValue; }
105     constexpr bool operator<=(const Serial &other) const { return mValue <= other.mValue; }
106 
107     // Useful for serialization.
getValue()108     constexpr uint64_t getValue() const { return mValue; }
109 
110   private:
111     friend class AtomicSerialFactory;
112     friend class RangedSerialFactory;
113     friend class AtomicQueueSerial;
Serial(uint64_t value)114     constexpr explicit Serial(uint64_t value) : mValue(value) {}
115     uint64_t mValue;
116 };
117 
118 // Defines class to track the queue serial that can be load/store from multiple threads atomically.
119 class alignas(8) AtomicQueueSerial final
120 {
121   public:
122     AtomicQueueSerial &operator=(const Serial &other)
123     {
124         mValue.store(other.mValue, std::memory_order_release);
125         return *this;
126     }
getSerial()127     Serial getSerial() const { return Serial(mValue.load(std::memory_order_consume)); }
128 
129   private:
130     static constexpr uint64_t kInvalid = 0;
131     std::atomic<uint64_t> mValue       = kInvalid;
132 };
133 
134 // Used as default/initial serial
135 static constexpr Serial kZeroSerial = Serial();
136 
137 // The factory to generate a serial number within the range [mSerial, mSerial+mCount}
138 class RangedSerialFactory final : angle::NonCopyable
139 {
140   public:
RangedSerialFactory()141     RangedSerialFactory() : mSerial(0), mCount(0) {}
142 
reset()143     void reset() { mCount = 0; }
empty()144     bool empty() const { return mCount == 0; }
generate(Serial * serialOut)145     bool generate(Serial *serialOut)
146     {
147         if (mCount > 0)
148         {
149             uint64_t current = mSerial++;
150             ASSERT(mSerial > current);  // Integer overflow
151             *serialOut = Serial(current);
152             mCount--;
153             return true;
154         }
155         return false;
156     }
157 
158   private:
159     friend class AtomicSerialFactory;
initialize(uint64_t initialSerial,size_t count)160     void initialize(uint64_t initialSerial, size_t count)
161     {
162         mSerial = initialSerial;
163         mCount  = count;
164     }
165     uint64_t mSerial;
166     size_t mCount;
167 };
168 
169 class AtomicSerialFactory final : angle::NonCopyable
170 {
171   public:
AtomicSerialFactory()172     AtomicSerialFactory() : mSerial(1) {}
173 
generate()174     Serial generate()
175     {
176         uint64_t current = mSerial++;
177         ASSERT(mSerial > current);  // Integer overflow
178         return Serial(current);
179     }
180 
reserve(RangedSerialFactory * rangeFactory,size_t count)181     void reserve(RangedSerialFactory *rangeFactory, size_t count)
182     {
183         uint64_t current = mSerial;
184         mSerial += count;
185         ASSERT(mSerial > current);  // Integer overflow
186         rangeFactory->initialize(current, count);
187     }
188 
189   private:
190     std::atomic<uint64_t> mSerial;
191 };
192 
193 // For backend that supports multiple queue serials, QueueSerial includes a Serial and an index.
194 using SerialIndex                                     = uint32_t;
195 static constexpr SerialIndex kInvalidQueueSerialIndex = SerialIndex(-1);
196 
197 class QueueSerial;
198 // Because we release queue index when context becomes non-current, in order to use up all index
199 // count, you will need to have 256 threads each has a context current. This is not a reasonable
200 // usage case.
201 constexpr size_t kMaxQueueSerialIndexCount = 256;
202 // Fixed array of queue serials
203 class AtomicQueueSerialFixedArray final
204 {
205   public:
206     AtomicQueueSerialFixedArray()  = default;
207     ~AtomicQueueSerialFixedArray() = default;
208 
209     void setQueueSerial(SerialIndex index, Serial serial);
210     void setQueueSerial(const QueueSerial &queueSerial);
fill(Serial serial)211     void fill(Serial serial) { std::fill(mSerials.begin(), mSerials.end(), serial); }
212     Serial operator[](SerialIndex index) const { return mSerials[index].getSerial(); }
size()213     size_t size() const { return mSerials.size(); }
214 
215   private:
216     std::array<AtomicQueueSerial, kMaxQueueSerialIndexCount> mSerials;
217 };
218 std::ostream &operator<<(std::ostream &os, const AtomicQueueSerialFixedArray &serials);
219 
220 class QueueSerial final
221 {
222   public:
QueueSerial()223     QueueSerial() : mIndex(kInvalidQueueSerialIndex) {}
QueueSerial(SerialIndex index,Serial serial)224     QueueSerial(SerialIndex index, Serial serial) : mIndex(index), mSerial(serial)
225     {
226         ASSERT(index != kInvalidQueueSerialIndex);
227     }
228     constexpr QueueSerial(const QueueSerial &other)  = default;
229     QueueSerial &operator=(const QueueSerial &other) = default;
230 
231     constexpr bool operator==(const QueueSerial &other) const
232     {
233         return mIndex == other.mIndex && mSerial == other.mSerial;
234     }
235     constexpr bool operator!=(const QueueSerial &other) const
236     {
237         return mIndex != other.mIndex || mSerial != other.mSerial;
238     }
239     constexpr bool operator<(const QueueSerial &other) const
240     {
241         ASSERT(mIndex != kInvalidQueueSerialIndex);
242         ASSERT(mIndex == other.mIndex);
243         return mSerial < other.mSerial;
244     }
245     constexpr bool operator<=(const QueueSerial &other) const
246     {
247         ASSERT(mIndex != kInvalidQueueSerialIndex);
248         ASSERT(mIndex == other.mIndex);
249         return mSerial <= other.mSerial;
250     }
251     constexpr bool operator>(const QueueSerial &other) const
252     {
253         ASSERT(mIndex != kInvalidQueueSerialIndex);
254         ASSERT(mIndex == other.mIndex);
255         return mSerial > other.mSerial;
256     }
257     constexpr bool operator>=(const QueueSerial &other) const
258     {
259         ASSERT(mIndex != kInvalidQueueSerialIndex);
260         ASSERT(mIndex == other.mIndex);
261         return mSerial >= other.mSerial;
262     }
263 
264     bool operator>(const AtomicQueueSerialFixedArray &serials) const
265     {
266         ASSERT(mIndex != kInvalidQueueSerialIndex);
267         return mSerial > serials[mIndex];
268     }
269     bool operator<=(const AtomicQueueSerialFixedArray &serials) const
270     {
271         ASSERT(mIndex != kInvalidQueueSerialIndex);
272         return mSerial <= serials[mIndex];
273     }
274 
valid()275     constexpr bool valid() const { return mIndex != kInvalidQueueSerialIndex; }
276 
getIndex()277     SerialIndex getIndex() const { return mIndex; }
getSerial()278     Serial getSerial() const { return mSerial; }
279 
280   private:
281     SerialIndex mIndex;
282     Serial mSerial;
283 };
284 std::ostream &operator<<(std::ostream &os, const QueueSerial &queueSerial);
285 
setQueueSerial(SerialIndex index,Serial serial)286 ANGLE_INLINE void AtomicQueueSerialFixedArray::setQueueSerial(SerialIndex index, Serial serial)
287 {
288     ASSERT(index != kInvalidQueueSerialIndex);
289     ASSERT(index < mSerials.size());
290     // Serial can only increase
291     ASSERT(serial > mSerials[index].getSerial());
292     mSerials[index] = serial;
293 }
294 
setQueueSerial(const QueueSerial & queueSerial)295 ANGLE_INLINE void AtomicQueueSerialFixedArray::setQueueSerial(const QueueSerial &queueSerial)
296 {
297     setQueueSerial(queueSerial.getIndex(), queueSerial.getSerial());
298 }
299 
300 ANGLE_INLINE std::ostream &operator<<(std::ostream &os, const AtomicQueueSerialFixedArray &serials)
301 {
302     // Search for last non-zero index (or 0 if all zeros).
303     SerialIndex lastIndex = serials.size() == 0 ? 0 : static_cast<SerialIndex>(serials.size() - 1);
304     while (lastIndex > 0 && serials[lastIndex].getValue() == 0)
305     {
306         lastIndex--;
307     }
308     os << '{';
309     for (SerialIndex i = 0; i < lastIndex; i++)
310     {
311         os << serials[i].getValue() << ',';
312     }
313     os << serials[lastIndex].getValue() << '}';
314     return os;
315 }
316 
317 ANGLE_INLINE std::ostream &operator<<(std::ostream &os, const QueueSerial &queueSerial)
318 {
319     os << '{' << queueSerial.getIndex() << ':' << queueSerial.getSerial().getValue() << '}';
320     return os;
321 }
322 }  // namespace rx
323 
324 #endif  // LIBANGLE_RENDERER_SERIAL_UTILS_H_
325