blob: 1d825f7106b38fc82ec407a9efa8a8b7c6c75da5 [file] [log] [blame]
Sami Väisänene45e53b2016-05-25 10:36:04 +03001//
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// Unit tests for HandleRangeAllocator.
7//
8
9#include "gmock/gmock.h"
10#include "gtest/gtest.h"
11
12#include "libANGLE/HandleRangeAllocator.h"
13
14namespace
15{
16
17class HandleRangeAllocatorTest : public testing::Test
18{
19 protected:
20 gl::HandleRangeAllocator *getAllocator() { return &mAllocator; }
21
22 private:
23 gl::HandleRangeAllocator mAllocator;
24};
25
26// Checks basic functionality: allocate, release, isUsed.
27TEST_F(HandleRangeAllocatorTest, TestBasic)
28{
29 auto *allocator = getAllocator();
30 // Check that resource 1 is not in use
31 EXPECT_FALSE(allocator->isUsed(1));
32
33 // Allocate an ID, check that it's in use.
34 GLuint id1 = allocator->allocate();
35 EXPECT_TRUE(allocator->isUsed(id1));
36
37 // Allocate another ID, check that it's in use, and different from the first
38 // one.
39 GLuint id2 = allocator->allocate();
40 EXPECT_TRUE(allocator->isUsed(id2));
41 EXPECT_NE(id1, id2);
42
43 // Free one of the IDs, check that it's not in use any more.
44 allocator->release(id1);
45 EXPECT_FALSE(allocator->isUsed(id1));
46
47 // Frees the other ID, check that it's not in use any more.
48 allocator->release(id2);
49 EXPECT_FALSE(allocator->isUsed(id2));
50}
51
52// Checks that the resource handles are re-used after being freed.
53TEST_F(HandleRangeAllocatorTest, TestAdvanced)
54{
55 auto *allocator = getAllocator();
56
57 // Allocate the highest possible ID, to make life awkward.
58 allocator->allocateAtOrAbove(~static_cast<GLuint>(0));
59
60 // Allocate a significant number of resources.
61 const unsigned int kNumResources = 100;
62 GLuint ids[kNumResources];
63 for (unsigned int i = 0; i < kNumResources; ++i)
64 {
65 ids[i] = allocator->allocate();
66 EXPECT_TRUE(allocator->isUsed(ids[i]));
67 }
68
69 // Check that a new allocation re-uses the resource we just freed.
70 GLuint id1 = ids[kNumResources / 2];
71 allocator->release(id1);
72 EXPECT_FALSE(allocator->isUsed(id1));
73 GLuint id2 = allocator->allocate();
74 EXPECT_TRUE(allocator->isUsed(id2));
75 EXPECT_EQ(id1, id2);
76}
77
78// Checks that we can choose our own ids and they won't be reused.
79TEST_F(HandleRangeAllocatorTest, MarkAsUsed)
80{
81 auto *allocator = getAllocator();
82 GLuint id = allocator->allocate();
83 allocator->release(id);
84 EXPECT_FALSE(allocator->isUsed(id));
85 EXPECT_TRUE(allocator->markAsUsed(id));
86 EXPECT_TRUE(allocator->isUsed(id));
87 GLuint id2 = allocator->allocate();
88 EXPECT_NE(id, id2);
89 EXPECT_TRUE(allocator->markAsUsed(id2 + 1));
90 GLuint id3 = allocator->allocate();
91 // Checks our algorithm. If the algorithm changes this check should be
92 // changed.
93 EXPECT_EQ(id3, id2 + 2);
94}
95
96// Checks allocateAtOrAbove.
97TEST_F(HandleRangeAllocatorTest, AllocateAtOrAbove)
98{
99 const GLuint kOffset = 123456;
100 auto *allocator = getAllocator();
101 GLuint id1 = allocator->allocateAtOrAbove(kOffset);
102 EXPECT_EQ(kOffset, id1);
103 GLuint id2 = allocator->allocateAtOrAbove(kOffset);
104 EXPECT_GT(id2, kOffset);
105 GLuint id3 = allocator->allocateAtOrAbove(kOffset);
106 EXPECT_GT(id3, kOffset);
107}
108
109// Checks that allocateAtOrAbove wraps around at the maximum value.
110TEST_F(HandleRangeAllocatorTest, AllocateIdAtOrAboveWrapsAround)
111{
112 const GLuint kMaxPossibleOffset = ~static_cast<GLuint>(0);
113 auto *allocator = getAllocator();
114 GLuint id1 = allocator->allocateAtOrAbove(kMaxPossibleOffset);
115 EXPECT_EQ(kMaxPossibleOffset, id1);
116 GLuint id2 = allocator->allocateAtOrAbove(kMaxPossibleOffset);
117 EXPECT_EQ(1u, id2);
118 GLuint id3 = allocator->allocateAtOrAbove(kMaxPossibleOffset);
119 EXPECT_EQ(2u, id3);
120}
121
122// Checks that freeing an already freed range causes no harm.
123TEST_F(HandleRangeAllocatorTest, RedundantFreeIsIgnored)
124{
125 auto *allocator = getAllocator();
126 GLuint id1 = allocator->allocate();
127 allocator->release(0);
128 allocator->release(id1);
129 allocator->release(id1);
130 allocator->release(id1 + 1);
131 GLuint id2 = allocator->allocate();
132 GLuint id3 = allocator->allocate();
133 EXPECT_NE(id2, id3);
134 EXPECT_NE(allocator->kInvalidHandle, id2);
135 EXPECT_NE(allocator->kInvalidHandle, id3);
136}
137
138// Check allocating and releasing multiple ranges.
139TEST_F(HandleRangeAllocatorTest, allocateRange)
140{
141 const GLuint kMaxPossibleOffset = std::numeric_limits<GLuint>::max();
142
143 auto *allocator = getAllocator();
144
145 GLuint id1 = allocator->allocateRange(1);
146 EXPECT_EQ(1u, id1);
147 GLuint id2 = allocator->allocateRange(2);
148 EXPECT_EQ(2u, id2);
149 GLuint id3 = allocator->allocateRange(3);
150 EXPECT_EQ(4u, id3);
151 GLuint id4 = allocator->allocate();
152 EXPECT_EQ(7u, id4);
153 allocator->release(3);
154 GLuint id5 = allocator->allocateRange(1);
155 EXPECT_EQ(3u, id5);
156 allocator->release(5);
157 allocator->release(2);
158 allocator->release(4);
159 GLuint id6 = allocator->allocateRange(2);
160 EXPECT_EQ(4u, id6);
161 GLuint id7 = allocator->allocateAtOrAbove(kMaxPossibleOffset);
162 EXPECT_EQ(kMaxPossibleOffset, id7);
163 GLuint id8 = allocator->allocateAtOrAbove(kMaxPossibleOffset);
164 EXPECT_EQ(2u, id8);
165 GLuint id9 = allocator->allocateRange(50);
166 EXPECT_EQ(8u, id9);
167 GLuint id10 = allocator->allocateRange(50);
168 EXPECT_EQ(58u, id10);
169 // Remove all the low-numbered ids.
170 allocator->release(1);
171 allocator->release(15);
172 allocator->releaseRange(2, 107);
173 GLuint id11 = allocator->allocateRange(100);
174 EXPECT_EQ(1u, id11);
175 allocator->release(kMaxPossibleOffset);
176 GLuint id12 = allocator->allocateRange(100);
177 EXPECT_EQ(101u, id12);
178
179 GLuint id13 = allocator->allocateAtOrAbove(kMaxPossibleOffset - 2u);
180 EXPECT_EQ(kMaxPossibleOffset - 2u, id13);
181 GLuint id14 = allocator->allocateRange(3);
182 EXPECT_EQ(201u, id14);
183}
184
185// Checks that having allocated a high range doesn't interfere
186// with normal low range allocation.
187TEST_F(HandleRangeAllocatorTest, AllocateRangeEndNoEffect)
188{
189 const GLuint kMaxPossibleOffset = std::numeric_limits<GLuint>::max();
190
191 auto *allocator = getAllocator();
192 GLuint id1 = allocator->allocateAtOrAbove(kMaxPossibleOffset - 2u);
193 EXPECT_EQ(kMaxPossibleOffset - 2u, id1);
194 GLuint id3 = allocator->allocateRange(3);
195 EXPECT_EQ(1u, id3);
196 GLuint id2 = allocator->allocateRange(2);
197 EXPECT_EQ(4u, id2);
198}
199
200// Checks allocating a range that consumes the whole uint32 space.
201TEST_F(HandleRangeAllocatorTest, AllocateMax)
202{
203 const uint32_t kMaxPossibleRange = std::numeric_limits<uint32_t>::max();
204
205 auto *allocator = getAllocator();
206 GLuint id = allocator->allocateRange(kMaxPossibleRange);
207 EXPECT_EQ(1u, id);
208 allocator->releaseRange(id, kMaxPossibleRange - 1u);
209 GLuint id2 = allocator->allocateRange(kMaxPossibleRange);
210 EXPECT_EQ(0u, id2);
211 allocator->releaseRange(id, kMaxPossibleRange);
212 GLuint id3 = allocator->allocateRange(kMaxPossibleRange);
213 EXPECT_EQ(1u, id3);
214}
215
216// Checks allocating a range that consumes the whole uint32 space
217// causes next allocation to fail.
218// Subsequently checks that once the big range is reduced new allocations
219// are possible.
220TEST_F(HandleRangeAllocatorTest, AllocateFullRange)
221{
222 const uint32_t kMaxPossibleRange = std::numeric_limits<uint32_t>::max();
223 const GLuint kFreedId = 555u;
224 auto *allocator = getAllocator();
225
226 GLuint id1 = allocator->allocateRange(kMaxPossibleRange);
227 EXPECT_EQ(1u, id1);
228 GLuint id2 = allocator->allocate();
229 EXPECT_EQ(gl::HandleRangeAllocator::kInvalidHandle, id2);
230 allocator->release(kFreedId);
231 GLuint id3 = allocator->allocate();
232 EXPECT_EQ(kFreedId, id3);
233 GLuint id4 = allocator->allocate();
234 EXPECT_EQ(0u, id4);
235 allocator->release(kFreedId + 1u);
236 allocator->release(kFreedId + 4u);
237 allocator->release(kFreedId + 3u);
238 allocator->release(kFreedId + 5u);
239 allocator->release(kFreedId + 2u);
240 GLuint id5 = allocator->allocateRange(5);
241 EXPECT_EQ(kFreedId + 1u, id5);
242}
243
244// Checks that allocating a range that exceeds uint32
245// does not wrap incorrectly and fails.
246TEST_F(HandleRangeAllocatorTest, AllocateRangeNoWrapInRange)
247{
248 const uint32_t kMaxPossibleRange = std::numeric_limits<uint32_t>::max();
249 const GLuint kAllocId = 10u;
250 auto *allocator = getAllocator();
251
252 GLuint id1 = allocator->allocateAtOrAbove(kAllocId);
253 EXPECT_EQ(kAllocId, id1);
254 GLuint id2 = allocator->allocateRange(kMaxPossibleRange - 5u);
255 EXPECT_EQ(0u, id2);
256 GLuint id3 = allocator->allocateRange(kMaxPossibleRange - kAllocId);
257 EXPECT_EQ(kAllocId + 1u, id3);
258}
259
260// Check special cases for 0 range allocations and zero handles.
261TEST_F(HandleRangeAllocatorTest, ZeroIdCases)
262{
263 auto *allocator = getAllocator();
264 EXPECT_FALSE(allocator->isUsed(0));
265 GLuint id1 = allocator->allocateAtOrAbove(0);
266 EXPECT_NE(0u, id1);
267 EXPECT_FALSE(allocator->isUsed(0));
268 allocator->release(0);
269 EXPECT_FALSE(allocator->isUsed(0));
270 EXPECT_TRUE(allocator->isUsed(id1));
271 allocator->release(id1);
272 EXPECT_FALSE(allocator->isUsed(id1));
273}
274
275} // namespace