diff options
author | apatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-22 21:00:46 +0000 |
---|---|---|
committer | apatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-22 21:00:46 +0000 |
commit | b484deaa8a388caad6bac705a88ac575d3edf1c5 (patch) | |
tree | 25ebc6119a9ef6f35db10bfae37ebc97d1f0bdb4 | |
parent | 564ba361b30ba95793ef505f8895d48b0df3ee2f (diff) | |
download | chromium_src-b484deaa8a388caad6bac705a88ac575d3edf1c5.zip chromium_src-b484deaa8a388caad6bac705a88ac575d3edf1c5.tar.gz chromium_src-b484deaa8a388caad6bac705a88ac575d3edf1c5.tar.bz2 |
Added support for registering additional shared memory objects (textures and buffers etc) with the CommandBuffer.
TEST=none
BUG=none
Review URL: http://codereview.chromium.org/216043
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@26857 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | o3d/gpu_plugin/command_buffer.cc | 57 | ||||
-rw-r--r-- | o3d/gpu_plugin/command_buffer.h | 26 | ||||
-rw-r--r-- | o3d/gpu_plugin/command_buffer_mock.h | 3 | ||||
-rw-r--r-- | o3d/gpu_plugin/command_buffer_unittest.cc | 78 |
4 files changed, 161 insertions, 3 deletions
diff --git a/o3d/gpu_plugin/command_buffer.cc b/o3d/gpu_plugin/command_buffer.cc index ab97e28..badda14 100644 --- a/o3d/gpu_plugin/command_buffer.cc +++ b/o3d/gpu_plugin/command_buffer.cc @@ -12,6 +12,8 @@ CommandBuffer::CommandBuffer(NPP npp) size_(0), get_offset_(0), put_offset_(0) { + // Element zero is always NULL. + registered_objects_.push_back(NPObjectPointer<NPObject>()); } CommandBuffer::~CommandBuffer() { @@ -42,7 +44,7 @@ bool CommandBuffer::Initialize(int32 size) { return false; } - // TODO(spatrick): validate NPClass before assuming a CHRSHaredMemory is + // TODO(spatrick): validate NPClass before assuming a CHRSharedMemory is // returned. shared_memory_ = NPObjectPointer<CHRSharedMemory>( static_cast<CHRSharedMemory*>(result.Get())); @@ -97,5 +99,58 @@ void CommandBuffer::SetPutOffsetChangeCallback(Callback0::Type* callback) { put_offset_change_callback_.reset(callback); } +int32 CommandBuffer::RegisterObject(NPObjectPointer<NPObject> object) { + if (!object.Get()) + return 0; + + if (unused_registered_object_elements_.empty()) { + // Check we haven't exceeded the range that fits in a 32-bit integer. + int32 handle = static_cast<int32>(registered_objects_.size()); + if (handle != registered_objects_.size()) + return -1; + + registered_objects_.push_back(object); + return handle; + } + + int32 handle = *unused_registered_object_elements_.begin(); + unused_registered_object_elements_.erase( + unused_registered_object_elements_.begin()); + DCHECK(!registered_objects_[handle].Get()); + registered_objects_[handle] = object; + return handle; +} + +void CommandBuffer::UnregisterObject(NPObjectPointer<NPObject> object, + int32 handle) { + if (handle <= 0) + return; + + if (static_cast<size_t>(handle) >= registered_objects_.size()) + return; + + if (registered_objects_[handle] != object) + return; + + registered_objects_[handle] = NPObjectPointer<NPObject>(); + 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().Get()) { + registered_objects_.pop_back(); + unused_registered_object_elements_.erase( + static_cast<int32>(registered_objects_.size())); + } +} + +NPObjectPointer<NPObject> CommandBuffer::GetRegisteredObject(int32 handle) { + DCHECK_GE(handle, 0); + DCHECK_LT(static_cast<size_t>(handle), registered_objects_.size()); + + return registered_objects_[handle]; +} + } // namespace gpu_plugin } // namespace o3d diff --git a/o3d/gpu_plugin/command_buffer.h b/o3d/gpu_plugin/command_buffer.h index 40b8ff3..145cbe7 100644 --- a/o3d/gpu_plugin/command_buffer.h +++ b/o3d/gpu_plugin/command_buffer.h @@ -5,6 +5,9 @@ #ifndef O3D_GPU_PLUGIN_COMMAND_BUFFER_H_ #define O3D_GPU_PLUGIN_COMMAND_BUFFER_H_ +#include <set> +#include <vector> + #include "base/message_loop.h" #include "base/scoped_ptr.h" #include "base/task.h" @@ -55,7 +58,21 @@ class CommandBuffer : public DefaultNPObject<NPObject> { // synchronize reader and writer reduces the risk of deadlock. // Takes ownership of callback. The callback is invoked on the plugin thread. virtual void SetPutOffsetChangeCallback(Callback0::Type* callback); - + + // Get an opaque integer handle for an NPObject. This can be used + // to identify the shared memory object from the ring buffer. Note that the + // object will be retained. Consider reference cycle issues. Returns zero for + // NULL, positive for non-NULL and -1 on error. Objects may be registered + // multiple times and have multiple associated handles. Each handle for a + // distinct object must be separately unregistered. + virtual int32 RegisterObject(NPObjectPointer<NPObject> object); + + // Unregister a previously registered NPObject. It is safe to unregister the + // zero handle. + virtual void UnregisterObject(NPObjectPointer<NPObject> object, int32 handle); + + virtual NPObjectPointer<NPObject> GetRegisteredObject(int32 handle); + NP_UTILS_BEGIN_DISPATCHER_CHAIN(CommandBuffer, DefaultNPObject<NPObject>) NP_UTILS_DISPATCHER(Initialize, bool(int32)) NP_UTILS_DISPATCHER(GetRingBuffer, NPObjectPointer<CHRSharedMemory>()) @@ -63,6 +80,9 @@ class CommandBuffer : public DefaultNPObject<NPObject> { NP_UTILS_DISPATCHER(SyncOffsets, int32(int32)) NP_UTILS_DISPATCHER(GetGetOffset, int32()); NP_UTILS_DISPATCHER(GetPutOffset, int32()); + NP_UTILS_DISPATCHER(RegisterObject, int32(NPObjectPointer<NPObject>)); + NP_UTILS_DISPATCHER(UnregisterObject, + void(NPObjectPointer<NPObject>, int32)); NP_UTILS_END_DISPATCHER_CHAIN private: @@ -72,9 +92,11 @@ class CommandBuffer : public DefaultNPObject<NPObject> { int32 get_offset_; int32 put_offset_; scoped_ptr<Callback0::Type> put_offset_change_callback_; + std::vector<NPObjectPointer<NPObject> > registered_objects_; + std::set<int32> unused_registered_object_elements_; }; } // namespace gpu_plugin } // namespace o3d -#endif // O3D_GPU_PLUGIN_COMMAND_BUFFER_H_
\ No newline at end of file +#endif // O3D_GPU_PLUGIN_COMMAND_BUFFER_H_ diff --git a/o3d/gpu_plugin/command_buffer_mock.h b/o3d/gpu_plugin/command_buffer_mock.h index 191cb3fb..d9f7379 100644 --- a/o3d/gpu_plugin/command_buffer_mock.h +++ b/o3d/gpu_plugin/command_buffer_mock.h @@ -26,6 +26,9 @@ class MockCommandBuffer : public CommandBuffer { MOCK_METHOD1(SetGetOffset, void(int32)); MOCK_METHOD0(GetPutOffset, int32()); MOCK_METHOD1(SetPutOffsetChangeCallback, void(Callback0::Type*)); + MOCK_METHOD1(RegisterObject, int32(NPObjectPointer<NPObject>)); + MOCK_METHOD2(UnregisterObject, void(NPObjectPointer<NPObject>, int32)); + MOCK_METHOD0(GetRegisteredObject, NPObjectPointer<NPObject>()); private: DISALLOW_COPY_AND_ASSIGN(MockCommandBuffer); diff --git a/o3d/gpu_plugin/command_buffer_unittest.cc b/o3d/gpu_plugin/command_buffer_unittest.cc index 174a754..435a0fc 100644 --- a/o3d/gpu_plugin/command_buffer_unittest.cc +++ b/o3d/gpu_plugin/command_buffer_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/thread.h" #include "o3d/gpu_plugin/command_buffer.h" #include "o3d/gpu_plugin/np_utils/dynamic_np_object.h" #include "o3d/gpu_plugin/np_utils/np_browser_mock.h" @@ -158,5 +159,82 @@ TEST_F(CommandBufferTest, CanSyncGetAndPutOffset) { EXPECT_EQ(-1, command_buffer_->SyncOffsets(1024)); } +TEST_F(CommandBufferTest, ZeroHandleMapsToNull) { + EXPECT_TRUE(NULL == command_buffer_->GetRegisteredObject(0).Get()); +} + +TEST_F(CommandBufferTest, RegisteringNullObjectReturnsZero) { + EXPECT_EQ(0, command_buffer_->RegisterObject(NPObjectPointer<NPObject>())); +} + +TEST_F(CommandBufferTest, RegistersDistinctNonZeroHandlesForObject) { + EXPECT_EQ(1, command_buffer_->RegisterObject(window_object_)); + EXPECT_EQ(window_object_, command_buffer_->GetRegisteredObject(1)); + EXPECT_EQ(2, command_buffer_->RegisterObject(window_object_)); + EXPECT_EQ(window_object_, command_buffer_->GetRegisteredObject(2)); +} + +TEST_F(CommandBufferTest, RegisterObjectReusesUnregisteredHandles) { + EXPECT_EQ(1, command_buffer_->RegisterObject(window_object_)); + EXPECT_EQ(window_object_, command_buffer_->GetRegisteredObject(1)); + EXPECT_EQ(2, command_buffer_->RegisterObject(window_object_)); + EXPECT_EQ(window_object_, command_buffer_->GetRegisteredObject(2)); + command_buffer_->UnregisterObject(window_object_, 1); + EXPECT_EQ(1, command_buffer_->RegisterObject(window_object_)); + EXPECT_EQ(window_object_, command_buffer_->GetRegisteredObject(1)); + EXPECT_EQ(3, command_buffer_->RegisterObject(window_object_)); + EXPECT_EQ(window_object_, command_buffer_->GetRegisteredObject(3)); +} + +TEST_F(CommandBufferTest, CannotUnregisterHandleZero) { + command_buffer_->UnregisterObject(window_object_, 0); + EXPECT_TRUE(NULL == command_buffer_->GetRegisteredObject(0).Get()); + EXPECT_EQ(1, command_buffer_->RegisterObject(window_object_)); + EXPECT_EQ(window_object_, command_buffer_->GetRegisteredObject(1)); +} + +TEST_F(CommandBufferTest, CannotUnregisterNegativeHandles) { + command_buffer_->UnregisterObject(window_object_, -1); + EXPECT_EQ(1, command_buffer_->RegisterObject(window_object_)); + EXPECT_EQ(window_object_, command_buffer_->GetRegisteredObject(1)); +} + +TEST_F(CommandBufferTest, CannotUnregisterUnregisteredHandles) { + command_buffer_->UnregisterObject(window_object_, 1); + EXPECT_EQ(1, command_buffer_->RegisterObject(window_object_)); + EXPECT_EQ(window_object_, command_buffer_->GetRegisteredObject(1)); +} + +TEST_F(CommandBufferTest, + CannotUnregisterHandleWithoutDemonstratingAccessToObject) { + EXPECT_EQ(1, command_buffer_->RegisterObject(window_object_)); + command_buffer_->UnregisterObject(chromium_object_, 1); + EXPECT_EQ(window_object_, command_buffer_->GetRegisteredObject(1)); + EXPECT_EQ(2, command_buffer_->RegisterObject(window_object_)); +} + +// Testing this case specifically because there is an optimization that takes +// a different code path in this case. +TEST_F(CommandBufferTest, UnregistersLastRegisteredHandle) { + EXPECT_EQ(1, command_buffer_->RegisterObject(window_object_)); + EXPECT_EQ(window_object_, command_buffer_->GetRegisteredObject(1)); + command_buffer_->UnregisterObject(window_object_, 1); + EXPECT_EQ(1, command_buffer_->RegisterObject(window_object_)); + EXPECT_EQ(window_object_, command_buffer_->GetRegisteredObject(1)); +} + +// Testing this case specifically because there is an optimization that takes +// a different code path in this case. +TEST_F(CommandBufferTest, UnregistersTwoLastRegisteredHandles) { + EXPECT_EQ(1, command_buffer_->RegisterObject(window_object_)); + EXPECT_EQ(window_object_, command_buffer_->GetRegisteredObject(1)); + EXPECT_EQ(2, command_buffer_->RegisterObject(window_object_)); + EXPECT_EQ(window_object_, command_buffer_->GetRegisteredObject(2)); + command_buffer_->UnregisterObject(window_object_, 2); + command_buffer_->UnregisterObject(window_object_, 1); + EXPECT_EQ(1, command_buffer_->RegisterObject(window_object_)); + EXPECT_EQ(window_object_, command_buffer_->GetRegisteredObject(1)); +} + } // namespace gpu_plugin } // namespace o3d |