From 09ddb91f6a81adebe023e461387c6510471e6778 Mon Sep 17 00:00:00 2001 From: "apatrick@chromium.org" Date: Thu, 14 Apr 2011 23:16:22 +0000 Subject: Landing issue 6828049 on behalf of KushalP. http://codereview.chromium.org/6826049/ Original message: Renaming GPUProcessor to GpuScheduler TEST=try BUG=76585 Review URL: http://codereview.chromium.org/6853027 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81667 0039d316-1c4b-4281-b951-d872f2087c98 --- .../client/cmd_buffer_helper_test.cc | 14 +- gpu/command_buffer/client/fenced_allocator_test.cc | 16 +- gpu/command_buffer/client/gles2_demo.cc | 10 +- .../client/mapped_memory_unittest.cc | 14 +- gpu/command_buffer/client/ring_buffer_test.cc | 16 +- gpu/command_buffer/service/gles2_cmd_decoder.cc | 2 +- gpu/command_buffer/service/gpu_processor.cc | 256 -------------------- gpu/command_buffer/service/gpu_processor.h | 163 ------------- gpu/command_buffer/service/gpu_processor_linux.cc | 67 ------ gpu/command_buffer/service/gpu_processor_mac.cc | 142 ----------- gpu/command_buffer/service/gpu_processor_mock.h | 29 --- .../service/gpu_processor_unittest.cc | 259 --------------------- gpu/command_buffer/service/gpu_processor_win.cc | 66 ------ gpu/command_buffer/service/gpu_scheduler.cc | 256 ++++++++++++++++++++ gpu/command_buffer/service/gpu_scheduler.h | 163 +++++++++++++ gpu/command_buffer/service/gpu_scheduler_linux.cc | 67 ++++++ gpu/command_buffer/service/gpu_scheduler_mac.cc | 142 +++++++++++ gpu/command_buffer/service/gpu_scheduler_mock.h | 29 +++ .../service/gpu_scheduler_unittest.cc | 259 +++++++++++++++++++++ gpu/command_buffer/service/gpu_scheduler_win.cc | 66 ++++++ gpu/demos/framework/window.cc | 12 +- gpu/gpu.gyp | 14 +- 22 files changed, 1031 insertions(+), 1031 deletions(-) delete mode 100644 gpu/command_buffer/service/gpu_processor.cc delete mode 100644 gpu/command_buffer/service/gpu_processor.h delete mode 100644 gpu/command_buffer/service/gpu_processor_linux.cc delete mode 100644 gpu/command_buffer/service/gpu_processor_mac.cc delete mode 100644 gpu/command_buffer/service/gpu_processor_mock.h delete mode 100644 gpu/command_buffer/service/gpu_processor_unittest.cc delete mode 100644 gpu/command_buffer/service/gpu_processor_win.cc create mode 100644 gpu/command_buffer/service/gpu_scheduler.cc create mode 100644 gpu/command_buffer/service/gpu_scheduler.h create mode 100644 gpu/command_buffer/service/gpu_scheduler_linux.cc create mode 100644 gpu/command_buffer/service/gpu_scheduler_mac.cc create mode 100644 gpu/command_buffer/service/gpu_scheduler_mock.h create mode 100644 gpu/command_buffer/service/gpu_scheduler_unittest.cc create mode 100644 gpu/command_buffer/service/gpu_scheduler_win.cc (limited to 'gpu') diff --git a/gpu/command_buffer/client/cmd_buffer_helper_test.cc b/gpu/command_buffer/client/cmd_buffer_helper_test.cc index 9f526df..1daa942 100644 --- a/gpu/command_buffer/client/cmd_buffer_helper_test.cc +++ b/gpu/command_buffer/client/cmd_buffer_helper_test.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,7 +10,7 @@ #include "gpu/command_buffer/client/cmd_buffer_helper.h" #include "gpu/command_buffer/service/mocks.h" #include "gpu/command_buffer/service/command_buffer_service.h" -#include "gpu/command_buffer/service/gpu_processor.h" +#include "gpu/command_buffer/service/gpu_scheduler.h" #include "testing/gtest/include/gtest/gtest.h" namespace gpu { @@ -77,19 +77,19 @@ class CommandBufferHelperTest : public testing::Test { .WillRepeatedly( Invoke(do_jump_command_.get(), &DoJumpCommand::DoCommand)); - gpu_processor_.reset(new GPUProcessor( + gpu_scheduler_.reset(new GpuScheduler( command_buffer_.get(), NULL, parser_, 1)); command_buffer_->SetPutOffsetChangeCallback(NewCallback( - gpu_processor_.get(), &GPUProcessor::ProcessCommands)); + gpu_scheduler_.get(), &GpuScheduler::ProcessCommands)); - api_mock_->set_engine(gpu_processor_.get()); + api_mock_->set_engine(gpu_scheduler_.get()); helper_.reset(new CommandBufferHelper(command_buffer_.get())); helper_->Initialize(kCommandBufferSizeBytes); } virtual void TearDown() { - // If the GPUProcessor posts any tasks, this forces them to run. + // If the GpuScheduler posts any tasks, this forces them to run. MessageLoop::current()->RunAllPending(); } @@ -156,7 +156,7 @@ class CommandBufferHelperTest : public testing::Test { MessageLoop message_loop_; scoped_ptr api_mock_; scoped_ptr command_buffer_; - scoped_ptr gpu_processor_; + scoped_ptr gpu_scheduler_; CommandParser* parser_; scoped_ptr helper_; Sequence sequence_; diff --git a/gpu/command_buffer/client/fenced_allocator_test.cc b/gpu/command_buffer/client/fenced_allocator_test.cc index 658deef2..533e867 100644 --- a/gpu/command_buffer/client/fenced_allocator_test.cc +++ b/gpu/command_buffer/client/fenced_allocator_test.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -12,7 +12,7 @@ #include "gpu/command_buffer/service/cmd_buffer_engine.h" #include "gpu/command_buffer/service/mocks.h" #include "gpu/command_buffer/service/command_buffer_service.h" -#include "gpu/command_buffer/service/gpu_processor.h" +#include "gpu/command_buffer/service/gpu_scheduler.h" #include "testing/gtest/include/gtest/gtest.h" namespace gpu { @@ -51,12 +51,12 @@ class BaseFencedAllocatorTest : public testing::Test { 0, api_mock_.get()); - gpu_processor_.reset(new GPUProcessor( + gpu_scheduler_.reset(new GpuScheduler( command_buffer_.get(), NULL, parser_, INT_MAX)); command_buffer_->SetPutOffsetChangeCallback(NewCallback( - gpu_processor_.get(), &GPUProcessor::ProcessCommands)); + gpu_scheduler_.get(), &GpuScheduler::ProcessCommands)); - api_mock_->set_engine(gpu_processor_.get()); + api_mock_->set_engine(gpu_scheduler_.get()); helper_.reset(new CommandBufferHelper(command_buffer_.get())); helper_->Initialize(kBufferSize); @@ -70,7 +70,7 @@ class BaseFencedAllocatorTest : public testing::Test { MessageLoop message_loop_; scoped_ptr api_mock_; scoped_ptr command_buffer_; - scoped_ptr gpu_processor_; + scoped_ptr gpu_scheduler_; CommandParser* parser_; scoped_ptr helper_; }; @@ -91,7 +91,7 @@ class FencedAllocatorTest : public BaseFencedAllocatorTest { } virtual void TearDown() { - // If the GPUProcessor posts any tasks, this forces them to run. + // If the GpuScheduler posts any tasks, this forces them to run. MessageLoop::current()->RunAllPending(); EXPECT_TRUE(allocator_->CheckConsistency()); @@ -387,7 +387,7 @@ class FencedAllocatorWrapperTest : public BaseFencedAllocatorTest { } virtual void TearDown() { - // If the GPUProcessor posts any tasks, this forces them to run. + // If the GpuScheduler posts any tasks, this forces them to run. MessageLoop::current()->RunAllPending(); EXPECT_TRUE(allocator_->CheckConsistency()); diff --git a/gpu/command_buffer/client/gles2_demo.cc b/gpu/command_buffer/client/gles2_demo.cc index 91ef9bf2..096a9d3 100644 --- a/gpu/command_buffer/client/gles2_demo.cc +++ b/gpu/command_buffer/client/gles2_demo.cc @@ -19,7 +19,7 @@ #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" #include "base/shared_memory.h" -#include "gpu/command_buffer/service/gpu_processor.h" +#include "gpu/command_buffer/service/gpu_scheduler.h" #include "gpu/command_buffer/service/command_buffer_service.h" #include "gpu/command_buffer/client/gles2_implementation.h" #include "gpu/command_buffer/client/gles2_lib.h" @@ -29,7 +29,7 @@ using base::SharedMemory; using gpu::Buffer; -using gpu::GPUProcessor; +using gpu::GpuScheduler; using gpu::CommandBufferService; using gpu::gles2::GLES2CmdHelper; using gpu::gles2::GLES2Implementation; @@ -56,8 +56,8 @@ bool GLES2Demo::Setup(void* hwnd, int32 size) { if (!command_buffer->Initialize(size)) return NULL; - GPUProcessor* gpu_processor = new GPUProcessor(command_buffer.get(), NULL); - if (!gpu_processor->Initialize(reinterpret_cast(hwnd), + GpuScheduler* gpu_scheduler = new GpuScheduler(command_buffer.get(), NULL); + if (!gpu_scheduler->Initialize(reinterpret_cast(hwnd), gfx::Size(), gpu::gles2::DisallowedExtensions(), NULL, @@ -68,7 +68,7 @@ bool GLES2Demo::Setup(void* hwnd, int32 size) { } command_buffer->SetPutOffsetChangeCallback( - NewCallback(gpu_processor, &GPUProcessor::ProcessCommands)); + NewCallback(gpu_scheduler, &GpuScheduler::ProcessCommands)); GLES2CmdHelper* helper = new GLES2CmdHelper(command_buffer.get()); if (!helper->Initialize(size)) { diff --git a/gpu/command_buffer/client/mapped_memory_unittest.cc b/gpu/command_buffer/client/mapped_memory_unittest.cc index 87bac68..93e63e7 100644 --- a/gpu/command_buffer/client/mapped_memory_unittest.cc +++ b/gpu/command_buffer/client/mapped_memory_unittest.cc @@ -10,7 +10,7 @@ #include "gpu/command_buffer/client/cmd_buffer_helper.h" #include "gpu/command_buffer/service/mocks.h" #include "gpu/command_buffer/service/command_buffer_service.h" -#include "gpu/command_buffer/service/gpu_processor.h" +#include "gpu/command_buffer/service/gpu_scheduler.h" #include "testing/gtest/include/gtest/gtest.h" namespace gpu { @@ -49,12 +49,12 @@ class MappedMemoryTestBase : public testing::Test { 0, api_mock_.get()); - gpu_processor_.reset(new GPUProcessor( + gpu_scheduler_.reset(new GpuScheduler( command_buffer_.get(), NULL, parser_, INT_MAX)); command_buffer_->SetPutOffsetChangeCallback(NewCallback( - gpu_processor_.get(), &GPUProcessor::ProcessCommands)); + gpu_scheduler_.get(), &GpuScheduler::ProcessCommands)); - api_mock_->set_engine(gpu_processor_.get()); + api_mock_->set_engine(gpu_scheduler_.get()); helper_.reset(new CommandBufferHelper(command_buffer_.get())); helper_->Initialize(kBufferSize); @@ -68,7 +68,7 @@ class MappedMemoryTestBase : public testing::Test { MessageLoop message_loop_; scoped_ptr api_mock_; scoped_ptr command_buffer_; - scoped_ptr gpu_processor_; + scoped_ptr gpu_scheduler_; CommandParser* parser_; scoped_ptr helper_; }; @@ -94,7 +94,7 @@ class MemoryChunkTest : public MappedMemoryTestBase { } virtual void TearDown() { - // If the GPUProcessor posts any tasks, this forces them to run. + // If the GpuScheduler posts any tasks, this forces them to run. MessageLoop::current()->RunAllPending(); MappedMemoryTestBase::TearDown(); @@ -145,7 +145,7 @@ class MappedMemoryManagerTest : public MappedMemoryTestBase { } virtual void TearDown() { - // If the GPUProcessor posts any tasks, this forces them to run. + // If the GpuScheduler posts any tasks, this forces them to run. MessageLoop::current()->RunAllPending(); manager_.reset(); MappedMemoryTestBase::TearDown(); diff --git a/gpu/command_buffer/client/ring_buffer_test.cc b/gpu/command_buffer/client/ring_buffer_test.cc index 6510611..e3c14c7 100644 --- a/gpu/command_buffer/client/ring_buffer_test.cc +++ b/gpu/command_buffer/client/ring_buffer_test.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -12,7 +12,7 @@ #include "gpu/command_buffer/service/cmd_buffer_engine.h" #include "gpu/command_buffer/service/mocks.h" #include "gpu/command_buffer/service/command_buffer_service.h" -#include "gpu/command_buffer/service/gpu_processor.h" +#include "gpu/command_buffer/service/gpu_scheduler.h" #include "testing/gtest/include/gtest/gtest.h" namespace gpu { @@ -52,12 +52,12 @@ class BaseRingBufferTest : public testing::Test { 0, api_mock_.get()); - gpu_processor_.reset(new GPUProcessor( + gpu_scheduler_.reset(new GpuScheduler( command_buffer_.get(), NULL, parser_, INT_MAX)); command_buffer_->SetPutOffsetChangeCallback(NewCallback( - gpu_processor_.get(), &GPUProcessor::ProcessCommands)); + gpu_scheduler_.get(), &GpuScheduler::ProcessCommands)); - api_mock_->set_engine(gpu_processor_.get()); + api_mock_->set_engine(gpu_scheduler_.get()); helper_.reset(new CommandBufferHelper(command_buffer_.get())); helper_->Initialize(kBufferSize); @@ -71,7 +71,7 @@ class BaseRingBufferTest : public testing::Test { MessageLoop message_loop_; scoped_ptr api_mock_; scoped_ptr command_buffer_; - scoped_ptr gpu_processor_; + scoped_ptr gpu_scheduler_; CommandParser* parser_; scoped_ptr helper_; }; @@ -93,7 +93,7 @@ class RingBufferTest : public BaseRingBufferTest { } virtual void TearDown() { - // If the GPUProcessor posts any tasks, this forces them to run. + // If the GpuScheduler posts any tasks, this forces them to run. MessageLoop::current()->RunAllPending(); BaseRingBufferTest::TearDown(); @@ -189,7 +189,7 @@ class RingBufferWrapperTest : public BaseRingBufferTest { } virtual void TearDown() { - // If the GPUProcessor posts any tasks, this forces them to run. + // If the GpuScheduler posts any tasks, this forces them to run. MessageLoop::current()->RunAllPending(); BaseRingBufferTest::TearDown(); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 3b6990d..03b4735 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -1841,7 +1841,7 @@ bool GLES2DecoderImpl::Initialize( } if (!group_->Initialize(disallowed_extensions, allowed_extensions)) { - LOG(ERROR) << "GPUProcessor::InitializeCommon failed because group " + LOG(ERROR) << "GpuScheduler::InitializeCommon failed because group " << "failed to initialize."; Destroy(); return false; diff --git a/gpu/command_buffer/service/gpu_processor.cc b/gpu/command_buffer/service/gpu_processor.cc deleted file mode 100644 index c2363b8..0000000 --- a/gpu/command_buffer/service/gpu_processor.cc +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "gpu/command_buffer/service/gpu_processor.h" - -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/message_loop.h" -#include "gpu/common/gpu_trace_event.h" -#include "ui/gfx/gl/gl_context.h" -#include "ui/gfx/gl/gl_bindings.h" - -using ::base::SharedMemory; - -static size_t kNumThrottleFences = 1; - -namespace gpu { - -GPUProcessor::GPUProcessor(CommandBuffer* command_buffer, - gles2::ContextGroup* group) - : command_buffer_(command_buffer), - commands_per_update_(100), - num_throttle_fences_(0), -#if defined(OS_MACOSX) - swap_buffers_count_(0), - acknowledged_swap_buffers_count_(0), -#endif - method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { - DCHECK(command_buffer); - decoder_.reset(gles2::GLES2Decoder::Create(group)); - decoder_->set_engine(this); -} - -GPUProcessor::GPUProcessor(CommandBuffer* command_buffer, - gles2::GLES2Decoder* decoder, - CommandParser* parser, - int commands_per_update) - : command_buffer_(command_buffer), - commands_per_update_(commands_per_update), - num_throttle_fences_(0), -#if defined(OS_MACOSX) - swap_buffers_count_(0), - acknowledged_swap_buffers_count_(0), -#endif - method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { - DCHECK(command_buffer); - decoder_.reset(decoder); - parser_.reset(parser); -} - -GPUProcessor::~GPUProcessor() { - Destroy(); -} - -bool GPUProcessor::InitializeCommon( - gfx::GLContext* context, - const gfx::Size& size, - const gles2::DisallowedExtensions& disallowed_extensions, - const char* allowed_extensions, - const std::vector& attribs, - gles2::GLES2Decoder* parent_decoder, - uint32 parent_texture_id) { - DCHECK(context); - - if (!context->MakeCurrent()) - return false; - - // If the NV_fence extension is present, use fences to defer the issue of - // commands once a certain fixed number of frames have been rendered. - num_throttle_fences_ = - context->HasExtension("GL_NV_fence") ? kNumThrottleFences : 0; - - // Do not limit to a certain number of commands before scheduling another - // update when rendering onscreen. - if (!context->IsOffscreen()) - commands_per_update_ = INT_MAX; - - // Map the ring buffer and create the parser. - Buffer ring_buffer = command_buffer_->GetRingBuffer(); - if (ring_buffer.ptr) { - parser_.reset(new CommandParser(ring_buffer.ptr, - ring_buffer.size, - 0, - ring_buffer.size, - 0, - decoder_.get())); - } else { - parser_.reset(new CommandParser(NULL, 0, 0, 0, 0, - decoder_.get())); - } - - // Initialize the decoder with either the view or pbuffer GLContext. - if (!decoder_->Initialize(context, - size, - disallowed_extensions, - allowed_extensions, - attribs, - parent_decoder, - parent_texture_id)) { - LOG(ERROR) << "GPUProcessor::InitializeCommon failed because decoder " - << "failed to initialize."; - Destroy(); - return false; - } - - return true; -} - -void GPUProcessor::DestroyCommon() { - bool have_context = false; - if (decoder_.get()) { - have_context = decoder_->MakeCurrent(); - decoder_->Destroy(); - decoder_.reset(); - } - - parser_.reset(); -} - -#if defined(OS_MACOSX) -namespace { -const unsigned int kMaxOutstandingSwapBuffersCallsPerOnscreenContext = 1; -} -#endif - -void GPUProcessor::ProcessCommands() { - GPU_TRACE_EVENT0("gpu", "GPUProcessor:ProcessCommands"); - CommandBuffer::State state = command_buffer_->GetState(); - if (state.error != error::kNoError) - return; - - if (decoder_.get()) { - if (!decoder_->MakeCurrent()) { - LOG(ERROR) << "Context lost because MakeCurrent failed."; - command_buffer_->SetParseError(error::kLostContext); - return; - } - } - - parser_->set_put(state.put_offset); - -#if defined(OS_MACOSX) - bool do_rate_limiting = surface_.get() != NULL; - // Don't swamp the browser process with SwapBuffers calls it can't handle. - if (do_rate_limiting && - swap_buffers_count_ - acknowledged_swap_buffers_count_ >= - kMaxOutstandingSwapBuffersCallsPerOnscreenContext) { - // Stop doing work on this command buffer. In the GPU process, - // receipt of the GpuMsg_AcceleratedSurfaceBuffersSwappedACK - // message causes ProcessCommands to be scheduled again. - return; - } -#endif - - // Defer this command until the fence queue is not full. - while (num_throttle_fences_ > 0 && - throttle_fences_.size() >= num_throttle_fences_) { - GLuint fence = throttle_fences_.front(); - if (!glTestFenceNV(fence)) { - ScheduleProcessCommands(); - return; - } - - glDeleteFencesNV(1, &fence); - throttle_fences_.pop(); - } - - int commands_processed = 0; - while (commands_processed < commands_per_update_ && !parser_->IsEmpty()) { - error::Error error = parser_->ProcessCommand(); - if (error == error::kWaiting) { - break; - } - - // If the command indicated it should be throttled, insert a new fence into - // the fence queue. - if (error == error::kThrottle) { - if (num_throttle_fences_ > 0 && - throttle_fences_.size() < num_throttle_fences_) { - GLuint fence; - glGenFencesNV(1, &fence); - glSetFenceNV(fence, GL_ALL_COMPLETED_NV); - throttle_fences_.push(fence); - - // Neither glTestFenceNV or glSetFenceNV are guaranteed to flush. - // Without an explicit flush, the glTestFenceNV loop might never - // make progress. - glFlush(); - break; - } - } else if (error != error::kNoError) { - command_buffer_->SetParseError(error); - return; - } - ++commands_processed; - if (command_processed_callback_.get()) { - command_processed_callback_->Run(); - } - } - - command_buffer_->SetGetOffset(static_cast(parser_->get())); - - if (!parser_->IsEmpty()) { - ScheduleProcessCommands(); - } -} - -void GPUProcessor::ScheduleProcessCommands() { - MessageLoop::current()->PostTask( - FROM_HERE, - method_factory_.NewRunnableMethod(&GPUProcessor::ProcessCommands)); -} - -Buffer GPUProcessor::GetSharedMemoryBuffer(int32 shm_id) { - return command_buffer_->GetTransferBuffer(shm_id); -} - -void GPUProcessor::set_token(int32 token) { - command_buffer_->SetToken(token); -} - -bool GPUProcessor::SetGetOffset(int32 offset) { - if (parser_->set_get(offset)) { - command_buffer_->SetGetOffset(static_cast(parser_->get())); - return true; - } - return false; -} - -int32 GPUProcessor::GetGetOffset() { - return parser_->get(); -} - -void GPUProcessor::ResizeOffscreenFrameBuffer(const gfx::Size& size) { - decoder_->ResizeOffscreenFrameBuffer(size); -} - -void GPUProcessor::SetResizeCallback(Callback1::Type* callback) { - decoder_->SetResizeCallback(callback); -} - -void GPUProcessor::SetSwapBuffersCallback( - Callback0::Type* callback) { - wrapped_swap_buffers_callback_.reset(callback); - decoder_->SetSwapBuffersCallback( - NewCallback(this, - &GPUProcessor::WillSwapBuffers)); -} - -void GPUProcessor::SetCommandProcessedCallback( - Callback0::Type* callback) { - command_processed_callback_.reset(callback); -} - -} // namespace gpu diff --git a/gpu/command_buffer/service/gpu_processor.h b/gpu/command_buffer/service/gpu_processor.h deleted file mode 100644 index 234c437..0000000 --- a/gpu/command_buffer/service/gpu_processor.h +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_PROCESSOR_H_ -#define GPU_COMMAND_BUFFER_SERVICE_GPU_PROCESSOR_H_ - -#include -#include - -#include "base/callback.h" -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "base/shared_memory.h" -#include "base/task.h" -#include "gpu/command_buffer/common/command_buffer.h" -#include "gpu/command_buffer/service/cmd_buffer_engine.h" -#include "gpu/command_buffer/service/cmd_parser.h" -#include "gpu/command_buffer/service/gles2_cmd_decoder.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gfx/size.h" -#include "ui/gfx/surface/transport_dib.h" - -#if defined(OS_MACOSX) -#include "ui/gfx/surface/accelerated_surface_mac.h" -#endif - -namespace gfx { -class GLContext; -} - -namespace gpu { -namespace gles2 { -class ContextGroup; -} - -// 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 CommandBufferEngine { - public: - // If a group is not passed in one will be created. - GPUProcessor(CommandBuffer* command_buffer, gles2::ContextGroup* group); - - // This constructor is for unit tests. - GPUProcessor(CommandBuffer* command_buffer, - gles2::GLES2Decoder* decoder, - CommandParser* parser, - int commands_per_update); - - virtual ~GPUProcessor(); - - // Perform platform specific and common initialization. - bool Initialize(gfx::PluginWindowHandle hwnd, - const gfx::Size& size, - const gles2::DisallowedExtensions& disallowed_extensions, - const char* allowed_extensions, - const std::vector& attribs, - GPUProcessor* parent, - uint32 parent_texture_id); - - void Destroy(); - void DestroyCommon(); - - virtual void ProcessCommands(); - - // Helper which causes a call to ProcessCommands to be scheduled later. - void ScheduleProcessCommands(); - - // Implementation of CommandBufferEngine. - virtual Buffer GetSharedMemoryBuffer(int32 shm_id); - virtual void set_token(int32 token); - virtual bool SetGetOffset(int32 offset); - virtual int32 GetGetOffset(); - - // Asynchronously resizes an offscreen frame buffer. - void ResizeOffscreenFrameBuffer(const gfx::Size& size); - -#if defined(OS_MACOSX) - // Needed only on Mac OS X, which does not render into an on-screen - // window and therefore requires the backing store to be resized - // manually. Returns an opaque identifier for the new backing store. - // There are two versions of this method: one for use with the IOSurface - // available in Mac OS X 10.6; and, one for use with the - // TransportDIB-based version used on Mac OS X 10.5. - virtual uint64 SetWindowSizeForIOSurface(const gfx::Size& size); - virtual TransportDIB::Handle SetWindowSizeForTransportDIB( - const gfx::Size& size); - virtual void SetTransportDIBAllocAndFree( - Callback2::Type* allocator, - Callback1::Type* deallocator); - // Returns the id of the current IOSurface, or 0. - virtual uint64 GetSurfaceId(); - // To prevent the GPU process from overloading the browser process, - // we need to track the number of swap buffers calls issued and - // acknowledged per on-screen (IOSurface-backed) context, and keep - // the GPU from getting too far ahead of the browser. Note that this - // is also predicated on a flow control mechanism between the - // renderer and GPU processes. - uint64 swap_buffers_count() const; - void set_acknowledged_swap_buffers_count( - uint64 acknowledged_swap_buffers_count); - - void DidDestroySurface(); -#endif - - // Sets a callback that is called when a glResizeCHROMIUM command - // is processed. - virtual void SetResizeCallback(Callback1::Type* callback); - - // Sets a callback which is called when a SwapBuffers command is processed. - // Must be called after Initialize(). - // It is not defined on which thread this callback is called. - virtual void SetSwapBuffersCallback(Callback0::Type* callback); - - virtual void SetCommandProcessedCallback(Callback0::Type* callback); - - // Get the GLES2Decoder associated with this processor. - gles2::GLES2Decoder* decoder() const { return decoder_.get(); } - - protected: - // Perform common initialization. Takes ownership of GLContext. - bool InitializeCommon( - gfx::GLContext* context, - const gfx::Size& size, - const gles2::DisallowedExtensions& disallowed_extensions, - const char* allowed_extensions, - const std::vector& attribs, - gles2::GLES2Decoder* parent_decoder, - uint32 parent_texture_id); - - - private: - // Called via a callback just before we are supposed to call the - // user's swap buffers callback. - virtual void WillSwapBuffers(); - - // The GPUProcessor holds a weak reference to the CommandBuffer. The - // CommandBuffer owns the GPUProcessor and holds a strong reference to it - // through the ProcessCommands callback. - CommandBuffer* command_buffer_; - - int commands_per_update_; - - scoped_ptr decoder_; - scoped_ptr parser_; - - size_t num_throttle_fences_; - std::queue throttle_fences_; - -#if defined(OS_MACOSX) - scoped_ptr surface_; - uint64 swap_buffers_count_; - uint64 acknowledged_swap_buffers_count_; -#endif - - ScopedRunnableMethodFactory method_factory_; - scoped_ptr wrapped_swap_buffers_callback_; - scoped_ptr command_processed_callback_; -}; - -} // namespace gpu - -#endif // GPU_COMMAND_BUFFER_SERVICE_GPU_PROCESSOR_H_ diff --git a/gpu/command_buffer/service/gpu_processor_linux.cc b/gpu/command_buffer/service/gpu_processor_linux.cc deleted file mode 100644 index 87f694e..0000000 --- a/gpu/command_buffer/service/gpu_processor_linux.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "gpu/command_buffer/service/gpu_processor.h" -#include "ui/gfx/gl/gl_context.h" - -using ::base::SharedMemory; - -namespace gpu { - -bool GPUProcessor::Initialize( - gfx::PluginWindowHandle window, - const gfx::Size& size, - const gles2::DisallowedExtensions& disallowed_extensions, - const char* allowed_extensions, - const std::vector& attribs, - GPUProcessor* parent, - uint32 parent_texture_id) { - // Get the parent decoder and the GLContext to share IDs with, if any. - gles2::GLES2Decoder* parent_decoder = NULL; - gfx::GLContext* parent_context = NULL; - void* parent_handle = NULL; - if (parent) { - parent_decoder = parent->decoder_.get(); - DCHECK(parent_decoder); - - parent_context = parent_decoder->GetGLContext(); - DCHECK(parent_context); - } - - // Create either a view or pbuffer based GLContext. - scoped_ptr context; - if (window) { - DCHECK(!parent_handle); - - // TODO(apatrick): support multisampling. - context.reset(gfx::GLContext::CreateViewGLContext(window, false)); - } else { - context.reset(gfx::GLContext::CreateOffscreenGLContext(parent_context)); - } - - if (!context.get()) { - LOG(ERROR) << "GPUProcessor::Initialize failed"; - return false; - } - - return InitializeCommon(context.release(), - size, - disallowed_extensions, - allowed_extensions, - attribs, - parent_decoder, - parent_texture_id); -} - -void GPUProcessor::Destroy() { - DestroyCommon(); -} - -void GPUProcessor::WillSwapBuffers() { - if (wrapped_swap_buffers_callback_.get()) { - wrapped_swap_buffers_callback_->Run(); - } -} - -} // namespace gpu diff --git a/gpu/command_buffer/service/gpu_processor_mac.cc b/gpu/command_buffer/service/gpu_processor_mac.cc deleted file mode 100644 index 4d250ac..0000000 --- a/gpu/command_buffer/service/gpu_processor_mac.cc +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "gpu/command_buffer/service/gpu_processor.h" -#include "ui/gfx/gl/gl_context.h" - -using ::base::SharedMemory; - -namespace gpu { - -bool GPUProcessor::Initialize( - gfx::PluginWindowHandle window, - const gfx::Size& size, - const gles2::DisallowedExtensions& disallowed_extensions, - const char* allowed_extensions, - const std::vector& attribs, - GPUProcessor* parent, - uint32 parent_texture_id) { - // Get the parent decoder and the GLContext to share IDs with, if any. - gles2::GLES2Decoder* parent_decoder = NULL; - gfx::GLContext* parent_context = NULL; - if (parent) { - parent_decoder = parent->decoder_.get(); - DCHECK(parent_decoder); - - parent_context = parent_decoder->GetGLContext(); - DCHECK(parent_context); - } - - scoped_ptr context( - gfx::GLContext::CreateOffscreenGLContext(parent_context)); - if (!context.get()) - return false; - - // On Mac OS X since we can not render on-screen we don't even - // attempt to create a view based GLContext. The only difference - // between "on-screen" and "off-screen" rendering on this platform - // is whether we allocate an AcceleratedSurface, which transmits the - // rendering results back to the browser. - if (window) { - surface_.reset(new AcceleratedSurface()); - - // Note that although the GLContext is passed to Initialize and the - // GLContext will later be owned by the decoder, AcceleratedSurface does - // not hold on to the reference. It simply extracts the underlying GL - // context in order to share the namespace with another context. - if (!surface_->Initialize(context.get(), false)) { - LOG(ERROR) << "GPUProcessor::Initialize failed to " - << "initialize AcceleratedSurface."; - Destroy(); - return false; - } - } - - return InitializeCommon(context.release(), - size, - disallowed_extensions, - allowed_extensions, - attribs, - parent_decoder, - parent_texture_id); -} - -void GPUProcessor::Destroy() { - if (surface_.get()) { - surface_->Destroy(); - surface_.reset(); - } - - DestroyCommon(); -} - -uint64 GPUProcessor::SetWindowSizeForIOSurface(const gfx::Size& size) { - // This is called from an IPC handler, so it's undefined which context is - // current. Make sure the right one is. - decoder_->GetGLContext()->MakeCurrent(); - - ResizeOffscreenFrameBuffer(size); - decoder_->UpdateOffscreenFrameBufferSize(); - - // Note: The following line changes the current context again. - return surface_->SetSurfaceSize(size); -} - -TransportDIB::Handle GPUProcessor::SetWindowSizeForTransportDIB( - const gfx::Size& size) { - ResizeOffscreenFrameBuffer(size); - decoder_->UpdateOffscreenFrameBufferSize(); - return surface_->SetTransportDIBSize(size); -} - -void GPUProcessor::SetTransportDIBAllocAndFree( - Callback2::Type* allocator, - Callback1::Type* deallocator) { - surface_->SetTransportDIBAllocAndFree(allocator, deallocator); -} - -uint64 GPUProcessor::GetSurfaceId() { - if (!surface_.get()) - return 0; - return surface_->GetSurfaceId(); -} - -uint64 GPUProcessor::swap_buffers_count() const { - return swap_buffers_count_; -} - -void GPUProcessor::set_acknowledged_swap_buffers_count( - uint64 acknowledged_swap_buffers_count) { - acknowledged_swap_buffers_count_ = acknowledged_swap_buffers_count; -} - -void GPUProcessor::DidDestroySurface() { - // When a browser window with a GPUProcessor is closed, the render process - // will attempt to finish all GL commands, it will busy-wait on the GPU - // process until the command queue is empty. If a paint is pending, the GPU - // process won't process any GL commands until the browser sends a paint ack, - // but since the browser window is already closed, it will never arrive. - // To break this infinite loop, the browser tells the GPU process that the - // surface became invalid, which causes the GPU process to not wait for paint - // acks. - surface_.reset(); -} - -void GPUProcessor::WillSwapBuffers() { - DCHECK(decoder_.get()); - DCHECK(decoder_->GetGLContext()); - DCHECK(decoder_->GetGLContext()->IsCurrent()); - - ++swap_buffers_count_; - - if (surface_.get()) { - surface_->SwapBuffers(); - } - - if (wrapped_swap_buffers_callback_.get()) { - wrapped_swap_buffers_callback_->Run(); - } -} - -} // namespace gpu diff --git a/gpu/command_buffer/service/gpu_processor_mock.h b/gpu/command_buffer/service/gpu_processor_mock.h deleted file mode 100644 index 8eab35d..0000000 --- a/gpu/command_buffer/service/gpu_processor_mock.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_PROCESSOR_MOCK_H_ -#define GPU_COMMAND_BUFFER_SERVICE_GPU_PROCESSOR_MOCK_H_ - -#include "gpu/command_buffer/service/gpu_processor.h" -#include "testing/gmock/include/gmock/gmock.h" - -namespace gpu { - -class MockGPUProcessor : public GPUProcessor { - public: - explicit MockGPUProcessor(CommandBuffer* command_buffer) - : GPUProcessor(command_buffer) { - } - - MOCK_METHOD0(ProcessCommands, void()); - MOCK_METHOD1(GetSharedMemoryBuffer, Buffer(int32 shm_id)); - MOCK_METHOD1(set_token, void(int32 token)); - - private: - DISALLOW_COPY_AND_ASSIGN(MockGPUProcessor); -}; - -} // namespace gpu - -#endif // GPU_COMMAND_BUFFER_SERVICE_GPU_PROCESSOR_MOCK_H_ diff --git a/gpu/command_buffer/service/gpu_processor_unittest.cc b/gpu/command_buffer/service/gpu_processor_unittest.cc deleted file mode 100644 index ce91210..0000000 --- a/gpu/command_buffer/service/gpu_processor_unittest.cc +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/mac/scoped_nsautorelease_pool.h" -#include "base/message_loop.h" -#include "gpu/command_buffer/common/command_buffer_mock.h" -#include "gpu/command_buffer/service/gpu_processor.h" -#include "gpu/command_buffer/service/gles2_cmd_decoder.h" -#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h" -#include "gpu/command_buffer/service/mocks.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/gmock/include/gmock/gmock.h" - -using testing::_; -using testing::DoAll; -using testing::Invoke; -using testing::NiceMock; -using testing::Return; -using testing::SetArgumentPointee; -using testing::StrictMock; - -namespace gpu { - -const size_t kRingBufferSize = 1024; -const size_t kRingBufferEntries = kRingBufferSize / sizeof(CommandBufferEntry); - -class GPUProcessorTest : public testing::Test { - protected: - virtual void SetUp() { - shared_memory_.reset(new ::base::SharedMemory); - shared_memory_->CreateAndMapAnonymous(kRingBufferSize); - buffer_ = static_cast(shared_memory_->memory()); - shared_memory_buffer_.ptr = buffer_; - shared_memory_buffer_.size = kRingBufferSize; - memset(buffer_, 0, kRingBufferSize); - - command_buffer_.reset(new MockCommandBuffer); - ON_CALL(*command_buffer_.get(), GetRingBuffer()) - .WillByDefault(Return(shared_memory_buffer_)); - - CommandBuffer::State default_state; - default_state.num_entries = kRingBufferEntries; - ON_CALL(*command_buffer_.get(), GetState()) - .WillByDefault(Return(default_state)); - - async_api_.reset(new StrictMock); - - decoder_ = new gles2::MockGLES2Decoder(); - - parser_ = new CommandParser(buffer_, - kRingBufferEntries, - 0, - kRingBufferEntries, - 0, - async_api_.get()); - - processor_.reset(new GPUProcessor(command_buffer_.get(), - decoder_, - parser_, - 2)); - - EXPECT_CALL(*decoder_, Destroy()) - .Times(1) - .RetiresOnSaturation(); - } - - virtual void TearDown() { - // Ensure that any unexpected tasks posted by the GPU processor are executed - // in order to fail the test. - MessageLoop::current()->RunAllPending(); - } - - error::Error GetError() { - return command_buffer_->GetState().error; - } - - base::mac::ScopedNSAutoreleasePool autorelease_pool_; - MessageLoop message_loop; - scoped_ptr command_buffer_; - scoped_ptr shared_memory_; - Buffer shared_memory_buffer_; - int32* buffer_; - gles2::MockGLES2Decoder* decoder_; - CommandParser* parser_; - scoped_ptr async_api_; - scoped_ptr processor_; -}; - -TEST_F(GPUProcessorTest, ProcessorDoesNothingIfRingBufferIsEmpty) { - CommandBuffer::State state; - - state.put_offset = 0; - EXPECT_CALL(*command_buffer_, GetState()) - .WillOnce(Return(state)); - EXPECT_CALL(*command_buffer_, SetGetOffset(0)); - - EXPECT_CALL(*command_buffer_, SetParseError(_)) - .Times(0); - - processor_->ProcessCommands(); -} - -TEST_F(GPUProcessorTest, ProcessesOneCommand) { - CommandHeader* header = reinterpret_cast(&buffer_[0]); - header[0].command = 7; - header[0].size = 2; - buffer_[1] = 123; - - CommandBuffer::State state; - - state.put_offset = 2; - EXPECT_CALL(*command_buffer_, GetState()) - .WillOnce(Return(state)); - EXPECT_CALL(*command_buffer_, SetGetOffset(2)); - - EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0])) - .WillOnce(Return(error::kNoError)); - - EXPECT_CALL(*command_buffer_, SetParseError(_)) - .Times(0); - - processor_->ProcessCommands(); -} - -TEST_F(GPUProcessorTest, ProcessesTwoCommands) { - CommandHeader* header = reinterpret_cast(&buffer_[0]); - header[0].command = 7; - header[0].size = 2; - buffer_[1] = 123; - header[2].command = 8; - header[2].size = 1; - - CommandBuffer::State state; - - state.put_offset = 3; - EXPECT_CALL(*command_buffer_, GetState()) - .WillOnce(Return(state)); - EXPECT_CALL(*command_buffer_, SetGetOffset(3)); - - EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0])) - .WillOnce(Return(error::kNoError)); - - EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[2])) - .WillOnce(Return(error::kNoError)); - - processor_->ProcessCommands(); -} - -TEST_F(GPUProcessorTest, ProcessorSetsTheGLContext) { - EXPECT_CALL(*decoder_, MakeCurrent()) - .WillOnce(Return(true)) - .WillOnce(Return(true)); - - CommandBuffer::State state; - state.put_offset = 0; - EXPECT_CALL(*command_buffer_, GetState()) - .WillOnce(Return(state)); - - EXPECT_CALL(*command_buffer_, SetGetOffset(0)); - - processor_->ProcessCommands(); -} - -TEST_F(GPUProcessorTest, PostsTaskToFinishRemainingCommands) { - CommandHeader* header = reinterpret_cast(&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; - - CommandBuffer::State state; - - state.put_offset = 4; - EXPECT_CALL(*command_buffer_, GetState()) - .WillOnce(Return(state)); - - EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0])) - .WillOnce(Return(error::kNoError)); - - EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[2])) - .WillOnce(Return(error::kNoError)); - - EXPECT_CALL(*command_buffer_, SetGetOffset(3)); - - processor_->ProcessCommands(); - - // ProcessCommands is called a second time when the pending task is run. - - state.put_offset = 4; - EXPECT_CALL(*command_buffer_, GetState()) - .WillOnce(Return(state)); - - EXPECT_CALL(*async_api_, DoCommand(9, 0, &buffer_[3])) - .WillOnce(Return(error::kNoError)); - - EXPECT_CALL(*command_buffer_, SetGetOffset(4)); - - MessageLoop::current()->RunAllPending(); -} - -TEST_F(GPUProcessorTest, SetsErrorCodeOnCommandBuffer) { - CommandHeader* header = reinterpret_cast(&buffer_[0]); - header[0].command = 7; - header[0].size = 1; - - CommandBuffer::State state; - - state.put_offset = 1; - EXPECT_CALL(*command_buffer_, GetState()) - .WillOnce(Return(state)); - - EXPECT_CALL(*async_api_, DoCommand(7, 0, &buffer_[0])) - .WillOnce(Return( - error::kUnknownCommand)); - - EXPECT_CALL(*command_buffer_, - SetParseError(error::kUnknownCommand)); - - processor_->ProcessCommands(); -} - -TEST_F(GPUProcessorTest, ProcessCommandsDoesNothingAfterError) { - CommandBuffer::State state; - state.error = error::kGenericError; - - EXPECT_CALL(*command_buffer_, GetState()) - .WillOnce(Return(state)); - - processor_->ProcessCommands(); -} - -TEST_F(GPUProcessorTest, CanGetAddressOfSharedMemory) { - EXPECT_CALL(*command_buffer_.get(), GetTransferBuffer(7)) - .WillOnce(Return(shared_memory_buffer_)); - - EXPECT_EQ(&buffer_[0], processor_->GetSharedMemoryBuffer(7).ptr); -} - -ACTION_P2(SetPointee, address, value) { - *address = value; -} - -TEST_F(GPUProcessorTest, CanGetSizeOfSharedMemory) { - EXPECT_CALL(*command_buffer_.get(), GetTransferBuffer(7)) - .WillOnce(Return(shared_memory_buffer_)); - - EXPECT_EQ(kRingBufferSize, processor_->GetSharedMemoryBuffer(7).size); -} - -TEST_F(GPUProcessorTest, SetTokenForwardsToCommandBuffer) { - EXPECT_CALL(*command_buffer_, SetToken(7)); - processor_->set_token(7); -} - -} // namespace gpu diff --git a/gpu/command_buffer/service/gpu_processor_win.cc b/gpu/command_buffer/service/gpu_processor_win.cc deleted file mode 100644 index fb48f74..0000000 --- a/gpu/command_buffer/service/gpu_processor_win.cc +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "gpu/command_buffer/service/gpu_processor.h" -#include "ui/gfx/gl/gl_context.h" - -using ::base::SharedMemory; - -namespace gpu { - -bool GPUProcessor::Initialize( - gfx::PluginWindowHandle window, - const gfx::Size& size, - const gles2::DisallowedExtensions& disallowed_extensions, - const char* allowed_extensions, - const std::vector& attribs, - GPUProcessor* parent, - uint32 parent_texture_id) { - // Get the parent decoder and the GLContext to share IDs with, if any. - gles2::GLES2Decoder* parent_decoder = NULL; - gfx::GLContext* parent_context = NULL; - if (parent) { - parent_decoder = parent->decoder_.get(); - DCHECK(parent_decoder); - - parent_context = parent_decoder->GetGLContext(); - DCHECK(parent_context); - } - - // Create either a view or pbuffer based GLContext. - scoped_ptr context; - if (window) { - DCHECK(!parent_context); - - // TODO(apatrick): support multisampling. - context.reset(gfx::GLContext::CreateViewGLContext(window, false)); - } else { - context.reset(gfx::GLContext::CreateOffscreenGLContext(parent_context)); - } - - if (!context.get()) - return false; - - return InitializeCommon(context.release(), - size, - disallowed_extensions, - allowed_extensions, - attribs, - parent_decoder, - parent_texture_id); -} - -void GPUProcessor::Destroy() { - DestroyCommon(); -} - -void GPUProcessor::WillSwapBuffers() { - if (wrapped_swap_buffers_callback_.get()) { - wrapped_swap_buffers_callback_->Run(); - } -} - -} // namespace gpu diff --git a/gpu/command_buffer/service/gpu_scheduler.cc b/gpu/command_buffer/service/gpu_scheduler.cc new file mode 100644 index 0000000..933b468 --- /dev/null +++ b/gpu/command_buffer/service/gpu_scheduler.cc @@ -0,0 +1,256 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gpu/command_buffer/service/gpu_scheduler.h" + +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/message_loop.h" +#include "gpu/common/gpu_trace_event.h" +#include "ui/gfx/gl/gl_context.h" +#include "ui/gfx/gl/gl_bindings.h" + +using ::base::SharedMemory; + +static size_t kNumThrottleFences = 1; + +namespace gpu { + +GpuScheduler::GpuScheduler(CommandBuffer* command_buffer, + gles2::ContextGroup* group) + : command_buffer_(command_buffer), + commands_per_update_(100), + num_throttle_fences_(0), +#if defined(OS_MACOSX) + swap_buffers_count_(0), + acknowledged_swap_buffers_count_(0), +#endif + method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { + DCHECK(command_buffer); + decoder_.reset(gles2::GLES2Decoder::Create(group)); + decoder_->set_engine(this); +} + +GpuScheduler::GpuScheduler(CommandBuffer* command_buffer, + gles2::GLES2Decoder* decoder, + CommandParser* parser, + int commands_per_update) + : command_buffer_(command_buffer), + commands_per_update_(commands_per_update), + num_throttle_fences_(0), +#if defined(OS_MACOSX) + swap_buffers_count_(0), + acknowledged_swap_buffers_count_(0), +#endif + method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { + DCHECK(command_buffer); + decoder_.reset(decoder); + parser_.reset(parser); +} + +GpuScheduler::~GpuScheduler() { + Destroy(); +} + +bool GpuScheduler::InitializeCommon( + gfx::GLContext* context, + const gfx::Size& size, + const gles2::DisallowedExtensions& disallowed_extensions, + const char* allowed_extensions, + const std::vector& attribs, + gles2::GLES2Decoder* parent_decoder, + uint32 parent_texture_id) { + DCHECK(context); + + if (!context->MakeCurrent()) + return false; + + // If the NV_fence extension is present, use fences to defer the issue of + // commands once a certain fixed number of frames have been rendered. + num_throttle_fences_ = + context->HasExtension("GL_NV_fence") ? kNumThrottleFences : 0; + + // Do not limit to a certain number of commands before scheduling another + // update when rendering onscreen. + if (!context->IsOffscreen()) + commands_per_update_ = INT_MAX; + + // Map the ring buffer and create the parser. + Buffer ring_buffer = command_buffer_->GetRingBuffer(); + if (ring_buffer.ptr) { + parser_.reset(new CommandParser(ring_buffer.ptr, + ring_buffer.size, + 0, + ring_buffer.size, + 0, + decoder_.get())); + } else { + parser_.reset(new CommandParser(NULL, 0, 0, 0, 0, + decoder_.get())); + } + + // Initialize the decoder with either the view or pbuffer GLContext. + if (!decoder_->Initialize(context, + size, + disallowed_extensions, + allowed_extensions, + attribs, + parent_decoder, + parent_texture_id)) { + LOG(ERROR) << "GpuScheduler::InitializeCommon failed because decoder " + << "failed to initialize."; + Destroy(); + return false; + } + + return true; +} + +void GpuScheduler::DestroyCommon() { + bool have_context = false; + if (decoder_.get()) { + have_context = decoder_->MakeCurrent(); + decoder_->Destroy(); + decoder_.reset(); + } + + parser_.reset(); +} + +#if defined(OS_MACOSX) +namespace { +const unsigned int kMaxOutstandingSwapBuffersCallsPerOnscreenContext = 1; +} +#endif + +void GpuScheduler::ProcessCommands() { + GPU_TRACE_EVENT0("gpu", "GpuScheduler:ProcessCommands"); + CommandBuffer::State state = command_buffer_->GetState(); + if (state.error != error::kNoError) + return; + + if (decoder_.get()) { + if (!decoder_->MakeCurrent()) { + LOG(ERROR) << "Context lost because MakeCurrent failed."; + command_buffer_->SetParseError(error::kLostContext); + return; + } + } + + parser_->set_put(state.put_offset); + +#if defined(OS_MACOSX) + bool do_rate_limiting = surface_.get() != NULL; + // Don't swamp the browser process with SwapBuffers calls it can't handle. + if (do_rate_limiting && + swap_buffers_count_ - acknowledged_swap_buffers_count_ >= + kMaxOutstandingSwapBuffersCallsPerOnscreenContext) { + // Stop doing work on this command buffer. In the GPU process, + // receipt of the GpuMsg_AcceleratedSurfaceBuffersSwappedACK + // message causes ProcessCommands to be scheduled again. + return; + } +#endif + + // Defer this command until the fence queue is not full. + while (num_throttle_fences_ > 0 && + throttle_fences_.size() >= num_throttle_fences_) { + GLuint fence = throttle_fences_.front(); + if (!glTestFenceNV(fence)) { + ScheduleProcessCommands(); + return; + } + + glDeleteFencesNV(1, &fence); + throttle_fences_.pop(); + } + + int commands_processed = 0; + while (commands_processed < commands_per_update_ && !parser_->IsEmpty()) { + error::Error error = parser_->ProcessCommand(); + if (error == error::kWaiting) { + break; + } + + // If the command indicated it should be throttled, insert a new fence into + // the fence queue. + if (error == error::kThrottle) { + if (num_throttle_fences_ > 0 && + throttle_fences_.size() < num_throttle_fences_) { + GLuint fence; + glGenFencesNV(1, &fence); + glSetFenceNV(fence, GL_ALL_COMPLETED_NV); + throttle_fences_.push(fence); + + // Neither glTestFenceNV or glSetFenceNV are guaranteed to flush. + // Without an explicit flush, the glTestFenceNV loop might never + // make progress. + glFlush(); + break; + } + } else if (error != error::kNoError) { + command_buffer_->SetParseError(error); + return; + } + ++commands_processed; + if (command_processed_callback_.get()) { + command_processed_callback_->Run(); + } + } + + command_buffer_->SetGetOffset(static_cast(parser_->get())); + + if (!parser_->IsEmpty()) { + ScheduleProcessCommands(); + } +} + +void GpuScheduler::ScheduleProcessCommands() { + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod(&GpuScheduler::ProcessCommands)); +} + +Buffer GpuScheduler::GetSharedMemoryBuffer(int32 shm_id) { + return command_buffer_->GetTransferBuffer(shm_id); +} + +void GpuScheduler::set_token(int32 token) { + command_buffer_->SetToken(token); +} + +bool GpuScheduler::SetGetOffset(int32 offset) { + if (parser_->set_get(offset)) { + command_buffer_->SetGetOffset(static_cast(parser_->get())); + return true; + } + return false; +} + +int32 GpuScheduler::GetGetOffset() { + return parser_->get(); +} + +void GpuScheduler::ResizeOffscreenFrameBuffer(const gfx::Size& size) { + decoder_->ResizeOffscreenFrameBuffer(size); +} + +void GpuScheduler::SetResizeCallback(Callback1::Type* callback) { + decoder_->SetResizeCallback(callback); +} + +void GpuScheduler::SetSwapBuffersCallback( + Callback0::Type* callback) { + wrapped_swap_buffers_callback_.reset(callback); + decoder_->SetSwapBuffersCallback( + NewCallback(this, + &GpuScheduler::WillSwapBuffers)); +} + +void GpuScheduler::SetCommandProcessedCallback( + Callback0::Type* callback) { + command_processed_callback_.reset(callback); +} + +} // namespace gpu diff --git a/gpu/command_buffer/service/gpu_scheduler.h b/gpu/command_buffer/service/gpu_scheduler.h new file mode 100644 index 0000000..5ed808c --- /dev/null +++ b/gpu/command_buffer/service/gpu_scheduler.h @@ -0,0 +1,163 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_SCHEDULER_H_ +#define GPU_COMMAND_BUFFER_SERVICE_GPU_SCHEDULER_H_ + +#include +#include + +#include "base/callback.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/shared_memory.h" +#include "base/task.h" +#include "gpu/command_buffer/common/command_buffer.h" +#include "gpu/command_buffer/service/cmd_buffer_engine.h" +#include "gpu/command_buffer/service/cmd_parser.h" +#include "gpu/command_buffer/service/gles2_cmd_decoder.h" +#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/size.h" +#include "ui/gfx/surface/transport_dib.h" + +#if defined(OS_MACOSX) +#include "ui/gfx/surface/accelerated_surface_mac.h" +#endif + +namespace gfx { +class GLContext; +} + +namespace gpu { +namespace gles2 { +class ContextGroup; +} + +// 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 GpuScheduler : public CommandBufferEngine { + public: + // If a group is not passed in one will be created. + GpuScheduler(CommandBuffer* command_buffer, gles2::ContextGroup* group); + + // This constructor is for unit tests. + GpuScheduler(CommandBuffer* command_buffer, + gles2::GLES2Decoder* decoder, + CommandParser* parser, + int commands_per_update); + + virtual ~GpuScheduler(); + + // Perform platform specific and common initialization. + bool Initialize(gfx::PluginWindowHandle hwnd, + const gfx::Size& size, + const gles2::DisallowedExtensions& disallowed_extensions, + const char* allowed_extensions, + const std::vector& attribs, + GpuScheduler* parent, + uint32 parent_texture_id); + + void Destroy(); + void DestroyCommon(); + + virtual void ProcessCommands(); + + // Helper which causes a call to ProcessCommands to be scheduled later. + void ScheduleProcessCommands(); + + // Implementation of CommandBufferEngine. + virtual Buffer GetSharedMemoryBuffer(int32 shm_id); + virtual void set_token(int32 token); + virtual bool SetGetOffset(int32 offset); + virtual int32 GetGetOffset(); + + // Asynchronously resizes an offscreen frame buffer. + void ResizeOffscreenFrameBuffer(const gfx::Size& size); + +#if defined(OS_MACOSX) + // Needed only on Mac OS X, which does not render into an on-screen + // window and therefore requires the backing store to be resized + // manually. Returns an opaque identifier for the new backing store. + // There are two versions of this method: one for use with the IOSurface + // available in Mac OS X 10.6; and, one for use with the + // TransportDIB-based version used on Mac OS X 10.5. + virtual uint64 SetWindowSizeForIOSurface(const gfx::Size& size); + virtual TransportDIB::Handle SetWindowSizeForTransportDIB( + const gfx::Size& size); + virtual void SetTransportDIBAllocAndFree( + Callback2::Type* allocator, + Callback1::Type* deallocator); + // Returns the id of the current IOSurface, or 0. + virtual uint64 GetSurfaceId(); + // To prevent the GPU process from overloading the browser process, + // we need to track the number of swap buffers calls issued and + // acknowledged per on-screen (IOSurface-backed) context, and keep + // the GPU from getting too far ahead of the browser. Note that this + // is also predicated on a flow control mechanism between the + // renderer and GPU processes. + uint64 swap_buffers_count() const; + void set_acknowledged_swap_buffers_count( + uint64 acknowledged_swap_buffers_count); + + void DidDestroySurface(); +#endif + + // Sets a callback that is called when a glResizeCHROMIUM command + // is processed. + virtual void SetResizeCallback(Callback1::Type* callback); + + // Sets a callback which is called when a SwapBuffers command is processed. + // Must be called after Initialize(). + // It is not defined on which thread this callback is called. + virtual void SetSwapBuffersCallback(Callback0::Type* callback); + + virtual void SetCommandProcessedCallback(Callback0::Type* callback); + + // Get the GLES2Decoder associated with this scheduler. + gles2::GLES2Decoder* decoder() const { return decoder_.get(); } + + protected: + // Perform common initialization. Takes ownership of GLContext. + bool InitializeCommon( + gfx::GLContext* context, + const gfx::Size& size, + const gles2::DisallowedExtensions& disallowed_extensions, + const char* allowed_extensions, + const std::vector& attribs, + gles2::GLES2Decoder* parent_decoder, + uint32 parent_texture_id); + + + private: + // Called via a callback just before we are supposed to call the + // user's swap buffers callback. + virtual void WillSwapBuffers(); + + // The GpuScheduler holds a weak reference to the CommandBuffer. The + // CommandBuffer owns the GpuScheduler and holds a strong reference to it + // through the ProcessCommands callback. + CommandBuffer* command_buffer_; + + int commands_per_update_; + + scoped_ptr decoder_; + scoped_ptr parser_; + + size_t num_throttle_fences_; + std::queue throttle_fences_; + +#if defined(OS_MACOSX) + scoped_ptr surface_; + uint64 swap_buffers_count_; + uint64 acknowledged_swap_buffers_count_; +#endif + + ScopedRunnableMethodFactory method_factory_; + scoped_ptr wrapped_swap_buffers_callback_; + scoped_ptr command_processed_callback_; +}; + +} // namespace gpu + +#endif // GPU_COMMAND_BUFFER_SERVICE_GPU_SCHEDULER_H_ diff --git a/gpu/command_buffer/service/gpu_scheduler_linux.cc b/gpu/command_buffer/service/gpu_scheduler_linux.cc new file mode 100644 index 0000000..48ed470 --- /dev/null +++ b/gpu/command_buffer/service/gpu_scheduler_linux.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gpu/command_buffer/service/gpu_scheduler.h" +#include "ui/gfx/gl/gl_context.h" + +using ::base::SharedMemory; + +namespace gpu { + +bool GpuScheduler::Initialize( + gfx::PluginWindowHandle window, + const gfx::Size& size, + const gles2::DisallowedExtensions& disallowed_extensions, + const char* allowed_extensions, + const std::vector& attribs, + GpuScheduler* parent, + uint32 parent_texture_id) { + // Get the parent decoder and the GLContext to share IDs with, if any. + gles2::GLES2Decoder* parent_decoder = NULL; + gfx::GLContext* parent_context = NULL; + void* parent_handle = NULL; + if (parent) { + parent_decoder = parent->decoder_.get(); + DCHECK(parent_decoder); + + parent_context = parent_decoder->GetGLContext(); + DCHECK(parent_context); + } + + // Create either a view or pbuffer based GLContext. + scoped_ptr context; + if (window) { + DCHECK(!parent_handle); + + // TODO(apatrick): support multisampling. + context.reset(gfx::GLContext::CreateViewGLContext(window, false)); + } else { + context.reset(gfx::GLContext::CreateOffscreenGLContext(parent_context)); + } + + if (!context.get()) { + LOG(ERROR) << "GpuScheduler::Initialize failed"; + return false; + } + + return InitializeCommon(context.release(), + size, + disallowed_extensions, + allowed_extensions, + attribs, + parent_decoder, + parent_texture_id); +} + +void GpuScheduler::Destroy() { + DestroyCommon(); +} + +void GpuScheduler::WillSwapBuffers() { + if (wrapped_swap_buffers_callback_.get()) { + wrapped_swap_buffers_callback_->Run(); + } +} + +} // namespace gpu diff --git a/gpu/command_buffer/service/gpu_scheduler_mac.cc b/gpu/command_buffer/service/gpu_scheduler_mac.cc new file mode 100644 index 0000000..f89bfb5 --- /dev/null +++ b/gpu/command_buffer/service/gpu_scheduler_mac.cc @@ -0,0 +1,142 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gpu/command_buffer/service/gpu_scheduler.h" +#include "ui/gfx/gl/gl_context.h" + +using ::base::SharedMemory; + +namespace gpu { + +bool GpuScheduler::Initialize( + gfx::PluginWindowHandle window, + const gfx::Size& size, + const gles2::DisallowedExtensions& disallowed_extensions, + const char* allowed_extensions, + const std::vector& attribs, + GpuScheduler* parent, + uint32 parent_texture_id) { + // Get the parent decoder and the GLContext to share IDs with, if any. + gles2::GLES2Decoder* parent_decoder = NULL; + gfx::GLContext* parent_context = NULL; + if (parent) { + parent_decoder = parent->decoder_.get(); + DCHECK(parent_decoder); + + parent_context = parent_decoder->GetGLContext(); + DCHECK(parent_context); + } + + scoped_ptr context( + gfx::GLContext::CreateOffscreenGLContext(parent_context)); + if (!context.get()) + return false; + + // On Mac OS X since we can not render on-screen we don't even + // attempt to create a view based GLContext. The only difference + // between "on-screen" and "off-screen" rendering on this platform + // is whether we allocate an AcceleratedSurface, which transmits the + // rendering results back to the browser. + if (window) { + surface_.reset(new AcceleratedSurface()); + + // Note that although the GLContext is passed to Initialize and the + // GLContext will later be owned by the decoder, AcceleratedSurface does + // not hold on to the reference. It simply extracts the underlying GL + // context in order to share the namespace with another context. + if (!surface_->Initialize(context.get(), false)) { + LOG(ERROR) << "GpuScheduler::Initialize failed to " + << "initialize AcceleratedSurface."; + Destroy(); + return false; + } + } + + return InitializeCommon(context.release(), + size, + disallowed_extensions, + allowed_extensions, + attribs, + parent_decoder, + parent_texture_id); +} + +void GpuScheduler::Destroy() { + if (surface_.get()) { + surface_->Destroy(); + surface_.reset(); + } + + DestroyCommon(); +} + +uint64 GpuScheduler::SetWindowSizeForIOSurface(const gfx::Size& size) { + // This is called from an IPC handler, so it's undefined which context is + // current. Make sure the right one is. + decoder_->GetGLContext()->MakeCurrent(); + + ResizeOffscreenFrameBuffer(size); + decoder_->UpdateOffscreenFrameBufferSize(); + + // Note: The following line changes the current context again. + return surface_->SetSurfaceSize(size); +} + +TransportDIB::Handle GpuScheduler::SetWindowSizeForTransportDIB( + const gfx::Size& size) { + ResizeOffscreenFrameBuffer(size); + decoder_->UpdateOffscreenFrameBufferSize(); + return surface_->SetTransportDIBSize(size); +} + +void GpuScheduler::SetTransportDIBAllocAndFree( + Callback2::Type* allocator, + Callback1::Type* deallocator) { + surface_->SetTransportDIBAllocAndFree(allocator, deallocator); +} + +uint64 GpuScheduler::GetSurfaceId() { + if (!surface_.get()) + return 0; + return surface_->GetSurfaceId(); +} + +uint64 GpuScheduler::swap_buffers_count() const { + return swap_buffers_count_; +} + +void GpuScheduler::set_acknowledged_swap_buffers_count( + uint64 acknowledged_swap_buffers_count) { + acknowledged_swap_buffers_count_ = acknowledged_swap_buffers_count; +} + +void GpuScheduler::DidDestroySurface() { + // When a browser window with a GpuScheduler is closed, the render process + // will attempt to finish all GL commands, it will busy-wait on the GPU + // process until the command queue is empty. If a paint is pending, the GPU + // process won't process any GL commands until the browser sends a paint ack, + // but since the browser window is already closed, it will never arrive. + // To break this infinite loop, the browser tells the GPU process that the + // surface became invalid, which causes the GPU process to not wait for paint + // acks. + surface_.reset(); +} + +void GpuScheduler::WillSwapBuffers() { + DCHECK(decoder_.get()); + DCHECK(decoder_->GetGLContext()); + DCHECK(decoder_->GetGLContext()->IsCurrent()); + + ++swap_buffers_count_; + + if (surface_.get()) { + surface_->SwapBuffers(); + } + + if (wrapped_swap_buffers_callback_.get()) { + wrapped_swap_buffers_callback_->Run(); + } +} + +} // namespace gpu diff --git a/gpu/command_buffer/service/gpu_scheduler_mock.h b/gpu/command_buffer/service/gpu_scheduler_mock.h new file mode 100644 index 0000000..4bc1bb5 --- /dev/null +++ b/gpu/command_buffer/service/gpu_scheduler_mock.h @@ -0,0 +1,29 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_SCHEDULER_MOCK_H_ +#define GPU_COMMAND_BUFFER_SERVICE_GPU_SCHEDULER_MOCK_H_ + +#include "gpu/command_buffer/service/gpu_scheduler.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace gpu { + +class MockGpuScheduler : public GpuScheduler { + public: + explicit MockGpuScheduler(CommandBuffer* command_buffer) + : GpuScheduler(command_buffer) { + } + + MOCK_METHOD0(ProcessCommands, void()); + MOCK_METHOD1(GetSharedMemoryBuffer, Buffer(int32 shm_id)); + MOCK_METHOD1(set_token, void(int32 token)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockGpuScheduler); +}; + +} // namespace gpu + +#endif // GPU_COMMAND_BUFFER_SERVICE_GPU_SCHEDULER_MOCK_H_ diff --git a/gpu/command_buffer/service/gpu_scheduler_unittest.cc b/gpu/command_buffer/service/gpu_scheduler_unittest.cc new file mode 100644 index 0000000..b992fa7 --- /dev/null +++ b/gpu/command_buffer/service/gpu_scheduler_unittest.cc @@ -0,0 +1,259 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/mac/scoped_nsautorelease_pool.h" +#include "base/message_loop.h" +#include "gpu/command_buffer/common/command_buffer_mock.h" +#include "gpu/command_buffer/service/gpu_scheduler.h" +#include "gpu/command_buffer/service/gles2_cmd_decoder.h" +#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h" +#include "gpu/command_buffer/service/mocks.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/gmock/include/gmock/gmock.h" + +using testing::_; +using testing::DoAll; +using testing::Invoke; +using testing::NiceMock; +using testing::Return; +using testing::SetArgumentPointee; +using testing::StrictMock; + +namespace gpu { + +const size_t kRingBufferSize = 1024; +const size_t kRingBufferEntries = kRingBufferSize / sizeof(CommandBufferEntry); + +class GpuSchedulerTest : public testing::Test { + protected: + virtual void SetUp() { + shared_memory_.reset(new ::base::SharedMemory); + shared_memory_->CreateAndMapAnonymous(kRingBufferSize); + buffer_ = static_cast(shared_memory_->memory()); + shared_memory_buffer_.ptr = buffer_; + shared_memory_buffer_.size = kRingBufferSize; + memset(buffer_, 0, kRingBufferSize); + + command_buffer_.reset(new MockCommandBuffer); + ON_CALL(*command_buffer_.get(), GetRingBuffer()) + .WillByDefault(Return(shared_memory_buffer_)); + + CommandBuffer::State default_state; + default_state.num_entries = kRingBufferEntries; + ON_CALL(*command_buffer_.get(), GetState()) + .WillByDefault(Return(default_state)); + + async_api_.reset(new StrictMock); + + decoder_ = new gles2::MockGLES2Decoder(); + + parser_ = new CommandParser(buffer_, + kRingBufferEntries, + 0, + kRingBufferEntries, + 0, + async_api_.get()); + + scheduler_.reset(new GpuScheduler(command_buffer_.get(), + decoder_, + parser_, + 2)); + + EXPECT_CALL(*decoder_, Destroy()) + .Times(1) + .RetiresOnSaturation(); + } + + virtual void TearDown() { + // Ensure that any unexpected tasks posted by the GPU scheduler are executed + // in order to fail the test. + MessageLoop::current()->RunAllPending(); + } + + error::Error GetError() { + return command_buffer_->GetState().error; + } + + base::mac::ScopedNSAutoreleasePool autorelease_pool_; + MessageLoop message_loop; + scoped_ptr command_buffer_; + scoped_ptr shared_memory_; + Buffer shared_memory_buffer_; + int32* buffer_; + gles2::MockGLES2Decoder* decoder_; + CommandParser* parser_; + scoped_ptr async_api_; + scoped_ptr scheduler_; +}; + +TEST_F(GpuSchedulerTest, SchedulerDoesNothingIfRingBufferIsEmpty) { + CommandBuffer::State state; + + state.put_offset = 0; + EXPECT_CALL(*command_buffer_, GetState()) + .WillOnce(Return(state)); + EXPECT_CALL(*command_buffer_, SetGetOffset(0)); + + EXPECT_CALL(*command_buffer_, SetParseError(_)) + .Times(0); + + scheduler_->ProcessCommands(); +} + +TEST_F(GpuSchedulerTest, ProcessesOneCommand) { + CommandHeader* header = reinterpret_cast(&buffer_[0]); + header[0].command = 7; + header[0].size = 2; + buffer_[1] = 123; + + CommandBuffer::State state; + + state.put_offset = 2; + EXPECT_CALL(*command_buffer_, GetState()) + .WillOnce(Return(state)); + EXPECT_CALL(*command_buffer_, SetGetOffset(2)); + + EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0])) + .WillOnce(Return(error::kNoError)); + + EXPECT_CALL(*command_buffer_, SetParseError(_)) + .Times(0); + + scheduler_->ProcessCommands(); +} + +TEST_F(GpuSchedulerTest, ProcessesTwoCommands) { + CommandHeader* header = reinterpret_cast(&buffer_[0]); + header[0].command = 7; + header[0].size = 2; + buffer_[1] = 123; + header[2].command = 8; + header[2].size = 1; + + CommandBuffer::State state; + + state.put_offset = 3; + EXPECT_CALL(*command_buffer_, GetState()) + .WillOnce(Return(state)); + EXPECT_CALL(*command_buffer_, SetGetOffset(3)); + + EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0])) + .WillOnce(Return(error::kNoError)); + + EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[2])) + .WillOnce(Return(error::kNoError)); + + scheduler_->ProcessCommands(); +} + +TEST_F(GpuSchedulerTest, SchedulerSetsTheGLContext) { + EXPECT_CALL(*decoder_, MakeCurrent()) + .WillOnce(Return(true)) + .WillOnce(Return(true)); + + CommandBuffer::State state; + state.put_offset = 0; + EXPECT_CALL(*command_buffer_, GetState()) + .WillOnce(Return(state)); + + EXPECT_CALL(*command_buffer_, SetGetOffset(0)); + + scheduler_->ProcessCommands(); +} + +TEST_F(GpuSchedulerTest, PostsTaskToFinishRemainingCommands) { + CommandHeader* header = reinterpret_cast(&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; + + CommandBuffer::State state; + + state.put_offset = 4; + EXPECT_CALL(*command_buffer_, GetState()) + .WillOnce(Return(state)); + + EXPECT_CALL(*async_api_, DoCommand(7, 1, &buffer_[0])) + .WillOnce(Return(error::kNoError)); + + EXPECT_CALL(*async_api_, DoCommand(8, 0, &buffer_[2])) + .WillOnce(Return(error::kNoError)); + + EXPECT_CALL(*command_buffer_, SetGetOffset(3)); + + scheduler_->ProcessCommands(); + + // ProcessCommands is called a second time when the pending task is run. + + state.put_offset = 4; + EXPECT_CALL(*command_buffer_, GetState()) + .WillOnce(Return(state)); + + EXPECT_CALL(*async_api_, DoCommand(9, 0, &buffer_[3])) + .WillOnce(Return(error::kNoError)); + + EXPECT_CALL(*command_buffer_, SetGetOffset(4)); + + MessageLoop::current()->RunAllPending(); +} + +TEST_F(GpuSchedulerTest, SetsErrorCodeOnCommandBuffer) { + CommandHeader* header = reinterpret_cast(&buffer_[0]); + header[0].command = 7; + header[0].size = 1; + + CommandBuffer::State state; + + state.put_offset = 1; + EXPECT_CALL(*command_buffer_, GetState()) + .WillOnce(Return(state)); + + EXPECT_CALL(*async_api_, DoCommand(7, 0, &buffer_[0])) + .WillOnce(Return( + error::kUnknownCommand)); + + EXPECT_CALL(*command_buffer_, + SetParseError(error::kUnknownCommand)); + + scheduler_->ProcessCommands(); +} + +TEST_F(GpuSchedulerTest, ProcessCommandsDoesNothingAfterError) { + CommandBuffer::State state; + state.error = error::kGenericError; + + EXPECT_CALL(*command_buffer_, GetState()) + .WillOnce(Return(state)); + + scheduler_->ProcessCommands(); +} + +TEST_F(GpuSchedulerTest, CanGetAddressOfSharedMemory) { + EXPECT_CALL(*command_buffer_.get(), GetTransferBuffer(7)) + .WillOnce(Return(shared_memory_buffer_)); + + EXPECT_EQ(&buffer_[0], scheduler_->GetSharedMemoryBuffer(7).ptr); +} + +ACTION_P2(SetPointee, address, value) { + *address = value; +} + +TEST_F(GpuSchedulerTest, CanGetSizeOfSharedMemory) { + EXPECT_CALL(*command_buffer_.get(), GetTransferBuffer(7)) + .WillOnce(Return(shared_memory_buffer_)); + + EXPECT_EQ(kRingBufferSize, scheduler_->GetSharedMemoryBuffer(7).size); +} + +TEST_F(GpuSchedulerTest, SetTokenForwardsToCommandBuffer) { + EXPECT_CALL(*command_buffer_, SetToken(7)); + scheduler_->set_token(7); +} + +} // namespace gpu diff --git a/gpu/command_buffer/service/gpu_scheduler_win.cc b/gpu/command_buffer/service/gpu_scheduler_win.cc new file mode 100644 index 0000000..23c8782 --- /dev/null +++ b/gpu/command_buffer/service/gpu_scheduler_win.cc @@ -0,0 +1,66 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include "gpu/command_buffer/service/gpu_scheduler.h" +#include "ui/gfx/gl/gl_context.h" + +using ::base::SharedMemory; + +namespace gpu { + +bool GpuScheduler::Initialize( + gfx::PluginWindowHandle window, + const gfx::Size& size, + const gles2::DisallowedExtensions& disallowed_extensions, + const char* allowed_extensions, + const std::vector& attribs, + GpuScheduler* parent, + uint32 parent_texture_id) { + // Get the parent decoder and the GLContext to share IDs with, if any. + gles2::GLES2Decoder* parent_decoder = NULL; + gfx::GLContext* parent_context = NULL; + if (parent) { + parent_decoder = parent->decoder_.get(); + DCHECK(parent_decoder); + + parent_context = parent_decoder->GetGLContext(); + DCHECK(parent_context); + } + + // Create either a view or pbuffer based GLContext. + scoped_ptr context; + if (window) { + DCHECK(!parent_context); + + // TODO(apatrick): support multisampling. + context.reset(gfx::GLContext::CreateViewGLContext(window, false)); + } else { + context.reset(gfx::GLContext::CreateOffscreenGLContext(parent_context)); + } + + if (!context.get()) + return false; + + return InitializeCommon(context.release(), + size, + disallowed_extensions, + allowed_extensions, + attribs, + parent_decoder, + parent_texture_id); +} + +void GpuScheduler::Destroy() { + DestroyCommon(); +} + +void GpuScheduler::WillSwapBuffers() { + if (wrapped_swap_buffers_callback_.get()) { + wrapped_swap_buffers_callback_->Run(); + } +} + +} // namespace gpu diff --git a/gpu/demos/framework/window.cc b/gpu/demos/framework/window.cc index fead4ac..974a5ee 100644 --- a/gpu/demos/framework/window.cc +++ b/gpu/demos/framework/window.cc @@ -8,13 +8,13 @@ #include "gpu/command_buffer/client/gles2_implementation.h" #include "gpu/command_buffer/client/gles2_lib.h" #include "gpu/command_buffer/service/command_buffer_service.h" -#include "gpu/command_buffer/service/gpu_processor.h" +#include "gpu/command_buffer/service/gpu_scheduler.h" #include "gpu/demos/framework/demo.h" #include "gpu/demos/framework/demo_factory.h" using gpu::Buffer; using gpu::CommandBufferService; -using gpu::GPUProcessor; +using gpu::GpuScheduler; using gpu::gles2::GLES2CmdHelper; using gpu::gles2::GLES2Implementation; @@ -59,9 +59,9 @@ bool Window::CreateRenderContext(gfx::PluginWindowHandle hwnd) { return false; } - GPUProcessor* gpu_processor( - new GPUProcessor(command_buffer.get(), NULL)); - if (!gpu_processor->Initialize(hwnd, gfx::Size(), + GpuScheduler* gpu_scheduler( + new GpuScheduler(command_buffer.get(), NULL)); + if (!gpu_scheduler->Initialize(hwnd, gfx::Size(), gpu::gles2::DisallowedExtensions(), NULL, std::vector(), NULL, 0)) { @@ -69,7 +69,7 @@ bool Window::CreateRenderContext(gfx::PluginWindowHandle hwnd) { } command_buffer->SetPutOffsetChangeCallback( - NewCallback(gpu_processor, &GPUProcessor::ProcessCommands)); + NewCallback(gpu_scheduler, &GpuScheduler::ProcessCommands)); GLES2CmdHelper* helper = new GLES2CmdHelper(command_buffer.get()); if (!helper->Initialize(kCommandBufferSize)) { diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp index e33c78ca..3915877 100644 --- a/gpu/gpu.gyp +++ b/gpu/gpu.gyp @@ -217,12 +217,12 @@ 'command_buffer/service/gles2_cmd_validation_autogen.h', 'command_buffer/service/gles2_cmd_validation_implementation_autogen.h', 'command_buffer/service/gl_utils.h', - 'command_buffer/service/gpu_processor.h', - 'command_buffer/service/gpu_processor.cc', - 'command_buffer/service/gpu_processor_linux.cc', - 'command_buffer/service/gpu_processor_mac.cc', - 'command_buffer/service/gpu_processor_mock.h', - 'command_buffer/service/gpu_processor_win.cc', + 'command_buffer/service/gpu_scheduler.h', + 'command_buffer/service/gpu_scheduler.cc', + 'command_buffer/service/gpu_scheduler_linux.cc', + 'command_buffer/service/gpu_scheduler_mac.cc', + 'command_buffer/service/gpu_scheduler_mock.h', + 'command_buffer/service/gpu_scheduler_win.cc', 'command_buffer/service/id_manager.h', 'command_buffer/service/id_manager.cc', 'command_buffer/service/mocks.h', @@ -293,7 +293,7 @@ 'command_buffer/service/common_decoder_unittest.cc', 'command_buffer/service/feature_info_unittest.cc', 'command_buffer/service/framebuffer_manager_unittest.cc', - 'command_buffer/service/gpu_processor_unittest.cc', + 'command_buffer/service/gpu_scheduler_unittest.cc', 'command_buffer/service/gles2_cmd_decoder_unittest_base.h', 'command_buffer/service/gles2_cmd_decoder_unittest_base.cc', 'command_buffer/service/gles2_cmd_decoder_unittest.cc', -- cgit v1.1