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   static const unsigned int kAlignment = 4;
     39 
     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 
     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 
     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 
     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:
    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 
    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.
    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.
    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
    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 
    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