Home | History | Annotate | Download | only in client
      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 
     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 
     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 
     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 
     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:
    123   virtual void SetUp() {
    124     BaseRingBufferTest::SetUp();
    125     allocator_.reset(new RingBuffer(kBaseOffset, kBufferSize, helper_.get()));
    126   }
    127 
    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.
    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.
    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
    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 
    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:
    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 
    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.
    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.
    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