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_
.reset(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_ptr
<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());