summaryrefslogtreecommitdiffstats
path: root/o3d
diff options
context:
space:
mode:
authorapatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-21 23:24:18 +0000
committerapatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-21 23:24:18 +0000
commitb19ed717676f1dcf50e8bb530404019a3fbb308a (patch)
tree5ba3d65e39b878a05290d612fa705fa8e14f498d /o3d
parenta33457b842b5b8e70622d7c73f266bb94dec6a49 (diff)
downloadchromium_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.cc40
-rw-r--r--o3d/gpu_plugin/command_buffer.h49
-rw-r--r--o3d/gpu_plugin/command_buffer_mock.h11
-rw-r--r--o3d/gpu_plugin/command_buffer_unittest.cc72
-rw-r--r--o3d/gpu_plugin/gpu_plugin.gyp6
-rw-r--r--o3d/gpu_plugin/gpu_plugin_object.cc29
-rw-r--r--o3d/gpu_plugin/gpu_plugin_object.h8
-rw-r--r--o3d/gpu_plugin/gpu_plugin_object_unittest.cc21
-rw-r--r--o3d/gpu_plugin/gpu_plugin_object_win.cc11
-rw-r--r--o3d/gpu_plugin/gpu_processor.cc78
-rw-r--r--o3d/gpu_plugin/gpu_processor.h42
-rw-r--r--o3d/gpu_plugin/gpu_processor_unittest.cc163
-rw-r--r--o3d/gpu_plugin/gpu_processor_win.cc39
-rw-r--r--o3d/gpu_plugin/system_services/shared_memory.cc14
-rw-r--r--o3d/gpu_plugin/system_services/shared_memory.h5
-rw-r--r--o3d/gpu_plugin/system_services/shared_memory_unittest.cc44
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