• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 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 
7 // HandleRangeAllocator.cpp : Implementation for HandleRangeAllocator.h
8 
9 #include "libANGLE/HandleRangeAllocator.h"
10 
11 #include <algorithm>
12 #include <limits>
13 #include <utility>
14 
15 #include "common/angleutils.h"
16 #include "common/debug.h"
17 
18 namespace gl
19 {
20 
21 const GLuint HandleRangeAllocator::kInvalidHandle = 0;
22 
HandleRangeAllocator()23 HandleRangeAllocator::HandleRangeAllocator()
24 {
25     // Simplify the code by making sure that lower_bound(id) never
26     // returns the beginning of the map, if id is valid (eg != kInvalidHandle).
27     mUsed.insert(std::make_pair(0u, 0u));
28 }
29 
~HandleRangeAllocator()30 HandleRangeAllocator::~HandleRangeAllocator() {}
31 
allocate()32 GLuint HandleRangeAllocator::allocate()
33 {
34     return allocateRange(1u);
35 }
36 
allocateAtOrAbove(GLuint wanted)37 GLuint HandleRangeAllocator::allocateAtOrAbove(GLuint wanted)
38 {
39     if (wanted == 0u || wanted == 1u)
40         return allocateRange(1u);
41 
42     auto current = mUsed.lower_bound(wanted);
43     auto next    = current;
44     if (current == mUsed.end() || current->first > wanted)
45     {
46         current--;
47     }
48     else
49     {
50         next++;
51     }
52 
53     GLuint firstId = current->first;
54     GLuint lastId  = current->second;
55     ASSERT(wanted >= firstId);
56 
57     if (wanted - 1u <= lastId)
58     {
59         // Append to current range.
60         lastId++;
61         if (lastId == 0)
62         {
63             // The increment overflowed.
64             return allocateRange(1u);
65         }
66 
67         current->second = lastId;
68 
69         if (next != mUsed.end() && next->first - 1u == lastId)
70         {
71             // Merge with next range.
72             current->second = next->second;
73             mUsed.erase(next);
74         }
75         return lastId;
76     }
77     else if (next != mUsed.end() && next->first - 1u == wanted)
78     {
79         // Prepend to next range.
80         GLuint lastExisting = next->second;
81         mUsed.erase(next);
82         mUsed.insert(std::make_pair(wanted, lastExisting));
83         return wanted;
84     }
85     mUsed.insert(std::make_pair(wanted, wanted));
86     return wanted;
87 }
88 
allocateRange(GLuint range)89 GLuint HandleRangeAllocator::allocateRange(GLuint range)
90 {
91     ASSERT(range != 0);
92 
93     auto current = mUsed.begin();
94     auto next    = current;
95 
96     while (++next != mUsed.end())
97     {
98         if (next->first - current->second > range)
99             break;
100         current = next;
101     }
102     const GLuint firstId = current->second + 1u;
103     const GLuint lastId  = firstId + range - 1u;
104 
105     // deal with wraparound
106     if (firstId == 0u || lastId < firstId)
107         return kInvalidHandle;
108 
109     current->second = lastId;
110 
111     if (next != mUsed.end() && next->first - 1u == lastId)
112     {
113         // merge with next range
114         current->second = next->second;
115         mUsed.erase(next);
116     }
117     return firstId;
118 }
119 
markAsUsed(GLuint handle)120 bool HandleRangeAllocator::markAsUsed(GLuint handle)
121 {
122     ASSERT(handle);
123     auto current = mUsed.lower_bound(handle);
124     if (current != mUsed.end() && current->first == handle)
125         return false;
126 
127     auto next = current;
128     --current;
129 
130     if (current->second >= handle)
131         return false;
132 
133     ASSERT(current->first < handle && current->second < handle);
134 
135     if (current->second + 1u == handle)
136     {
137         // Append to current range.
138         current->second = handle;
139         if (next != mUsed.end() && next->first - 1u == handle)
140         {
141             // Merge with next range.
142             current->second = next->second;
143             mUsed.erase(next);
144         }
145         return true;
146     }
147     else if (next != mUsed.end() && next->first - 1u == handle)
148     {
149         // Prepend to next range.
150         GLuint lastExisting = next->second;
151         mUsed.erase(next);
152         mUsed.insert(std::make_pair(handle, lastExisting));
153         return true;
154     }
155 
156     mUsed.insert(std::make_pair(handle, handle));
157     return true;
158 }
159 
release(GLuint handle)160 void HandleRangeAllocator::release(GLuint handle)
161 {
162     releaseRange(handle, 1u);
163 }
164 
releaseRange(GLuint first,GLuint range)165 void HandleRangeAllocator::releaseRange(GLuint first, GLuint range)
166 {
167     if (range == 0u || (first == 0u && range == 1u))
168         return;
169 
170     if (first == 0u)
171     {
172         first++;
173         range--;
174     }
175 
176     GLuint last = first + range - 1u;
177     if (last < first)
178         last = std::numeric_limits<GLuint>::max();
179 
180     while (true)
181     {
182         auto current = mUsed.lower_bound(last);
183         if (current == mUsed.end() || current->first > last)
184             --current;
185 
186         if (current->second < first)
187             return;
188 
189         if (current->first >= first)
190         {
191             const GLuint lastExisting = current->second;
192             mUsed.erase(current);
193             if (last < lastExisting)
194             {
195                 mUsed.insert(std::make_pair(last + 1u, lastExisting));
196             }
197         }
198         else if (current->second <= last)
199         {
200             current->second = first - 1u;
201         }
202         else
203         {
204             ASSERT(current->first < first && current->second > last);
205             const GLuint lastExisting = current->second;
206             current->second           = first - 1u;
207             mUsed.insert(std::make_pair(last + 1u, lastExisting));
208         }
209     }
210 }
211 
isUsed(GLuint handle) const212 bool HandleRangeAllocator::isUsed(GLuint handle) const
213 {
214     if (handle == kInvalidHandle)
215         return false;
216 
217     auto current = mUsed.lower_bound(handle);
218     if (current != mUsed.end())
219     {
220         if (current->first == handle)
221             return true;
222     }
223     --current;
224     return current->second >= handle;
225 }
226 
227 }  // namespace gl
228