• 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   static const unsigned int kAlignment = 4;
39 
RunPendingSetToken()40   void RunPendingSetToken() {
41     for (std::vector<const void*>::iterator it = set_token_arguments_.begin();
42          it != set_token_arguments_.end();
43          ++it) {
44       api_mock_->SetToken(cmd::kSetToken, 1, *it);
45     }
46     set_token_arguments_.clear();
47     delay_set_token_ = false;
48   }
49 
SetToken(unsigned int command,unsigned int arg_count,const void * _args)50   void SetToken(unsigned int command,
51                 unsigned int arg_count,
52                 const void* _args) {
53     EXPECT_EQ(static_cast<unsigned int>(cmd::kSetToken), command);
54     EXPECT_EQ(1u, arg_count);
55     if (delay_set_token_)
56       set_token_arguments_.push_back(_args);
57     else
58       api_mock_->SetToken(cmd::kSetToken, 1, _args);
59   }
60 
SetUp()61   virtual void SetUp() {
62     delay_set_token_ = false;
63     api_mock_.reset(new AsyncAPIMock);
64     // ignore noops in the mock - we don't want to inspect the internals of the
65     // helper.
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)));
72 
73     {
74       TransferBufferManager* manager = new TransferBufferManager();
75       transfer_buffer_manager_.reset(manager);
76       EXPECT_TRUE(manager->Initialize());
77     }
78     command_buffer_.reset(
79         new CommandBufferService(transfer_buffer_manager_.get()));
80     EXPECT_TRUE(command_buffer_->Initialize());
81 
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())));
88 
89     api_mock_->set_engine(gpu_scheduler_.get());
90 
91     helper_.reset(new CommandBufferHelper(command_buffer_.get()));
92     helper_->Initialize(kBufferSize);
93   }
94 
GetToken()95   int32 GetToken() {
96     return command_buffer_->GetLastState().token;
97   }
98 
99 #if defined(OS_MACOSX)
100   base::mac::ScopedNSAutoreleasePool autorelease_pool_;
101 #endif
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_;
110 
111   scoped_ptr<int8[]> buffer_;
112   int8* buffer_start_;
113 };
114 
115 #ifndef _MSC_VER
116 const unsigned int BaseRingBufferTest::kBaseOffset;
117 const unsigned int BaseRingBufferTest::kBufferSize;
118 #endif
119 
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 {
125  protected:
SetUp()126   virtual void SetUp() {
127     BaseRingBufferTest::SetUp();
128 
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_));
133   }
134 
TearDown()135   virtual void TearDown() {
136     // If the GpuScheduler posts any tasks, this forces them to run.
137     base::MessageLoop::current()->RunUntilIdle();
138 
139     BaseRingBufferTest::TearDown();
140   }
141 
142   scoped_ptr<RingBuffer> allocator_;
143 };
144 
145 // Checks basic alloc and free.
TEST_F(RingBufferTest,TestBasic)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);
156 }
157 
158 // Checks the free-pending-token mechanism.
TEST_F(RingBufferTest,TestFreePendingToken)159 TEST_F(RingBufferTest, TestFreePendingToken) {
160   const unsigned int kSize = 16;
161   const unsigned int kAllocCount = kBufferSize / kSize;
162   CHECK(kAllocCount * kSize == kBufferSize);
163 
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]);
173   }
174 
175   EXPECT_EQ(kBufferSize - (kSize * kAllocCount),
176             allocator_->GetLargestFreeSizeNoWaiting());
177 
178   RunPendingSetToken();
179 
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));
184 
185   // Check that the token has indeed passed.
186   EXPECT_LE(tokens[0], GetToken());
187 
188   allocator_->FreePendingToken(pointer1, helper_->InsertToken());
189 }
190 
191 // Tests GetLargestFreeSizeNoWaiting
TEST_F(RingBufferTest,TestGetLargestFreeSizeNoWaiting)192 TEST_F(RingBufferTest, TestGetLargestFreeSizeNoWaiting) {
193   EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeSizeNoWaiting());
194 
195   void* pointer = allocator_->Alloc(kBufferSize);
196   EXPECT_EQ(0u, allocator_->GetLargestFreeSizeNoWaiting());
197   allocator_->FreePendingToken(pointer, helper_->InsertToken());
198 }
199 
TEST_F(RingBufferTest,TestFreeBug)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());
214 }
215 
216 }  // namespace gpu
217