xref: /aosp_15_r20/external/angle/src/common/RingBufferAllocator.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2022 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // RingBufferAllocator.h:
7*8975f5c5SAndroid Build Coastguard Worker //    Classes used to implement ring buffer allocators.
8*8975f5c5SAndroid Build Coastguard Worker //
9*8975f5c5SAndroid Build Coastguard Worker 
10*8975f5c5SAndroid Build Coastguard Worker #ifndef COMMON_RING_BUFFER_ALLOCATOR_H_
11*8975f5c5SAndroid Build Coastguard Worker #define COMMON_RING_BUFFER_ALLOCATOR_H_
12*8975f5c5SAndroid Build Coastguard Worker 
13*8975f5c5SAndroid Build Coastguard Worker #include "angleutils.h"
14*8975f5c5SAndroid Build Coastguard Worker #include "common/SimpleMutex.h"
15*8975f5c5SAndroid Build Coastguard Worker #include "common/debug.h"
16*8975f5c5SAndroid Build Coastguard Worker 
17*8975f5c5SAndroid Build Coastguard Worker #include <atomic>
18*8975f5c5SAndroid Build Coastguard Worker 
19*8975f5c5SAndroid Build Coastguard Worker namespace angle
20*8975f5c5SAndroid Build Coastguard Worker {
21*8975f5c5SAndroid Build Coastguard Worker 
22*8975f5c5SAndroid Build Coastguard Worker static constexpr uint32_t kMinRingBufferAllocationCapacity = 1024;
23*8975f5c5SAndroid Build Coastguard Worker static constexpr uint32_t kDefaultDecaySpeedFactor         = 10;
24*8975f5c5SAndroid Build Coastguard Worker 
25*8975f5c5SAndroid Build Coastguard Worker // Only called from RingBufferAllocator::allocate(). Other function may also change the fragment.
26*8975f5c5SAndroid Build Coastguard Worker class RingBufferAllocateListener
27*8975f5c5SAndroid Build Coastguard Worker {
28*8975f5c5SAndroid Build Coastguard Worker   public:
29*8975f5c5SAndroid Build Coastguard Worker     virtual void onRingBufferNewFragment() = 0;
30*8975f5c5SAndroid Build Coastguard Worker     virtual void onRingBufferFragmentEnd() = 0;
31*8975f5c5SAndroid Build Coastguard Worker 
32*8975f5c5SAndroid Build Coastguard Worker   protected:
33*8975f5c5SAndroid Build Coastguard Worker     ~RingBufferAllocateListener() = default;
34*8975f5c5SAndroid Build Coastguard Worker };
35*8975f5c5SAndroid Build Coastguard Worker 
36*8975f5c5SAndroid Build Coastguard Worker class RingBufferAllocatorCheckPoint final
37*8975f5c5SAndroid Build Coastguard Worker {
38*8975f5c5SAndroid Build Coastguard Worker   public:
reset()39*8975f5c5SAndroid Build Coastguard Worker     void reset() { *this = {}; }
valid()40*8975f5c5SAndroid Build Coastguard Worker     bool valid() const { return (mReleasePtr != nullptr); }
41*8975f5c5SAndroid Build Coastguard Worker 
42*8975f5c5SAndroid Build Coastguard Worker   private:
43*8975f5c5SAndroid Build Coastguard Worker     friend class RingBufferAllocator;
44*8975f5c5SAndroid Build Coastguard Worker     uint64_t mBufferId   = 0;
45*8975f5c5SAndroid Build Coastguard Worker     uint8_t *mReleasePtr = nullptr;
46*8975f5c5SAndroid Build Coastguard Worker };
47*8975f5c5SAndroid Build Coastguard Worker 
48*8975f5c5SAndroid Build Coastguard Worker class RingBufferAllocatorBuffer final
49*8975f5c5SAndroid Build Coastguard Worker {
50*8975f5c5SAndroid Build Coastguard Worker   public:
51*8975f5c5SAndroid Build Coastguard Worker     static constexpr uint32_t kBaseOffset = alignof(std::max_align_t);
52*8975f5c5SAndroid Build Coastguard Worker 
resize(uint32_t size)53*8975f5c5SAndroid Build Coastguard Worker     void resize(uint32_t size) { mStorage.resize(size + kBaseOffset); }
data()54*8975f5c5SAndroid Build Coastguard Worker     uint8_t *data() { return mStorage.data() + kBaseOffset; }
55*8975f5c5SAndroid Build Coastguard Worker 
decClamped(uint8_t * ptr,uint32_t offset)56*8975f5c5SAndroid Build Coastguard Worker     uint8_t *decClamped(uint8_t *ptr, uint32_t offset) const
57*8975f5c5SAndroid Build Coastguard Worker     {
58*8975f5c5SAndroid Build Coastguard Worker         ASSERT(ptr >= mStorage.data() + kBaseOffset && ptr <= mStorage.data() + mStorage.size());
59*8975f5c5SAndroid Build Coastguard Worker         return ptr - std::min(offset, static_cast<uint32_t>(ptr - mStorage.data()));
60*8975f5c5SAndroid Build Coastguard Worker     }
61*8975f5c5SAndroid Build Coastguard Worker 
getId()62*8975f5c5SAndroid Build Coastguard Worker     uint64_t getId() const { return mId; }
resetId()63*8975f5c5SAndroid Build Coastguard Worker     void resetId() { mId = 0; }
incrementId()64*8975f5c5SAndroid Build Coastguard Worker     void incrementId() { ++mId; }
65*8975f5c5SAndroid Build Coastguard Worker 
isEmpty()66*8975f5c5SAndroid Build Coastguard Worker     bool isEmpty() const { return mStorage.empty(); }
67*8975f5c5SAndroid Build Coastguard Worker 
68*8975f5c5SAndroid Build Coastguard Worker   private:
69*8975f5c5SAndroid Build Coastguard Worker     uint64_t mId = 0;
70*8975f5c5SAndroid Build Coastguard Worker     std::vector<uint8_t> mStorage;
71*8975f5c5SAndroid Build Coastguard Worker };
72*8975f5c5SAndroid Build Coastguard Worker 
73*8975f5c5SAndroid Build Coastguard Worker class RingBufferAllocator final : angle::NonCopyable
74*8975f5c5SAndroid Build Coastguard Worker {
75*8975f5c5SAndroid Build Coastguard Worker   public:
76*8975f5c5SAndroid Build Coastguard Worker     RingBufferAllocator() = default;
77*8975f5c5SAndroid Build Coastguard Worker     RingBufferAllocator(RingBufferAllocator &&other);
78*8975f5c5SAndroid Build Coastguard Worker     RingBufferAllocator &operator=(RingBufferAllocator &&other);
79*8975f5c5SAndroid Build Coastguard Worker 
80*8975f5c5SAndroid Build Coastguard Worker     void reset();
valid()81*8975f5c5SAndroid Build Coastguard Worker     bool valid() const { return (getPointer() != nullptr); }
82*8975f5c5SAndroid Build Coastguard Worker 
83*8975f5c5SAndroid Build Coastguard Worker     void setListener(RingBufferAllocateListener *listener);
84*8975f5c5SAndroid Build Coastguard Worker 
85*8975f5c5SAndroid Build Coastguard Worker     void setDecaySpeedFactor(uint32_t decaySpeedFactor);
86*8975f5c5SAndroid Build Coastguard Worker 
87*8975f5c5SAndroid Build Coastguard Worker     void setFragmentReserve(uint32_t reserve);
88*8975f5c5SAndroid Build Coastguard Worker 
allocate(uint32_t size)89*8975f5c5SAndroid Build Coastguard Worker     uint8_t *allocate(uint32_t size)
90*8975f5c5SAndroid Build Coastguard Worker     {
91*8975f5c5SAndroid Build Coastguard Worker         ASSERT(valid());
92*8975f5c5SAndroid Build Coastguard Worker         if (ANGLE_LIKELY(mFragmentEndR - mDataEnd >= static_cast<ptrdiff_t>(size)))
93*8975f5c5SAndroid Build Coastguard Worker         {
94*8975f5c5SAndroid Build Coastguard Worker             uint8_t *const result = mDataEnd;
95*8975f5c5SAndroid Build Coastguard Worker             mDataEnd              = result + size;
96*8975f5c5SAndroid Build Coastguard Worker             return result;
97*8975f5c5SAndroid Build Coastguard Worker         }
98*8975f5c5SAndroid Build Coastguard Worker         return allocateInNewFragment(size);
99*8975f5c5SAndroid Build Coastguard Worker     }
100*8975f5c5SAndroid Build Coastguard Worker 
getPointer()101*8975f5c5SAndroid Build Coastguard Worker     uint8_t *getPointer() const { return mDataEnd; }
getFragmentSize()102*8975f5c5SAndroid Build Coastguard Worker     uint32_t getFragmentSize() const
103*8975f5c5SAndroid Build Coastguard Worker     {
104*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mFragmentEnd >= mDataEnd);
105*8975f5c5SAndroid Build Coastguard Worker         return static_cast<uint32_t>(mFragmentEnd - mDataEnd);
106*8975f5c5SAndroid Build Coastguard Worker     }
107*8975f5c5SAndroid Build Coastguard Worker 
108*8975f5c5SAndroid Build Coastguard Worker     RingBufferAllocatorCheckPoint getReleaseCheckPoint() const;
109*8975f5c5SAndroid Build Coastguard Worker     void release(const RingBufferAllocatorCheckPoint &checkPoint);
110*8975f5c5SAndroid Build Coastguard Worker 
111*8975f5c5SAndroid Build Coastguard Worker   private:
112*8975f5c5SAndroid Build Coastguard Worker     void release(uint8_t *releasePtr);
113*8975f5c5SAndroid Build Coastguard Worker     uint32_t getNumAllocatedInBuffer() const;
114*8975f5c5SAndroid Build Coastguard Worker     void resetPointers();
115*8975f5c5SAndroid Build Coastguard Worker 
116*8975f5c5SAndroid Build Coastguard Worker     uint8_t *allocateInNewFragment(uint32_t size);
117*8975f5c5SAndroid Build Coastguard Worker     void resize(uint32_t newCapacity);
118*8975f5c5SAndroid Build Coastguard Worker 
119*8975f5c5SAndroid Build Coastguard Worker     RingBufferAllocateListener *mListener = nullptr;
120*8975f5c5SAndroid Build Coastguard Worker 
121*8975f5c5SAndroid Build Coastguard Worker     std::vector<RingBufferAllocatorBuffer> mOldBuffers;
122*8975f5c5SAndroid Build Coastguard Worker     RingBufferAllocatorBuffer mBuffer;
123*8975f5c5SAndroid Build Coastguard Worker     uint8_t *mDataBegin       = nullptr;
124*8975f5c5SAndroid Build Coastguard Worker     uint8_t *mDataEnd         = nullptr;
125*8975f5c5SAndroid Build Coastguard Worker     uint8_t *mFragmentEnd     = nullptr;
126*8975f5c5SAndroid Build Coastguard Worker     uint8_t *mFragmentEndR    = nullptr;
127*8975f5c5SAndroid Build Coastguard Worker     uint32_t mFragmentReserve = 0;
128*8975f5c5SAndroid Build Coastguard Worker 
129*8975f5c5SAndroid Build Coastguard Worker     uint32_t mMinCapacity      = 0;
130*8975f5c5SAndroid Build Coastguard Worker     uint32_t mCurrentCapacity  = 0;
131*8975f5c5SAndroid Build Coastguard Worker     uint32_t mAllocationMargin = 0;
132*8975f5c5SAndroid Build Coastguard Worker 
133*8975f5c5SAndroid Build Coastguard Worker     // 1 - fastest decay speed.
134*8975f5c5SAndroid Build Coastguard Worker     // 2 - 2x slower than fastest, and so on.
135*8975f5c5SAndroid Build Coastguard Worker     uint32_t mDecaySpeedFactor = 0;
136*8975f5c5SAndroid Build Coastguard Worker };
137*8975f5c5SAndroid Build Coastguard Worker 
138*8975f5c5SAndroid Build Coastguard Worker class SharedRingBufferAllocatorCheckPoint final : angle::NonCopyable
139*8975f5c5SAndroid Build Coastguard Worker {
140*8975f5c5SAndroid Build Coastguard Worker   public:
141*8975f5c5SAndroid Build Coastguard Worker     void releaseAndUpdate(RingBufferAllocatorCheckPoint *newValue);
142*8975f5c5SAndroid Build Coastguard Worker 
143*8975f5c5SAndroid Build Coastguard Worker   private:
144*8975f5c5SAndroid Build Coastguard Worker     friend class SharedRingBufferAllocator;
145*8975f5c5SAndroid Build Coastguard Worker     RingBufferAllocatorCheckPoint pop();
146*8975f5c5SAndroid Build Coastguard Worker     angle::SimpleMutex mMutex;
147*8975f5c5SAndroid Build Coastguard Worker     RingBufferAllocatorCheckPoint mValue;
148*8975f5c5SAndroid Build Coastguard Worker 
149*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_ENABLE_ASSERTS)
150*8975f5c5SAndroid Build Coastguard Worker     std::atomic<uint32_t> mRefCount{1};
151*8975f5c5SAndroid Build Coastguard Worker #endif
152*8975f5c5SAndroid Build Coastguard Worker };
153*8975f5c5SAndroid Build Coastguard Worker 
154*8975f5c5SAndroid Build Coastguard Worker class SharedRingBufferAllocator final : angle::NonCopyable
155*8975f5c5SAndroid Build Coastguard Worker {
156*8975f5c5SAndroid Build Coastguard Worker   public:
157*8975f5c5SAndroid Build Coastguard Worker     SharedRingBufferAllocator();
158*8975f5c5SAndroid Build Coastguard Worker     ~SharedRingBufferAllocator();
159*8975f5c5SAndroid Build Coastguard Worker 
get()160*8975f5c5SAndroid Build Coastguard Worker     RingBufferAllocator &get() { return mAllocator; }
161*8975f5c5SAndroid Build Coastguard Worker 
162*8975f5c5SAndroid Build Coastguard Worker     // Once shared - always shared
isShared()163*8975f5c5SAndroid Build Coastguard Worker     bool isShared() const { return mSharedCP != nullptr; }
164*8975f5c5SAndroid Build Coastguard Worker 
165*8975f5c5SAndroid Build Coastguard Worker     // Once acquired must be released with releaseAndUpdate().
166*8975f5c5SAndroid Build Coastguard Worker     SharedRingBufferAllocatorCheckPoint *acquireSharedCP();
167*8975f5c5SAndroid Build Coastguard Worker     void releaseToSharedCP();
168*8975f5c5SAndroid Build Coastguard Worker 
169*8975f5c5SAndroid Build Coastguard Worker   private:
170*8975f5c5SAndroid Build Coastguard Worker     RingBufferAllocator mAllocator;
171*8975f5c5SAndroid Build Coastguard Worker     SharedRingBufferAllocatorCheckPoint *mSharedCP = nullptr;
172*8975f5c5SAndroid Build Coastguard Worker };
173*8975f5c5SAndroid Build Coastguard Worker 
174*8975f5c5SAndroid Build Coastguard Worker }  // namespace angle
175*8975f5c5SAndroid Build Coastguard Worker 
176*8975f5c5SAndroid Build Coastguard Worker #endif  // COMMON_RING_BUFFER_ALLOCATOR_H_
177