summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorapatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-22 21:00:46 +0000
committerapatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-22 21:00:46 +0000
commitb484deaa8a388caad6bac705a88ac575d3edf1c5 (patch)
tree25ebc6119a9ef6f35db10bfae37ebc97d1f0bdb4
parent564ba361b30ba95793ef505f8895d48b0df3ee2f (diff)
downloadchromium_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.cc57
-rw-r--r--o3d/gpu_plugin/command_buffer.h26
-rw-r--r--o3d/gpu_plugin/command_buffer_mock.h3
-rw-r--r--o3d/gpu_plugin/command_buffer_unittest.cc78
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