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