mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
487 lines
16 KiB
C++
487 lines
16 KiB
C++
// 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) {
|
|
}
|
|
|
|
void SetUp() override;
|
|
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));
|
|
EXPECT_CALL(*command_buffer(), Flush(_)).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, MemoryAlignmentAfterZeroAllocation) {
|
|
Initialize(32u);
|
|
void* ptr = transfer_buffer_->Alloc(0);
|
|
EXPECT_EQ((reinterpret_cast<uintptr_t>(ptr) & (kAlignment - 1)), 0u);
|
|
transfer_buffer_->FreePendingToken(ptr, static_cast<unsigned int>(-1));
|
|
// Check that the pointer is aligned on the following allocation.
|
|
ptr = transfer_buffer_->Alloc(4);
|
|
EXPECT_EQ((reinterpret_cast<uintptr_t>(ptr) & (kAlignment - 1)), 0u);
|
|
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) {
|
|
}
|
|
|
|
void SetUp() override;
|
|
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
|
|
|
|
|