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 "base/message_loop/message_loop.h"
12 #include "gpu/command_buffer/client/cmd_buffer_helper.h"
13 #include "gpu/command_buffer/service/cmd_buffer_engine.h"
14 #include "gpu/command_buffer/service/command_buffer_service.h"
15 #include "gpu/command_buffer/service/gpu_scheduler.h"
16 #include "gpu/command_buffer/service/mocks.h"
17 #include "gpu/command_buffer/service/transfer_buffer_manager.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 #if defined(OS_MACOSX)
21 #include "base/mac/scoped_nsautorelease_pool.h"
26 using testing::Return
;
29 using testing::Sequence
;
31 using testing::Invoke
;
34 class BaseRingBufferTest
: public testing::Test
{
36 static const unsigned int kBaseOffset
= 128;
37 static const unsigned int kBufferSize
= 1024;
38 static const unsigned int kAlignment
= 4;
40 void RunPendingSetToken() {
41 for (std::vector
<const void*>::iterator it
= set_token_arguments_
.begin();
42 it
!= set_token_arguments_
.end();
44 api_mock_
->SetToken(cmd::kSetToken
, 1, *it
);
46 set_token_arguments_
.clear();
47 delay_set_token_
= false;
50 void SetToken(unsigned int command
,
51 unsigned int arg_count
,
53 EXPECT_EQ(static_cast<unsigned int>(cmd::kSetToken
), command
);
54 EXPECT_EQ(1u, arg_count
);
56 set_token_arguments_
.push_back(_args
);
58 api_mock_
->SetToken(cmd::kSetToken
, 1, _args
);
61 void SetUp() override
{
62 delay_set_token_
= false;
63 api_mock_
.reset(new AsyncAPIMock(true));
64 // ignore noops in the mock - we don't want to inspect the internals of the
66 EXPECT_CALL(*api_mock_
, DoCommand(cmd::kNoop
, 0, _
))
67 .WillRepeatedly(Return(error::kNoError
));
68 // Forward the SetToken calls to the engine
69 EXPECT_CALL(*api_mock_
.get(), DoCommand(cmd::kSetToken
, 1, _
))
70 .WillRepeatedly(DoAll(Invoke(this, &BaseRingBufferTest::SetToken
),
71 Return(error::kNoError
)));
74 TransferBufferManager
* manager
= new TransferBufferManager();
75 transfer_buffer_manager_
.reset(manager
);
76 EXPECT_TRUE(manager
->Initialize());
78 command_buffer_
.reset(
79 new CommandBufferService(transfer_buffer_manager_
.get()));
80 EXPECT_TRUE(command_buffer_
->Initialize());
82 gpu_scheduler_
.reset(new GpuScheduler(
83 command_buffer_
.get(), api_mock_
.get(), NULL
));
84 command_buffer_
->SetPutOffsetChangeCallback(base::Bind(
85 &GpuScheduler::PutChanged
, base::Unretained(gpu_scheduler_
.get())));
86 command_buffer_
->SetGetBufferChangeCallback(base::Bind(
87 &GpuScheduler::SetGetBuffer
, base::Unretained(gpu_scheduler_
.get())));
89 api_mock_
->set_engine(gpu_scheduler_
.get());
91 helper_
.reset(new CommandBufferHelper(command_buffer_
.get()));
92 helper_
->Initialize(kBufferSize
);
96 return command_buffer_
->GetLastState().token
;
99 #if defined(OS_MACOSX)
100 base::mac::ScopedNSAutoreleasePool autorelease_pool_
;
102 base::MessageLoop message_loop_
;
103 scoped_ptr
<AsyncAPIMock
> api_mock_
;
104 scoped_ptr
<TransferBufferManagerInterface
> transfer_buffer_manager_
;
105 scoped_ptr
<CommandBufferService
> command_buffer_
;
106 scoped_ptr
<GpuScheduler
> gpu_scheduler_
;
107 scoped_ptr
<CommandBufferHelper
> helper_
;
108 std::vector
<const void*> set_token_arguments_
;
109 bool delay_set_token_
;
111 scoped_ptr
<int8
[]> buffer_
;
116 const unsigned int BaseRingBufferTest::kBaseOffset
;
117 const unsigned int BaseRingBufferTest::kBufferSize
;
120 // Test fixture for RingBuffer test - Creates a RingBuffer, using a
121 // CommandBufferHelper with a mock AsyncAPIInterface for its interface (calling
122 // it directly, not through the RPC mechanism), making sure Noops are ignored
123 // and SetToken are properly forwarded to the engine.
124 class RingBufferTest
: public BaseRingBufferTest
{
126 void SetUp() override
{
127 BaseRingBufferTest::SetUp();
129 buffer_
.reset(new int8
[kBufferSize
+ kBaseOffset
]);
130 buffer_start_
= buffer_
.get() + kBaseOffset
;
131 allocator_
.reset(new RingBuffer(kAlignment
, kBaseOffset
, kBufferSize
,
132 helper_
.get(), buffer_start_
));
135 void TearDown() override
{
136 // If the GpuScheduler posts any tasks, this forces them to run.
137 base::MessageLoop::current()->RunUntilIdle();
139 BaseRingBufferTest::TearDown();
142 scoped_ptr
<RingBuffer
> allocator_
;
145 // Checks basic alloc and free.
146 TEST_F(RingBufferTest
, TestBasic
) {
147 const unsigned int kSize
= 16;
148 EXPECT_EQ(kBufferSize
, allocator_
->GetLargestFreeOrPendingSize());
149 EXPECT_EQ(kBufferSize
, allocator_
->GetLargestFreeSizeNoWaiting());
150 void* pointer
= allocator_
->Alloc(kSize
);
151 EXPECT_GE(kBufferSize
, allocator_
->GetOffset(pointer
) - kBaseOffset
+ kSize
);
152 EXPECT_EQ(kBufferSize
, allocator_
->GetLargestFreeOrPendingSize());
153 EXPECT_EQ(kBufferSize
- kSize
, allocator_
->GetLargestFreeSizeNoWaiting());
154 int32 token
= helper_
->InsertToken();
155 allocator_
->FreePendingToken(pointer
, token
);
158 // Checks the free-pending-token mechanism.
159 TEST_F(RingBufferTest
, TestFreePendingToken
) {
160 const unsigned int kSize
= 16;
161 const unsigned int kAllocCount
= kBufferSize
/ kSize
;
162 CHECK(kAllocCount
* kSize
== kBufferSize
);
164 delay_set_token_
= true;
165 // Allocate several buffers to fill in the memory.
166 int32 tokens
[kAllocCount
];
167 for (unsigned int ii
= 0; ii
< kAllocCount
; ++ii
) {
168 void* pointer
= allocator_
->Alloc(kSize
);
169 EXPECT_GE(kBufferSize
,
170 allocator_
->GetOffset(pointer
) - kBaseOffset
+ kSize
);
171 tokens
[ii
] = helper_
->InsertToken();
172 allocator_
->FreePendingToken(pointer
, tokens
[ii
]);
175 EXPECT_EQ(kBufferSize
- (kSize
* kAllocCount
),
176 allocator_
->GetLargestFreeSizeNoWaiting());
178 RunPendingSetToken();
180 // This allocation will need to reclaim the space freed above, so that should
181 // process the commands until a token is passed.
182 void* pointer1
= allocator_
->Alloc(kSize
);
183 EXPECT_EQ(kBaseOffset
, allocator_
->GetOffset(pointer1
));
185 // Check that the token has indeed passed.
186 EXPECT_LE(tokens
[0], GetToken());
188 allocator_
->FreePendingToken(pointer1
, helper_
->InsertToken());
191 // Tests GetLargestFreeSizeNoWaiting
192 TEST_F(RingBufferTest
, TestGetLargestFreeSizeNoWaiting
) {
193 EXPECT_EQ(kBufferSize
, allocator_
->GetLargestFreeSizeNoWaiting());
195 void* pointer
= allocator_
->Alloc(kBufferSize
);
196 EXPECT_EQ(0u, allocator_
->GetLargestFreeSizeNoWaiting());
197 allocator_
->FreePendingToken(pointer
, helper_
->InsertToken());
200 TEST_F(RingBufferTest
, TestFreeBug
) {
201 // The first and second allocations must not match.
202 const unsigned int kAlloc1
= 3*kAlignment
;
203 const unsigned int kAlloc2
= 20;
204 void* pointer
= allocator_
->Alloc(kAlloc1
);
205 EXPECT_EQ(kBufferSize
- kAlloc1
, allocator_
->GetLargestFreeSizeNoWaiting());
206 allocator_
->FreePendingToken(pointer
, helper_
.get()->InsertToken());
207 pointer
= allocator_
->Alloc(kAlloc2
);
208 EXPECT_EQ(kBufferSize
- kAlloc1
- kAlloc2
,
209 allocator_
->GetLargestFreeSizeNoWaiting());
210 allocator_
->FreePendingToken(pointer
, helper_
.get()->InsertToken());
211 pointer
= allocator_
->Alloc(kBufferSize
);
212 EXPECT_EQ(0u, allocator_
->GetLargestFreeSizeNoWaiting());
213 allocator_
->FreePendingToken(pointer
, helper_
.get()->InsertToken());