This source file includes following definitions.
- last_flush_
 
- Flush
 
- LockFlush
 
- UnlockFlush
 
- WaitForGetOffsetInRange
 
- SetUp
 
- TearDown
 
- GetParser
 
- ImmediateEntryCount
 
- AddCommandWithExpect
 
- AddUniqueCommandWithExpect
 
- TestCommandWrappingFull
 
- CheckFreeSpace
 
- GetGetOffset
 
- GetPutOffset
 
- GetHelperGetOffset
 
- GetHelperPutOffset
 
- GetHelperFlushGeneration
 
- GetError
 
- get_helper_put
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
- TEST_F
 
#include <list>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/memory/linked_ptr.h"
#include "base/message_loop/message_loop.h"
#include "gpu/command_buffer/client/cmd_buffer_helper.h"
#include "gpu/command_buffer/service/command_buffer_service.h"
#include "gpu/command_buffer/service/gpu_scheduler.h"
#include "gpu/command_buffer/service/mocks.h"
#include "gpu/command_buffer/service/transfer_buffer_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_MACOSX)
#include "base/mac/scoped_nsautorelease_pool.h"
#endif
namespace gpu {
using testing::Return;
using testing::Mock;
using testing::Truly;
using testing::Sequence;
using testing::DoAll;
using testing::Invoke;
using testing::_;
const int32 kTotalNumCommandEntries = 32;
const int32 kCommandBufferSizeBytes =
    kTotalNumCommandEntries * sizeof(CommandBufferEntry);
const int32 kUnusedCommandId = 5;  
class CommandBufferServiceLocked : public CommandBufferService {
 public:
  explicit CommandBufferServiceLocked(
      TransferBufferManagerInterface* transfer_buffer_manager)
      : CommandBufferService(transfer_buffer_manager),
        flush_locked_(false),
        last_flush_(-1) {}
  virtual ~CommandBufferServiceLocked() {}
  virtual void Flush(int32 put_offset) OVERRIDE {
    if (!flush_locked_) {
      last_flush_ = -1;
      CommandBufferService::Flush(put_offset);
    } else {
      last_flush_ = put_offset;
    }
  }
  void LockFlush() { flush_locked_ = true; }
  void UnlockFlush() { flush_locked_ = false; }
  virtual void WaitForGetOffsetInRange(int32 start, int32 end) OVERRIDE {
    if (last_flush_ != -1) {
      CommandBufferService::Flush(last_flush_);
      last_flush_ = -1;
    }
    CommandBufferService::WaitForGetOffsetInRange(start, end);
  }
 private:
  bool flush_locked_;
  int last_flush_;
  DISALLOW_COPY_AND_ASSIGN(CommandBufferServiceLocked);
};
class CommandBufferHelperTest : public testing::Test {
 protected:
  virtual void SetUp() {
    api_mock_.reset(new AsyncAPIMock);
    
    
    EXPECT_CALL(*api_mock_, DoCommand(cmd::kNoop, _, _))
        .WillRepeatedly(Return(error::kNoError));
    {
      TransferBufferManager* manager = new TransferBufferManager();
      transfer_buffer_manager_.reset(manager);
      EXPECT_TRUE(manager->Initialize());
    }
    command_buffer_.reset(
        new CommandBufferServiceLocked(transfer_buffer_manager_.get()));
    EXPECT_TRUE(command_buffer_->Initialize());
    gpu_scheduler_.reset(new GpuScheduler(
        command_buffer_.get(), api_mock_.get(), NULL));
    command_buffer_->SetPutOffsetChangeCallback(base::Bind(
        &GpuScheduler::PutChanged, base::Unretained(gpu_scheduler_.get())));
    command_buffer_->SetGetBufferChangeCallback(base::Bind(
        &GpuScheduler::SetGetBuffer, base::Unretained(gpu_scheduler_.get())));
    api_mock_->set_engine(gpu_scheduler_.get());
    helper_.reset(new CommandBufferHelper(command_buffer_.get()));
    helper_->Initialize(kCommandBufferSizeBytes);
    test_command_next_id_ = kUnusedCommandId;
  }
  virtual void TearDown() {
    
    base::MessageLoop::current()->RunUntilIdle();
    test_command_args_.clear();
  }
  const CommandParser* GetParser() const {
    return gpu_scheduler_->parser();
  }
  int32 ImmediateEntryCount() const { return helper_->immediate_entry_count_; }
  
  
  void AddCommandWithExpect(error::Error _return,
                            unsigned int command,
                            int arg_count,
                            CommandBufferEntry *args) {
    CommandHeader header;
    header.size = arg_count + 1;
    header.command = command;
    CommandBufferEntry* cmds = helper_->GetSpace(arg_count + 1);
    CommandBufferOffset put = 0;
    cmds[put++].value_header = header;
    for (int ii = 0; ii < arg_count; ++ii) {
      cmds[put++] = args[ii];
    }
    EXPECT_CALL(*api_mock_, DoCommand(command, arg_count,
        Truly(AsyncAPIMock::IsArgs(arg_count, args))))
        .InSequence(sequence_)
        .WillOnce(Return(_return));
  }
  void AddUniqueCommandWithExpect(error::Error _return, int cmd_size) {
    EXPECT_GE(cmd_size, 1);
    EXPECT_LT(cmd_size, kTotalNumCommandEntries);
    int arg_count = cmd_size - 1;
    
    linked_ptr<std::vector<CommandBufferEntry> > args_ptr(
        new std::vector<CommandBufferEntry>(arg_count ? arg_count : 1));
    for (int32 ii = 0; ii < arg_count; ++ii) {
      (*args_ptr)[ii].value_uint32 = 0xF00DF00D + ii;
    }
    
    AddCommandWithExpect(
        _return, test_command_next_id_++, arg_count, &(*args_ptr)[0]);
    test_command_args_.insert(test_command_args_.end(), args_ptr);
  }
  void TestCommandWrappingFull(int32 cmd_size, int32 start_commands) {
    const int32 num_args = cmd_size - 1;
    EXPECT_EQ(kTotalNumCommandEntries % cmd_size, 0);
    std::vector<CommandBufferEntry> args(num_args);
    for (int32 ii = 0; ii < num_args; ++ii) {
      args[ii].value_uint32 = ii + 1;
    }
    
    for (int32 ii = 0; ii < start_commands; ++ii) {
      AddCommandWithExpect(
          error::kNoError, ii + kUnusedCommandId, num_args, &args[0]);
    }
    helper_->Finish();
    EXPECT_EQ(GetParser()->put(),
              (start_commands * cmd_size) % kTotalNumCommandEntries);
    EXPECT_EQ(GetParser()->get(),
              (start_commands * cmd_size) % kTotalNumCommandEntries);
    
    command_buffer_->LockFlush();
    
    for (int32 ii = 0; ii < kTotalNumCommandEntries / cmd_size + 2; ++ii) {
      AddCommandWithExpect(error::kNoError,
                           start_commands + ii + kUnusedCommandId,
                           num_args,
                           &args[0]);
    }
    
    command_buffer_->UnlockFlush();
    helper_->Finish();
    
    Mock::VerifyAndClearExpectations(api_mock_.get());
    
    EXPECT_EQ(error::kNoError, GetError());
  }
  
  void CheckFreeSpace(CommandBufferOffset put, unsigned int size) {
    CommandBufferOffset parser_put = GetParser()->put();
    CommandBufferOffset parser_get = GetParser()->get();
    CommandBufferOffset limit = put + size;
    if (parser_get > parser_put) {
      
      
      EXPECT_LE(parser_put, put);
      EXPECT_GT(parser_get, limit);
    } else {
      
      
      if (put >= parser_put) {
        
        EXPECT_GE(kTotalNumCommandEntries, limit);
      } else {
        
        EXPECT_GT(parser_get, limit);
      }
    }
  }
  int32 GetGetOffset() {
    return command_buffer_->GetState().get_offset;
  }
  int32 GetPutOffset() {
    return command_buffer_->GetState().put_offset;
  }
  int32 GetHelperGetOffset() { return helper_->get_offset(); }
  int32 GetHelperPutOffset() { return helper_->put_; }
  uint32 GetHelperFlushGeneration() { return helper_->flush_generation(); }
  error::Error GetError() {
    return command_buffer_->GetState().error;
  }
  CommandBufferOffset get_helper_put() { return helper_->put_; }
#if defined(OS_MACOSX)
  base::mac::ScopedNSAutoreleasePool autorelease_pool_;
#endif
  base::MessageLoop message_loop_;
  scoped_ptr<AsyncAPIMock> api_mock_;
  scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_;
  scoped_ptr<CommandBufferServiceLocked> command_buffer_;
  scoped_ptr<GpuScheduler> gpu_scheduler_;
  scoped_ptr<CommandBufferHelper> helper_;
  std::list<linked_ptr<std::vector<CommandBufferEntry> > > test_command_args_;
  unsigned int test_command_next_id_;
  Sequence sequence_;
};
TEST_F(CommandBufferHelperTest, TestCalcImmediateEntriesNotUsable) {
  
  helper_->SetAutomaticFlushes(false);
  EXPECT_EQ(helper_->usable(), true);
  EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries - 1);
  helper_->ClearUsable();
  EXPECT_EQ(ImmediateEntryCount(), 0);
}
TEST_F(CommandBufferHelperTest, TestCalcImmediateEntriesNoRingBuffer) {
  helper_->SetAutomaticFlushes(false);
  EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries - 1);
  helper_->FreeRingBuffer();
  EXPECT_EQ(ImmediateEntryCount(), 0);
}
TEST_F(CommandBufferHelperTest, TestCalcImmediateEntriesGetAtZero) {
  
  helper_->SetAutomaticFlushes(false);
  command_buffer_->LockFlush();
  
  EXPECT_EQ(GetHelperPutOffset(), 0);
  EXPECT_EQ(GetHelperGetOffset(), 0);
  
  EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries - 1);
  AddUniqueCommandWithExpect(error::kNoError, 2);
  EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries - 3);
  helper_->Finish();
  
  Mock::VerifyAndClearExpectations(api_mock_.get());
  
  EXPECT_EQ(error::kNoError, GetError());
}
TEST_F(CommandBufferHelperTest, TestCalcImmediateEntriesGetInMiddle) {
  
  helper_->SetAutomaticFlushes(false);
  command_buffer_->LockFlush();
  
  AddUniqueCommandWithExpect(error::kNoError, 2);
  helper_->Finish();
  EXPECT_EQ(GetHelperPutOffset(), 2);
  EXPECT_EQ(GetHelperGetOffset(), 2);
  
  EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries - 2);
  AddUniqueCommandWithExpect(error::kNoError, 2);
  EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries - 4);
  helper_->Finish();
  
  Mock::VerifyAndClearExpectations(api_mock_.get());
  
  EXPECT_EQ(error::kNoError, GetError());
}
TEST_F(CommandBufferHelperTest, TestCalcImmediateEntriesGetBeforePut) {
  
  const int kInitGetOffset = kTotalNumCommandEntries / 4;
  helper_->SetAutomaticFlushes(false);
  command_buffer_->LockFlush();
  AddUniqueCommandWithExpect(error::kNoError, kInitGetOffset);
  helper_->Finish();
  AddUniqueCommandWithExpect(error::kNoError,
                             kTotalNumCommandEntries - kInitGetOffset);
  
  
  helper_->Flush();
  EXPECT_EQ(GetHelperGetOffset(), kInitGetOffset);
  EXPECT_EQ(GetHelperPutOffset(), 0);
  
  EXPECT_EQ(ImmediateEntryCount(), kInitGetOffset - 1);
  AddUniqueCommandWithExpect(error::kNoError, 2);
  EXPECT_EQ(ImmediateEntryCount(), kInitGetOffset - 3);
  helper_->Finish();
  
  Mock::VerifyAndClearExpectations(api_mock_.get());
  
  EXPECT_EQ(error::kNoError, GetError());
}
TEST_F(CommandBufferHelperTest, TestCalcImmediateEntriesAutoFlushing) {
  command_buffer_->LockFlush();
  
  EXPECT_EQ(GetHelperPutOffset(), 0);
  EXPECT_EQ(GetHelperGetOffset(), 0);
  
  helper_->SetAutomaticFlushes(false);
  EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries - 1);
  
  
  helper_->SetAutomaticFlushes(true);
  EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries / kAutoFlushSmall);
  
  
  AddUniqueCommandWithExpect(error::kNoError, 2);
  helper_->Flush();
  EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries / kAutoFlushBig);
  helper_->Finish();
  
  Mock::VerifyAndClearExpectations(api_mock_.get());
  
  EXPECT_EQ(error::kNoError, GetError());
}
TEST_F(CommandBufferHelperTest, TestCalcImmediateEntriesOverFlushLimit) {
  
  command_buffer_->LockFlush();
  
  EXPECT_EQ(GetHelperPutOffset(), 0);
  EXPECT_EQ(GetHelperGetOffset(), 0);
  
  helper_->SetAutomaticFlushes(true);
  EXPECT_EQ(ImmediateEntryCount(), kTotalNumCommandEntries / kAutoFlushSmall);
  
  AddUniqueCommandWithExpect(error::kNoError, ImmediateEntryCount() + 1);
  
  
  EXPECT_EQ(ImmediateEntryCount(), 0);
  
  AddUniqueCommandWithExpect(error::kNoError, ImmediateEntryCount() + 1);
  helper_->Finish();
  
  Mock::VerifyAndClearExpectations(api_mock_.get());
  
  EXPECT_EQ(error::kNoError, GetError());
}
TEST_F(CommandBufferHelperTest, TestCommandProcessing) {
  
  
  EXPECT_TRUE(GetParser() != NULL);
  EXPECT_EQ(error::kNoError, GetError());
  EXPECT_EQ(0, GetGetOffset());
  
  AddCommandWithExpect(error::kNoError, kUnusedCommandId, 0, NULL);
  CommandBufferEntry args1[2];
  args1[0].value_uint32 = 3;
  args1[1].value_float = 4.f;
  AddCommandWithExpect(error::kNoError, kUnusedCommandId, 2, args1);
  CommandBufferEntry args2[2];
  args2[0].value_uint32 = 5;
  args2[1].value_float = 6.f;
  AddCommandWithExpect(error::kNoError, kUnusedCommandId, 2, args2);
  
  helper_->Finish();
  
  EXPECT_TRUE(GetParser()->IsEmpty());
  
  Mock::VerifyAndClearExpectations(api_mock_.get());
  
  EXPECT_EQ(error::kNoError, GetError());
}
TEST_F(CommandBufferHelperTest, TestCommandWrapping) {
  
  
  COMPILE_ASSERT(kTotalNumCommandEntries % 3 != 0,
                 Is_multiple_of_num_command_entries);
  const int kNumCommands = (kTotalNumCommandEntries / 3) * 2;
  CommandBufferEntry args1[2];
  args1[0].value_uint32 = 5;
  args1[1].value_float = 4.f;
  for (int i = 0; i < kNumCommands; ++i) {
    AddCommandWithExpect(error::kNoError, kUnusedCommandId + i, 2, args1);
  }
  helper_->Finish();
  
  Mock::VerifyAndClearExpectations(api_mock_.get());
  
  EXPECT_EQ(error::kNoError, GetError());
}
TEST_F(CommandBufferHelperTest, TestCommandWrappingExactMultiple) {
  const int32 kCommandSize = kTotalNumCommandEntries / 2;
  const size_t kNumArgs = kCommandSize - 1;
  COMPILE_ASSERT(kTotalNumCommandEntries % kCommandSize == 0,
                 Not_multiple_of_num_command_entries);
  CommandBufferEntry args1[kNumArgs];
  for (size_t ii = 0; ii < kNumArgs; ++ii) {
    args1[ii].value_uint32 = ii + 1;
  }
  for (unsigned int i = 0; i < 5; ++i) {
    AddCommandWithExpect(
        error::kNoError, i + kUnusedCommandId, kNumArgs, args1);
  }
  helper_->Finish();
  
  Mock::VerifyAndClearExpectations(api_mock_.get());
  
  EXPECT_EQ(error::kNoError, GetError());
}
TEST_F(CommandBufferHelperTest, TestCommandWrappingFullAtStart) {
  TestCommandWrappingFull(2, 0);
}
TEST_F(CommandBufferHelperTest, TestCommandWrappingFullInMiddle) {
  TestCommandWrappingFull(2, 1);
}
TEST_F(CommandBufferHelperTest, TestCommandWrappingFullAtEnd) {
  TestCommandWrappingFull(2, kTotalNumCommandEntries / 2);
}
TEST_F(CommandBufferHelperTest, TestAvailableEntries) {
  CommandBufferEntry args[2];
  args[0].value_uint32 = 3;
  args[1].value_float = 4.f;
  
  AddCommandWithExpect(error::kNoError, kUnusedCommandId + 1, 0, NULL);
  AddCommandWithExpect(error::kNoError, kUnusedCommandId + 2, 0, NULL);
  AddCommandWithExpect(error::kNoError, kUnusedCommandId + 3, 2, args);
  AddCommandWithExpect(error::kNoError, kUnusedCommandId + 4, 2, args);
  
  helper_->WaitForAvailableEntries(5);
  CommandBufferOffset put = get_helper_put();
  CheckFreeSpace(put, 5);
  
  AddCommandWithExpect(error::kNoError, kUnusedCommandId + 5, 2, args);
  
  helper_->Finish();
  
  Mock::VerifyAndClearExpectations(api_mock_.get());
  
  EXPECT_EQ(error::kNoError, GetError());
}
TEST_F(CommandBufferHelperTest, TestToken) {
  CommandBufferEntry args[2];
  args[0].value_uint32 = 3;
  args[1].value_float = 4.f;
  
  AddCommandWithExpect(error::kNoError, kUnusedCommandId + 3, 2, args);
  
  CommandBufferOffset command1_put = get_helper_put();
  int32 token = helper_->InsertToken();
  EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
      .WillOnce(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
                      Return(error::kNoError)));
  
  AddCommandWithExpect(error::kNoError, kUnusedCommandId + 4, 2, args);
  helper_->WaitForToken(token);
  
  EXPECT_LE(command1_put, GetGetOffset());
  helper_->Finish();
  
  Mock::VerifyAndClearExpectations(api_mock_.get());
  
  EXPECT_EQ(error::kNoError, GetError());
}
TEST_F(CommandBufferHelperTest, FreeRingBuffer) {
  EXPECT_TRUE(helper_->HaveRingBuffer());
  
  helper_->FreeRingBuffer();
  EXPECT_FALSE(helper_->HaveRingBuffer());
  
  int32 token = helper_->InsertToken();
  EXPECT_TRUE(helper_->HaveRingBuffer());
  EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
      .WillOnce(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
                      Return(error::kNoError)));
  helper_->WaitForToken(token);
  helper_->FreeRingBuffer();
  EXPECT_FALSE(helper_->HaveRingBuffer());
  
  AddCommandWithExpect(error::kNoError, kUnusedCommandId, 0, NULL);
  EXPECT_TRUE(helper_->HaveRingBuffer());
  helper_->Finish();
  helper_->FreeRingBuffer();
  EXPECT_FALSE(helper_->HaveRingBuffer());
  
  Mock::VerifyAndClearExpectations(api_mock_.get());
}
TEST_F(CommandBufferHelperTest, Noop) {
  for (int ii = 1; ii < 4; ++ii) {
    CommandBufferOffset put_before = get_helper_put();
    helper_->Noop(ii);
    CommandBufferOffset put_after = get_helper_put();
    EXPECT_EQ(ii, put_after - put_before);
  }
}
TEST_F(CommandBufferHelperTest, IsContextLost) {
  EXPECT_FALSE(helper_->IsContextLost());
  command_buffer_->SetParseError(error::kGenericError);
  EXPECT_TRUE(helper_->IsContextLost());
}
TEST_F(CommandBufferHelperTest, TestFlushGeneration) {
  
  helper_->SetAutomaticFlushes(false);
  
  uint32 gen1, gen2, gen3;
  gen1 = GetHelperFlushGeneration();
  AddUniqueCommandWithExpect(error::kNoError, 2);
  gen2 = GetHelperFlushGeneration();
  helper_->Flush();
  gen3 = GetHelperFlushGeneration();
  EXPECT_EQ(gen2, gen1);
  EXPECT_NE(gen3, gen2);
  
  gen1 = GetHelperFlushGeneration();
  AddUniqueCommandWithExpect(error::kNoError, 2);
  gen2 = GetHelperFlushGeneration();
  helper_->Finish();
  gen3 = GetHelperFlushGeneration();
  EXPECT_EQ(gen2, gen1);
  EXPECT_NE(gen3, gen2);
  helper_->Finish();
  
  Mock::VerifyAndClearExpectations(api_mock_.get());
  
  EXPECT_EQ(error::kNoError, GetError());
}
}