xref: /aosp_15_r20/external/angle/src/libANGLE/HandleAllocator.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2002 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 
7*8975f5c5SAndroid Build Coastguard Worker // HandleAllocator.cpp: Implements the gl::HandleAllocator class, which is used
8*8975f5c5SAndroid Build Coastguard Worker // to allocate GL handles.
9*8975f5c5SAndroid Build Coastguard Worker 
10*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/HandleAllocator.h"
11*8975f5c5SAndroid Build Coastguard Worker 
12*8975f5c5SAndroid Build Coastguard Worker #include <algorithm>
13*8975f5c5SAndroid Build Coastguard Worker #include <functional>
14*8975f5c5SAndroid Build Coastguard Worker #include <limits>
15*8975f5c5SAndroid Build Coastguard Worker 
16*8975f5c5SAndroid Build Coastguard Worker #include "common/debug.h"
17*8975f5c5SAndroid Build Coastguard Worker 
18*8975f5c5SAndroid Build Coastguard Worker namespace gl
19*8975f5c5SAndroid Build Coastguard Worker {
20*8975f5c5SAndroid Build Coastguard Worker 
21*8975f5c5SAndroid Build Coastguard Worker struct HandleAllocator::HandleRangeComparator
22*8975f5c5SAndroid Build Coastguard Worker {
operator ()gl::HandleAllocator::HandleRangeComparator23*8975f5c5SAndroid Build Coastguard Worker     bool operator()(const HandleRange &range, GLuint handle) const { return (range.end < handle); }
24*8975f5c5SAndroid Build Coastguard Worker };
25*8975f5c5SAndroid Build Coastguard Worker 
HandleAllocator()26*8975f5c5SAndroid Build Coastguard Worker HandleAllocator::HandleAllocator()
27*8975f5c5SAndroid Build Coastguard Worker     : mBaseValue(1),
28*8975f5c5SAndroid Build Coastguard Worker       mNextValue(1),
29*8975f5c5SAndroid Build Coastguard Worker       mMaxValue(std::numeric_limits<GLuint>::max()),
30*8975f5c5SAndroid Build Coastguard Worker       mLoggingEnabled(false)
31*8975f5c5SAndroid Build Coastguard Worker {
32*8975f5c5SAndroid Build Coastguard Worker     mUnallocatedList.push_back(HandleRange(1, mMaxValue));
33*8975f5c5SAndroid Build Coastguard Worker }
34*8975f5c5SAndroid Build Coastguard Worker 
HandleAllocator(GLuint maximumHandleValue)35*8975f5c5SAndroid Build Coastguard Worker HandleAllocator::HandleAllocator(GLuint maximumHandleValue)
36*8975f5c5SAndroid Build Coastguard Worker     : mBaseValue(1), mNextValue(1), mMaxValue(maximumHandleValue), mLoggingEnabled(false)
37*8975f5c5SAndroid Build Coastguard Worker {
38*8975f5c5SAndroid Build Coastguard Worker     mUnallocatedList.push_back(HandleRange(1, mMaxValue));
39*8975f5c5SAndroid Build Coastguard Worker }
40*8975f5c5SAndroid Build Coastguard Worker 
~HandleAllocator()41*8975f5c5SAndroid Build Coastguard Worker HandleAllocator::~HandleAllocator() {}
42*8975f5c5SAndroid Build Coastguard Worker 
setBaseHandle(GLuint value)43*8975f5c5SAndroid Build Coastguard Worker void HandleAllocator::setBaseHandle(GLuint value)
44*8975f5c5SAndroid Build Coastguard Worker {
45*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mBaseValue == mNextValue);
46*8975f5c5SAndroid Build Coastguard Worker     mBaseValue = value;
47*8975f5c5SAndroid Build Coastguard Worker     mNextValue = value;
48*8975f5c5SAndroid Build Coastguard Worker }
49*8975f5c5SAndroid Build Coastguard Worker 
allocate()50*8975f5c5SAndroid Build Coastguard Worker GLuint HandleAllocator::allocate()
51*8975f5c5SAndroid Build Coastguard Worker {
52*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!mUnallocatedList.empty() || !mReleasedList.empty());
53*8975f5c5SAndroid Build Coastguard Worker 
54*8975f5c5SAndroid Build Coastguard Worker     // Allocate from released list, logarithmic time for pop_heap.
55*8975f5c5SAndroid Build Coastguard Worker     if (!mReleasedList.empty())
56*8975f5c5SAndroid Build Coastguard Worker     {
57*8975f5c5SAndroid Build Coastguard Worker         std::pop_heap(mReleasedList.begin(), mReleasedList.end(), std::greater<GLuint>());
58*8975f5c5SAndroid Build Coastguard Worker         GLuint reusedHandle = mReleasedList.back();
59*8975f5c5SAndroid Build Coastguard Worker         mReleasedList.pop_back();
60*8975f5c5SAndroid Build Coastguard Worker 
61*8975f5c5SAndroid Build Coastguard Worker         if (mLoggingEnabled)
62*8975f5c5SAndroid Build Coastguard Worker         {
63*8975f5c5SAndroid Build Coastguard Worker             WARN() << "HandleAllocator::allocate reusing " << reusedHandle << std::endl;
64*8975f5c5SAndroid Build Coastguard Worker         }
65*8975f5c5SAndroid Build Coastguard Worker 
66*8975f5c5SAndroid Build Coastguard Worker         return reusedHandle;
67*8975f5c5SAndroid Build Coastguard Worker     }
68*8975f5c5SAndroid Build Coastguard Worker 
69*8975f5c5SAndroid Build Coastguard Worker     // Allocate from unallocated list, constant time.
70*8975f5c5SAndroid Build Coastguard Worker     auto listIt = mUnallocatedList.begin();
71*8975f5c5SAndroid Build Coastguard Worker 
72*8975f5c5SAndroid Build Coastguard Worker     GLuint freeListHandle = listIt->begin;
73*8975f5c5SAndroid Build Coastguard Worker     ASSERT(freeListHandle > 0);
74*8975f5c5SAndroid Build Coastguard Worker 
75*8975f5c5SAndroid Build Coastguard Worker     if (listIt->begin == listIt->end)
76*8975f5c5SAndroid Build Coastguard Worker     {
77*8975f5c5SAndroid Build Coastguard Worker         mUnallocatedList.erase(listIt);
78*8975f5c5SAndroid Build Coastguard Worker     }
79*8975f5c5SAndroid Build Coastguard Worker     else
80*8975f5c5SAndroid Build Coastguard Worker     {
81*8975f5c5SAndroid Build Coastguard Worker         listIt->begin++;
82*8975f5c5SAndroid Build Coastguard Worker     }
83*8975f5c5SAndroid Build Coastguard Worker 
84*8975f5c5SAndroid Build Coastguard Worker     if (mLoggingEnabled)
85*8975f5c5SAndroid Build Coastguard Worker     {
86*8975f5c5SAndroid Build Coastguard Worker         WARN() << "HandleAllocator::allocate allocating " << freeListHandle << std::endl;
87*8975f5c5SAndroid Build Coastguard Worker     }
88*8975f5c5SAndroid Build Coastguard Worker 
89*8975f5c5SAndroid Build Coastguard Worker     return freeListHandle;
90*8975f5c5SAndroid Build Coastguard Worker }
91*8975f5c5SAndroid Build Coastguard Worker 
release(GLuint handle)92*8975f5c5SAndroid Build Coastguard Worker void HandleAllocator::release(GLuint handle)
93*8975f5c5SAndroid Build Coastguard Worker {
94*8975f5c5SAndroid Build Coastguard Worker     if (mLoggingEnabled)
95*8975f5c5SAndroid Build Coastguard Worker     {
96*8975f5c5SAndroid Build Coastguard Worker         WARN() << "HandleAllocator::release releasing " << handle << std::endl;
97*8975f5c5SAndroid Build Coastguard Worker     }
98*8975f5c5SAndroid Build Coastguard Worker 
99*8975f5c5SAndroid Build Coastguard Worker     // Try consolidating the ranges first.
100*8975f5c5SAndroid Build Coastguard Worker     for (HandleRange &handleRange : mUnallocatedList)
101*8975f5c5SAndroid Build Coastguard Worker     {
102*8975f5c5SAndroid Build Coastguard Worker         if (handleRange.begin - 1 == handle)
103*8975f5c5SAndroid Build Coastguard Worker         {
104*8975f5c5SAndroid Build Coastguard Worker             handleRange.begin--;
105*8975f5c5SAndroid Build Coastguard Worker             return;
106*8975f5c5SAndroid Build Coastguard Worker         }
107*8975f5c5SAndroid Build Coastguard Worker 
108*8975f5c5SAndroid Build Coastguard Worker         if (handleRange.end == handle - 1)
109*8975f5c5SAndroid Build Coastguard Worker         {
110*8975f5c5SAndroid Build Coastguard Worker             handleRange.end++;
111*8975f5c5SAndroid Build Coastguard Worker             return;
112*8975f5c5SAndroid Build Coastguard Worker         }
113*8975f5c5SAndroid Build Coastguard Worker     }
114*8975f5c5SAndroid Build Coastguard Worker 
115*8975f5c5SAndroid Build Coastguard Worker     // Add to released list, logarithmic time for push_heap.
116*8975f5c5SAndroid Build Coastguard Worker     mReleasedList.push_back(handle);
117*8975f5c5SAndroid Build Coastguard Worker     std::push_heap(mReleasedList.begin(), mReleasedList.end(), std::greater<GLuint>());
118*8975f5c5SAndroid Build Coastguard Worker }
119*8975f5c5SAndroid Build Coastguard Worker 
reserve(GLuint handle)120*8975f5c5SAndroid Build Coastguard Worker void HandleAllocator::reserve(GLuint handle)
121*8975f5c5SAndroid Build Coastguard Worker {
122*8975f5c5SAndroid Build Coastguard Worker     if (mLoggingEnabled)
123*8975f5c5SAndroid Build Coastguard Worker     {
124*8975f5c5SAndroid Build Coastguard Worker         WARN() << "HandleAllocator::reserve reserving " << handle << std::endl;
125*8975f5c5SAndroid Build Coastguard Worker     }
126*8975f5c5SAndroid Build Coastguard Worker 
127*8975f5c5SAndroid Build Coastguard Worker     // Clear from released list -- might be a slow operation.
128*8975f5c5SAndroid Build Coastguard Worker     if (!mReleasedList.empty())
129*8975f5c5SAndroid Build Coastguard Worker     {
130*8975f5c5SAndroid Build Coastguard Worker         auto releasedIt = std::find(mReleasedList.begin(), mReleasedList.end(), handle);
131*8975f5c5SAndroid Build Coastguard Worker         if (releasedIt != mReleasedList.end())
132*8975f5c5SAndroid Build Coastguard Worker         {
133*8975f5c5SAndroid Build Coastguard Worker             mReleasedList.erase(releasedIt);
134*8975f5c5SAndroid Build Coastguard Worker             std::make_heap(mReleasedList.begin(), mReleasedList.end(), std::greater<GLuint>());
135*8975f5c5SAndroid Build Coastguard Worker             return;
136*8975f5c5SAndroid Build Coastguard Worker         }
137*8975f5c5SAndroid Build Coastguard Worker     }
138*8975f5c5SAndroid Build Coastguard Worker 
139*8975f5c5SAndroid Build Coastguard Worker     // Not in released list, reserve in the unallocated list.
140*8975f5c5SAndroid Build Coastguard Worker     auto boundIt = std::lower_bound(mUnallocatedList.begin(), mUnallocatedList.end(), handle,
141*8975f5c5SAndroid Build Coastguard Worker                                     HandleRangeComparator());
142*8975f5c5SAndroid Build Coastguard Worker 
143*8975f5c5SAndroid Build Coastguard Worker     ASSERT(boundIt != mUnallocatedList.end());
144*8975f5c5SAndroid Build Coastguard Worker 
145*8975f5c5SAndroid Build Coastguard Worker     GLuint begin = boundIt->begin;
146*8975f5c5SAndroid Build Coastguard Worker     GLuint end   = boundIt->end;
147*8975f5c5SAndroid Build Coastguard Worker 
148*8975f5c5SAndroid Build Coastguard Worker     if (handle == begin || handle == end)
149*8975f5c5SAndroid Build Coastguard Worker     {
150*8975f5c5SAndroid Build Coastguard Worker         if (begin == end)
151*8975f5c5SAndroid Build Coastguard Worker         {
152*8975f5c5SAndroid Build Coastguard Worker             mUnallocatedList.erase(boundIt);
153*8975f5c5SAndroid Build Coastguard Worker         }
154*8975f5c5SAndroid Build Coastguard Worker         else if (handle == begin)
155*8975f5c5SAndroid Build Coastguard Worker         {
156*8975f5c5SAndroid Build Coastguard Worker             boundIt->begin++;
157*8975f5c5SAndroid Build Coastguard Worker         }
158*8975f5c5SAndroid Build Coastguard Worker         else
159*8975f5c5SAndroid Build Coastguard Worker         {
160*8975f5c5SAndroid Build Coastguard Worker             ASSERT(handle == end);
161*8975f5c5SAndroid Build Coastguard Worker             boundIt->end--;
162*8975f5c5SAndroid Build Coastguard Worker         }
163*8975f5c5SAndroid Build Coastguard Worker         return;
164*8975f5c5SAndroid Build Coastguard Worker     }
165*8975f5c5SAndroid Build Coastguard Worker 
166*8975f5c5SAndroid Build Coastguard Worker     ASSERT(begin < handle && handle < end);
167*8975f5c5SAndroid Build Coastguard Worker 
168*8975f5c5SAndroid Build Coastguard Worker     // need to split the range
169*8975f5c5SAndroid Build Coastguard Worker     auto placementIt = mUnallocatedList.erase(boundIt);
170*8975f5c5SAndroid Build Coastguard Worker     placementIt      = mUnallocatedList.insert(placementIt, HandleRange(handle + 1, end));
171*8975f5c5SAndroid Build Coastguard Worker     mUnallocatedList.insert(placementIt, HandleRange(begin, handle - 1));
172*8975f5c5SAndroid Build Coastguard Worker }
173*8975f5c5SAndroid Build Coastguard Worker 
reset()174*8975f5c5SAndroid Build Coastguard Worker void HandleAllocator::reset()
175*8975f5c5SAndroid Build Coastguard Worker {
176*8975f5c5SAndroid Build Coastguard Worker     mUnallocatedList.clear();
177*8975f5c5SAndroid Build Coastguard Worker     mUnallocatedList.push_back(HandleRange(1, mMaxValue));
178*8975f5c5SAndroid Build Coastguard Worker     mReleasedList.clear();
179*8975f5c5SAndroid Build Coastguard Worker     mBaseValue = 1;
180*8975f5c5SAndroid Build Coastguard Worker     mNextValue = 1;
181*8975f5c5SAndroid Build Coastguard Worker }
182*8975f5c5SAndroid Build Coastguard Worker 
anyHandleAvailableForAllocation() const183*8975f5c5SAndroid Build Coastguard Worker bool HandleAllocator::anyHandleAvailableForAllocation() const
184*8975f5c5SAndroid Build Coastguard Worker {
185*8975f5c5SAndroid Build Coastguard Worker     return !mUnallocatedList.empty() || !mReleasedList.empty();
186*8975f5c5SAndroid Build Coastguard Worker }
187*8975f5c5SAndroid Build Coastguard Worker 
enableLogging(bool enabled)188*8975f5c5SAndroid Build Coastguard Worker void HandleAllocator::enableLogging(bool enabled)
189*8975f5c5SAndroid Build Coastguard Worker {
190*8975f5c5SAndroid Build Coastguard Worker     mLoggingEnabled = enabled;
191*8975f5c5SAndroid Build Coastguard Worker }
192*8975f5c5SAndroid Build Coastguard Worker 
193*8975f5c5SAndroid Build Coastguard Worker }  // namespace gl
194