diff options
author | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-26 08:05:03 +0000 |
---|---|---|
committer | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-05-26 08:05:03 +0000 |
commit | c87015f53fc61bea2b94f2dc80d0c699d9aebcd5 (patch) | |
tree | e34dd0f6151caef21cf51ea39c67af080127fccc /gpu/command_buffer/service | |
parent | 12e54045b113f6aca10188b012b1ea529cec6bf2 (diff) | |
download | chromium_src-c87015f53fc61bea2b94f2dc80d0c699d9aebcd5.zip chromium_src-c87015f53fc61bea2b94f2dc80d0c699d9aebcd5.tar.gz chromium_src-c87015f53fc61bea2b94f2dc80d0c699d9aebcd5.tar.bz2 |
Separate management of shared memory from CmdBufService to separate class
This is a step on the way to making this per ContextGroup instead
of per context
TEST=unit tests
BUG=129803
R=apatrick@chromium.org
Review URL: https://chromiumcodereview.appspot.com/10448030
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@139196 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu/command_buffer/service')
6 files changed, 374 insertions, 231 deletions
diff --git a/gpu/command_buffer/service/command_buffer_service.cc b/gpu/command_buffer/service/command_buffer_service.cc index 13d3098..402cb7c 100644 --- a/gpu/command_buffer/service/command_buffer_service.cc +++ b/gpu/command_buffer/service/command_buffer_service.cc @@ -10,6 +10,7 @@ #include "base/debug/trace_event.h" #include "gpu/command_buffer/common/cmd_buffer_common.h" #include "gpu/command_buffer/common/command_buffer_shared.h" +#include "gpu/command_buffer/service/transfer_buffer_manager.h" using ::base::SharedMemory; @@ -24,24 +25,16 @@ CommandBufferService::CommandBufferService() token_(0), generation_(0), error_(error::kNoError), - context_lost_reason_(error::kUnknown), - shared_memory_bytes_allocated_(0) { - // Element zero is always NULL. - registered_objects_.push_back(Buffer()); + context_lost_reason_(error::kUnknown) { } CommandBufferService::~CommandBufferService() { - for (size_t i = 0; i < registered_objects_.size(); ++i) { - if (registered_objects_[i].shared_memory) { - shared_memory_bytes_allocated_ -= registered_objects_[i].size; - delete registered_objects_[i].shared_memory; - } - } - // TODO(gman): Should we report 0 bytes to TRACE here? } bool CommandBufferService::Initialize() { - return true; + TransferBufferManager* manager = new TransferBufferManager(); + transfer_buffer_manager_.reset(manager); + return manager->Initialize(); } CommandBufferService::State CommandBufferService::GetState() { @@ -125,96 +118,17 @@ void CommandBufferService::SetGetOffset(int32 get_offset) { int32 CommandBufferService::CreateTransferBuffer(size_t size, int32 id_request) { - SharedMemory buffer; - if (!buffer.CreateAnonymous(size)) - return -1; - - shared_memory_bytes_allocated_ += size; - TRACE_COUNTER_ID1( - "CommandBuffer", "SharedMemory", this, shared_memory_bytes_allocated_); - - return RegisterTransferBuffer(&buffer, size, id_request); + return transfer_buffer_manager_->CreateTransferBuffer(size, id_request); } int32 CommandBufferService::RegisterTransferBuffer( base::SharedMemory* shared_memory, size_t size, int32 id_request) { - // Check we haven't exceeded the range that fits in a 32-bit integer. - if (unused_registered_object_elements_.empty()) { - if (registered_objects_.size() > std::numeric_limits<uint32>::max()) - return -1; - } - - // Check that the requested ID is sane (not too large, or less than -1) - if (id_request != -1 && (id_request > 100 || id_request < -1)) - return -1; - - // Duplicate the handle. - base::SharedMemoryHandle duped_shared_memory_handle; - if (!shared_memory->ShareToProcess(base::GetCurrentProcessHandle(), - &duped_shared_memory_handle)) { - return -1; - } - scoped_ptr<SharedMemory> duped_shared_memory( - new SharedMemory(duped_shared_memory_handle, false)); - - // Map the shared memory into this process. This validates the size. - if (!duped_shared_memory->Map(size)) - return -1; - - // If it could be mapped, allocate an ID and register the shared memory with - // that ID. - Buffer buffer; - buffer.ptr = duped_shared_memory->memory(); - buffer.size = size; - buffer.shared_memory = duped_shared_memory.release(); - - // If caller requested specific id, first try to use id_request. - if (id_request != -1) { - int32 cur_size = static_cast<int32>(registered_objects_.size()); - if (cur_size <= id_request) { - // Pad registered_objects_ to reach id_request. - registered_objects_.resize(static_cast<size_t>(id_request + 1)); - for (int32 id = cur_size; id < id_request; ++id) - unused_registered_object_elements_.insert(id); - registered_objects_[id_request] = buffer; - return id_request; - } else if (!registered_objects_[id_request].shared_memory) { - // id_request is already in free list. - registered_objects_[id_request] = buffer; - unused_registered_object_elements_.erase(id_request); - return id_request; - } - } - - if (unused_registered_object_elements_.empty()) { - int32 handle = static_cast<int32>(registered_objects_.size()); - registered_objects_.push_back(buffer); - return handle; - } else { - int32 handle = *unused_registered_object_elements_.begin(); - unused_registered_object_elements_.erase( - unused_registered_object_elements_.begin()); - DCHECK(!registered_objects_[handle].shared_memory); - registered_objects_[handle] = buffer; - return handle; - } + return transfer_buffer_manager_->RegisterTransferBuffer( + shared_memory, size, id_request); } void CommandBufferService::DestroyTransferBuffer(int32 handle) { - if (handle <= 0) - return; - - if (static_cast<size_t>(handle) >= registered_objects_.size()) - return; - - shared_memory_bytes_allocated_ -= registered_objects_[handle].size; - TRACE_COUNTER_ID1( - "CommandBuffer", "SharedMemory", this, shared_memory_bytes_allocated_); - - delete registered_objects_[handle].shared_memory; - registered_objects_[handle] = Buffer(); - unused_registered_object_elements_.insert(handle); - + transfer_buffer_manager_->DestroyTransferBuffer(handle); if (handle == ring_buffer_id_) { ring_buffer_id_ = -1; ring_buffer_ = Buffer(); @@ -222,26 +136,10 @@ void CommandBufferService::DestroyTransferBuffer(int32 handle) { get_offset_ = 0; put_offset_ = 0; } - - // Remove all null objects from the end of the vector. This allows the vector - // to shrink when, for example, all objects are unregistered. Note that this - // loop never removes element zero, which is always NULL. - while (registered_objects_.size() > 1 && - !registered_objects_.back().shared_memory) { - registered_objects_.pop_back(); - unused_registered_object_elements_.erase( - static_cast<int32>(registered_objects_.size())); - } } Buffer CommandBufferService::GetTransferBuffer(int32 handle) { - if (handle < 0) - return Buffer(); - - if (static_cast<size_t>(handle) >= registered_objects_.size()) - return Buffer(); - - return registered_objects_[handle]; + return transfer_buffer_manager_->GetTransferBuffer(handle); } void CommandBufferService::SetToken(int32 token) { diff --git a/gpu/command_buffer/service/command_buffer_service.h b/gpu/command_buffer/service/command_buffer_service.h index 8b3e038..77fe951 100644 --- a/gpu/command_buffer/service/command_buffer_service.h +++ b/gpu/command_buffer/service/command_buffer_service.h @@ -5,9 +5,6 @@ #ifndef GPU_COMMAND_BUFFER_SERVICE_COMMAND_BUFFER_SERVICE_H_ #define GPU_COMMAND_BUFFER_SERVICE_COMMAND_BUFFER_SERVICE_H_ -#include <set> -#include <vector> - #include "base/callback.h" #include "base/memory/linked_ptr.h" #include "base/memory/scoped_ptr.h" @@ -17,6 +14,8 @@ namespace gpu { +class TransferBufferManagerInterface; + // An object that implements a shared memory command buffer and a synchronous // API to manage the put and get pointers. class GPU_EXPORT CommandBufferService : public CommandBuffer { @@ -73,13 +72,11 @@ class GPU_EXPORT CommandBufferService : public CommandBuffer { base::Closure put_offset_change_callback_; GetBufferChangedCallback get_buffer_change_callback_; base::Closure parse_error_callback_; - std::vector<Buffer> registered_objects_; - std::set<int32> unused_registered_object_elements_; + scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_; int32 token_; uint32 generation_; error::Error error_; error::ContextLostReason context_lost_reason_; - size_t shared_memory_bytes_allocated_; }; } // namespace gpu diff --git a/gpu/command_buffer/service/command_buffer_service_unittest.cc b/gpu/command_buffer/service/command_buffer_service_unittest.cc index 7f06639..a771018 100644 --- a/gpu/command_buffer/service/command_buffer_service_unittest.cc +++ b/gpu/command_buffer/service/command_buffer_service_unittest.cc @@ -1,9 +1,9 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// 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. -#include "base/callback.h" -#include "base/mac/scoped_nsautorelease_pool.h" +#include "base/bind.h" +#include "base/bind_helpers.h" #include "base/threading/thread.h" #include "gpu/command_buffer/common/cmd_buffer_common.h" #include "gpu/command_buffer/service/command_buffer_service.h" @@ -23,6 +23,7 @@ class CommandBufferServiceTest : public testing::Test { protected: virtual void SetUp() { command_buffer_.reset(new CommandBufferService); + EXPECT_TRUE(command_buffer_->Initialize()); } int32 GetGetOffset() { @@ -41,145 +42,88 @@ class CommandBufferServiceTest : public testing::Test { return command_buffer_->GetState().error; } - base::mac::ScopedNSAutoreleasePool autorelease_pool_; + bool Initialize(size_t size) { + int32 id = command_buffer_->CreateTransferBuffer(size, -1); + EXPECT_GT(id, 0); + command_buffer_->SetGetBuffer(id); + return true; + } + scoped_ptr<CommandBufferService> command_buffer_; }; -TEST_F(CommandBufferServiceTest, NullRingBufferByDefault) { - EXPECT_TRUE(NULL == command_buffer_->GetRingBuffer().ptr); -} - TEST_F(CommandBufferServiceTest, InitializesCommandBuffer) { - EXPECT_TRUE(command_buffer_->Initialize(1024)); - EXPECT_TRUE(NULL != command_buffer_->GetRingBuffer().ptr); + EXPECT_TRUE(Initialize(1024)); CommandBuffer::State state = command_buffer_->GetState(); - EXPECT_EQ(1024, state.size); EXPECT_EQ(0, state.get_offset); EXPECT_EQ(0, state.put_offset); EXPECT_EQ(0, state.token); EXPECT_EQ(error::kNoError, state.error); } -TEST_F(CommandBufferServiceTest, InitializationSizeIsInEntriesNotBytes) { - EXPECT_TRUE(command_buffer_->Initialize(1024)); - EXPECT_TRUE(NULL != command_buffer_->GetRingBuffer().ptr); - EXPECT_GE(1024 * sizeof(CommandBufferEntry), - command_buffer_->GetRingBuffer().size); -} - -TEST_F(CommandBufferServiceTest, InitializationFailsIfSizeIsZero) { - EXPECT_FALSE(command_buffer_->Initialize(0)); -} - -TEST_F(CommandBufferServiceTest, InitializationFailsIfSizeOutOfRange) { - EXPECT_FALSE(command_buffer_->Initialize( - CommandBuffer::kMaxCommandBufferSize + 1)); -} +namespace { -TEST_F(CommandBufferServiceTest, InitializationFailsIfSizeIsNegative) { - EXPECT_FALSE(command_buffer_->Initialize(-1)); -} - -TEST_F(CommandBufferServiceTest, InitializeFailsSecondTime) { - EXPECT_TRUE(command_buffer_->Initialize(1024)); - EXPECT_FALSE(command_buffer_->Initialize(1024)); -} - -class MockCallback : public CallbackRunner<Tuple0> { +class CallbackTest { public: - MOCK_METHOD1(RunWithParams, void(const Tuple0&)); + virtual void PutOffsetChanged() = 0; + virtual bool GetBufferChanged(int32 id) = 0; }; -TEST_F(CommandBufferServiceTest, CanSyncGetAndPutOffset) { - command_buffer_->Initialize(1024); +class MockCallbackTest : public CallbackTest { + public: + MOCK_METHOD0(PutOffsetChanged, void()); + MOCK_METHOD1(GetBufferChanged, bool(int32)); +}; - StrictMock<MockCallback>* put_offset_change_callback = - new StrictMock<MockCallback>; - command_buffer_->SetPutOffsetChangeCallback(put_offset_change_callback); +} // anonymous namespace - EXPECT_CALL(*put_offset_change_callback, RunWithParams(_)); - EXPECT_EQ(0, command_buffer_->Flush(2).get_offset); +TEST_F(CommandBufferServiceTest, CanSyncGetAndPutOffset) { + Initialize(1024); + + scoped_ptr<StrictMock<MockCallbackTest> > change_callback( + new StrictMock<MockCallbackTest>); + command_buffer_->SetPutOffsetChangeCallback( + base::Bind( + &CallbackTest::PutOffsetChanged, + base::Unretained(change_callback.get()))); + + EXPECT_CALL(*change_callback, PutOffsetChanged()); + command_buffer_->Flush(2); + EXPECT_EQ(0, GetGetOffset()); EXPECT_EQ(2, GetPutOffset()); - EXPECT_CALL(*put_offset_change_callback, RunWithParams(_)); - EXPECT_EQ(0, command_buffer_->Flush(4).get_offset); + EXPECT_CALL(*change_callback, PutOffsetChanged()); + command_buffer_->Flush(4); + EXPECT_EQ(0, GetGetOffset()); EXPECT_EQ(4, GetPutOffset()); command_buffer_->SetGetOffset(2); EXPECT_EQ(2, GetGetOffset()); - EXPECT_CALL(*put_offset_change_callback, RunWithParams(_)); - EXPECT_EQ(2, command_buffer_->Flush(6).get_offset); + EXPECT_CALL(*change_callback, PutOffsetChanged()); + command_buffer_->Flush(6); - EXPECT_NE(error::kNoError, command_buffer_->Flush(-1).error); - EXPECT_NE(error::kNoError, - command_buffer_->Flush(1024).error); + command_buffer_->Flush(-1); + EXPECT_NE(error::kNoError, GetError()); + command_buffer_->Flush(1024); + EXPECT_NE(error::kNoError, GetError()); } -TEST_F(CommandBufferServiceTest, ZeroHandleMapsToNull) { - EXPECT_TRUE(NULL == command_buffer_->GetTransferBuffer(0).ptr); -} +TEST_F(CommandBufferServiceTest, SetGetBuffer) { + int32 ring_buffer_id = command_buffer_->CreateTransferBuffer(1024, -1); + EXPECT_GT(ring_buffer_id, 0); -TEST_F(CommandBufferServiceTest, NegativeHandleMapsToNull) { - EXPECT_TRUE(NULL == command_buffer_->GetTransferBuffer(-1).ptr); -} + scoped_ptr<StrictMock<MockCallbackTest> > change_callback( + new StrictMock<MockCallbackTest>); + command_buffer_->SetGetBufferChangeCallback( + base::Bind( + &CallbackTest::GetBufferChanged, + base::Unretained(change_callback.get()))); -TEST_F(CommandBufferServiceTest, OutOfRangeHandleMapsToNull) { - EXPECT_TRUE(NULL == command_buffer_->GetTransferBuffer(1).ptr); -} - -TEST_F(CommandBufferServiceTest, CanCreateTransferBuffers) { - int32 handle = command_buffer_->CreateTransferBuffer(1024); - EXPECT_EQ(1, handle); - Buffer buffer = command_buffer_->GetTransferBuffer(handle); - ASSERT_TRUE(NULL != buffer.ptr); - EXPECT_EQ(1024u, buffer.size); -} - -TEST_F(CommandBufferServiceTest, CreateTransferBufferReturnsDistinctHandles) { - EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); -} - -TEST_F(CommandBufferServiceTest, - CreateTransferBufferReusesUnregisteredHandles) { - EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); - EXPECT_EQ(2, command_buffer_->CreateTransferBuffer(1024)); - command_buffer_->DestroyTransferBuffer(1); - EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); - EXPECT_EQ(3, command_buffer_->CreateTransferBuffer(1024)); -} - -TEST_F(CommandBufferServiceTest, CannotUnregisterHandleZero) { - command_buffer_->DestroyTransferBuffer(0); - EXPECT_TRUE(NULL == command_buffer_->GetTransferBuffer(0).ptr); - EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); -} - -TEST_F(CommandBufferServiceTest, CannotUnregisterNegativeHandles) { - command_buffer_->DestroyTransferBuffer(-1); - EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); -} - -TEST_F(CommandBufferServiceTest, CannotUnregisterUnregisteredHandles) { - command_buffer_->DestroyTransferBuffer(1); - EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); -} - -// Testing this case specifically because there is an optimization that takes -// a different code path in this case. -TEST_F(CommandBufferServiceTest, UnregistersLastRegisteredHandle) { - EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); - command_buffer_->DestroyTransferBuffer(1); - EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); -} + EXPECT_CALL(*change_callback, GetBufferChanged(ring_buffer_id)) + .WillOnce(Return(true)); -// Testing this case specifically because there is an optimization that takes -// a different code path in this case. -TEST_F(CommandBufferServiceTest, UnregistersTwoLastRegisteredHandles) { - EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); - EXPECT_EQ(2, command_buffer_->CreateTransferBuffer(1024)); - command_buffer_->DestroyTransferBuffer(2); - command_buffer_->DestroyTransferBuffer(1); - EXPECT_EQ(1, command_buffer_->CreateTransferBuffer(1024)); + command_buffer_->SetGetBuffer(ring_buffer_id); + EXPECT_EQ(0, GetGetOffset()); } TEST_F(CommandBufferServiceTest, DefaultTokenIsZero) { diff --git a/gpu/command_buffer/service/transfer_buffer_manager.cc b/gpu/command_buffer/service/transfer_buffer_manager.cc new file mode 100644 index 0000000..f55dfbd --- /dev/null +++ b/gpu/command_buffer/service/transfer_buffer_manager.cc @@ -0,0 +1,153 @@ +// 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. + +#include "gpu/command_buffer/service/transfer_buffer_manager.h" + +#include <limits> + +#include "base/process_util.h" +#include "base/debug/trace_event.h" + +using ::base::SharedMemory; + +namespace gpu { + +TransferBufferManagerInterface::~TransferBufferManagerInterface() { +} + +TransferBufferManager::TransferBufferManager() + : shared_memory_bytes_allocated_(0) { + // Element zero is always NULL. + registered_objects_.push_back(Buffer()); +} + +TransferBufferManager::~TransferBufferManager() { + for (size_t i = 0; i < registered_objects_.size(); ++i) { + if (registered_objects_[i].shared_memory) { + shared_memory_bytes_allocated_ -= registered_objects_[i].size; + delete registered_objects_[i].shared_memory; + } + } + // TODO(gman): Should we report 0 bytes to TRACE here? +} + +bool TransferBufferManager::Initialize() { + return true; +} + +int32 TransferBufferManager::CreateTransferBuffer( + size_t size, int32 id_request) { + SharedMemory buffer; + if (!buffer.CreateAnonymous(size)) + return -1; + + shared_memory_bytes_allocated_ += size; + TRACE_COUNTER_ID1( + "CommandBuffer", "SharedMemory", this, shared_memory_bytes_allocated_); + + return RegisterTransferBuffer(&buffer, size, id_request); +} + +int32 TransferBufferManager::RegisterTransferBuffer( + base::SharedMemory* shared_memory, size_t size, int32 id_request) { + // Check we haven't exceeded the range that fits in a 32-bit integer. + if (unused_registered_object_elements_.empty()) { + if (registered_objects_.size() > std::numeric_limits<uint32>::max()) + return -1; + } + + // Check that the requested ID is sane (not too large, or less than -1) + if (id_request != -1 && (id_request > 100 || id_request < -1)) + return -1; + + // Duplicate the handle. + base::SharedMemoryHandle duped_shared_memory_handle; + if (!shared_memory->ShareToProcess(base::GetCurrentProcessHandle(), + &duped_shared_memory_handle)) { + return -1; + } + scoped_ptr<SharedMemory> duped_shared_memory( + new SharedMemory(duped_shared_memory_handle, false)); + + // Map the shared memory into this process. This validates the size. + if (!duped_shared_memory->Map(size)) + return -1; + + // If it could be mapped, allocate an ID and register the shared memory with + // that ID. + Buffer buffer; + buffer.ptr = duped_shared_memory->memory(); + buffer.size = size; + buffer.shared_memory = duped_shared_memory.release(); + + // If caller requested specific id, first try to use id_request. + if (id_request != -1) { + int32 cur_size = static_cast<int32>(registered_objects_.size()); + if (cur_size <= id_request) { + // Pad registered_objects_ to reach id_request. + registered_objects_.resize(static_cast<size_t>(id_request + 1)); + for (int32 id = cur_size; id < id_request; ++id) + unused_registered_object_elements_.insert(id); + registered_objects_[id_request] = buffer; + return id_request; + } else if (!registered_objects_[id_request].shared_memory) { + // id_request is already in free list. + registered_objects_[id_request] = buffer; + unused_registered_object_elements_.erase(id_request); + return id_request; + } + } + + if (unused_registered_object_elements_.empty()) { + int32 handle = static_cast<int32>(registered_objects_.size()); + registered_objects_.push_back(buffer); + return handle; + } else { + int32 handle = *unused_registered_object_elements_.begin(); + unused_registered_object_elements_.erase( + unused_registered_object_elements_.begin()); + DCHECK(!registered_objects_[handle].shared_memory); + registered_objects_[handle] = buffer; + return handle; + } +} + +void TransferBufferManager::DestroyTransferBuffer(int32 handle) { + if (handle <= 0) + return; + + if (static_cast<size_t>(handle) >= registered_objects_.size()) + return; + + shared_memory_bytes_allocated_ -= registered_objects_[handle].size; + TRACE_COUNTER_ID1( + "CommandBuffer", "SharedMemory", this, shared_memory_bytes_allocated_); + + delete registered_objects_[handle].shared_memory; + registered_objects_[handle] = Buffer(); + unused_registered_object_elements_.insert(handle); + + // Remove all null objects from the end of the vector. This allows the vector + // to shrink when, for example, all objects are unregistered. Note that this + // loop never removes element zero, which is always NULL. + while (registered_objects_.size() > 1 && + !registered_objects_.back().shared_memory) { + registered_objects_.pop_back(); + unused_registered_object_elements_.erase( + static_cast<int32>(registered_objects_.size())); + } +} + +Buffer TransferBufferManager::GetTransferBuffer(int32 handle) { + if (handle < 0) + return Buffer(); + + if (static_cast<size_t>(handle) >= registered_objects_.size()) + return Buffer(); + + return registered_objects_[handle]; +} + +} // namespace gpu + diff --git a/gpu/command_buffer/service/transfer_buffer_manager.h b/gpu/command_buffer/service/transfer_buffer_manager.h new file mode 100644 index 0000000..9f24e2c --- /dev/null +++ b/gpu/command_buffer/service/transfer_buffer_manager.h @@ -0,0 +1,58 @@ +// 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. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_TRANSFER_BUFFER_MANAGER_H_ +#define GPU_COMMAND_BUFFER_SERVICE_TRANSFER_BUFFER_MANAGER_H_ + +#include <set> +#include <vector> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/shared_memory.h" +#include "gpu/command_buffer/common/command_buffer_shared.h" + +namespace gpu { + +class GPU_EXPORT TransferBufferManagerInterface { + public: + virtual ~TransferBufferManagerInterface(); + + virtual int32 CreateTransferBuffer(size_t size, int32 id_request) = 0; + virtual int32 RegisterTransferBuffer( + base::SharedMemory* shared_memory, + size_t size, + int32 id_request) = 0; + virtual void DestroyTransferBuffer(int32 id) = 0; + virtual Buffer GetTransferBuffer(int32 handle) = 0; + +}; + +class GPU_EXPORT TransferBufferManager + : public TransferBufferManagerInterface { + public: + TransferBufferManager(); + + bool Initialize(); + virtual int32 CreateTransferBuffer(size_t size, int32 id_request) OVERRIDE; + virtual int32 RegisterTransferBuffer( + base::SharedMemory* shared_memory, + size_t size, + int32 id_request) OVERRIDE; + virtual void DestroyTransferBuffer(int32 id) OVERRIDE; + virtual Buffer GetTransferBuffer(int32 handle) OVERRIDE; + + private: + virtual ~TransferBufferManager(); + + std::set<int32> unused_registered_object_elements_; + std::vector<Buffer> registered_objects_; + size_t shared_memory_bytes_allocated_; + + DISALLOW_COPY_AND_ASSIGN(TransferBufferManager); +}; + +} // namespace gpu + +#endif // GPU_COMMAND_BUFFER_SERVICE_TRANSFER_BUFFER_MANAGER_H_ diff --git a/gpu/command_buffer/service/transfer_buffer_manager_unittest.cc b/gpu/command_buffer/service/transfer_buffer_manager_unittest.cc new file mode 100644 index 0000000..029cb0e --- /dev/null +++ b/gpu/command_buffer/service/transfer_buffer_manager_unittest.cc @@ -0,0 +1,93 @@ +// 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. + +#include "gpu/command_buffer/service/transfer_buffer_manager.h" + +#include "base/memory/scoped_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gmock/include/gmock/gmock.h" + +using base::SharedMemory; + +namespace gpu { + +class TransferBufferManagerTest : public testing::Test { + protected: + virtual void SetUp() { + TransferBufferManager* manager = new TransferBufferManager(); + transfer_buffer_manager_.reset(manager); + manager->Initialize(); + } + + scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_; +}; + +TEST_F(TransferBufferManagerTest, ZeroHandleMapsToNull) { + EXPECT_TRUE(NULL == transfer_buffer_manager_->GetTransferBuffer(0).ptr); +} + +TEST_F(TransferBufferManagerTest, NegativeHandleMapsToNull) { + EXPECT_TRUE(NULL == transfer_buffer_manager_->GetTransferBuffer(-1).ptr); +} + +TEST_F(TransferBufferManagerTest, OutOfRangeHandleMapsToNull) { + EXPECT_TRUE(NULL == transfer_buffer_manager_->GetTransferBuffer(1).ptr); +} + +TEST_F(TransferBufferManagerTest, CanCreateTransferBuffers) { + int32 handle = transfer_buffer_manager_->CreateTransferBuffer(1024, -1); + EXPECT_EQ(1, handle); + Buffer buffer = transfer_buffer_manager_->GetTransferBuffer(handle); + ASSERT_TRUE(NULL != buffer.ptr); + EXPECT_EQ(1024u, buffer.size); +} + +TEST_F(TransferBufferManagerTest, CreateTransferBufferReturnsDistinctHandles) { + EXPECT_EQ(1, transfer_buffer_manager_->CreateTransferBuffer(1024, -1)); +} + +TEST_F(TransferBufferManagerTest, + CreateTransferBufferReusesUnregisteredHandles) { + EXPECT_EQ(1, transfer_buffer_manager_->CreateTransferBuffer(1024, -1)); + EXPECT_EQ(2, transfer_buffer_manager_->CreateTransferBuffer(1024, -1)); + transfer_buffer_manager_->DestroyTransferBuffer(1); + EXPECT_EQ(1, transfer_buffer_manager_->CreateTransferBuffer(1024, -1)); + EXPECT_EQ(3, transfer_buffer_manager_->CreateTransferBuffer(1024, -1)); +} + +TEST_F(TransferBufferManagerTest, CannotUnregisterHandleZero) { + transfer_buffer_manager_->DestroyTransferBuffer(0); + EXPECT_TRUE(NULL == transfer_buffer_manager_->GetTransferBuffer(0).ptr); + EXPECT_EQ(1, transfer_buffer_manager_->CreateTransferBuffer(1024, -1)); +} + +TEST_F(TransferBufferManagerTest, CannotUnregisterNegativeHandles) { + transfer_buffer_manager_->DestroyTransferBuffer(-1); + EXPECT_EQ(1, transfer_buffer_manager_->CreateTransferBuffer(1024, -1)); +} + +TEST_F(TransferBufferManagerTest, CannotUnregisterUnregisteredHandles) { + transfer_buffer_manager_->DestroyTransferBuffer(1); + EXPECT_EQ(1, transfer_buffer_manager_->CreateTransferBuffer(1024, -1)); +} + +// Testing this case specifically because there is an optimization that takes +// a different code path in this case. +TEST_F(TransferBufferManagerTest, UnregistersLastRegisteredHandle) { + EXPECT_EQ(1, transfer_buffer_manager_->CreateTransferBuffer(1024, -1)); + transfer_buffer_manager_->DestroyTransferBuffer(1); + EXPECT_EQ(1, transfer_buffer_manager_->CreateTransferBuffer(1024, -1)); +} + +// Testing this case specifically because there is an optimization that takes +// a different code path in this case. +TEST_F(TransferBufferManagerTest, UnregistersTwoLastRegisteredHandles) { + EXPECT_EQ(1, transfer_buffer_manager_->CreateTransferBuffer(1024, -1)); + EXPECT_EQ(2, transfer_buffer_manager_->CreateTransferBuffer(1024, -1)); + transfer_buffer_manager_->DestroyTransferBuffer(2); + transfer_buffer_manager_->DestroyTransferBuffer(1); + EXPECT_EQ(1, transfer_buffer_manager_->CreateTransferBuffer(1024, -1)); +} + +} // namespace gpu |