• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 // This file contains the tests for the RingBuffer class.
6 
7 #include "gpu/command_buffer/client/ring_buffer.h"
8 
9 #include "base/bind.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"
19 
20 #if defined(OS_MACOSX)
21 #include "base/mac/scoped_nsautorelease_pool.h"
22 #endif
23 
24 namespace gpu {
25 
26 using testing::Return;
27 using testing::Mock;
28 using testing::Truly;
29 using testing::Sequence;
30 using testing::DoAll;
31 using testing::Invoke;
32 using testing::_;
33 
34 class BaseRingBufferTest : public testing::Test {
35  protected:
36   static const unsigned int kBaseOffset = 128;
37   static const unsigned int kBufferSize = 1024;
38 
RunPendingSetToken()39   void RunPendingSetToken() {
40     for (std::vector<const void*>::iterator it = set_token_arguments_.begin();
41          it != set_token_arguments_.end();
42          ++it) {
43       api_mock_->SetToken(cmd::kSetToken, 1, *it);
44     }
45     set_token_arguments_.clear();
46     delay_set_token_ = false;
47   }
48 
SetToken(unsigned int command,unsigned int arg_count,const void * _args)49   void SetToken(unsigned int command,
50                 unsigned int arg_count,
51                 const void* _args) {
52     EXPECT_EQ(static_cast<unsigned int>(cmd::kSetToken), command);
53     EXPECT_EQ(1u, arg_count);
54     if (delay_set_token_)
55       set_token_arguments_.push_back(_args);
56     else
57       api_mock_->SetToken(cmd::kSetToken, 1, _args);
58   }
59 
SetUp()60   virtual void SetUp() {
61     delay_set_token_ = false;
62     api_mock_.reset(new AsyncAPIMock);
63     // ignore noops in the mock - we don't want to inspect the internals of the
64     // helper.
65     EXPECT_CALL(*api_mock_, DoCommand(cmd::kNoop, 0, _))
66         .WillRepeatedly(Return(error::kNoError));
67     // Forward the SetToken calls to the engine
68     EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
69         .WillRepeatedly(DoAll(Invoke(this, &BaseRingBufferTest::SetToken),
70                               Return(error::kNoError)));
71 
72     {
73       TransferBufferManager* manager = new TransferBufferManager();
74       transfer_buffer_manager_.reset(manager);
75       EXPECT_TRUE(manager->Initialize());
76     }
77     command_buffer_.reset(
78         new CommandBufferService(transfer_buffer_manager_.get()));
79     EXPECT_TRUE(command_buffer_->Initialize());
80 
81     gpu_scheduler_.reset(new GpuScheduler(
82         command_buffer_.get(), api_mock_.get(), NULL));
83     command_buffer_->SetPutOffsetChangeCallback(base::Bind(
84         &GpuScheduler::PutChanged, base::Unretained(gpu_scheduler_.get())));
85     command_buffer_->SetGetBufferChangeCallback(base::Bind(
86         &GpuScheduler::SetGetBuffer, base::Unretained(gpu_scheduler_.get())));
87 
88     api_mock_->set_engine(gpu_scheduler_.get());
89 
90     helper_.reset(new CommandBufferHelper(command_buffer_.get()));
91     helper_->Initialize(kBufferSize);
92   }
93 
GetToken()94   int32 GetToken() {
95     return command_buffer_->GetState().token;
96   }
97 
98 #if defined(OS_MACOSX)
99   base::mac::ScopedNSAutoreleasePool autorelease_pool_;
100 #endif
101   base::MessageLoop message_loop_;
102   scoped_ptr<AsyncAPIMock> api_mock_;
103   scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_;
104   scoped_ptr<CommandBufferService> command_buffer_;
105   scoped_ptr<GpuScheduler> gpu_scheduler_;
106   scoped_ptr<CommandBufferHelper> helper_;
107   std::vector<const void*> set_token_arguments_;
108   bool delay_set_token_;
109 
110 };
111 
112 #ifndef _MSC_VER
113 const unsigned int BaseRingBufferTest::kBaseOffset;
114 const unsigned int BaseRingBufferTest::kBufferSize;
115 #endif
116 
117 // Test fixture for RingBuffer test - Creates a RingBuffer, using a
118 // CommandBufferHelper with a mock AsyncAPIInterface for its interface (calling
119 // it directly, not through the RPC mechanism), making sure Noops are ignored
120 // and SetToken are properly forwarded to the engine.
121 class RingBufferTest : public BaseRingBufferTest {
122  protected:
SetUp()123   virtual void SetUp() {
124     BaseRingBufferTest::SetUp();
125     allocator_.reset(new RingBuffer(kBaseOffset, kBufferSize, helper_.get()));
126   }
127 
TearDown()128   virtual void TearDown() {
129     // If the GpuScheduler posts any tasks, this forces them to run.
130     base::MessageLoop::current()->RunUntilIdle();
131 
132     BaseRingBufferTest::TearDown();
133   }
134 
135   scoped_ptr<RingBuffer> allocator_;
136 };
137 
138 // Checks basic alloc and free.
TEST_F(RingBufferTest,TestBasic)139 TEST_F(RingBufferTest, TestBasic) {
140   const unsigned int kSize = 16;
141   EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeOrPendingSize());
142   EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeSizeNoWaiting());
143   RingBuffer::Offset offset = allocator_->Alloc(kSize);
144   EXPECT_GE(kBufferSize, offset - kBaseOffset + kSize);
145   EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeOrPendingSize());
146   EXPECT_EQ(kBufferSize - kSize, allocator_->GetLargestFreeSizeNoWaiting());
147   int32 token = helper_->InsertToken();
148   allocator_->FreePendingToken(offset, token);
149 }
150 
151 // Checks the free-pending-token mechanism.
TEST_F(RingBufferTest,TestFreePendingToken)152 TEST_F(RingBufferTest, TestFreePendingToken) {
153   const unsigned int kSize = 16;
154   const unsigned int kAllocCount = kBufferSize / kSize;
155   CHECK(kAllocCount * kSize == kBufferSize);
156 
157   delay_set_token_ = true;
158   // Allocate several buffers to fill in the memory.
159   int32 tokens[kAllocCount];
160   for (unsigned int ii = 0; ii < kAllocCount; ++ii) {
161     RingBuffer::Offset offset = allocator_->Alloc(kSize);
162     EXPECT_GE(kBufferSize, offset - kBaseOffset + kSize);
163     tokens[ii] = helper_->InsertToken();
164     allocator_->FreePendingToken(offset, tokens[ii]);
165   }
166 
167   EXPECT_EQ(kBufferSize - (kSize * kAllocCount),
168             allocator_->GetLargestFreeSizeNoWaiting());
169 
170   RunPendingSetToken();
171 
172   // This allocation will need to reclaim the space freed above, so that should
173   // process the commands until a token is passed.
174   RingBuffer::Offset offset1 = allocator_->Alloc(kSize);
175   EXPECT_EQ(kBaseOffset, offset1);
176 
177   // Check that the token has indeed passed.
178   EXPECT_LE(tokens[0], GetToken());
179 
180   allocator_->FreePendingToken(offset1, helper_->InsertToken());
181 }
182 
183 // Tests GetLargestFreeSizeNoWaiting
TEST_F(RingBufferTest,TestGetLargestFreeSizeNoWaiting)184 TEST_F(RingBufferTest, TestGetLargestFreeSizeNoWaiting) {
185   EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeSizeNoWaiting());
186 
187   RingBuffer::Offset offset = allocator_->Alloc(kBufferSize);
188   EXPECT_EQ(0u, allocator_->GetLargestFreeSizeNoWaiting());
189   allocator_->FreePendingToken(offset, helper_->InsertToken());
190 }
191 
TEST_F(RingBufferTest,TestFreeBug)192 TEST_F(RingBufferTest, TestFreeBug) {
193   // The first and second allocations must not match.
194   const unsigned int kAlloc1 = 10;
195   const unsigned int kAlloc2 = 20;
196   RingBuffer::Offset offset = allocator_->Alloc(kAlloc1);
197   EXPECT_EQ(kBufferSize - kAlloc1, allocator_->GetLargestFreeSizeNoWaiting());
198   allocator_->FreePendingToken(offset, helper_.get()->InsertToken());
199   offset = allocator_->Alloc(kAlloc2);
200   EXPECT_EQ(kBufferSize - kAlloc1 - kAlloc2,
201             allocator_->GetLargestFreeSizeNoWaiting());
202   allocator_->FreePendingToken(offset, helper_.get()->InsertToken());
203   offset = allocator_->Alloc(kBufferSize);
204   EXPECT_EQ(0u, allocator_->GetLargestFreeSizeNoWaiting());
205   allocator_->FreePendingToken(offset, helper_.get()->InsertToken());
206 }
207 
208 // Test fixture for RingBufferWrapper test - Creates a
209 // RingBufferWrapper, using a CommandBufferHelper with a mock
210 // AsyncAPIInterface for its interface (calling it directly, not through the
211 // RPC mechanism), making sure Noops are ignored and SetToken are properly
212 // forwarded to the engine.
213 class RingBufferWrapperTest : public BaseRingBufferTest {
214  protected:
SetUp()215   virtual void SetUp() {
216     BaseRingBufferTest::SetUp();
217 
218     // Though allocating this buffer isn't strictly necessary, it makes
219     // allocations point to valid addresses, so they could be used for
220     // something.
221     buffer_.reset(new int8[kBufferSize + kBaseOffset]);
222     buffer_start_ = buffer_.get() + kBaseOffset;
223     allocator_.reset(new RingBufferWrapper(
224         kBaseOffset, kBufferSize, helper_.get(), buffer_start_));
225   }
226 
TearDown()227   virtual void TearDown() {
228     // If the GpuScheduler posts any tasks, this forces them to run.
229     base::MessageLoop::current()->RunUntilIdle();
230 
231     BaseRingBufferTest::TearDown();
232   }
233 
234   scoped_ptr<RingBufferWrapper> allocator_;
235   scoped_ptr<int8[]> buffer_;
236   int8* buffer_start_;
237 };
238 
239 // Checks basic alloc and free.
TEST_F(RingBufferWrapperTest,TestBasic)240 TEST_F(RingBufferWrapperTest, TestBasic) {
241   const unsigned int kSize = 16;
242   void* pointer = allocator_->Alloc(kSize);
243   ASSERT_TRUE(pointer);
244   EXPECT_LE(buffer_start_, static_cast<int8*>(pointer));
245   EXPECT_GE(kBufferSize, static_cast<int8*>(pointer) - buffer_start_ + kSize);
246 
247   allocator_->FreePendingToken(pointer, helper_->InsertToken());
248 
249   int8* pointer_int8 = allocator_->AllocTyped<int8>(kSize);
250   ASSERT_TRUE(pointer_int8);
251   EXPECT_LE(buffer_start_, pointer_int8);
252   EXPECT_GE(buffer_start_ + kBufferSize, pointer_int8 + kSize);
253   allocator_->FreePendingToken(pointer_int8, helper_->InsertToken());
254 
255   unsigned int* pointer_uint = allocator_->AllocTyped<unsigned int>(kSize);
256   ASSERT_TRUE(pointer_uint);
257   EXPECT_LE(buffer_start_, reinterpret_cast<int8*>(pointer_uint));
258   EXPECT_GE(buffer_start_ + kBufferSize,
259             reinterpret_cast<int8* >(pointer_uint + kSize));
260 
261   // Check that it did allocate kSize * sizeof(unsigned int). We can't tell
262   // directly, except from the remaining size.
263   EXPECT_EQ(kBufferSize - kSize - kSize - kSize * sizeof(*pointer_uint),
264             allocator_->GetLargestFreeSizeNoWaiting());
265   allocator_->FreePendingToken(pointer_uint, helper_->InsertToken());
266 }
267 
268 // Checks the free-pending-token mechanism.
TEST_F(RingBufferWrapperTest,TestFreePendingToken)269 TEST_F(RingBufferWrapperTest, TestFreePendingToken) {
270   const unsigned int kSize = 16;
271   const unsigned int kAllocCount = kBufferSize / kSize;
272   CHECK(kAllocCount * kSize == kBufferSize);
273 
274   delay_set_token_ = true;
275   // Allocate several buffers to fill in the memory.
276   int32 tokens[kAllocCount];
277   for (unsigned int ii = 0; ii < kAllocCount; ++ii) {
278     void* pointer = allocator_->Alloc(kSize);
279     EXPECT_TRUE(pointer != NULL);
280     tokens[ii] = helper_->InsertToken();
281     allocator_->FreePendingToken(pointer, helper_->InsertToken());
282   }
283 
284   EXPECT_EQ(kBufferSize - (kSize * kAllocCount),
285             allocator_->GetLargestFreeSizeNoWaiting());
286 
287   RunPendingSetToken();
288 
289   // This allocation will need to reclaim the space freed above, so that should
290   // process the commands until the token is passed.
291   void* pointer1 = allocator_->Alloc(kSize);
292   EXPECT_EQ(buffer_start_, static_cast<int8*>(pointer1));
293 
294   // Check that the token has indeed passed.
295   EXPECT_LE(tokens[0], GetToken());
296 
297   allocator_->FreePendingToken(pointer1, helper_->InsertToken());
298   EXPECT_LE(command_buffer_->GetState().token, helper_->InsertToken());
299 }
300 
301 }  // namespace gpu
302