root/gpu/command_buffer/client/transfer_buffer_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. Initialize
  2. command_buffer
  3. SetUp
  4. TearDown
  5. TEST_F
  6. TEST_F
  7. TEST_F
  8. TEST_F
  9. RealCreateTransferBuffer
  10. command_buffer
  11. SetUp
  12. TearDown
  13. TEST_F
  14. TEST_F
  15. TEST_F
  16. TEST_F

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Tests for the Command Buffer Helper.

#include "gpu/command_buffer/client/transfer_buffer.h"

#include "base/compiler_specific.h"
#include "gpu/command_buffer/client/client_test_helper.h"
#include "gpu/command_buffer/client/cmd_buffer_helper.h"
#include "gpu/command_buffer/common/command_buffer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gmock/include/gmock/gmock.h"

using ::testing::_;
using ::testing::AtMost;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::StrictMock;

namespace gpu {


class TransferBufferTest : public testing::Test {
 protected:
  static const int32 kNumCommandEntries = 400;
  static const int32 kCommandBufferSizeBytes =
      kNumCommandEntries * sizeof(CommandBufferEntry);
  static const unsigned int kStartingOffset = 64;
  static const unsigned int kAlignment = 4;
  static const size_t kTransferBufferSize = 256;

  TransferBufferTest()
      : transfer_buffer_id_(0) {
  }

  virtual void SetUp() OVERRIDE;
  virtual void TearDown() OVERRIDE;

  virtual void Initialize(unsigned int size_to_flush) {
    ASSERT_TRUE(transfer_buffer_->Initialize(
        kTransferBufferSize,
        kStartingOffset,
        kTransferBufferSize,
        kTransferBufferSize,
        kAlignment,
        size_to_flush));
  }

  MockClientCommandBufferMockFlush* command_buffer() const {
    return command_buffer_.get();
  }

  scoped_ptr<MockClientCommandBufferMockFlush> command_buffer_;
  scoped_ptr<CommandBufferHelper> helper_;
  scoped_ptr<TransferBuffer> transfer_buffer_;
  int32 transfer_buffer_id_;
};

void TransferBufferTest::SetUp() {
  command_buffer_.reset(new StrictMock<MockClientCommandBufferMockFlush>());
  ASSERT_TRUE(command_buffer_->Initialize());

  helper_.reset(new CommandBufferHelper(command_buffer()));
  ASSERT_TRUE(helper_->Initialize(kCommandBufferSizeBytes));

  transfer_buffer_id_ = command_buffer()->GetNextFreeTransferBufferId();

  transfer_buffer_.reset(new TransferBuffer(helper_.get()));
}

void TransferBufferTest::TearDown() {
  if (transfer_buffer_->HaveBuffer()) {
    EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
        .Times(1)
        .RetiresOnSaturation();
  }
  // For command buffer.
  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
      .Times(1)
      .RetiresOnSaturation();
  EXPECT_CALL(*command_buffer(), OnFlush()).Times(AtMost(1));
  transfer_buffer_.reset();
}

// GCC requires these declarations, but MSVC requires they not be present
#ifndef _MSC_VER
const int32 TransferBufferTest::kNumCommandEntries;
const int32 TransferBufferTest::kCommandBufferSizeBytes;
const unsigned int TransferBufferTest::kStartingOffset;
const unsigned int TransferBufferTest::kAlignment;
const size_t TransferBufferTest::kTransferBufferSize;
#endif

TEST_F(TransferBufferTest, Basic) {
  Initialize(0);
  EXPECT_TRUE(transfer_buffer_->HaveBuffer());
  EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId());
  EXPECT_EQ(
      kTransferBufferSize - kStartingOffset,
      transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
}

TEST_F(TransferBufferTest, Free) {
  Initialize(0);
  EXPECT_TRUE(transfer_buffer_->HaveBuffer());
  EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId());

  // Free buffer.
  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
      .Times(1)
      .RetiresOnSaturation();
  transfer_buffer_->Free();
  // See it's freed.
  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
  // See that it gets reallocated.
  EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId());
  EXPECT_TRUE(transfer_buffer_->HaveBuffer());

  // Free buffer.
  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
      .Times(1)
      .RetiresOnSaturation();
  transfer_buffer_->Free();
  // See it's freed.
  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
  // See that it gets reallocated.
  EXPECT_TRUE(transfer_buffer_->GetResultBuffer() != NULL);
  EXPECT_TRUE(transfer_buffer_->HaveBuffer());

  // Free buffer.
  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
      .Times(1)
      .RetiresOnSaturation();
  transfer_buffer_->Free();
  // See it's freed.
  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
  // See that it gets reallocated.
  unsigned int size = 0;
  void* data = transfer_buffer_->AllocUpTo(1, &size);
  EXPECT_TRUE(data != NULL);
  EXPECT_TRUE(transfer_buffer_->HaveBuffer());
  transfer_buffer_->FreePendingToken(data, 1);

  // Free buffer.
  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
      .Times(1)
      .RetiresOnSaturation();
  transfer_buffer_->Free();
  // See it's freed.
  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
  // See that it gets reallocated.
  transfer_buffer_->GetResultOffset();
  EXPECT_TRUE(transfer_buffer_->HaveBuffer());

  EXPECT_EQ(
      kTransferBufferSize - kStartingOffset,
      transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());

  // Test freeing twice.
  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
      .Times(1)
      .RetiresOnSaturation();
  transfer_buffer_->Free();
  transfer_buffer_->Free();
}

TEST_F(TransferBufferTest, TooLargeAllocation) {
  Initialize(0);
  // Check that we can't allocate large than max size.
  void* ptr = transfer_buffer_->Alloc(kTransferBufferSize + 1);
  EXPECT_TRUE(ptr == NULL);
  // Check we if we try to allocate larger than max we get max.
  unsigned int size_allocated = 0;
  ptr = transfer_buffer_->AllocUpTo(
      kTransferBufferSize + 1, &size_allocated);
  ASSERT_TRUE(ptr != NULL);
  EXPECT_EQ(kTransferBufferSize - kStartingOffset, size_allocated);
  transfer_buffer_->FreePendingToken(ptr, 1);
}

TEST_F(TransferBufferTest, Flush) {
  Initialize(16u);
  unsigned int size_allocated = 0;
  for (int i = 0; i < 8; ++i) {
    void* ptr = transfer_buffer_->AllocUpTo(8u, &size_allocated);
    ASSERT_TRUE(ptr != NULL);
    EXPECT_EQ(8u, size_allocated);
    if (i % 2) {
      EXPECT_CALL(*command_buffer(), Flush(_))
          .Times(1)
          .RetiresOnSaturation();
    }
    transfer_buffer_->FreePendingToken(ptr, helper_->InsertToken());
  }
  for (int i = 0; i < 8; ++i) {
    void* ptr = transfer_buffer_->Alloc(8u);
    ASSERT_TRUE(ptr != NULL);
    if (i % 2) {
      EXPECT_CALL(*command_buffer(), Flush(_))
          .Times(1)
          .RetiresOnSaturation();
    }
    transfer_buffer_->FreePendingToken(ptr, helper_->InsertToken());
  }
}

class MockClientCommandBufferCanFail : public MockClientCommandBufferMockFlush {
 public:
  MockClientCommandBufferCanFail() {
  }
  virtual ~MockClientCommandBufferCanFail() {
  }

  MOCK_METHOD2(CreateTransferBuffer,
               scoped_refptr<Buffer>(size_t size, int32* id));

  scoped_refptr<gpu::Buffer> RealCreateTransferBuffer(size_t size, int32* id) {
    return MockCommandBufferBase::CreateTransferBuffer(size, id);
  }
};

class TransferBufferExpandContractTest : public testing::Test {
 protected:
  static const int32 kNumCommandEntries = 400;
  static const int32 kCommandBufferSizeBytes =
      kNumCommandEntries * sizeof(CommandBufferEntry);
  static const unsigned int kStartingOffset = 64;
  static const unsigned int kAlignment = 4;
  static const size_t kStartTransferBufferSize = 256;
  static const size_t kMaxTransferBufferSize = 1024;
  static const size_t kMinTransferBufferSize = 128;

  TransferBufferExpandContractTest()
      : transfer_buffer_id_(0) {
  }

  virtual void SetUp() OVERRIDE;
  virtual void TearDown() OVERRIDE;

  MockClientCommandBufferCanFail* command_buffer() const {
    return command_buffer_.get();
  }

  scoped_ptr<MockClientCommandBufferCanFail> command_buffer_;
  scoped_ptr<CommandBufferHelper> helper_;
  scoped_ptr<TransferBuffer> transfer_buffer_;
  int32 transfer_buffer_id_;
};

void TransferBufferExpandContractTest::SetUp() {
  command_buffer_.reset(new StrictMock<MockClientCommandBufferCanFail>());
  ASSERT_TRUE(command_buffer_->Initialize());

  EXPECT_CALL(*command_buffer(),
              CreateTransferBuffer(kCommandBufferSizeBytes, _))
      .WillOnce(Invoke(
          command_buffer(),
          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
      .RetiresOnSaturation();

  helper_.reset(new CommandBufferHelper(command_buffer()));
  ASSERT_TRUE(helper_->Initialize(kCommandBufferSizeBytes));

  transfer_buffer_id_ = command_buffer()->GetNextFreeTransferBufferId();

  EXPECT_CALL(*command_buffer(),
              CreateTransferBuffer(kStartTransferBufferSize, _))
      .WillOnce(Invoke(
          command_buffer(),
          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
      .RetiresOnSaturation();

  transfer_buffer_.reset(new TransferBuffer(helper_.get()));
  ASSERT_TRUE(transfer_buffer_->Initialize(
      kStartTransferBufferSize,
      kStartingOffset,
      kMinTransferBufferSize,
      kMaxTransferBufferSize,
      kAlignment,
      0));
}

void TransferBufferExpandContractTest::TearDown() {
  if (transfer_buffer_->HaveBuffer()) {
    EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
        .Times(1)
        .RetiresOnSaturation();
  }
  // For command buffer.
  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
      .Times(1)
      .RetiresOnSaturation();
  transfer_buffer_.reset();
}

// GCC requires these declarations, but MSVC requires they not be present
#ifndef _MSC_VER
const int32 TransferBufferExpandContractTest::kNumCommandEntries;
const int32 TransferBufferExpandContractTest::kCommandBufferSizeBytes;
const unsigned int TransferBufferExpandContractTest::kStartingOffset;
const unsigned int TransferBufferExpandContractTest::kAlignment;
const size_t TransferBufferExpandContractTest::kStartTransferBufferSize;
const size_t TransferBufferExpandContractTest::kMaxTransferBufferSize;
const size_t TransferBufferExpandContractTest::kMinTransferBufferSize;
#endif

TEST_F(TransferBufferExpandContractTest, Expand) {
  // Check it starts at starting size.
  EXPECT_EQ(
      kStartTransferBufferSize - kStartingOffset,
      transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());

  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
      .Times(1)
      .RetiresOnSaturation();
  EXPECT_CALL(*command_buffer(),
              CreateTransferBuffer(kStartTransferBufferSize * 2, _))
      .WillOnce(Invoke(
          command_buffer(),
          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
      .RetiresOnSaturation();

  // Try next power of 2.
  const size_t kSize1 = 512 - kStartingOffset;
  unsigned int size_allocated = 0;
  void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
  ASSERT_TRUE(ptr != NULL);
  EXPECT_EQ(kSize1, size_allocated);
  EXPECT_EQ(kSize1, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
  transfer_buffer_->FreePendingToken(ptr, 1);

  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
      .Times(1)
      .RetiresOnSaturation();
  EXPECT_CALL(*command_buffer(),
              CreateTransferBuffer(kMaxTransferBufferSize, _))
      .WillOnce(Invoke(
          command_buffer(),
          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
      .RetiresOnSaturation();

  // Try next power of 2.
  const size_t kSize2 = 1024 - kStartingOffset;
  ptr = transfer_buffer_->AllocUpTo(kSize2, &size_allocated);
  ASSERT_TRUE(ptr != NULL);
  EXPECT_EQ(kSize2, size_allocated);
  EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
  transfer_buffer_->FreePendingToken(ptr, 1);

  // Try next one more. Should not go past max.
  size_allocated = 0;
  const size_t kSize3 = kSize2 + 1;
  ptr = transfer_buffer_->AllocUpTo(kSize3, &size_allocated);
  EXPECT_EQ(kSize2, size_allocated);
  EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
  transfer_buffer_->FreePendingToken(ptr, 1);
}

TEST_F(TransferBufferExpandContractTest, Contract) {
  // Check it starts at starting size.
  EXPECT_EQ(
      kStartTransferBufferSize - kStartingOffset,
      transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());

  // Free buffer.
  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
      .Times(1)
      .RetiresOnSaturation();
  transfer_buffer_->Free();
  // See it's freed.
  EXPECT_FALSE(transfer_buffer_->HaveBuffer());

  // Try to allocate again, fail first request
  EXPECT_CALL(*command_buffer(),
              CreateTransferBuffer(kStartTransferBufferSize, _))
      .WillOnce(
           DoAll(SetArgPointee<1>(-1), Return(scoped_refptr<gpu::Buffer>())))
      .RetiresOnSaturation();
  EXPECT_CALL(*command_buffer(),
              CreateTransferBuffer(kMinTransferBufferSize, _))
      .WillOnce(Invoke(
          command_buffer(),
          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
      .RetiresOnSaturation();

  const size_t kSize1 = 256 - kStartingOffset;
  const size_t kSize2 = 128 - kStartingOffset;
  unsigned int size_allocated = 0;
  void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
  ASSERT_TRUE(ptr != NULL);
  EXPECT_EQ(kSize2, size_allocated);
  EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
  transfer_buffer_->FreePendingToken(ptr, 1);

  // Free buffer.
  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
      .Times(1)
      .RetiresOnSaturation();
  transfer_buffer_->Free();
  // See it's freed.
  EXPECT_FALSE(transfer_buffer_->HaveBuffer());

  // Try to allocate again,
  EXPECT_CALL(*command_buffer(),
              CreateTransferBuffer(kMinTransferBufferSize, _))
      .WillOnce(Invoke(
          command_buffer(),
          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
      .RetiresOnSaturation();

  ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
  ASSERT_TRUE(ptr != NULL);
  EXPECT_EQ(kSize2, size_allocated);
  EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
  transfer_buffer_->FreePendingToken(ptr, 1);
}

TEST_F(TransferBufferExpandContractTest, OutOfMemory) {
  // Free buffer.
  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
      .Times(1)
      .RetiresOnSaturation();
  transfer_buffer_->Free();
  // See it's freed.
  EXPECT_FALSE(transfer_buffer_->HaveBuffer());

  // Try to allocate again, fail both requests.
  EXPECT_CALL(*command_buffer(), CreateTransferBuffer(_, _))
      .WillOnce(
           DoAll(SetArgPointee<1>(-1), Return(scoped_refptr<gpu::Buffer>())))
      .WillOnce(
           DoAll(SetArgPointee<1>(-1), Return(scoped_refptr<gpu::Buffer>())))
      .WillOnce(
           DoAll(SetArgPointee<1>(-1), Return(scoped_refptr<gpu::Buffer>())))
      .RetiresOnSaturation();

  const size_t kSize1 = 512 - kStartingOffset;
  unsigned int size_allocated = 0;
  void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
  ASSERT_TRUE(ptr == NULL);
  EXPECT_FALSE(transfer_buffer_->HaveBuffer());
}

TEST_F(TransferBufferExpandContractTest, ReallocsToDefault) {
  // Free buffer.
  EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
      .Times(1)
      .RetiresOnSaturation();
  transfer_buffer_->Free();
  // See it's freed.
  EXPECT_FALSE(transfer_buffer_->HaveBuffer());

  // See that it gets reallocated.
  EXPECT_CALL(*command_buffer(),
              CreateTransferBuffer(kStartTransferBufferSize, _))
      .WillOnce(Invoke(
          command_buffer(),
          &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
      .RetiresOnSaturation();
  EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId());
  EXPECT_TRUE(transfer_buffer_->HaveBuffer());

  // Check it's the default size.
  EXPECT_EQ(
      kStartTransferBufferSize - kStartingOffset,
      transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
}

}  // namespace gpu



/* [<][>][^][v][top][bottom][index][help] */