1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // This file contains the tests for the RingBuffer class.
7 #include "gpu/command_buffer/client/ring_buffer.h"
10 #include "base/bind_helpers.h"
11 #include "gpu/command_buffer/client/cmd_buffer_helper.h"
12 #include "gpu/command_buffer/service/cmd_buffer_engine.h"
13 #include "gpu/command_buffer/service/command_buffer_service.h"
14 #include "gpu/command_buffer/service/gpu_scheduler.h"
15 #include "gpu/command_buffer/service/mocks.h"
16 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
17 #include "testing/gtest/include/gtest/gtest.h"
21 using testing::Return
;
24 using testing::Sequence
;
26 using testing::Invoke
;
29 class BaseRingBufferTest
: public testing::Test
{
31 static const unsigned int kBaseOffset
= 128;
32 static const unsigned int kBufferSize
= 1024;
33 static const unsigned int kAlignment
= 4;
35 void RunPendingSetToken() {
36 for (std::vector
<const void*>::iterator it
= set_token_arguments_
.begin();
37 it
!= set_token_arguments_
.end();
39 api_mock_
->SetToken(cmd::kSetToken
, 1, *it
);
41 set_token_arguments_
.clear();
42 delay_set_token_
= false;
45 void SetToken(unsigned int command
,
46 unsigned int arg_count
,
48 EXPECT_EQ(static_cast<unsigned int>(cmd::kSetToken
), command
);
49 EXPECT_EQ(1u, arg_count
);
51 set_token_arguments_
.push_back(_args
);
53 api_mock_
->SetToken(cmd::kSetToken
, 1, _args
);
56 void SetUp() override
{
57 delay_set_token_
= false;
58 api_mock_
.reset(new AsyncAPIMock(true));
59 // ignore noops in the mock - we don't want to inspect the internals of the
61 EXPECT_CALL(*api_mock_
, DoCommand(cmd::kNoop
, 0, _
))
62 .WillRepeatedly(Return(error::kNoError
));
63 // Forward the SetToken calls to the engine
64 EXPECT_CALL(*api_mock_
.get(), DoCommand(cmd::kSetToken
, 1, _
))
65 .WillRepeatedly(DoAll(Invoke(this, &BaseRingBufferTest::SetToken
),
66 Return(error::kNoError
)));
69 TransferBufferManager
* manager
= new TransferBufferManager();
70 transfer_buffer_manager_
= manager
;
71 EXPECT_TRUE(manager
->Initialize());
73 command_buffer_
.reset(
74 new CommandBufferService(transfer_buffer_manager_
.get()));
75 EXPECT_TRUE(command_buffer_
->Initialize());
77 gpu_scheduler_
.reset(new GpuScheduler(
78 command_buffer_
.get(), api_mock_
.get(), NULL
));
79 command_buffer_
->SetPutOffsetChangeCallback(base::Bind(
80 &GpuScheduler::PutChanged
, base::Unretained(gpu_scheduler_
.get())));
81 command_buffer_
->SetGetBufferChangeCallback(base::Bind(
82 &GpuScheduler::SetGetBuffer
, base::Unretained(gpu_scheduler_
.get())));
84 api_mock_
->set_engine(gpu_scheduler_
.get());
86 helper_
.reset(new CommandBufferHelper(command_buffer_
.get()));
87 helper_
->Initialize(kBufferSize
);
91 return command_buffer_
->GetLastState().token
;
94 scoped_ptr
<AsyncAPIMock
> api_mock_
;
95 scoped_refptr
<TransferBufferManagerInterface
> transfer_buffer_manager_
;
96 scoped_ptr
<CommandBufferService
> command_buffer_
;
97 scoped_ptr
<GpuScheduler
> gpu_scheduler_
;
98 scoped_ptr
<CommandBufferHelper
> helper_
;
99 std::vector
<const void*> set_token_arguments_
;
100 bool delay_set_token_
;
102 scoped_ptr
<int8
[]> buffer_
;
107 const unsigned int BaseRingBufferTest::kBaseOffset
;
108 const unsigned int BaseRingBufferTest::kBufferSize
;
111 // Test fixture for RingBuffer test - Creates a RingBuffer, using a
112 // CommandBufferHelper with a mock AsyncAPIInterface for its interface (calling
113 // it directly, not through the RPC mechanism), making sure Noops are ignored
114 // and SetToken are properly forwarded to the engine.
115 class RingBufferTest
: public BaseRingBufferTest
{
117 void SetUp() override
{
118 BaseRingBufferTest::SetUp();
120 buffer_
.reset(new int8
[kBufferSize
+ kBaseOffset
]);
121 buffer_start_
= buffer_
.get() + kBaseOffset
;
122 allocator_
.reset(new RingBuffer(kAlignment
, kBaseOffset
, kBufferSize
,
123 helper_
.get(), buffer_start_
));
126 void TearDown() override
{
127 // If the GpuScheduler posts any tasks, this forces them to run.
128 base::MessageLoop::current()->RunUntilIdle();
130 BaseRingBufferTest::TearDown();
133 scoped_ptr
<RingBuffer
> allocator_
;
136 // Checks basic alloc and free.
137 TEST_F(RingBufferTest
, TestBasic
) {
138 const unsigned int kSize
= 16;
139 EXPECT_EQ(kBufferSize
, allocator_
->GetLargestFreeOrPendingSize());
140 EXPECT_EQ(kBufferSize
, allocator_
->GetLargestFreeSizeNoWaiting());
141 void* pointer
= allocator_
->Alloc(kSize
);
142 EXPECT_GE(kBufferSize
, allocator_
->GetOffset(pointer
) - kBaseOffset
+ kSize
);
143 EXPECT_EQ(kBufferSize
, allocator_
->GetLargestFreeOrPendingSize());
144 EXPECT_EQ(kBufferSize
- kSize
, allocator_
->GetLargestFreeSizeNoWaiting());
145 int32 token
= helper_
->InsertToken();
146 allocator_
->FreePendingToken(pointer
, token
);
149 // Checks the free-pending-token mechanism.
150 TEST_F(RingBufferTest
, TestFreePendingToken
) {
151 const unsigned int kSize
= 16;
152 const unsigned int kAllocCount
= kBufferSize
/ kSize
;
153 CHECK(kAllocCount
* kSize
== kBufferSize
);
155 delay_set_token_
= true;
156 // Allocate several buffers to fill in the memory.
157 int32 tokens
[kAllocCount
];
158 for (unsigned int ii
= 0; ii
< kAllocCount
; ++ii
) {
159 void* pointer
= allocator_
->Alloc(kSize
);
160 EXPECT_GE(kBufferSize
,
161 allocator_
->GetOffset(pointer
) - kBaseOffset
+ kSize
);
162 tokens
[ii
] = helper_
->InsertToken();
163 allocator_
->FreePendingToken(pointer
, tokens
[ii
]);
166 EXPECT_EQ(kBufferSize
- (kSize
* kAllocCount
),
167 allocator_
->GetLargestFreeSizeNoWaiting());
169 RunPendingSetToken();
171 // This allocation will need to reclaim the space freed above, so that should
172 // process the commands until a token is passed.
173 void* pointer1
= allocator_
->Alloc(kSize
);
174 EXPECT_EQ(kBaseOffset
, allocator_
->GetOffset(pointer1
));
176 // Check that the token has indeed passed.
177 EXPECT_LE(tokens
[0], GetToken());
179 allocator_
->FreePendingToken(pointer1
, helper_
->InsertToken());
182 // Tests GetLargestFreeSizeNoWaiting
183 TEST_F(RingBufferTest
, TestGetLargestFreeSizeNoWaiting
) {
184 EXPECT_EQ(kBufferSize
, allocator_
->GetLargestFreeSizeNoWaiting());
186 void* pointer
= allocator_
->Alloc(kBufferSize
);
187 EXPECT_EQ(0u, allocator_
->GetLargestFreeSizeNoWaiting());
188 allocator_
->FreePendingToken(pointer
, helper_
->InsertToken());
191 TEST_F(RingBufferTest
, TestFreeBug
) {
192 // The first and second allocations must not match.
193 const unsigned int kAlloc1
= 3*kAlignment
;
194 const unsigned int kAlloc2
= 20;
195 void* pointer
= allocator_
->Alloc(kAlloc1
);
196 EXPECT_EQ(kBufferSize
- kAlloc1
, allocator_
->GetLargestFreeSizeNoWaiting());
197 allocator_
->FreePendingToken(pointer
, helper_
.get()->InsertToken());
198 pointer
= allocator_
->Alloc(kAlloc2
);
199 EXPECT_EQ(kBufferSize
- kAlloc1
- kAlloc2
,
200 allocator_
->GetLargestFreeSizeNoWaiting());
201 allocator_
->FreePendingToken(pointer
, helper_
.get()->InsertToken());
202 pointer
= allocator_
->Alloc(kBufferSize
);
203 EXPECT_EQ(0u, allocator_
->GetLargestFreeSizeNoWaiting());
204 allocator_
->FreePendingToken(pointer
, helper_
.get()->InsertToken());
207 // Test that discarding a single allocation clears the block.
208 TEST_F(RingBufferTest
, DiscardTest
) {
209 const unsigned int kAlloc1
= 3*kAlignment
;
210 void* ptr
= allocator_
->Alloc(kAlloc1
);
211 EXPECT_EQ(kBufferSize
- kAlloc1
, allocator_
->GetLargestFreeSizeNoWaiting());
212 allocator_
->DiscardBlock(ptr
);
213 EXPECT_EQ(kBufferSize
, allocator_
->GetLargestFreeSizeNoWaiting());
216 // Test that discarding front of the buffer effectively frees the block.
217 TEST_F(RingBufferTest
, DiscardFrontTest
) {
218 const unsigned int kAlloc1
= 3*kAlignment
;
219 const unsigned int kAlloc2
= 2*kAlignment
;
220 const unsigned int kAlloc3
= kBufferSize
- kAlloc1
- kAlloc2
;
221 void* ptr1
= allocator_
->Alloc(kAlloc1
);
222 EXPECT_EQ(kBufferSize
- kAlloc1
, allocator_
->GetLargestFreeSizeNoWaiting());
223 allocator_
->FreePendingToken(ptr1
, helper_
.get()->InsertToken());
225 void* ptr2
= allocator_
->Alloc(kAlloc2
);
226 EXPECT_EQ(static_cast<uint8_t*>(ptr1
) + kAlloc1
,
227 static_cast<uint8_t*>(ptr2
));
228 EXPECT_EQ(kBufferSize
- kAlloc1
- kAlloc2
,
229 allocator_
->GetLargestFreeSizeNoWaiting());
230 allocator_
->FreePendingToken(ptr2
, helper_
.get()->InsertToken());
232 void* ptr3
= allocator_
->Alloc(kAlloc3
);
233 EXPECT_EQ(static_cast<uint8_t*>(ptr2
) + kAlloc2
,
234 static_cast<uint8_t*>(ptr3
));
235 EXPECT_EQ(0u, allocator_
->GetLargestFreeSizeNoWaiting());
237 // Discard first block should free it up upon GetLargestFreeSizeNoWaiting().
238 allocator_
->DiscardBlock(ptr1
);
239 EXPECT_EQ(kAlloc1
, allocator_
->GetLargestFreeSizeNoWaiting());
240 allocator_
->FreePendingToken(ptr3
, helper_
.get()->InsertToken());
243 // Test that discarding middle of the buffer merely marks it as padding.
244 TEST_F(RingBufferTest
, DiscardMiddleTest
) {
245 const unsigned int kAlloc1
= 3*kAlignment
;
246 const unsigned int kAlloc2
= 2*kAlignment
;
247 const unsigned int kAlloc3
= kBufferSize
- kAlloc1
- kAlloc2
;
248 void* ptr1
= allocator_
->Alloc(kAlloc1
);
249 EXPECT_EQ(kBufferSize
- kAlloc1
, allocator_
->GetLargestFreeSizeNoWaiting());
250 allocator_
->FreePendingToken(ptr1
, helper_
.get()->InsertToken());
252 void* ptr2
= allocator_
->Alloc(kAlloc2
);
253 EXPECT_EQ(static_cast<uint8_t*>(ptr1
) + kAlloc1
,
254 static_cast<uint8_t*>(ptr2
));
255 EXPECT_EQ(kBufferSize
- kAlloc1
- kAlloc2
,
256 allocator_
->GetLargestFreeSizeNoWaiting());
257 allocator_
->FreePendingToken(ptr2
, helper_
.get()->InsertToken());
259 void* ptr3
= allocator_
->Alloc(kAlloc3
);
260 EXPECT_EQ(static_cast<uint8_t*>(ptr2
) + kAlloc2
,
261 static_cast<uint8_t*>(ptr3
));
262 EXPECT_EQ(0u, allocator_
->GetLargestFreeSizeNoWaiting());
264 // Discard middle block should just set it as padding.
265 allocator_
->DiscardBlock(ptr2
);
266 EXPECT_EQ(0u, allocator_
->GetLargestFreeSizeNoWaiting());
267 allocator_
->FreePendingToken(ptr3
, helper_
.get()->InsertToken());
270 // Test that discarding end of the buffer frees it for no waiting.
271 TEST_F(RingBufferTest
, DiscardEndTest
) {
272 const unsigned int kAlloc1
= 3*kAlignment
;
273 const unsigned int kAlloc2
= 2*kAlignment
;
274 const unsigned int kAlloc3
= kBufferSize
- kAlloc1
- kAlloc2
;
275 void* ptr1
= allocator_
->Alloc(kAlloc1
);
276 EXPECT_EQ(kBufferSize
- kAlloc1
, allocator_
->GetLargestFreeSizeNoWaiting());
277 allocator_
->FreePendingToken(ptr1
, helper_
.get()->InsertToken());
279 void* ptr2
= allocator_
->Alloc(kAlloc2
);
280 EXPECT_EQ(static_cast<uint8_t*>(ptr1
) + kAlloc1
,
281 static_cast<uint8_t*>(ptr2
));
282 EXPECT_EQ(kBufferSize
- kAlloc1
- kAlloc2
,
283 allocator_
->GetLargestFreeSizeNoWaiting());
284 allocator_
->FreePendingToken(ptr2
, helper_
.get()->InsertToken());
286 void* ptr3
= allocator_
->Alloc(kAlloc3
);
287 EXPECT_EQ(static_cast<uint8_t*>(ptr2
) + kAlloc2
,
288 static_cast<uint8_t*>(ptr3
));
289 EXPECT_EQ(0u, allocator_
->GetLargestFreeSizeNoWaiting());
291 // Discard end block should discard it.
292 allocator_
->DiscardBlock(ptr3
);
293 EXPECT_EQ(kAlloc3
, allocator_
->GetLargestFreeSizeNoWaiting());
296 // Test discard end of the buffer that has looped around.
297 TEST_F(RingBufferTest
, DiscardLoopedEndTest
) {
298 const unsigned int kAlloc1
= 3*kAlignment
;
299 const unsigned int kAlloc2
= 2*kAlignment
;
300 const unsigned int kAlloc3
= kBufferSize
- kAlloc1
- kAlloc2
;
301 void* ptr1
= allocator_
->Alloc(kAlloc1
);
302 EXPECT_EQ(kBufferSize
- kAlloc1
, allocator_
->GetLargestFreeSizeNoWaiting());
303 allocator_
->FreePendingToken(ptr1
, helper_
.get()->InsertToken());
305 void* ptr2
= allocator_
->Alloc(kAlloc2
);
306 EXPECT_EQ(static_cast<uint8_t*>(ptr1
) + kAlloc1
,
307 static_cast<uint8_t*>(ptr2
));
308 EXPECT_EQ(kBufferSize
- kAlloc1
- kAlloc2
,
309 allocator_
->GetLargestFreeSizeNoWaiting());
310 allocator_
->FreePendingToken(ptr2
, helper_
.get()->InsertToken());
312 void* ptr3
= allocator_
->Alloc(kAlloc3
);
313 EXPECT_EQ(static_cast<uint8_t*>(ptr2
) + kAlloc2
,
314 static_cast<uint8_t*>(ptr3
));
315 EXPECT_EQ(0u, allocator_
->GetLargestFreeSizeNoWaiting());
316 allocator_
->FreePendingToken(ptr3
, helper_
.get()->InsertToken());
318 // This allocation should be at the beginning again, we need to utilize
319 // DiscardBlock here to discard the first item so that we can allocate
320 // at the beginning without the FreeOldestBlock() getting called and freeing
321 // the whole ring buffer.
322 allocator_
->DiscardBlock(ptr1
);
323 void* ptr4
= allocator_
->Alloc(kAlloc1
);
324 EXPECT_EQ(ptr1
, ptr4
);
325 EXPECT_EQ(0u, allocator_
->GetLargestFreeSizeNoWaiting());
327 // Discard end block should work properly still.
328 allocator_
->DiscardBlock(ptr4
);
329 EXPECT_EQ(kAlloc1
, allocator_
->GetLargestFreeSizeNoWaiting());
332 // Test discard end of the buffer that has looped around with padding.
333 TEST_F(RingBufferTest
, DiscardEndWithPaddingTest
) {
334 const unsigned int kAlloc1
= 3*kAlignment
;
335 const unsigned int kAlloc2
= 2*kAlignment
;
336 const unsigned int kPadding
= kAlignment
;
337 const unsigned int kAlloc3
= kBufferSize
- kAlloc1
- kAlloc2
- kPadding
;
338 void* ptr1
= allocator_
->Alloc(kAlloc1
);
339 EXPECT_EQ(kBufferSize
- kAlloc1
, allocator_
->GetLargestFreeSizeNoWaiting());
340 allocator_
->FreePendingToken(ptr1
, helper_
.get()->InsertToken());
342 void* ptr2
= allocator_
->Alloc(kAlloc2
);
343 EXPECT_EQ(static_cast<uint8_t*>(ptr1
) + kAlloc1
,
344 static_cast<uint8_t*>(ptr2
));
345 EXPECT_EQ(kBufferSize
- kAlloc1
- kAlloc2
,
346 allocator_
->GetLargestFreeSizeNoWaiting());
347 allocator_
->FreePendingToken(ptr2
, helper_
.get()->InsertToken());
349 void* ptr3
= allocator_
->Alloc(kAlloc3
);
350 EXPECT_EQ(static_cast<uint8_t*>(ptr2
) + kAlloc2
,
351 static_cast<uint8_t*>(ptr3
));
352 EXPECT_EQ(kPadding
, allocator_
->GetLargestFreeSizeNoWaiting());
353 allocator_
->FreePendingToken(ptr3
, helper_
.get()->InsertToken());
355 // Cause it to loop around with padding at the end of ptr3.
356 allocator_
->DiscardBlock(ptr1
);
357 void* ptr4
= allocator_
->Alloc(kAlloc1
);
358 EXPECT_EQ(ptr1
, ptr4
);
359 EXPECT_EQ(0u, allocator_
->GetLargestFreeSizeNoWaiting());
361 // Discard end block should also discard the padding.
362 allocator_
->DiscardBlock(ptr4
);
363 EXPECT_EQ(kAlloc1
, allocator_
->GetLargestFreeSizeNoWaiting());
365 // We can test that there is padding by attempting to allocate the padding.
366 void* padding
= allocator_
->Alloc(kPadding
);
367 EXPECT_EQ(kAlloc1
, allocator_
->GetLargestFreeSizeNoWaiting());
368 allocator_
->FreePendingToken(padding
, helper_
.get()->InsertToken());
371 // Test that discard will effectively remove all padding at the end.
372 TEST_F(RingBufferTest
, DiscardAllPaddingFromEndTest
) {
373 const unsigned int kAlloc1
= 3*kAlignment
;
374 const unsigned int kAlloc2
= 2*kAlignment
;
375 const unsigned int kAlloc3
= kBufferSize
- kAlloc1
- kAlloc2
;
376 void* ptr1
= allocator_
->Alloc(kAlloc1
);
377 EXPECT_EQ(kBufferSize
- kAlloc1
, allocator_
->GetLargestFreeSizeNoWaiting());
378 allocator_
->FreePendingToken(ptr1
, helper_
.get()->InsertToken());
380 void* ptr2
= allocator_
->Alloc(kAlloc2
);
381 EXPECT_EQ(static_cast<uint8_t*>(ptr1
) + kAlloc1
,
382 static_cast<uint8_t*>(ptr2
));
383 EXPECT_EQ(kBufferSize
- kAlloc1
- kAlloc2
,
384 allocator_
->GetLargestFreeSizeNoWaiting());
385 allocator_
->FreePendingToken(ptr2
, helper_
.get()->InsertToken());
387 void* ptr3
= allocator_
->Alloc(kAlloc3
);
388 EXPECT_EQ(static_cast<uint8_t*>(ptr2
) + kAlloc2
,
389 static_cast<uint8_t*>(ptr3
));
390 EXPECT_EQ(0u, allocator_
->GetLargestFreeSizeNoWaiting());
392 // Discarding the middle allocation should turn it into padding.
393 allocator_
->DiscardBlock(ptr2
);
394 EXPECT_EQ(0u, allocator_
->GetLargestFreeSizeNoWaiting());
396 // Discarding the last allocation should discard the middle padding as well.
397 allocator_
->DiscardBlock(ptr3
);
398 EXPECT_EQ(kAlloc2
+ kAlloc3
, allocator_
->GetLargestFreeSizeNoWaiting());
401 // Test that discard will effectively remove all padding from the beginning.
402 TEST_F(RingBufferTest
, DiscardAllPaddingFromBeginningTest
) {
403 const unsigned int kAlloc1
= 3*kAlignment
;
404 const unsigned int kAlloc2
= 2*kAlignment
;
405 const unsigned int kAlloc3
= kBufferSize
- kAlloc1
- kAlloc2
;
406 void* ptr1
= allocator_
->Alloc(kAlloc1
);
407 EXPECT_EQ(kBufferSize
- kAlloc1
, allocator_
->GetLargestFreeSizeNoWaiting());
408 allocator_
->FreePendingToken(ptr1
, helper_
.get()->InsertToken());
410 void* ptr2
= allocator_
->Alloc(kAlloc2
);
411 EXPECT_EQ(static_cast<uint8_t*>(ptr1
) + kAlloc1
,
412 static_cast<uint8_t*>(ptr2
));
413 EXPECT_EQ(kBufferSize
- kAlloc1
- kAlloc2
,
414 allocator_
->GetLargestFreeSizeNoWaiting());
415 allocator_
->FreePendingToken(ptr2
, helper_
.get()->InsertToken());
417 void* ptr3
= allocator_
->Alloc(kAlloc3
);
418 EXPECT_EQ(static_cast<uint8_t*>(ptr2
) + kAlloc2
,
419 static_cast<uint8_t*>(ptr3
));
420 EXPECT_EQ(0u, allocator_
->GetLargestFreeSizeNoWaiting());
421 allocator_
->FreePendingToken(ptr3
, helper_
.get()->InsertToken());
423 // Discarding the middle allocation should turn it into padding.
424 allocator_
->DiscardBlock(ptr2
);
425 EXPECT_EQ(0u, allocator_
->GetLargestFreeSizeNoWaiting());
427 // Discarding the first allocation should discard the middle padding as well.
428 allocator_
->DiscardBlock(ptr1
);
429 EXPECT_EQ(kAlloc1
+ kAlloc2
, allocator_
->GetLargestFreeSizeNoWaiting());