diff options
author | apatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-21 23:24:18 +0000 |
---|---|---|
committer | apatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-21 23:24:18 +0000 |
commit | b19ed717676f1dcf50e8bb530404019a3fbb308a (patch) | |
tree | 5ba3d65e39b878a05290d612fa705fa8e14f498d /o3d | |
parent | a33457b842b5b8e70622d7c73f266bb94dec6a49 (diff) | |
download | chromium_src-b19ed717676f1dcf50e8bb530404019a3fbb308a.zip chromium_src-b19ed717676f1dcf50e8bb530404019a3fbb308a.tar.gz chromium_src-b19ed717676f1dcf50e8bb530404019a3fbb308a.tar.bz2 |
Implemented get and put offset synchronization via NPObject interface in GPU plugin CommandBuffer.
Added GPUProcessor which handles commands (currently 4-byte "colors") put into the command buffer.
TEST=none
BUG=none
Review URL: http://codereview.chromium.org/203003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@26762 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r-- | o3d/gpu_plugin/command_buffer.cc | 40 | ||||
-rw-r--r-- | o3d/gpu_plugin/command_buffer.h | 49 | ||||
-rw-r--r-- | o3d/gpu_plugin/command_buffer_mock.h | 11 | ||||
-rw-r--r-- | o3d/gpu_plugin/command_buffer_unittest.cc | 72 | ||||
-rw-r--r-- | o3d/gpu_plugin/gpu_plugin.gyp | 6 | ||||
-rw-r--r-- | o3d/gpu_plugin/gpu_plugin_object.cc | 29 | ||||
-rw-r--r-- | o3d/gpu_plugin/gpu_plugin_object.h | 8 | ||||
-rw-r--r-- | o3d/gpu_plugin/gpu_plugin_object_unittest.cc | 21 | ||||
-rw-r--r-- | o3d/gpu_plugin/gpu_plugin_object_win.cc | 11 | ||||
-rw-r--r-- | o3d/gpu_plugin/gpu_processor.cc | 78 | ||||
-rw-r--r-- | o3d/gpu_plugin/gpu_processor.h | 42 | ||||
-rw-r--r-- | o3d/gpu_plugin/gpu_processor_unittest.cc | 163 | ||||
-rw-r--r-- | o3d/gpu_plugin/gpu_processor_win.cc | 39 | ||||
-rw-r--r-- | o3d/gpu_plugin/system_services/shared_memory.cc | 14 | ||||
-rw-r--r-- | o3d/gpu_plugin/system_services/shared_memory.h | 5 | ||||
-rw-r--r-- | o3d/gpu_plugin/system_services/shared_memory_unittest.cc | 44 |
16 files changed, 586 insertions, 46 deletions
diff --git a/o3d/gpu_plugin/command_buffer.cc b/o3d/gpu_plugin/command_buffer.cc index 5f520dc..ab97e28 100644 --- a/o3d/gpu_plugin/command_buffer.cc +++ b/o3d/gpu_plugin/command_buffer.cc @@ -7,7 +7,11 @@ namespace o3d { namespace gpu_plugin { -CommandBuffer::CommandBuffer(NPP npp) : npp_(npp) { +CommandBuffer::CommandBuffer(NPP npp) + : npp_(npp), + size_(0), + get_offset_(0), + put_offset_(0) { } CommandBuffer::~CommandBuffer() { @@ -51,18 +55,46 @@ bool CommandBuffer::Initialize(int32 size) { return false; } + size_ = size; return true; } -NPObjectPointer<NPObject> CommandBuffer::GetSharedMemory() { +NPObjectPointer<CHRSharedMemory> CommandBuffer::GetRingBuffer() { return shared_memory_; } -void CommandBuffer::SetPutOffset(int32 offset) { +int32 CommandBuffer::GetSize() { + return size_; +} + +int32 CommandBuffer::SyncOffsets(int32 put_offset) { + if (put_offset < 0 || put_offset >= size_) + return -1; + + put_offset_ = put_offset; + + if (put_offset_change_callback_.get()) { + put_offset_change_callback_->Run(); + } + + return get_offset_; } int32 CommandBuffer::GetGetOffset() { - return 0; + return get_offset_; +} + +void CommandBuffer::SetGetOffset(int32 get_offset) { + DCHECK(get_offset >= 0 && get_offset < size_); + get_offset_ = get_offset; +} + +int32 CommandBuffer::GetPutOffset() { + return put_offset_; +} + +void CommandBuffer::SetPutOffsetChangeCallback(Callback0::Type* callback) { + put_offset_change_callback_.reset(callback); } } // namespace gpu_plugin diff --git a/o3d/gpu_plugin/command_buffer.h b/o3d/gpu_plugin/command_buffer.h index d7be196..40b8ff3 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 "base/message_loop.h" +#include "base/scoped_ptr.h" +#include "base/task.h" #include "o3d/gpu_plugin/np_utils/default_np_object.h" #include "o3d/gpu_plugin/np_utils/np_dispatcher.h" #include "o3d/gpu_plugin/system_services/shared_memory_public.h" @@ -22,28 +25,56 @@ class CommandBuffer : public DefaultNPObject<NPObject> { // Create a shared memory buffer of the given size. virtual bool Initialize(int32 size); - // Gets the shared memory object for the command buffer. - virtual NPObjectPointer<NPObject> GetSharedMemory(); + // Gets the shared memory ring buffer object for the command buffer. + virtual NPObjectPointer<CHRSharedMemory> GetRingBuffer(); - // The client calls this to update its put offset. - virtual void SetPutOffset(int32 offset); + virtual int32 GetSize(); - // The client calls this to get the servers current get offset. + // The writer calls this to update its put offset. This function returns the + // reader's most recent get offset. Does not return until after the put offset + // change callback has been invoked. Returns -1 if the put offset is invalid. + virtual int32 SyncOffsets(int32 put_offset); + + // Returns the current get offset. This can be called from any thread. virtual int32 GetGetOffset(); + // Sets the current get offset. This can be called from any thread. + virtual void SetGetOffset(int32 get_offset); + + // Returns the current put offset. This can be called from any thread. + virtual int32 GetPutOffset(); + + // Sets a callback that should be posted on another thread whenever the put + // offset is changed. The callback must not return until some progress has + // been made (unless the command buffer is empty), i.e. the + // get offset must have changed. It need not process the entire command + // buffer though. This allows concurrency between the writer and the reader + // while giving the writer a means of waiting for the reader to make some + // progress before attempting to write more to the command buffer. Avoiding + // the use of a synchronization primitive like a condition variable to + // 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); + NP_UTILS_BEGIN_DISPATCHER_CHAIN(CommandBuffer, DefaultNPObject<NPObject>) NP_UTILS_DISPATCHER(Initialize, bool(int32)) - NP_UTILS_DISPATCHER(SetPutOffset, void(int32)) - NP_UTILS_DISPATCHER(GetGetOffset, int32()) - NP_UTILS_DISPATCHER(GetSharedMemory, NPObjectPointer<NPObject>()) + NP_UTILS_DISPATCHER(GetRingBuffer, NPObjectPointer<CHRSharedMemory>()) + NP_UTILS_DISPATCHER(GetSize, int32()) + NP_UTILS_DISPATCHER(SyncOffsets, int32(int32)) + NP_UTILS_DISPATCHER(GetGetOffset, int32()); + NP_UTILS_DISPATCHER(GetPutOffset, int32()); NP_UTILS_END_DISPATCHER_CHAIN private: NPP npp_; NPObjectPointer<CHRSharedMemory> shared_memory_; + int32 size_; + int32 get_offset_; + int32 put_offset_; + scoped_ptr<Callback0::Type> put_offset_change_callback_; }; } // namespace gpu_plugin } // namespace o3d -#endif // O3D_GPU_PLUGIN_COMMAND_BUFFER_H_ +#endif // O3D_GPU_PLUGIN_COMMAND_BUFFER_H_
\ No newline at end of file diff --git a/o3d/gpu_plugin/command_buffer_mock.h b/o3d/gpu_plugin/command_buffer_mock.h index 9d3f799..191cb3fb 100644 --- a/o3d/gpu_plugin/command_buffer_mock.h +++ b/o3d/gpu_plugin/command_buffer_mock.h @@ -19,9 +19,16 @@ class MockCommandBuffer : public CommandBuffer { } MOCK_METHOD1(Initialize, bool(int32)); - MOCK_METHOD0(GetBuffer, NPObjectPointer<NPObject>()); - MOCK_METHOD1(SetPutOffset, void(int32)); + MOCK_METHOD0(GetRingBuffer, NPObjectPointer<CHRSharedMemory>()); + MOCK_METHOD0(GetSize, int32()); + MOCK_METHOD1(SyncOffsets, int32(int32)); MOCK_METHOD0(GetGetOffset, int32()); + MOCK_METHOD1(SetGetOffset, void(int32)); + MOCK_METHOD0(GetPutOffset, int32()); + MOCK_METHOD1(SetPutOffsetChangeCallback, void(Callback0::Type*)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockCommandBuffer); }; } // namespace gpu_plugin diff --git a/o3d/gpu_plugin/command_buffer_unittest.cc b/o3d/gpu_plugin/command_buffer_unittest.cc index acc5970..174a754 100644 --- a/o3d/gpu_plugin/command_buffer_unittest.cc +++ b/o3d/gpu_plugin/command_buffer_unittest.cc @@ -38,7 +38,7 @@ class MockSystemNPObject : public DefaultNPObject<NPObject> { class CommandBufferTest : public testing::Test { protected: virtual void SetUp() { - command_buffer_object_ = NPCreateObject<CommandBuffer>(NULL); + command_buffer_ = NPCreateObject<CommandBuffer>(NULL); window_object_ = NPCreateObject<DynamicNPObject>(NULL); @@ -50,16 +50,15 @@ class CommandBufferTest : public testing::Test { } MockNPBrowser mock_browser_; - NPObjectPointer<CommandBuffer> command_buffer_object_; + NPObjectPointer<CommandBuffer> command_buffer_; NPObjectPointer<DynamicNPObject> window_object_; NPObjectPointer<DynamicNPObject> chromium_object_; NPObjectPointer<MockSystemNPObject> system_object_; }; -TEST_F(CommandBufferTest, TestBehaviorWhileUninitialized) { +TEST_F(CommandBufferTest, NullRingBufferByDefault) { EXPECT_EQ(NPObjectPointer<NPObject>(), - command_buffer_object_->GetSharedMemory()); - EXPECT_EQ(0, command_buffer_object_->GetGetOffset()); + command_buffer_->GetRingBuffer()); } TEST_F(CommandBufferTest, InitializesCommandBuffer) { @@ -75,12 +74,12 @@ TEST_F(CommandBufferTest, InitializesCommandBuffer) { EXPECT_CALL(*expected_shared_memory.Get(), Map()) .WillOnce(Return(true)); - EXPECT_TRUE(command_buffer_object_->Initialize(1024)); - EXPECT_EQ(expected_shared_memory, command_buffer_object_->GetSharedMemory()); + EXPECT_TRUE(command_buffer_->Initialize(1024)); + EXPECT_EQ(expected_shared_memory, command_buffer_->GetRingBuffer()); // Cannot reinitialize. - EXPECT_FALSE(command_buffer_object_->Initialize(1024)); - EXPECT_EQ(expected_shared_memory, command_buffer_object_->GetSharedMemory()); + EXPECT_FALSE(command_buffer_->Initialize(1024)); + EXPECT_EQ(expected_shared_memory, command_buffer_->GetRingBuffer()); } TEST_F(CommandBufferTest, InitializeFailsIfCannotCreateSharedMemory) { @@ -90,9 +89,9 @@ TEST_F(CommandBufferTest, InitializeFailsIfCannotCreateSharedMemory) { EXPECT_CALL(*system_object_.Get(), CreateSharedMemory(1024)) .WillOnce(Return(NPObjectPointer<NPObject>())); - EXPECT_FALSE(command_buffer_object_->Initialize(1024)); + EXPECT_FALSE(command_buffer_->Initialize(1024)); EXPECT_EQ(NPObjectPointer<NPObject>(), - command_buffer_object_->GetSharedMemory()); + command_buffer_->GetRingBuffer()); } TEST_F(CommandBufferTest, InitializeFailsIfCannotMapSharedMemory) { @@ -108,9 +107,56 @@ TEST_F(CommandBufferTest, InitializeFailsIfCannotMapSharedMemory) { EXPECT_CALL(*expected_shared_memory.Get(), Map()) .WillOnce(Return(false)); - EXPECT_FALSE(command_buffer_object_->Initialize(1024)); + EXPECT_FALSE(command_buffer_->Initialize(1024)); EXPECT_EQ(NPObjectPointer<NPObject>(), - command_buffer_object_->GetSharedMemory()); + command_buffer_->GetRingBuffer()); } + +TEST_F(CommandBufferTest, GetAndPutOffsetsDefaultToZero) { + EXPECT_EQ(0, command_buffer_->GetGetOffset()); + EXPECT_EQ(0, command_buffer_->GetPutOffset()); +} + +class MockCallback : public CallbackRunner<Tuple0> { + public: + MOCK_METHOD1(RunWithParams, void(const Tuple0&)); +}; + +TEST_F(CommandBufferTest, CanSyncGetAndPutOffset) { + EXPECT_CALL(mock_browser_, GetWindowNPObject(NULL)) + .WillOnce(Return(window_object_.ToReturned())); + + NPObjectPointer<MockSharedMemory> expected_shared_memory = + NPCreateObject<StrictMock<MockSharedMemory> >(NULL); + + EXPECT_CALL(*system_object_.Get(), CreateSharedMemory(1024)) + .WillOnce(Return(expected_shared_memory)); + + EXPECT_CALL(*expected_shared_memory.Get(), Map()) + .WillOnce(Return(true)); + + EXPECT_TRUE(command_buffer_->Initialize(1024)); + + StrictMock<MockCallback>* put_offset_change_callback = + new StrictMock<MockCallback>; + command_buffer_->SetPutOffsetChangeCallback(put_offset_change_callback); + + EXPECT_CALL(*put_offset_change_callback, RunWithParams(_)); + EXPECT_EQ(0, command_buffer_->SyncOffsets(2)); + EXPECT_EQ(2, command_buffer_->GetPutOffset()); + + EXPECT_CALL(*put_offset_change_callback, RunWithParams(_)); + EXPECT_EQ(0, command_buffer_->SyncOffsets(4)); + EXPECT_EQ(4, command_buffer_->GetPutOffset()); + + command_buffer_->SetGetOffset(2); + EXPECT_EQ(2, command_buffer_->GetGetOffset()); + EXPECT_CALL(*put_offset_change_callback, RunWithParams(_)); + EXPECT_EQ(2, command_buffer_->SyncOffsets(6)); + + EXPECT_EQ(-1, command_buffer_->SyncOffsets(-1)); + EXPECT_EQ(-1, command_buffer_->SyncOffsets(1024)); +} + } // namespace gpu_plugin } // namespace o3d diff --git a/o3d/gpu_plugin/gpu_plugin.gyp b/o3d/gpu_plugin/gpu_plugin.gyp index 908cc99..4831568 100644 --- a/o3d/gpu_plugin/gpu_plugin.gyp +++ b/o3d/gpu_plugin/gpu_plugin.gyp @@ -120,6 +120,7 @@ 'sources': [ 'command_buffer.cc', 'command_buffer.h', + 'command_buffer_mock.h', 'gpu_plugin.cc', 'gpu_plugin.h', 'gpu_plugin_object.cc', @@ -127,6 +128,9 @@ 'gpu_plugin_object_win.cc', 'gpu_plugin_object_factory.cc', 'gpu_plugin_object_factory.h', + 'gpu_processor.h', + 'gpu_processor.cc', + 'gpu_processor_win.cc', ], }, @@ -148,11 +152,11 @@ '../../third_party/npapi', ], 'sources': [ - 'command_buffer_mock.h', 'command_buffer_unittest.cc', 'gpu_plugin_unittest.cc', 'gpu_plugin_object_unittest.cc', 'gpu_plugin_object_factory_unittest.cc', + 'gpu_processor_unittest.cc', ], }, ] diff --git a/o3d/gpu_plugin/gpu_plugin_object.cc b/o3d/gpu_plugin/gpu_plugin_object.cc index de67c8a4..0fdd85a 100644 --- a/o3d/gpu_plugin/gpu_plugin_object.cc +++ b/o3d/gpu_plugin/gpu_plugin_object.cc @@ -7,6 +7,7 @@ #include "base/logging.h" #include "o3d/gpu_plugin/np_utils/np_utils.h" #include "o3d/gpu_plugin/gpu_plugin_object.h" +#include "o3d/gpu_plugin/gpu_processor.h" namespace o3d { namespace gpu_plugin { @@ -48,6 +49,8 @@ NPError GPUPluginObject::SetWindow(NPWindow* new_window) { memset(&window_, 0, sizeof(window_)); } + UpdateProcessorWindow(); + return error; } @@ -59,7 +62,11 @@ NPError GPUPluginObject::Destroy(NPSavedData** saved) { if (status_ != INITIALIZED) return NPERR_GENERIC_ERROR; - command_buffer_object_ = NPObjectPointer<CommandBuffer>(); + processor_ = NULL; + if (command_buffer_.Get()) { + command_buffer_->SetPutOffsetChangeCallback(NULL); + command_buffer_ = NPObjectPointer<CommandBuffer>(); + } status_ = DESTROYED; @@ -77,15 +84,21 @@ NPObject*GPUPluginObject::GetScriptableNPObject() { } NPObjectPointer<NPObject> GPUPluginObject::OpenCommandBuffer() { - if (command_buffer_object_.Get()) - return command_buffer_object_; - - command_buffer_object_ = NPCreateObject<CommandBuffer>(npp_); - if (!command_buffer_object_->Initialize(kCommandBufferSize)) { - command_buffer_object_ = NPObjectPointer<CommandBuffer>(); + if (command_buffer_.Get()) + return command_buffer_; + + command_buffer_ = NPCreateObject<CommandBuffer>(npp_); + if (command_buffer_->Initialize(kCommandBufferSize)) { + processor_ = new GPUProcessor(command_buffer_); + command_buffer_->SetPutOffsetChangeCallback( + NewCallback(processor_.get(), + &GPUProcessor::ProcessCommands)); + UpdateProcessorWindow(); + return command_buffer_; } - return command_buffer_object_; + command_buffer_ = NPObjectPointer<CommandBuffer>(); + return command_buffer_; } } // namespace gpu_plugin diff --git a/o3d/gpu_plugin/gpu_plugin_object.h b/o3d/gpu_plugin/gpu_plugin_object.h index 0ca11e3..127ee8d 100644 --- a/o3d/gpu_plugin/gpu_plugin_object.h +++ b/o3d/gpu_plugin/gpu_plugin_object.h @@ -7,6 +7,8 @@ #include <string> +#include "base/ref_counted.h" +#include "base/thread.h" #include "o3d/gpu_plugin/command_buffer.h" #include "o3d/gpu_plugin/np_utils/default_np_object.h" #include "o3d/gpu_plugin/np_utils/np_dispatcher.h" @@ -18,6 +20,8 @@ namespace o3d { namespace gpu_plugin { +class GPUProcessor; + // The scriptable object for the GPU plugin. class GPUPluginObject : public DefaultNPObject<NPObject>, public PluginObject { @@ -52,6 +56,7 @@ class GPUPluginObject : public DefaultNPObject<NPObject>, private: NPError PlatformSpecificSetWindow(NPWindow* new_window); + void UpdateProcessorWindow(); enum Status { CREATED, @@ -62,7 +67,8 @@ class GPUPluginObject : public DefaultNPObject<NPObject>, NPP npp_; Status status_; NPWindow window_; - NPObjectPointer<CommandBuffer> command_buffer_object_; + NPObjectPointer<CommandBuffer> command_buffer_; + scoped_refptr<GPUProcessor> processor_; }; } // namespace gpu_plugin diff --git a/o3d/gpu_plugin/gpu_plugin_object_unittest.cc b/o3d/gpu_plugin/gpu_plugin_object_unittest.cc index 452cba5..ce9b306 100644 --- a/o3d/gpu_plugin/gpu_plugin_object_unittest.cc +++ b/o3d/gpu_plugin/gpu_plugin_object_unittest.cc @@ -13,6 +13,7 @@ using testing::_; using testing::DoAll; +using testing::NotNull; using testing::Return; using testing::SetArgumentPointee; using testing::StrictMock; @@ -104,38 +105,42 @@ TEST_F(GPUPluginObjectTest, CanGetScriptableNPObject) { TEST_F(GPUPluginObjectTest, OpenCommandBufferReturnsInitializedCommandBuffer) { // Intercept creation of command buffer object and return mock. - NPObjectPointer<MockCommandBuffer> command_buffer_object = + NPObjectPointer<MockCommandBuffer> command_buffer = NPCreateObject<StrictMock<MockCommandBuffer> >(NULL); EXPECT_CALL(mock_browser_, CreateObject(NULL, NPGetClass<CommandBuffer>())) - .WillOnce(Return(command_buffer_object.ToReturned())); + .WillOnce(Return(command_buffer.ToReturned())); - EXPECT_CALL(*command_buffer_object.Get(), Initialize(1024)) + EXPECT_CALL(*command_buffer.Get(), Initialize(1024)) .WillOnce(Return(true)); + EXPECT_CALL(*command_buffer.Get(), SetPutOffsetChangeCallback(NotNull())); + EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo", 0, NULL, NULL, NULL)); - EXPECT_EQ(command_buffer_object, plugin_object_->OpenCommandBuffer()); + EXPECT_EQ(command_buffer, plugin_object_->OpenCommandBuffer()); // Calling OpenCommandBuffer again just returns the existing command buffer. - EXPECT_EQ(command_buffer_object, plugin_object_->OpenCommandBuffer()); + EXPECT_EQ(command_buffer, plugin_object_->OpenCommandBuffer()); + + EXPECT_CALL(*command_buffer.Get(), SetPutOffsetChangeCallback(NULL)); EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->Destroy(NULL)); } TEST_F(GPUPluginObjectTest, OpenCommandBufferReturnsNullIfCannotInitialize) { // Intercept creation of command buffer object and return mock. - NPObjectPointer<MockCommandBuffer> command_buffer_object = + NPObjectPointer<MockCommandBuffer> command_buffer = NPCreateObject<StrictMock<MockCommandBuffer> >(NULL); EXPECT_CALL(mock_browser_, CreateObject(NULL, NPGetClass<CommandBuffer>())) - .WillOnce(Return(command_buffer_object.ToReturned())); + .WillOnce(Return(command_buffer.ToReturned())); - EXPECT_CALL(*command_buffer_object.Get(), Initialize(1024)) + EXPECT_CALL(*command_buffer.Get(), Initialize(1024)) .WillOnce(Return(false)); EXPECT_EQ(NPERR_NO_ERROR, plugin_object_->New("application/foo", diff --git a/o3d/gpu_plugin/gpu_plugin_object_win.cc b/o3d/gpu_plugin/gpu_plugin_object_win.cc index ddcdf2c..9bdb331 100644 --- a/o3d/gpu_plugin/gpu_plugin_object_win.cc +++ b/o3d/gpu_plugin/gpu_plugin_object_win.cc @@ -5,6 +5,7 @@ #include <windows.h> #include "o3d/gpu_plugin/gpu_plugin_object.h" +#include "o3d/gpu_plugin/gpu_processor.h" namespace o3d { namespace gpu_plugin { @@ -49,8 +50,18 @@ NPError GPUPluginObject::PlatformSpecificSetWindow(NPWindow* new_window) { reinterpret_cast<LONG>(WindowProc)); } + UpdateProcessorWindow(); + return NPERR_NO_ERROR; } +void GPUPluginObject::UpdateProcessorWindow() { + if (processor_) { + processor_->SetWindow(reinterpret_cast<HWND>(window_.window), + static_cast<int>(window_.width), + static_cast<int>(window_.height)); + } +} + } // namespace gpu_plugin } // namespace o3d diff --git a/o3d/gpu_plugin/gpu_processor.cc b/o3d/gpu_plugin/gpu_processor.cc new file mode 100644 index 0000000..49b13e3 --- /dev/null +++ b/o3d/gpu_plugin/gpu_processor.cc @@ -0,0 +1,78 @@ +// Copyright (c) 2006-2008 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 "o3d/gpu_plugin/gpu_processor.h" + +namespace o3d { +namespace gpu_plugin { + +// Placeholder command processing. +void GPUProcessor::ProcessCommands() { + int32 get_offset = command_buffer_->GetGetOffset(); + int32 put_offset = command_buffer_->GetPutOffset(); + int32 size = command_buffer_->GetSize(); + if (size == 0) + return; + + NPObjectPointer<CHRSharedMemory> shared_memory = + command_buffer_->GetRingBuffer(); + if (!shared_memory.Get()) + return; + if (!shared_memory->ptr) + return; + + int8* ptr = static_cast<int8*>(shared_memory->ptr); + + int32 end_offset = (get_offset + sizeof(int32)) % size; + if (get_offset > put_offset || end_offset <= put_offset) { + int32 command = *reinterpret_cast<int32*>(ptr + get_offset); + + switch (command) { + case 0: + get_offset = end_offset; + command_buffer_->SetGetOffset(get_offset); + break; + + // Rectangle case is temporary and not tested. + case 1: { + end_offset += 20; + if (end_offset >= size) { + DCHECK(false); + break; + } + + if (get_offset <= put_offset && end_offset > put_offset) { + DCHECK(false); + break; + } + + uint32 color = *reinterpret_cast<uint32*>(ptr + get_offset + 4); + int32 left = *reinterpret_cast<int32*>(ptr + get_offset + 8); + int32 top = *reinterpret_cast<int32*>(ptr + get_offset + 12); + int32 right = *reinterpret_cast<int32*>(ptr + get_offset + 16); + int32 bottom = *reinterpret_cast<int32*>(ptr + get_offset + 20); + DrawRectangle(color, left, top, right, bottom); + + get_offset = end_offset; + command_buffer_->SetGetOffset(get_offset); + break; + } + default: + DCHECK(false); + break; + } + + } + + // In practice, this will handle many more than one command before posting + // the processing of the remainder to the message loop. + if (get_offset != put_offset) { + MessageLoop::current()->PostTask( + FROM_HERE, + NewRunnableMethod(this, &GPUProcessor::ProcessCommands)); + } +} + +} // namespace gpu_plugin +} // namespace o3d diff --git a/o3d/gpu_plugin/gpu_processor.h b/o3d/gpu_plugin/gpu_processor.h new file mode 100644 index 0000000..9c3641b --- /dev/null +++ b/o3d/gpu_plugin/gpu_processor.h @@ -0,0 +1,42 @@ +// Copyright (c) 2006-2008 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 O3D_GPU_PLUGIN_GPU_PROCESSOR_H_ +#define O3D_GPU_PLUGIN_GPU_PROCESSOR_H_ + +#include "base/ref_counted.h" +#include "o3d/gpu_plugin/command_buffer.h" +#include "o3d/gpu_plugin/np_utils/np_object_pointer.h" + +namespace o3d { +namespace gpu_plugin { + +// This class processes commands in a command buffer. It is event driven and +// posts tasks to the current message loop to do additional work. +class GPUProcessor : public base::RefCountedThreadSafe<GPUProcessor> { + public: + explicit GPUProcessor(const NPObjectPointer<CommandBuffer>& command_buffer); + + void ProcessCommands(); + +#if defined(OS_WIN) + void SetWindow(HWND handle, int width, int height); +#endif + + void DrawRectangle(uint32 color, int left, int top, int right, int bottom); + + private: + NPObjectPointer<CommandBuffer> command_buffer_; + +#if defined(OS_WIN) + HWND window_handle_; + int window_width_; + int window_height_; +#endif +}; + +} // namespace gpu_plugin +} // namespace o3d + +#endif // O3D_GPU_PLUGIN_GPU_PROCESSOR_H_ diff --git a/o3d/gpu_plugin/gpu_processor_unittest.cc b/o3d/gpu_plugin/gpu_processor_unittest.cc new file mode 100644 index 0000000..dcb0c05 --- /dev/null +++ b/o3d/gpu_plugin/gpu_processor_unittest.cc @@ -0,0 +1,163 @@ +// Copyright (c) 2006-2008 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/at_exit.h" +#include "base/message_loop.h" +#include "o3d/gpu_plugin/command_buffer_mock.h" +#include "o3d/gpu_plugin/gpu_processor.h" +#include "o3d/gpu_plugin/np_utils/np_browser_stub.h" +#include "o3d/gpu_plugin/np_utils/np_object_pointer.h" +#include "o3d/gpu_plugin/system_services/shared_memory_mock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gmock/include/gmock/gmock.h" + +using testing::_; +using testing::DoAll; +using testing::NiceMock; +using testing::Return; +using testing::SetArgumentPointee; +using testing::StrictMock; + +namespace o3d { +namespace gpu_plugin { + +class GPUProcessorTest : public testing::Test { + protected: + virtual void SetUp() { + shared_memory_ = NPCreateObject<NiceMock<MockSharedMemory> >(NULL); + shared_memory_->ptr = buffer_; + shared_memory_->size = sizeof(buffer_); + memset(buffer_, 0, sizeof(buffer_)); + + command_buffer_ = NPCreateObject<MockCommandBuffer>(NULL); + ON_CALL(*command_buffer_.Get(), GetRingBuffer()) + .WillByDefault(Return(shared_memory_)); + + processor_ = new GPUProcessor(command_buffer_); + } + + virtual void TearDown() { + // Ensure that any unexpected tasks posted by the GPU processor are executed + // in order to fail the test. + MessageLoop::current()->RunAllPending(); + } + + base::AtExitManager at_exit_manager; + MessageLoop message_loop; + StubNPBrowser stub_browser_; + NPObjectPointer<MockCommandBuffer> command_buffer_; + NPObjectPointer<NiceMock<MockSharedMemory> > shared_memory_; + int32 buffer_[1024 / sizeof(int32)]; + scoped_refptr<GPUProcessor> processor_; +}; + +TEST_F(GPUProcessorTest, ProcessorDoesNothingIfNoSharedMemory) { + EXPECT_CALL(*command_buffer_, GetGetOffset()) + .WillOnce(Return(0)); + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(0)); + EXPECT_CALL(*command_buffer_, GetSize()) + .WillOnce(Return(1024)); + ON_CALL(*command_buffer_.Get(), GetRingBuffer()) + .WillByDefault(Return(NPObjectPointer<CHRSharedMemory>())); + + processor_->ProcessCommands(); +} + +TEST_F(GPUProcessorTest, ProcessorDoesNothingIfSharedMemoryIsUnmapped) { + EXPECT_CALL(*command_buffer_, GetGetOffset()) + .WillOnce(Return(0)); + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(0)); + EXPECT_CALL(*command_buffer_, GetSize()) + .WillOnce(Return(1024)); + shared_memory_->ptr = NULL; + + processor_->ProcessCommands(); +} + +TEST_F(GPUProcessorTest, ProcessorDoesNothingIfCommandBufferIsZeroSize) { + EXPECT_CALL(*command_buffer_, GetGetOffset()) + .WillOnce(Return(0)); + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(0)); + EXPECT_CALL(*command_buffer_, GetSize()) + .WillOnce(Return(0)); + + processor_->ProcessCommands(); +} + +TEST_F(GPUProcessorTest, ProcessorDoesNothingIfCommandBufferIsEmpty) { + EXPECT_CALL(*command_buffer_, GetGetOffset()) + .WillOnce(Return(0)); + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(0)); + EXPECT_CALL(*command_buffer_, GetSize()) + .WillOnce(Return(sizeof(buffer_))); + + processor_->ProcessCommands(); +} + +TEST_F(GPUProcessorTest, ProcessorHandlesSingleNopCommand) { + EXPECT_CALL(*command_buffer_, GetGetOffset()) + .WillOnce(Return(0)); + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(4)); + EXPECT_CALL(*command_buffer_, GetSize()) + .WillOnce(Return(sizeof(buffer_))); + EXPECT_CALL(*command_buffer_, SetGetOffset(4)); + + processor_->ProcessCommands(); +} + +TEST_F(GPUProcessorTest, ProcessorWrapsAroundToBeginningOfCommandBuffer) { + EXPECT_CALL(*command_buffer_, GetGetOffset()) + .WillOnce(Return(4)); + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(0)); + EXPECT_CALL(*command_buffer_, GetSize()) + .WillOnce(Return(8)); + EXPECT_CALL(*command_buffer_, SetGetOffset(0)); + + processor_->ProcessCommands(); +} + +TEST_F(GPUProcessorTest, + ProcessorHandlesSingleCommandAndPostsTaskToProcessAdditionalCommands) { + EXPECT_CALL(*command_buffer_, GetGetOffset()) + .WillOnce(Return(0)) + .WillOnce(Return(4)); + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(8)) + .WillOnce(Return(8)); + EXPECT_CALL(*command_buffer_, GetSize()) + .WillOnce(Return(sizeof(buffer_))) + .WillOnce(Return(sizeof(buffer_))); + EXPECT_CALL(*command_buffer_, SetGetOffset(4)); + + processor_->ProcessCommands(); + + EXPECT_CALL(*command_buffer_, SetGetOffset(8)); + MessageLoop::current()->RunAllPending(); +} + +TEST_F(GPUProcessorTest, ProcessorDoesNotImmediatelyHandlePartialCommands) { + EXPECT_CALL(*command_buffer_, GetGetOffset()) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + EXPECT_CALL(*command_buffer_, GetPutOffset()) + .WillOnce(Return(2)) + .WillOnce(Return(4)); + EXPECT_CALL(*command_buffer_, GetSize()) + .WillOnce(Return(sizeof(buffer_))) + .WillOnce(Return(sizeof(buffer_))); + + processor_->ProcessCommands(); + + EXPECT_CALL(*command_buffer_, SetGetOffset(4)); + MessageLoop::current()->RunAllPending(); +} + +} // namespace gpu_plugin +} // namespace o3d diff --git a/o3d/gpu_plugin/gpu_processor_win.cc b/o3d/gpu_plugin/gpu_processor_win.cc new file mode 100644 index 0000000..88a84e3 --- /dev/null +++ b/o3d/gpu_plugin/gpu_processor_win.cc @@ -0,0 +1,39 @@ +// Copyright (c) 2006-2008 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 <windows.h> + +#include "o3d/gpu_plugin/gpu_processor.h" + +namespace o3d { +namespace gpu_plugin { + +GPUProcessor::GPUProcessor(const NPObjectPointer<CommandBuffer>& command_buffer) + : command_buffer_(command_buffer), + window_handle_(NULL), + window_width_(0), + window_height_(0) { +} + +void GPUProcessor::SetWindow(HWND handle, int width, int height) { + window_handle_ = handle; + window_width_ = width; + window_height_ = height; +} + +void GPUProcessor::DrawRectangle(uint32 color, + int left, int top, int right, int bottom) { + if (!window_handle_) + return; + + HBRUSH brush = ::CreateSolidBrush(color); + HDC dc = ::GetDC(window_handle_); + RECT rect = { left, right, top, bottom }; + ::FillRect(dc, &rect, brush); + ::ReleaseDC(window_handle_, dc); + ::DeleteObject(brush); +} + +} // namespace gpu_plugin +} // namespace o3d diff --git a/o3d/gpu_plugin/system_services/shared_memory.cc b/o3d/gpu_plugin/system_services/shared_memory.cc index 2246d30..2e07e1a 100644 --- a/o3d/gpu_plugin/system_services/shared_memory.cc +++ b/o3d/gpu_plugin/system_services/shared_memory.cc @@ -61,5 +61,19 @@ bool SharedMemory::Map() { return true; } +bool SharedMemory::SetInt32(int32 offset, int32 value) { + if (!ptr) + return false; + + if (offset < 0 || offset + sizeof(value) >= size) + return false; + + if ((offset % sizeof(value)) != 0) + return false; + + *reinterpret_cast<int32*>(static_cast<int8*>(ptr) + offset) = value; + return true; +} + } // namespace gpu_plugin } // namespace o3d diff --git a/o3d/gpu_plugin/system_services/shared_memory.h b/o3d/gpu_plugin/system_services/shared_memory.h index eb45a96..fd591ee 100644 --- a/o3d/gpu_plugin/system_services/shared_memory.h +++ b/o3d/gpu_plugin/system_services/shared_memory.h @@ -33,6 +33,10 @@ class SharedMemory : public DefaultNPObject<CHRSharedMemory> { virtual bool Map(); + // This is a temporary function to allow me to drive the command buffer from + // JavaScript for the purposes of testing. + bool SetInt32(int32 offset, int32 value); + base::SharedMemory* shared_memory() const { return shared_memory_; } @@ -41,6 +45,7 @@ class SharedMemory : public DefaultNPObject<CHRSharedMemory> { NP_UTILS_DISPATCHER(Initialize, bool(int32)); NP_UTILS_DISPATCHER(GetSize, int32()) NP_UTILS_DISPATCHER(Map, bool()) + NP_UTILS_DISPATCHER(SetInt32, bool(int32, int32)); NP_UTILS_END_DISPATCHER_CHAIN private: diff --git a/o3d/gpu_plugin/system_services/shared_memory_unittest.cc b/o3d/gpu_plugin/system_services/shared_memory_unittest.cc index 9998b19..e2e0825 100644 --- a/o3d/gpu_plugin/system_services/shared_memory_unittest.cc +++ b/o3d/gpu_plugin/system_services/shared_memory_unittest.cc @@ -108,5 +108,49 @@ TEST_F(SharedMemoryTest, CanInitializeWithHandle) { EXPECT_EQ(65536, shared_memory_->size); } +TEST_F(SharedMemoryTest, CanSetInt32) { + base::SharedMemory* temp_shared_memory = new base::SharedMemory; + EXPECT_TRUE(temp_shared_memory->Create(std::wstring(), false, false, 65536)); + + shared_memory_->Initialize(temp_shared_memory, 65536); + EXPECT_TRUE(shared_memory_->Map()); + + EXPECT_TRUE(shared_memory_->SetInt32(4, 7)); + EXPECT_EQ(7, static_cast<int32*>(shared_memory_->ptr)[1]); + + EXPECT_TRUE(shared_memory_->SetInt32(4, 8)); + EXPECT_EQ(8, static_cast<int32*>(shared_memory_->ptr)[1]); +} + +TEST_F(SharedMemoryTest, FailsIfSetInt32CalledBeforeMap) { + base::SharedMemory* temp_shared_memory = new base::SharedMemory; + EXPECT_TRUE(temp_shared_memory->Create(std::wstring(), false, false, 65536)); + + shared_memory_->Initialize(temp_shared_memory, 65536); + + EXPECT_FALSE(shared_memory_->SetInt32(4, 7)); +} + +TEST_F(SharedMemoryTest, FailsIfSetInt32OffsetIsOutOfRange) { + base::SharedMemory* temp_shared_memory = new base::SharedMemory; + EXPECT_TRUE(temp_shared_memory->Create(std::wstring(), false, false, 65536)); + + shared_memory_->Initialize(temp_shared_memory, 65536); + EXPECT_TRUE(shared_memory_->Map()); + + EXPECT_FALSE(shared_memory_->SetInt32(-1, 7)); + EXPECT_FALSE(shared_memory_->SetInt32(65536, 7)); +} + +TEST_F(SharedMemoryTest, FailsIfSetInt32OffsetIsMisaligned) { + base::SharedMemory* temp_shared_memory = new base::SharedMemory; + EXPECT_TRUE(temp_shared_memory->Create(std::wstring(), false, false, 65536)); + + shared_memory_->Initialize(temp_shared_memory, 65536); + EXPECT_TRUE(shared_memory_->Map()); + + EXPECT_FALSE(shared_memory_->SetInt32(1, 7)); +} + } // namespace gpu_plugin } // namespace o3d |