summaryrefslogtreecommitdiffstats
path: root/o3d
diff options
context:
space:
mode:
authorapatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-24 19:19:25 +0000
committerapatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-24 19:19:25 +0000
commit2331a49ecb27f38888bf4f60f24e054cbb8a8890 (patch)
treede3d03558bd82742292cebb81f1ed68ba1626342 /o3d
parentdfb5a4cc453d4a78e655d6f4cb5e11e8ced54c1b (diff)
downloadchromium_src-2331a49ecb27f38888bf4f60f24e054cbb8a8890.zip
chromium_src-2331a49ecb27f38888bf4f60f24e054cbb8a8890.tar.gz
chromium_src-2331a49ecb27f38888bf4f60f24e054cbb8a8890.tar.bz2
GPUProcessor uses O3D command buffer service to render to a window.
Added libraries that contain a subset of the O3D command buffer code independent on NaCl. Extracted Upcall interface from CommandBufferEngine. Now this works in JavaScript to clear the GPU plugin element to a random color: // BEGIN_FRAME sharedMemory.setInt32(putOffset++, 0x00000201); // CLEAR sharedMemory.setInt32(putOffset++, 0x00000408); sharedMemory.setInt32(putOffset++, 7); sharedMemory.setFloat(putOffset++, Math.random()); sharedMemory.setFloat(putOffset++, Math.random()); sharedMemory.setFloat(putOffset++, Math.random()); sharedMemory.setFloat(putOffset++, 1); sharedMemory.setFloat(putOffset++, 0.5); sharedMemory.setInt32(putOffset++, 0); // END_FRAME sharedMemory.setInt32(putOffset++, 0x00000301); TEST=none BUG=none Review URL: http://codereview.chromium.org/234001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@27098 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r--o3d/command_buffer/service/cross/cmd_buffer_engine.h28
-rw-r--r--o3d/command_buffer/service/cross/gapi_decoder.h6
-rw-r--r--o3d/command_buffer/service/win/d3d9/gapi_d3d9.h1
-rw-r--r--o3d/gpu_plugin/command_buffer.cc24
-rw-r--r--o3d/gpu_plugin/command_buffer.h46
-rw-r--r--o3d/gpu_plugin/command_buffer_mock.h19
-rw-r--r--o3d/gpu_plugin/command_buffer_unittest.cc49
-rw-r--r--o3d/gpu_plugin/gpu_plugin.gyp136
-rw-r--r--o3d/gpu_plugin/gpu_plugin_object.cc15
-rw-r--r--o3d/gpu_plugin/gpu_plugin_object_unittest.cc2
-rw-r--r--o3d/gpu_plugin/gpu_processor.cc101
-rw-r--r--o3d/gpu_plugin/gpu_processor.h51
-rw-r--r--o3d/gpu_plugin/gpu_processor_unittest.cc271
-rw-r--r--o3d/gpu_plugin/gpu_processor_win.cc85
-rw-r--r--o3d/gpu_plugin/system_services/shared_memory.cc15
-rw-r--r--o3d/gpu_plugin/system_services/shared_memory.h9
-rw-r--r--o3d/gpu_plugin/system_services/shared_memory_unittest.cc36
17 files changed, 681 insertions, 213 deletions
diff --git a/o3d/command_buffer/service/cross/cmd_buffer_engine.h b/o3d/command_buffer/service/cross/cmd_buffer_engine.h
index 572d98f..479c267 100644
--- a/o3d/command_buffer/service/cross/cmd_buffer_engine.h
+++ b/o3d/command_buffer/service/cross/cmd_buffer_engine.h
@@ -46,7 +46,33 @@ namespace command_buffer {
class BufferRPCImpl;
-class CommandBufferEngine : public BufferSyncInterface {
+class CommandBufferUpcallInterface {
+ public:
+ CommandBufferUpcallInterface() {
+ }
+
+ virtual ~CommandBufferUpcallInterface() {
+ }
+
+ // Gets the base address of a registered shared memory buffer.
+ // Parameters:
+ // shm_id: the identifier for the shared memory buffer.
+ virtual void *GetSharedMemoryAddress(unsigned int shm_id) = 0;
+
+ // Gets the size of a registered shared memory buffer.
+ // Parameters:
+ // shm_id: the identifier for the shared memory buffer.
+ virtual size_t GetSharedMemorySize(unsigned int shm_id) = 0;
+
+ // Sets the token value.
+ virtual void set_token(unsigned int token) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CommandBufferUpcallInterface);
+};
+
+class CommandBufferEngine : public BufferSyncInterface,
+ public CommandBufferUpcallInterface {
public:
explicit CommandBufferEngine(AsyncAPIInterface *handler);
virtual ~CommandBufferEngine();
diff --git a/o3d/command_buffer/service/cross/gapi_decoder.h b/o3d/command_buffer/service/cross/gapi_decoder.h
index a9af75c..e75376c 100644
--- a/o3d/command_buffer/service/cross/gapi_decoder.h
+++ b/o3d/command_buffer/service/cross/gapi_decoder.h
@@ -42,7 +42,7 @@ namespace o3d {
namespace command_buffer {
class GAPIInterface;
-class CommandBufferEngine;
+class CommandBufferUpcallInterface;
// This class implements the AsyncAPIInterface interface, decoding GAPI
// commands and sending them to a GAPI interface.
@@ -60,7 +60,7 @@ class GAPIDecoder : public AsyncAPIInterface {
// Sets the engine, to get shared memory buffers from, and to set the token
// to.
- void set_engine(CommandBufferEngine *engine) { engine_ = engine; }
+ void set_engine(CommandBufferUpcallInterface *engine) { engine_ = engine; }
private:
// Gets the address of shared memory data, given a shared memory ID and an
// offset. Also checks that the size is consistent with the shared memory
@@ -88,7 +88,7 @@ class GAPIDecoder : public AsyncAPIInterface {
#undef O3D_COMMAND_BUFFER_CMD_OP
GAPIInterface *gapi_;
- CommandBufferEngine *engine_;
+ CommandBufferUpcallInterface *engine_;
};
} // namespace command_buffer
diff --git a/o3d/command_buffer/service/win/d3d9/gapi_d3d9.h b/o3d/command_buffer/service/win/d3d9/gapi_d3d9.h
index eb301ba..f4a9b4a 100644
--- a/o3d/command_buffer/service/win/d3d9/gapi_d3d9.h
+++ b/o3d/command_buffer/service/win/d3d9/gapi_d3d9.h
@@ -54,6 +54,7 @@ class GAPID3D9 : public GAPIInterface {
virtual ~GAPID3D9();
void set_hwnd(HWND hwnd) { hwnd_ = hwnd; }
+ HWND hwnd() const { return hwnd_; }
// Initializes the graphics context, bound to a window.
// Returns:
diff --git a/o3d/gpu_plugin/command_buffer.cc b/o3d/gpu_plugin/command_buffer.cc
index 04b1f41..c499866 100644
--- a/o3d/gpu_plugin/command_buffer.cc
+++ b/o3d/gpu_plugin/command_buffer.cc
@@ -13,7 +13,8 @@ CommandBuffer::CommandBuffer(NPP npp)
get_offset_(0),
put_offset_(0),
token_(0),
- error_(ERROR_NO_ERROR) {
+ parse_error_(0),
+ error_status_(false) {
// Element zero is always NULL.
registered_objects_.push_back(NPObjectPointer<NPObject>());
}
@@ -22,6 +23,12 @@ CommandBuffer::~CommandBuffer() {
}
bool CommandBuffer::Initialize(int32 size) {
+ // Check the size will not overflow when it is converted from count of int32s
+ // to count of bytes.
+ int32 num_bytes = static_cast<int32>(size * sizeof(int32));
+ if (num_bytes / sizeof(int32) != size)
+ return false;
+
if (shared_memory_.Get())
return false;
@@ -41,7 +48,7 @@ bool CommandBuffer::Initialize(int32 size) {
}
NPObjectPointer<NPObject> result;
- if (!NPInvoke(npp_, system, "createSharedMemory", size,
+ if (!NPInvoke(npp_, system, "createSharedMemory", num_bytes,
&result)) {
return false;
}
@@ -148,15 +155,18 @@ void CommandBuffer::UnregisterObject(NPObjectPointer<NPObject> object,
}
NPObjectPointer<NPObject> CommandBuffer::GetRegisteredObject(int32 handle) {
- DCHECK_GE(handle, 0);
- DCHECK_LT(static_cast<size_t>(handle), registered_objects_.size());
+ if (handle < 0)
+ return NPObjectPointer<NPObject>();
+
+ if (static_cast<size_t>(handle) >= registered_objects_.size())
+ return NPObjectPointer<NPObject>();
return registered_objects_[handle];
}
-int32 CommandBuffer::ResetError() {
- int32 last_error = error_;
- error_ = ERROR_NO_ERROR;
+int32 CommandBuffer::ResetParseError() {
+ int32 last_error = parse_error_;
+ parse_error_ = 0;
return last_error;
}
diff --git a/o3d/gpu_plugin/command_buffer.h b/o3d/gpu_plugin/command_buffer.h
index 31f60d1..7583def 100644
--- a/o3d/gpu_plugin/command_buffer.h
+++ b/o3d/gpu_plugin/command_buffer.h
@@ -22,14 +22,6 @@ namespace gpu_plugin {
// API to manage the put and get pointers.
class CommandBuffer : public DefaultNPObject<NPObject> {
public:
- enum {
- ERROR_NO_ERROR,
- ERROR_INVALID_SIZE,
- ERROR_OUT_OF_BOUNDS,
- ERROR_UNKNOWN_COMMAND,
- ERROR_INVALID_ARGUMENTS,
- };
-
explicit CommandBuffer(NPP npp);
virtual ~CommandBuffer();
@@ -95,27 +87,40 @@ class CommandBuffer : public DefaultNPObject<NPObject> {
token_ = token;
}
- // Get the current error status and reset it to ERROR_NO_ERROR.
- // The default error status is ERROR_NO_ERROR.
- int32 ResetError();
+ // Get the current parse error and reset it to zero. Zero means no error. Non-
+ // zero means error. The default error status is zero.
+ int32 ResetParseError();
+
+ // Allows the reader to set the current parse error.
+ void SetParseError(int32 parse_error) {
+ parse_error_ = parse_error;
+ }
+
+ // Returns whether the command buffer is in the error state.
+ bool GetErrorStatus() {
+ return error_status_;
+ }
- // Allows the reader to set the current error status.
- void SetError(int32 error) {
- error_ = error;
+ // Allows the reader to set the error status. Once in an error state, the
+ // command buffer cannot recover and ceases to process commands.
+ void RaiseErrorStatus() {
+ error_status_ = true;
}
NP_UTILS_BEGIN_DISPATCHER_CHAIN(CommandBuffer, DefaultNPObject<NPObject>)
- NP_UTILS_DISPATCHER(Initialize, bool(int32))
+ NP_UTILS_DISPATCHER(Initialize, bool(int32 size))
NP_UTILS_DISPATCHER(GetRingBuffer, NPObjectPointer<CHRSharedMemory>())
NP_UTILS_DISPATCHER(GetSize, int32())
- NP_UTILS_DISPATCHER(SyncOffsets, int32(int32))
+ NP_UTILS_DISPATCHER(SyncOffsets, int32(int32 get_offset))
NP_UTILS_DISPATCHER(GetGetOffset, int32());
NP_UTILS_DISPATCHER(GetPutOffset, int32());
- NP_UTILS_DISPATCHER(RegisterObject, int32(NPObjectPointer<NPObject>));
+ NP_UTILS_DISPATCHER(RegisterObject,
+ int32(NPObjectPointer<NPObject> object));
NP_UTILS_DISPATCHER(UnregisterObject,
- void(NPObjectPointer<NPObject>, int32));
+ void(NPObjectPointer<NPObject> object, int32 handle));
NP_UTILS_DISPATCHER(GetToken, int32());
- NP_UTILS_DISPATCHER(ResetError, int32());
+ NP_UTILS_DISPATCHER(ResetParseError, int32());
+ NP_UTILS_DISPATCHER(GetErrorStatus, bool());
NP_UTILS_END_DISPATCHER_CHAIN
private:
@@ -128,7 +133,8 @@ class CommandBuffer : public DefaultNPObject<NPObject> {
std::vector<NPObjectPointer<NPObject> > registered_objects_;
std::set<int32> unused_registered_object_elements_;
int32 token_;
- int32 error_;
+ int32 parse_error_;
+ bool error_status_;
};
} // namespace gpu_plugin
diff --git a/o3d/gpu_plugin/command_buffer_mock.h b/o3d/gpu_plugin/command_buffer_mock.h
index d9f7379..31e1d63 100644
--- a/o3d/gpu_plugin/command_buffer_mock.h
+++ b/o3d/gpu_plugin/command_buffer_mock.h
@@ -16,19 +16,24 @@ namespace gpu_plugin {
class MockCommandBuffer : public CommandBuffer {
public:
explicit MockCommandBuffer(NPP npp) : CommandBuffer(npp) {
+ ON_CALL(*this, GetRingBuffer())
+ .WillByDefault(testing::Return(NPObjectPointer<CHRSharedMemory>()));
+ ON_CALL(*this, GetRegisteredObject(testing::_))
+ .WillByDefault(testing::Return(NPObjectPointer<NPObject>()));
}
- MOCK_METHOD1(Initialize, bool(int32));
+ MOCK_METHOD1(Initialize, bool(int32 size));
MOCK_METHOD0(GetRingBuffer, NPObjectPointer<CHRSharedMemory>());
MOCK_METHOD0(GetSize, int32());
- MOCK_METHOD1(SyncOffsets, int32(int32));
+ MOCK_METHOD1(SyncOffsets, int32(int32 put_offset));
MOCK_METHOD0(GetGetOffset, int32());
- MOCK_METHOD1(SetGetOffset, void(int32));
+ MOCK_METHOD1(SetGetOffset, void(int32 get_offset));
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>());
+ MOCK_METHOD1(SetPutOffsetChangeCallback, void(Callback0::Type* callback));
+ MOCK_METHOD1(RegisterObject, int32(NPObjectPointer<NPObject> object));
+ MOCK_METHOD2(UnregisterObject, void(NPObjectPointer<NPObject> object,
+ int32 handle));
+ MOCK_METHOD1(GetRegisteredObject, NPObjectPointer<NPObject>(int32 handle));
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 b5e17d2..e9c720f 100644
--- a/o3d/gpu_plugin/command_buffer_unittest.cc
+++ b/o3d/gpu_plugin/command_buffer_unittest.cc
@@ -26,10 +26,11 @@ class MockSystemNPObject : public DefaultNPObject<NPObject> {
explicit MockSystemNPObject(NPP npp) {
}
- MOCK_METHOD1(CreateSharedMemory, NPObjectPointer<NPObject>(int32));
+ MOCK_METHOD1(CreateSharedMemory, NPObjectPointer<NPObject>(int32 size));
NP_UTILS_BEGIN_DISPATCHER_CHAIN(MockSystemNPObject, DefaultNPObject<NPObject>)
- NP_UTILS_DISPATCHER(CreateSharedMemory, NPObjectPointer<NPObject>(int32))
+ NP_UTILS_DISPATCHER(CreateSharedMemory,
+ NPObjectPointer<NPObject>(int32 size))
NP_UTILS_END_DISPATCHER_CHAIN
private:
@@ -75,14 +76,18 @@ TEST_F(CommandBufferTest, InitializesCommandBuffer) {
EXPECT_CALL(*expected_shared_memory.Get(), Map())
.WillOnce(Return(true));
- EXPECT_TRUE(command_buffer_->Initialize(1024));
+ EXPECT_TRUE(command_buffer_->Initialize(256));
EXPECT_EQ(expected_shared_memory, command_buffer_->GetRingBuffer());
// Cannot reinitialize.
- EXPECT_FALSE(command_buffer_->Initialize(1024));
+ EXPECT_FALSE(command_buffer_->Initialize(256));
EXPECT_EQ(expected_shared_memory, command_buffer_->GetRingBuffer());
}
+TEST_F(CommandBufferTest, InitializeFailsIfSizeIsTooBig) {
+ EXPECT_FALSE(command_buffer_->Initialize(0x40000000));
+}
+
TEST_F(CommandBufferTest, InitializeFailsIfCannotCreateSharedMemory) {
EXPECT_CALL(mock_browser_, GetWindowNPObject(NULL))
.WillOnce(Return(window_object_.ToReturned()));
@@ -90,7 +95,7 @@ TEST_F(CommandBufferTest, InitializeFailsIfCannotCreateSharedMemory) {
EXPECT_CALL(*system_object_.Get(), CreateSharedMemory(1024))
.WillOnce(Return(NPObjectPointer<NPObject>()));
- EXPECT_FALSE(command_buffer_->Initialize(1024));
+ EXPECT_FALSE(command_buffer_->Initialize(256));
EXPECT_EQ(NPObjectPointer<NPObject>(),
command_buffer_->GetRingBuffer());
}
@@ -108,7 +113,7 @@ TEST_F(CommandBufferTest, InitializeFailsIfCannotMapSharedMemory) {
EXPECT_CALL(*expected_shared_memory.Get(), Map())
.WillOnce(Return(false));
- EXPECT_FALSE(command_buffer_->Initialize(1024));
+ EXPECT_FALSE(command_buffer_->Initialize(256));
EXPECT_EQ(NPObjectPointer<NPObject>(),
command_buffer_->GetRingBuffer());
}
@@ -136,7 +141,7 @@ TEST_F(CommandBufferTest, CanSyncGetAndPutOffset) {
EXPECT_CALL(*expected_shared_memory.Get(), Map())
.WillOnce(Return(true));
- EXPECT_TRUE(command_buffer_->Initialize(1024));
+ EXPECT_TRUE(command_buffer_->Initialize(256));
StrictMock<MockCallback>* put_offset_change_callback =
new StrictMock<MockCallback>;
@@ -163,6 +168,14 @@ TEST_F(CommandBufferTest, ZeroHandleMapsToNull) {
EXPECT_TRUE(NULL == command_buffer_->GetRegisteredObject(0).Get());
}
+TEST_F(CommandBufferTest, NegativeHandleMapsToNull) {
+ EXPECT_TRUE(NULL == command_buffer_->GetRegisteredObject(-1).Get());
+}
+
+TEST_F(CommandBufferTest, OutOfRangeHandleMapsToNull) {
+ EXPECT_TRUE(NULL == command_buffer_->GetRegisteredObject(1).Get());
+}
+
TEST_F(CommandBufferTest, RegisteringNullObjectReturnsZero) {
EXPECT_EQ(0, command_buffer_->RegisterObject(NPObjectPointer<NPObject>()));
}
@@ -245,15 +258,23 @@ TEST_F(CommandBufferTest, CanSetToken) {
EXPECT_EQ(7, command_buffer_->GetToken());
}
-TEST_F(CommandBufferTest, DefaultErrorIsNoError) {
- EXPECT_EQ(CommandBuffer::ERROR_NO_ERROR, command_buffer_->ResetError());
+TEST_F(CommandBufferTest, DefaultParseErrorIsNoError) {
+ EXPECT_EQ(0, command_buffer_->ResetParseError());
+}
+
+TEST_F(CommandBufferTest, CanSetAndResetParseError) {
+ command_buffer_->SetParseError(1);
+ EXPECT_EQ(1, command_buffer_->ResetParseError());
+ EXPECT_EQ(0, command_buffer_->ResetParseError());
+}
+
+TEST_F(CommandBufferTest, DefaultErrorStatusIsFalse) {
+ EXPECT_FALSE(command_buffer_->GetErrorStatus());
}
-TEST_F(CommandBufferTest, CanSetAndResetError) {
- command_buffer_->SetError(CommandBuffer::ERROR_UNKNOWN_COMMAND);
- EXPECT_EQ(CommandBuffer::ERROR_UNKNOWN_COMMAND,
- command_buffer_->ResetError());
- EXPECT_EQ(CommandBuffer::ERROR_NO_ERROR, command_buffer_->ResetError());
+TEST_F(CommandBufferTest, CanRaiseErrorStatus) {
+ command_buffer_->RaiseErrorStatus();
+ EXPECT_TRUE(command_buffer_->GetErrorStatus());
}
} // namespace gpu_plugin
diff --git a/o3d/gpu_plugin/gpu_plugin.gyp b/o3d/gpu_plugin/gpu_plugin.gyp
index 4831568..0276ee9 100644
--- a/o3d/gpu_plugin/gpu_plugin.gyp
+++ b/o3d/gpu_plugin/gpu_plugin.gyp
@@ -106,11 +106,131 @@
],
},
+ # This builds a subset of the O3D command buffer common library. This is a
+ # separate library for the time being because I need a subset that is not
+ # dependent on NaCl.
+ {
+ 'target_name': 'command_buffer_common_subset',
+ 'type': '<(library)',
+ 'include_dirs': [
+ '..',
+ '../..',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '..',
+ ],
+ }, # 'direct_dependent_settings'
+ 'sources': [
+ '../command_buffer/common/cross/bitfield_helpers.h',
+ '../command_buffer/common/cross/cmd_buffer_format.h',
+ '../command_buffer/common/cross/gapi_interface.h',
+ '../command_buffer/common/cross/logging.h',
+ '../command_buffer/common/cross/mocks.h',
+ '../command_buffer/common/cross/resource.cc',
+ '../command_buffer/common/cross/resource.h',
+ '../command_buffer/common/cross/types.h',
+ ],
+ },
+
+ # This builds a subset of the O3D command buffer service. This is a separate
+ # library for the time being because I need a subset that is not dependent
+ # on NaCl.
+ {
+ 'target_name': 'command_buffer_service_subset',
+ 'type': '<(library)',
+ 'include_dirs': [
+ '..',
+ '../..',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '..',
+ ],
+ }, # 'direct_dependent_settings'
+ 'dependencies': [
+ 'command_buffer_common_subset',
+ ],
+ 'sources': [
+ '../command_buffer/service/cross/cmd_parser.cc',
+ '../command_buffer/service/cross/cmd_parser.h',
+ '../command_buffer/service/cross/effect_utils.cc',
+ '../command_buffer/service/cross/effect_utils.h',
+ '../command_buffer/service/cross/gapi_decoder.cc',
+ '../command_buffer/service/cross/gapi_decoder.h',
+ '../command_buffer/service/cross/mocks.h',
+ '../command_buffer/service/cross/precompile.cc',
+ '../command_buffer/service/cross/precompile.h',
+ '../command_buffer/service/cross/resource.cc',
+ '../command_buffer/service/cross/resource.h',
+ '../command_buffer/service/cross/texture_utils.cc',
+ '../command_buffer/service/cross/texture_utils.h',
+ ],
+
+ 'conditions': [
+ ['OS == "win"',
+ {
+ 'sources': [
+ '../command_buffer/service/win/d3d9/d3d9_utils.h',
+ '../command_buffer/service/win/d3d9/effect_d3d9.cc',
+ '../command_buffer/service/win/d3d9/effect_d3d9.h',
+ '../command_buffer/service/win/d3d9/gapi_d3d9.cc',
+ '../command_buffer/service/win/d3d9/gapi_d3d9.h',
+ '../command_buffer/service/win/d3d9/geometry_d3d9.cc',
+ '../command_buffer/service/win/d3d9/geometry_d3d9.h',
+ '../command_buffer/service/win/d3d9/render_surface_d3d9.cc',
+ '../command_buffer/service/win/d3d9/render_surface_d3d9.h',
+ '../command_buffer/service/win/d3d9/sampler_d3d9.cc',
+ '../command_buffer/service/win/d3d9/sampler_d3d9.h',
+ '../command_buffer/service/win/d3d9/states_d3d9.cc',
+ '../command_buffer/service/win/d3d9/texture_d3d9.cc',
+ '../command_buffer/service/win/d3d9/texture_d3d9.h',
+ ], # 'sources'
+ 'include_dirs': [
+ '$(DXSDK_DIR)/Include',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '$(DXSDK_DIR)/Include',
+ ],
+ }, # 'direct_dependent_settings'
+ },
+ ],
+ ['OS == "mac" or OS == "linux"',
+ {
+ 'sources': [
+ '../command_buffer/service/cross/gl/effect_gl.cc',
+ '../command_buffer/service/cross/gl/effect_gl.h',
+ '../command_buffer/service/cross/gl/gapi_gl.cc',
+ '../command_buffer/service/cross/gl/gapi_gl.h',
+ '../command_buffer/service/cross/gl/geometry_gl.cc',
+ '../command_buffer/service/cross/gl/geometry_gl.h',
+ '../command_buffer/service/cross/gl/gl_utils.h',
+ '../command_buffer/service/cross/gl/sampler_gl.cc',
+ '../command_buffer/service/cross/gl/sampler_gl.h',
+ '../command_buffer/service/cross/gl/states_gl.cc',
+ '../command_buffer/service/cross/gl/texture_gl.cc',
+ '../command_buffer/service/cross/gl/texture_gl.h',
+ ], # 'sources'
+ },
+ ],
+ ['OS == "linux"',
+ {
+ 'sources': [
+ '../command_buffer/service/linux/x_utils.cc',
+ '../command_buffer/service/linux/x_utils.h',
+ ],
+ },
+ ],
+ ],
+ },
+
{
'target_name': 'gpu_plugin',
'type': '<(library)',
'dependencies': [
'../../base/base.gyp:base',
+ 'command_buffer_service_subset',
'np_utils',
],
'include_dirs': [
@@ -140,6 +260,7 @@
'target_name': 'gpu_plugin_unittests',
'type': 'executable',
'dependencies': [
+ 'command_buffer_service_subset',
'gpu_plugin',
'np_utils',
'system_services',
@@ -151,6 +272,21 @@
'../..',
'../../third_party/npapi',
],
+ 'conditions': [
+ ['OS == "win" and (renderer == "d3d9" or renderer == "cb")',
+ {
+ # These dependencies are temporary until the command buffer code
+ # loads D3D and D3DX dynamically.
+ 'link_settings': {
+ 'libraries': [
+ '"$(DXSDK_DIR)/Lib/x86/DxErr.lib"',
+ '"$(DXSDK_DIR)/Lib/x86/d3dx9.lib"',
+ '-ld3d9.lib',
+ ],
+ },
+ },
+ ],
+ ],
'sources': [
'command_buffer_unittest.cc',
'gpu_plugin_unittest.cc',
diff --git a/o3d/gpu_plugin/gpu_plugin_object.cc b/o3d/gpu_plugin/gpu_plugin_object.cc
index 0fdd85a..60e3414 100644
--- a/o3d/gpu_plugin/gpu_plugin_object.cc
+++ b/o3d/gpu_plugin/gpu_plugin_object.cc
@@ -89,14 +89,17 @@ NPObjectPointer<NPObject> GPUPluginObject::OpenCommandBuffer() {
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_;
+ processor_ = new GPUProcessor(npp_, command_buffer_);
+ if (processor_->Initialize(static_cast<HWND>(window_.window))) {
+ command_buffer_->SetPutOffsetChangeCallback(
+ NewCallback(processor_.get(),
+ &GPUProcessor::ProcessCommands));
+ UpdateProcessorWindow();
+ return command_buffer_;
+ }
}
+ processor_ = NULL;
command_buffer_ = NPObjectPointer<CommandBuffer>();
return command_buffer_;
}
diff --git a/o3d/gpu_plugin/gpu_plugin_object_unittest.cc b/o3d/gpu_plugin/gpu_plugin_object_unittest.cc
index ce9b306..f87f3c4 100644
--- a/o3d/gpu_plugin/gpu_plugin_object_unittest.cc
+++ b/o3d/gpu_plugin/gpu_plugin_object_unittest.cc
@@ -106,7 +106,7 @@ TEST_F(GPUPluginObjectTest, CanGetScriptableNPObject) {
TEST_F(GPUPluginObjectTest, OpenCommandBufferReturnsInitializedCommandBuffer) {
// Intercept creation of command buffer object and return mock.
NPObjectPointer<MockCommandBuffer> command_buffer =
- NPCreateObject<StrictMock<MockCommandBuffer> >(NULL);
+ NPCreateObject<MockCommandBuffer>(NULL);
EXPECT_CALL(mock_browser_, CreateObject(NULL,
NPGetClass<CommandBuffer>()))
.WillOnce(Return(command_buffer.ToReturned()));
diff --git a/o3d/gpu_plugin/gpu_processor.cc b/o3d/gpu_plugin/gpu_processor.cc
index 49b13e3..201bef8 100644
--- a/o3d/gpu_plugin/gpu_processor.cc
+++ b/o3d/gpu_plugin/gpu_processor.cc
@@ -3,76 +3,75 @@
// found in the LICENSE file.
#include "o3d/gpu_plugin/gpu_processor.h"
+#include "o3d/gpu_plugin/system_services/shared_memory_public.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)
+ if (command_buffer_->GetErrorStatus())
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);
+ parser_->set_put(command_buffer_->GetPutOffset());
- 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);
+ int commands_processed = 0;
+ while (commands_processed < commands_per_update_ && !parser_->IsEmpty()) {
+ command_buffer::BufferSyncInterface::ParseError parse_error =
+ parser_->ProcessCommand();
+ switch (parse_error) {
+ case command_buffer::BufferSyncInterface::kParseUnknownCommand:
+ case command_buffer::BufferSyncInterface::kParseInvalidArguments:
+ command_buffer_->SetParseError(parse_error);
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;
+ case command_buffer::BufferSyncInterface::kParseInvalidSize:
+ case command_buffer::BufferSyncInterface::kParseOutOfBounds:
+ command_buffer_->SetParseError(parse_error);
+ command_buffer_->RaiseErrorStatus();
+ return;
}
+ ++commands_processed;
}
- // 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) {
+ command_buffer_->SetGetOffset(static_cast<int32>(parser_->get()));
+
+ if (!parser_->IsEmpty()) {
MessageLoop::current()->PostTask(
FROM_HERE,
NewRunnableMethod(this, &GPUProcessor::ProcessCommands));
}
}
+void *GPUProcessor::GetSharedMemoryAddress(unsigned int shm_id) {
+ // TODO(apatrick): Verify that the NPClass is in fact shared memory before
+ // accessing the members.
+ NPObjectPointer<CHRSharedMemory> shared_memory(static_cast<CHRSharedMemory*>(
+ command_buffer_->GetRegisteredObject(static_cast<int32>(shm_id)).Get()));
+
+ // Return address if shared memory is already mapped to this process.
+ if (shared_memory->ptr)
+ return shared_memory->ptr;
+
+ // If the call fails or returns false then ptr will still be NULL.
+ bool result;
+ NPInvoke(npp_, shared_memory, "map", &result);
+
+ return shared_memory->ptr;
+}
+
+size_t GPUProcessor::GetSharedMemorySize(unsigned int shm_id) {
+ // TODO(apatrick): Verify that the NPClass is in fact shared memory before
+ // accessing the members.
+ NPObjectPointer<CHRSharedMemory> shared_memory(static_cast<CHRSharedMemory*>(
+ command_buffer_->GetRegisteredObject(static_cast<int32>(shm_id)).Get()));
+
+ return shared_memory->size;
+}
+
+void GPUProcessor::set_token(unsigned int token) {
+ command_buffer_->SetToken(static_cast<int32>(token));
+}
+
} // namespace gpu_plugin
} // namespace o3d
diff --git a/o3d/gpu_plugin/gpu_processor.h b/o3d/gpu_plugin/gpu_processor.h
index 9c3641b..fd87b98 100644
--- a/o3d/gpu_plugin/gpu_processor.h
+++ b/o3d/gpu_plugin/gpu_processor.h
@@ -5,18 +5,40 @@
#ifndef O3D_GPU_PLUGIN_GPU_PROCESSOR_H_
#define O3D_GPU_PLUGIN_GPU_PROCESSOR_H_
-#include "base/ref_counted.h"
+#include "o3d/command_buffer/service/cross/cmd_buffer_engine.h"
+#include "o3d/command_buffer/service/cross/cmd_parser.h"
+#include "o3d/command_buffer/service/cross/gapi_decoder.h"
#include "o3d/gpu_plugin/command_buffer.h"
#include "o3d/gpu_plugin/np_utils/np_object_pointer.h"
+#if defined(OS_WIN)
+#include "o3d/command_buffer/service/win/d3d9/gapi_d3d9.h"
+#endif
+
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> {
+class GPUProcessor : public base::RefCountedThreadSafe<GPUProcessor>,
+ public command_buffer::CommandBufferUpcallInterface {
public:
- explicit GPUProcessor(const NPObjectPointer<CommandBuffer>& command_buffer);
+ GPUProcessor(NPP npp,
+ const NPObjectPointer<CommandBuffer>& command_buffer);
+
+#if defined(OS_WIN)
+ // This constructor is for unit tests.
+ GPUProcessor(NPP npp,
+ const NPObjectPointer<CommandBuffer>& command_buffer,
+ command_buffer::GAPID3D9* gapi,
+ command_buffer::GAPIDecoder* decoder,
+ command_buffer::CommandParser* parser,
+ int commands_per_update);
+
+ bool Initialize(HWND hwnd);
+#endif // OS_WIN
+
+ void Destroy();
void ProcessCommands();
@@ -24,15 +46,30 @@ class GPUProcessor : public base::RefCountedThreadSafe<GPUProcessor> {
void SetWindow(HWND handle, int width, int height);
#endif
- void DrawRectangle(uint32 color, int left, int top, int right, int bottom);
+ // Implementation of CommandBufferUpcallInterface.
+
+ // Gets the base address of a registered shared memory buffer.
+ // Parameters:
+ // shm_id: the identifier for the shared memory buffer.
+ virtual void *GetSharedMemoryAddress(unsigned int shm_id);
+
+ // Gets the size of a registered shared memory buffer.
+ // Parameters:
+ // shm_id: the identifier for the shared memory buffer.
+ virtual size_t GetSharedMemorySize(unsigned int shm_id);
+
+ // Sets the token value.
+ virtual void set_token(unsigned int token);
private:
+ NPP npp_;
NPObjectPointer<CommandBuffer> command_buffer_;
+ int commands_per_update_;
#if defined(OS_WIN)
- HWND window_handle_;
- int window_width_;
- int window_height_;
+ scoped_ptr<command_buffer::GAPID3D9> gapi_;
+ scoped_ptr<command_buffer::GAPIDecoder> decoder_;
+ scoped_ptr<command_buffer::CommandParser> parser_;
#endif
};
diff --git a/o3d/gpu_plugin/gpu_processor_unittest.cc b/o3d/gpu_plugin/gpu_processor_unittest.cc
index dcb0c05..7447bb8 100644
--- a/o3d/gpu_plugin/gpu_processor_unittest.cc
+++ b/o3d/gpu_plugin/gpu_processor_unittest.cc
@@ -4,6 +4,8 @@
#include "base/at_exit.h"
#include "base/message_loop.h"
+#include "o3d/command_buffer/common/cross/cmd_buffer_format.h"
+#include "o3d/command_buffer/service/cross/mocks.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"
@@ -33,8 +35,30 @@ class GPUProcessorTest : public testing::Test {
command_buffer_ = NPCreateObject<MockCommandBuffer>(NULL);
ON_CALL(*command_buffer_.Get(), GetRingBuffer())
.WillByDefault(Return(shared_memory_));
+ ON_CALL(*command_buffer_.Get(), GetSize())
+ .WillByDefault(Return(sizeof(buffer_)));
- processor_ = new GPUProcessor(command_buffer_);
+#if defined(OS_WIN)
+ gapi_ = new command_buffer::GAPID3D9;
+#endif
+
+ async_api_.reset(new StrictMock<command_buffer::AsyncAPIMock>);
+
+ decoder_ = new command_buffer::GAPIDecoder(gapi_);
+
+ parser_ = new command_buffer::CommandParser(buffer_,
+ sizeof(buffer_),
+ 0,
+ sizeof(buffer_),
+ 0,
+ async_api_.get());
+
+ processor_ = new GPUProcessor(NULL,
+ command_buffer_,
+ gapi_,
+ decoder_,
+ parser_,
+ 2);
}
virtual void TearDown() {
@@ -49,114 +73,233 @@ class GPUProcessorTest : public testing::Test {
NPObjectPointer<MockCommandBuffer> command_buffer_;
NPObjectPointer<NiceMock<MockSharedMemory> > shared_memory_;
int32 buffer_[1024 / sizeof(int32)];
+ command_buffer::GAPIDecoder* decoder_;
+ command_buffer::CommandParser* parser_;
+ scoped_ptr<command_buffer::AsyncAPIMock> async_api_;
scoped_refptr<GPUProcessor> processor_;
+
+#if defined(OS_WIN)
+ command_buffer::GAPID3D9* gapi_;
+#endif
};
-TEST_F(GPUProcessorTest, ProcessorDoesNothingIfNoSharedMemory) {
- EXPECT_CALL(*command_buffer_, GetGetOffset())
- .WillOnce(Return(0));
+TEST_F(GPUProcessorTest, ProcessorDoesNothingIfRingBufferIsEmpty) {
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>()));
+ EXPECT_CALL(*command_buffer_, SetGetOffset(0));
processor_->ProcessCommands();
+
+ EXPECT_EQ(command_buffer::BufferSyncInterface::kParseNoError,
+ command_buffer_->ResetParseError());
+ EXPECT_FALSE(command_buffer_->GetErrorStatus());
}
-TEST_F(GPUProcessorTest, ProcessorDoesNothingIfSharedMemoryIsUnmapped) {
- EXPECT_CALL(*command_buffer_, GetGetOffset())
- .WillOnce(Return(0));
+TEST_F(GPUProcessorTest, ProcessesOneCommand) {
+ command_buffer::CommandHeader* header =
+ reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 2;
+ buffer_[1] = 123;
+
EXPECT_CALL(*command_buffer_, GetPutOffset())
- .WillOnce(Return(0));
- EXPECT_CALL(*command_buffer_, GetSize())
- .WillOnce(Return(1024));
- shared_memory_->ptr = NULL;
+ .WillOnce(Return(2));
+ EXPECT_CALL(*command_buffer_, SetGetOffset(2));
+
+ EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0]))
+ .WillOnce(Return(command_buffer::BufferSyncInterface::kParseNoError));
processor_->ProcessCommands();
+
+ EXPECT_EQ(command_buffer::BufferSyncInterface::kParseNoError,
+ command_buffer_->ResetParseError());
+ EXPECT_FALSE(command_buffer_->GetErrorStatus());
}
-TEST_F(GPUProcessorTest, ProcessorDoesNothingIfCommandBufferIsZeroSize) {
- EXPECT_CALL(*command_buffer_, GetGetOffset())
- .WillOnce(Return(0));
+TEST_F(GPUProcessorTest, ProcessesTwoCommands) {
+ command_buffer::CommandHeader* header =
+ reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 2;
+ buffer_[1] = 123;
+ header[2].command = 8;
+ header[2].size = 1;
+
EXPECT_CALL(*command_buffer_, GetPutOffset())
- .WillOnce(Return(0));
- EXPECT_CALL(*command_buffer_, GetSize())
- .WillOnce(Return(0));
+ .WillOnce(Return(3));
+ EXPECT_CALL(*command_buffer_, SetGetOffset(3));
+
+ EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0]))
+ .WillOnce(Return(command_buffer::BufferSyncInterface::kParseNoError));
+
+ EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[2]))
+ .WillOnce(Return(command_buffer::BufferSyncInterface::kParseNoError));
processor_->ProcessCommands();
}
-TEST_F(GPUProcessorTest, ProcessorDoesNothingIfCommandBufferIsEmpty) {
- EXPECT_CALL(*command_buffer_, GetGetOffset())
- .WillOnce(Return(0));
+TEST_F(GPUProcessorTest, PostsTaskToFinishRemainingCommands) {
+ command_buffer::CommandHeader* header =
+ reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 2;
+ buffer_[1] = 123;
+ header[2].command = 8;
+ header[2].size = 1;
+ header[3].command = 9;
+ header[3].size = 1;
+
EXPECT_CALL(*command_buffer_, GetPutOffset())
- .WillOnce(Return(0));
- EXPECT_CALL(*command_buffer_, GetSize())
- .WillOnce(Return(sizeof(buffer_)));
+ .WillOnce(Return(4));
+
+ EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0]))
+ .WillOnce(Return(command_buffer::BufferSyncInterface::kParseNoError));
+
+ EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[2]))
+ .WillOnce(Return(command_buffer::BufferSyncInterface::kParseNoError));
+
+ EXPECT_CALL(*command_buffer_, SetGetOffset(3));
processor_->ProcessCommands();
-}
-TEST_F(GPUProcessorTest, ProcessorHandlesSingleNopCommand) {
- EXPECT_CALL(*command_buffer_, GetGetOffset())
- .WillOnce(Return(0));
+ // ProcessCommands is called a second time when the pending task is run.
+
EXPECT_CALL(*command_buffer_, GetPutOffset())
.WillOnce(Return(4));
- EXPECT_CALL(*command_buffer_, GetSize())
- .WillOnce(Return(sizeof(buffer_)));
+
+ EXPECT_CALL(*async_api_, DoCommand(9, 0, &buffer_[3]))
+ .WillOnce(Return(command_buffer::BufferSyncInterface::kParseNoError));
+
EXPECT_CALL(*command_buffer_, SetGetOffset(4));
- processor_->ProcessCommands();
+ MessageLoop::current()->RunAllPending();
}
-TEST_F(GPUProcessorTest, ProcessorWrapsAroundToBeginningOfCommandBuffer) {
- EXPECT_CALL(*command_buffer_, GetGetOffset())
- .WillOnce(Return(4));
+TEST_F(GPUProcessorTest, SetsErrorCodeOnCommandBuffer) {
+ command_buffer::CommandHeader* header =
+ reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 1;
+
EXPECT_CALL(*command_buffer_, GetPutOffset())
- .WillOnce(Return(0));
- EXPECT_CALL(*command_buffer_, GetSize())
- .WillOnce(Return(8));
- EXPECT_CALL(*command_buffer_, SetGetOffset(0));
+ .WillOnce(Return(1));
+ EXPECT_CALL(*command_buffer_, SetGetOffset(1));
+
+ EXPECT_CALL(*async_api_, DoCommand(7, 0, &buffer_[0]))
+ .WillOnce(Return(
+ command_buffer::BufferSyncInterface::kParseUnknownCommand));
processor_->ProcessCommands();
+
+ EXPECT_EQ(command_buffer::BufferSyncInterface::kParseUnknownCommand,
+ command_buffer_->ResetParseError());
+ EXPECT_FALSE(command_buffer_->GetErrorStatus());
}
TEST_F(GPUProcessorTest,
- ProcessorHandlesSingleCommandAndPostsTaskToProcessAdditionalCommands) {
- EXPECT_CALL(*command_buffer_, GetGetOffset())
- .WillOnce(Return(0))
- .WillOnce(Return(4));
+ RecoverableParseErrorsAreNotClearedByFollowingSuccessfulCommands) {
+ command_buffer::CommandHeader* header =
+ reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 1;
+ header[1].command = 8;
+ header[1].size = 1;
+
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));
+ .WillOnce(Return(2));
+ EXPECT_CALL(*command_buffer_, SetGetOffset(2));
+
+ EXPECT_CALL(*async_api_, DoCommand(7, 0, &buffer_[0]))
+ .WillOnce(Return(
+ command_buffer::BufferSyncInterface::kParseUnknownCommand));
+
+ EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[1]))
+ .WillOnce(Return(command_buffer::BufferSyncInterface::kParseNoError));
processor_->ProcessCommands();
- EXPECT_CALL(*command_buffer_, SetGetOffset(8));
- MessageLoop::current()->RunAllPending();
+ EXPECT_EQ(command_buffer::BufferSyncInterface::kParseUnknownCommand,
+ command_buffer_->ResetParseError());
+ EXPECT_FALSE(command_buffer_->GetErrorStatus());
}
-TEST_F(GPUProcessorTest, ProcessorDoesNotImmediatelyHandlePartialCommands) {
- EXPECT_CALL(*command_buffer_, GetGetOffset())
- .WillOnce(Return(0))
- .WillOnce(Return(0));
+TEST_F(GPUProcessorTest, UnrecoverableParseErrorsRaiseTheErrorStatus) {
+ command_buffer::CommandHeader* header =
+ reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 1;
+ header[1].command = 8;
+ header[1].size = 1;
+
EXPECT_CALL(*command_buffer_, GetPutOffset())
- .WillOnce(Return(2))
- .WillOnce(Return(4));
- EXPECT_CALL(*command_buffer_, GetSize())
- .WillOnce(Return(sizeof(buffer_)))
- .WillOnce(Return(sizeof(buffer_)));
+ .WillOnce(Return(2));
+
+ EXPECT_CALL(*async_api_, DoCommand(7, 0, &buffer_[0]))
+ .WillOnce(Return(command_buffer::BufferSyncInterface::kParseInvalidSize));
processor_->ProcessCommands();
- EXPECT_CALL(*command_buffer_, SetGetOffset(4));
- MessageLoop::current()->RunAllPending();
+ EXPECT_EQ(command_buffer::BufferSyncInterface::kParseInvalidSize,
+ command_buffer_->ResetParseError());
+ EXPECT_TRUE(command_buffer_->GetErrorStatus());
+}
+
+TEST_F(GPUProcessorTest, ProcessCommandsDoesNothingAfterUnrecoverableError) {
+ command_buffer::CommandHeader* header =
+ reinterpret_cast<command_buffer::CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 1;
+ header[1].command = 8;
+ header[1].size = 1;
+
+ EXPECT_CALL(*command_buffer_, GetPutOffset())
+ .WillOnce(Return(2));
+
+ EXPECT_CALL(*async_api_, DoCommand(7, 0, &buffer_[0]))
+ .WillOnce(Return(command_buffer::BufferSyncInterface::kParseInvalidSize));
+
+ processor_->ProcessCommands();
+ processor_->ProcessCommands();
+
+ EXPECT_EQ(command_buffer::BufferSyncInterface::kParseInvalidSize,
+ command_buffer_->ResetParseError());
+ EXPECT_TRUE(command_buffer_->GetErrorStatus());
+}
+
+TEST_F(GPUProcessorTest, CanGetAddressOfSharedMemory) {
+ EXPECT_CALL(*command_buffer_.Get(), GetRegisteredObject(7))
+ .WillOnce(Return(shared_memory_));
+
+ EXPECT_EQ(&buffer_[0], processor_->GetSharedMemoryAddress(7));
+}
+
+ACTION_P2(SetPointee, address, value) {
+ *address = value;
+}
+
+TEST_F(GPUProcessorTest, GetAddressOfSharedMemoryMapsMemoryIfUnmapped) {
+ EXPECT_CALL(*command_buffer_.Get(), GetRegisteredObject(7))
+ .WillOnce(Return(shared_memory_));
+
+ shared_memory_->ptr = NULL;
+
+ EXPECT_CALL(*shared_memory_.Get(), Map())
+ .WillOnce(DoAll(SetPointee(&shared_memory_->ptr, &buffer_[0]),
+ Return(true)));
+
+ EXPECT_EQ(&buffer_[0], processor_->GetSharedMemoryAddress(7));
+}
+
+TEST_F(GPUProcessorTest, CanGetSizeOfSharedMemory) {
+ EXPECT_CALL(*command_buffer_.Get(), GetRegisteredObject(7))
+ .WillOnce(Return(shared_memory_));
+
+ EXPECT_EQ(sizeof(buffer_), processor_->GetSharedMemorySize(7));
+}
+
+TEST_F(GPUProcessorTest, SetTokenForwardsToCommandBuffer) {
+ processor_->set_token(7);
+ EXPECT_EQ(7, command_buffer_->GetToken());
}
} // namespace gpu_plugin
diff --git a/o3d/gpu_plugin/gpu_processor_win.cc b/o3d/gpu_plugin/gpu_processor_win.cc
index 88a84e3..acd667f 100644
--- a/o3d/gpu_plugin/gpu_processor_win.cc
+++ b/o3d/gpu_plugin/gpu_processor_win.cc
@@ -9,30 +9,75 @@
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) {
+GPUProcessor::GPUProcessor(NPP npp,
+ const NPObjectPointer<CommandBuffer>& command_buffer)
+ : npp_(npp),
+ command_buffer_(command_buffer),
+ commands_per_update_(100) {
+ gapi_.reset(new command_buffer::GAPID3D9);
+
+ decoder_.reset(new command_buffer::GAPIDecoder(gapi_.get()));
+
+ NPObjectPointer<CHRSharedMemory> ring_buffer =
+ command_buffer->GetRingBuffer();
+
+ if (ring_buffer.Get()) {
+ parser_.reset(new command_buffer::CommandParser(ring_buffer->ptr,
+ ring_buffer->size,
+ 0,
+ ring_buffer->size,
+ 0,
+ decoder_.get()));
+ } else {
+ parser_.reset(new command_buffer::CommandParser(NULL, 0, 0, 0, 0,
+ decoder_.get()));
+ }
}
-void GPUProcessor::SetWindow(HWND handle, int width, int height) {
- window_handle_ = handle;
- window_width_ = width;
- window_height_ = height;
+GPUProcessor::GPUProcessor(NPP npp,
+ const NPObjectPointer<CommandBuffer>& command_buffer,
+ command_buffer::GAPID3D9* gapi,
+ command_buffer::GAPIDecoder* decoder,
+ command_buffer::CommandParser* parser,
+ int commands_per_update)
+ : npp_(npp),
+ command_buffer_(command_buffer),
+ commands_per_update_(commands_per_update) {
+ gapi_.reset(gapi);
+ decoder_.reset(decoder);
+ parser_.reset(parser);
+}
+
+bool GPUProcessor::Initialize(HWND handle) {
+ // Cannot reinitialize.
+ DCHECK(gapi_->hwnd() == NULL);
+
+ // Initialize GAPI immediately if the window handle is valid.
+ if (handle) {
+ gapi_->set_hwnd(handle);
+ return gapi_->Initialize();
+ } else {
+ return true;
+ }
}
-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);
+void GPUProcessor::Destroy() {
+ // Destroy GAPI if window handle has not already become invalid.
+ if (gapi_->hwnd()) {
+ gapi_->Destroy();
+ gapi_->set_hwnd(NULL);
+ }
+}
+
+void GPUProcessor::SetWindow(HWND handle, int width, int height) {
+ if (handle == NULL) {
+ // Destroy GAPI when the window handle becomes invalid.
+ Destroy();
+ } else {
+ if (handle != gapi_->hwnd()) {
+ Initialize(handle);
+ }
+ }
}
} // namespace gpu_plugin
diff --git a/o3d/gpu_plugin/system_services/shared_memory.cc b/o3d/gpu_plugin/system_services/shared_memory.cc
index 2e07e1a..9600111 100644
--- a/o3d/gpu_plugin/system_services/shared_memory.cc
+++ b/o3d/gpu_plugin/system_services/shared_memory.cc
@@ -65,15 +65,22 @@ bool SharedMemory::SetInt32(int32 offset, int32 value) {
if (!ptr)
return false;
- if (offset < 0 || offset + sizeof(value) >= size)
+ if (offset < 0 || offset * sizeof(value) >= size)
return false;
- if ((offset % sizeof(value)) != 0)
+ reinterpret_cast<int32*>(ptr)[offset] = value;
+ return true;
+}
+
+bool SharedMemory::SetFloat(int32 offset, float value) {
+ if (!ptr)
return false;
- *reinterpret_cast<int32*>(static_cast<int8*>(ptr) + offset) = value;
+ if (offset < 0 || offset * sizeof(value) >= size)
+ return false;
+
+ reinterpret_cast<float*>(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 fd591ee..7d72544 100644
--- a/o3d/gpu_plugin/system_services/shared_memory.h
+++ b/o3d/gpu_plugin/system_services/shared_memory.h
@@ -37,15 +37,20 @@ class SharedMemory : public DefaultNPObject<CHRSharedMemory> {
// JavaScript for the purposes of testing.
bool SetInt32(int32 offset, int32 value);
+ // This is a temporary function to allow me to drive the command buffer from
+ // JavaScript for the purposes of testing.
+ bool SetFloat(int32 offset, float value);
+
base::SharedMemory* shared_memory() const {
return shared_memory_;
}
NP_UTILS_BEGIN_DISPATCHER_CHAIN(SharedMemory, DefaultNPObject<NPObject>)
- NP_UTILS_DISPATCHER(Initialize, bool(int32));
+ NP_UTILS_DISPATCHER(Initialize, bool(int32 size));
NP_UTILS_DISPATCHER(GetSize, int32())
NP_UTILS_DISPATCHER(Map, bool())
- NP_UTILS_DISPATCHER(SetInt32, bool(int32, int32));
+ NP_UTILS_DISPATCHER(SetInt32, bool(int32 offset, int32 value));
+ NP_UTILS_DISPATCHER(SetFloat, bool(int32 offset, float value));
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 e2e0825..d6eea84 100644
--- a/o3d/gpu_plugin/system_services/shared_memory_unittest.cc
+++ b/o3d/gpu_plugin/system_services/shared_memory_unittest.cc
@@ -115,10 +115,10 @@ TEST_F(SharedMemoryTest, CanSetInt32) {
shared_memory_->Initialize(temp_shared_memory, 65536);
EXPECT_TRUE(shared_memory_->Map());
- EXPECT_TRUE(shared_memory_->SetInt32(4, 7));
+ EXPECT_TRUE(shared_memory_->SetInt32(1, 7));
EXPECT_EQ(7, static_cast<int32*>(shared_memory_->ptr)[1]);
- EXPECT_TRUE(shared_memory_->SetInt32(4, 8));
+ EXPECT_TRUE(shared_memory_->SetInt32(1, 8));
EXPECT_EQ(8, static_cast<int32*>(shared_memory_->ptr)[1]);
}
@@ -128,7 +128,7 @@ TEST_F(SharedMemoryTest, FailsIfSetInt32CalledBeforeMap) {
shared_memory_->Initialize(temp_shared_memory, 65536);
- EXPECT_FALSE(shared_memory_->SetInt32(4, 7));
+ EXPECT_FALSE(shared_memory_->SetInt32(1, 7));
}
TEST_F(SharedMemoryTest, FailsIfSetInt32OffsetIsOutOfRange) {
@@ -139,17 +139,41 @@ TEST_F(SharedMemoryTest, FailsIfSetInt32OffsetIsOutOfRange) {
EXPECT_TRUE(shared_memory_->Map());
EXPECT_FALSE(shared_memory_->SetInt32(-1, 7));
- EXPECT_FALSE(shared_memory_->SetInt32(65536, 7));
+ EXPECT_FALSE(shared_memory_->SetInt32(16384, 7));
}
-TEST_F(SharedMemoryTest, FailsIfSetInt32OffsetIsMisaligned) {
+TEST_F(SharedMemoryTest, CanSetFloat) {
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_TRUE(shared_memory_->SetFloat(1, 7));
+ EXPECT_EQ(7, static_cast<float*>(shared_memory_->ptr)[1]);
+
+ EXPECT_TRUE(shared_memory_->SetFloat(1, 8));
+ EXPECT_EQ(8, static_cast<float*>(shared_memory_->ptr)[1]);
+}
+
+TEST_F(SharedMemoryTest, FailsIfSetFloatCalledBeforeMap) {
+ 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_->SetFloat(1, 7));
+}
+
+TEST_F(SharedMemoryTest, FailsIfSetFloatOffsetIsOutOfRange) {
+ 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_->SetFloat(-1, 7));
+ EXPECT_FALSE(shared_memory_->SetFloat(16384, 7));
}
} // namespace gpu_plugin