diff options
author | apatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-24 19:19:25 +0000 |
---|---|---|
committer | apatrick@google.com <apatrick@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-24 19:19:25 +0000 |
commit | 2331a49ecb27f38888bf4f60f24e054cbb8a8890 (patch) | |
tree | de3d03558bd82742292cebb81f1ed68ba1626342 /o3d | |
parent | dfb5a4cc453d4a78e655d6f4cb5e11e8ced54c1b (diff) | |
download | chromium_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.h | 28 | ||||
-rw-r--r-- | o3d/command_buffer/service/cross/gapi_decoder.h | 6 | ||||
-rw-r--r-- | o3d/command_buffer/service/win/d3d9/gapi_d3d9.h | 1 | ||||
-rw-r--r-- | o3d/gpu_plugin/command_buffer.cc | 24 | ||||
-rw-r--r-- | o3d/gpu_plugin/command_buffer.h | 46 | ||||
-rw-r--r-- | o3d/gpu_plugin/command_buffer_mock.h | 19 | ||||
-rw-r--r-- | o3d/gpu_plugin/command_buffer_unittest.cc | 49 | ||||
-rw-r--r-- | o3d/gpu_plugin/gpu_plugin.gyp | 136 | ||||
-rw-r--r-- | o3d/gpu_plugin/gpu_plugin_object.cc | 15 | ||||
-rw-r--r-- | o3d/gpu_plugin/gpu_plugin_object_unittest.cc | 2 | ||||
-rw-r--r-- | o3d/gpu_plugin/gpu_processor.cc | 101 | ||||
-rw-r--r-- | o3d/gpu_plugin/gpu_processor.h | 51 | ||||
-rw-r--r-- | o3d/gpu_plugin/gpu_processor_unittest.cc | 271 | ||||
-rw-r--r-- | o3d/gpu_plugin/gpu_processor_win.cc | 85 | ||||
-rw-r--r-- | o3d/gpu_plugin/system_services/shared_memory.cc | 15 | ||||
-rw-r--r-- | o3d/gpu_plugin/system_services/shared_memory.h | 9 | ||||
-rw-r--r-- | o3d/gpu_plugin/system_services/shared_memory_unittest.cc | 36 |
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 |