diff options
20 files changed, 246 insertions, 57 deletions
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index 7e55b7b..f716102 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc @@ -27,6 +27,7 @@ #include "content/gpu/gpu_process.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" +#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/common/content_switches.h" #include "content/public/common/result_codes.h" @@ -47,6 +48,9 @@ using content::BrowserThread; using content::ChildProcessHost; +using content::RenderProcessHost; +using content::RenderWidgetHost; +using content::RenderWidgetHostImpl; bool GpuProcessHost::gpu_enabled_ = true; bool GpuProcessHost::hardware_gpu_enabled_ = true; @@ -97,27 +101,62 @@ void SendGpuProcessMessage(GpuProcessHost::GpuProcessKind kind, } } +void AcceleratedSurfaceBuffersSwappedCompletedForGPU(int host_id, + int route_id, + bool alive) { + if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&AcceleratedSurfaceBuffersSwappedCompletedForGPU, + host_id, + route_id, + alive)); + return; + } + + GpuProcessHost* host = GpuProcessHost::FromID(host_id); + if (host) { + if (alive) + host->Send(new AcceleratedSurfaceMsg_BufferPresented(route_id, 0)); + else + host->ForceShutdown(); + } +} + +// This sends a ViewMsg_SwapBuffers_ACK directly to the renderer process +// (RenderWidget). This path is currently not used with the threaded compositor. +void AcceleratedSurfaceBuffersSwappedCompletedForRenderer(int surface_id) { + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&AcceleratedSurfaceBuffersSwappedCompletedForRenderer, + surface_id)); + return; + } + + int render_process_id = 0; + int render_widget_id = 0; + if (!GpuSurfaceTracker::Get()->GetRenderWidgetIDForSurface( + surface_id, &render_process_id, &render_widget_id)) { + return; + } + RenderProcessHost* host = RenderProcessHost::FromID(render_process_id); + if (!host) + return; + RenderWidgetHost* rwh = host->GetRenderWidgetHostByID(render_widget_id); + if (!rwh) + return; + RenderWidgetHostImpl::From(rwh)->AcknowledgeSwapBuffersToRenderer(); +} + void AcceleratedSurfaceBuffersSwappedCompleted(int host_id, int route_id, + int surface_id, bool alive) { - if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { - GpuProcessHost* host = GpuProcessHost::FromID(host_id); - if (host) { - if (alive) - host->Send(new AcceleratedSurfaceMsg_BufferPresented(route_id, 0)); - else { - host->ForceShutdown(); - } - } - } else { - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind(&AcceleratedSurfaceBuffersSwappedCompleted, - host_id, - route_id, - alive)); - } + AcceleratedSurfaceBuffersSwappedCompletedForGPU(host_id, route_id, alive); + AcceleratedSurfaceBuffersSwappedCompletedForRenderer(surface_id); } } // anonymous namespace @@ -569,7 +608,7 @@ void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped( } base::ScopedClosureRunner scoped_completion_runner( - base::Bind(&AcceleratedSurfaceBuffersSwappedCompleted, + base::Bind(&AcceleratedSurfaceBuffersSwappedCompletedForGPU, host_id_, params.route_id, true)); int render_process_id = 0; @@ -607,6 +646,7 @@ void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped( base::Bind(&AcceleratedSurfaceBuffersSwappedCompleted, host_id_, params.route_id, + params.surface_id, true)); gfx::PluginWindowHandle handle = @@ -630,7 +670,8 @@ void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped( params.surface_handle, base::Bind(&AcceleratedSurfaceBuffersSwappedCompleted, host_id_, - params.route_id)); + params.route_id, + params.surface_id)); } void GpuProcessHost::OnAcceleratedSurfacePostSubBuffer( diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index d4d5982..33652c9 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc @@ -1857,6 +1857,16 @@ void RenderWidgetHostImpl::AcknowledgeBufferPresent( sync_point)); } +void RenderWidgetHostImpl::AcknowledgeSwapBuffersToRenderer() { + bool enable_threaded_compositing = + CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableThreadedCompositing) && + !CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableThreadedCompositing); + if (!enable_threaded_compositing) + Send(new ViewMsg_SwapBuffers_ACK(routing_id_)); +} + void RenderWidgetHostImpl::DelayedAutoResized() { gfx::Size new_size = new_auto_size_; // Clear the new_auto_size_ since the empty value is used as a flag to diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index a16eb45..2c97b54 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h @@ -363,6 +363,12 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, int gpu_host_id, uint32 sync_point); + // Called by the view in response to AcceleratedSurfaceBuffersSwapped for + // platforms that support deferred GPU process descheduling. This does + // nothing if the compositor thread is enabled. + // TODO(jbates) Once the compositor thread is always on, this can be removed. + void AcknowledgeSwapBuffersToRenderer(); + // Signals that the compositing surface was updated, e.g. after a lost context // event. void CompositingSurfaceUpdated(); diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index a9a8849..4abbe72 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm @@ -1032,6 +1032,8 @@ void RenderWidgetHostViewMac::AckPendingSwapBuffers() { pending_swap_buffers_acks_.front().first, pending_swap_buffers_acks_.front().second, 0); + if (render_widget_host_) + render_widget_host_->AcknowledgeSwapBuffersToRenderer(); } pending_swap_buffers_acks_.erase(pending_swap_buffers_acks_.begin()); } diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc index 2fa1fa4..a1718e2 100644 --- a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc +++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc @@ -519,9 +519,20 @@ void WebGraphicsContext3DCommandBufferImpl::prepareTexture() { if (command_buffer_->GetLastState().error == gpu::error::kNoError) gl_->SwapBuffers(); - command_buffer_->Echo(base::Bind( - &WebGraphicsContext3DCommandBufferImpl::OnSwapBuffersComplete, - weak_ptr_factory_.GetWeakPtr())); + bool use_echo_for_swap_ack = true; +#if defined(OS_MACOSX) || defined(OS_WIN) + // Get ViewMsg_SwapBuffers_ACK from browser for single-threaded path. + use_echo_for_swap_ack = + CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableThreadedCompositing) && + !CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableThreadedCompositing); +#endif + if (use_echo_for_swap_ack) { + command_buffer_->Echo(base::Bind( + &WebGraphicsContext3DCommandBufferImpl::OnSwapBuffersComplete, + weak_ptr_factory_.GetWeakPtr())); + } #if defined(OS_MACOSX) // It appears that making the compositor's on-screen context current on // other platforms implies this flush. TODO(kbr): this means that the diff --git a/content/common/gpu/image_transport_surface_mac.cc b/content/common/gpu/image_transport_surface_mac.cc index 52263e5..eed9e77 100644 --- a/content/common/gpu/image_transport_surface_mac.cc +++ b/content/common/gpu/image_transport_surface_mac.cc @@ -30,6 +30,7 @@ class IOSurfaceImageTransportSurface : public gfx::NoOpGLSurfaceCGL, // GLSurface implementation virtual bool Initialize() OVERRIDE; virtual void Destroy() OVERRIDE; + virtual bool DeferDraws() OVERRIDE; virtual bool IsOffscreen() OVERRIDE; virtual bool SwapBuffers() OVERRIDE; virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE; @@ -75,6 +76,12 @@ class IOSurfaceImageTransportSurface : public gfx::NoOpGLSurfaceCGL, // Whether or not we've successfully made the surface current once. bool made_current_; + // Whether a SwapBuffers is pending. + bool is_swap_buffers_pending_; + + // Whether we unscheduled command buffer because of pending SwapBuffers. + bool did_unschedule_; + scoped_ptr<ImageTransportHelper> helper_; DISALLOW_COPY_AND_ASSIGN(IOSurfaceImageTransportSurface); @@ -106,7 +113,9 @@ IOSurfaceImageTransportSurface::IOSurfaceImageTransportSurface( texture_id_(0), io_surface_handle_(0), context_(NULL), - made_current_(false) { + made_current_(false), + is_swap_buffers_pending_(false), + did_unschedule_(false) { helper_.reset(new ImageTransportHelper(this, manager, stub, handle)); } @@ -142,6 +151,20 @@ void IOSurfaceImageTransportSurface::Destroy() { NoOpGLSurfaceCGL::Destroy(); } +bool IOSurfaceImageTransportSurface::DeferDraws() { + // The command buffer hit a draw/clear command that could clobber the + // IOSurface in use by an earlier SwapBuffers. If a Swap is pending, abort + // processing of the command by returning true and unschedule until the Swap + // Ack arrives. + DCHECK(!did_unschedule_); + if (is_swap_buffers_pending_) { + did_unschedule_ = true; + helper_->SetScheduled(false); + return true; + } + return false; +} + bool IOSurfaceImageTransportSurface::IsOffscreen() { return false; } @@ -199,7 +222,8 @@ bool IOSurfaceImageTransportSurface::SwapBuffers() { params.surface_handle = io_surface_handle_; helper_->SendAcceleratedSurfaceBuffersSwapped(params); - helper_->SetScheduled(false); + DCHECK(!is_swap_buffers_pending_); + is_swap_buffers_pending_ = true; return true; } @@ -218,7 +242,8 @@ bool IOSurfaceImageTransportSurface::PostSubBuffer( params.height = height; helper_->SendAcceleratedSurfacePostSubBuffer(params); - helper_->SetScheduled(false); + DCHECK(!is_swap_buffers_pending_); + is_swap_buffers_pending_ = true; return true; } @@ -235,7 +260,12 @@ gfx::Size IOSurfaceImageTransportSurface::GetSize() { } void IOSurfaceImageTransportSurface::OnBufferPresented(uint32 sync_point) { - helper_->SetScheduled(true); + DCHECK(is_swap_buffers_pending_); + is_swap_buffers_pending_ = false; + if (did_unschedule_) { + did_unschedule_ = false; + helper_->SetScheduled(true); + } } void IOSurfaceImageTransportSurface::OnNewSurfaceACK( diff --git a/content/common/gpu/image_transport_surface_win.cc b/content/common/gpu/image_transport_surface_win.cc index 80630e6..cc6dc87 100644 --- a/content/common/gpu/image_transport_surface_win.cc +++ b/content/common/gpu/image_transport_surface_win.cc @@ -36,6 +36,7 @@ class PbufferImageTransportSurface // gfx::GLSurface implementation virtual bool Initialize() OVERRIDE; virtual void Destroy() OVERRIDE; + virtual bool DeferDraws() OVERRIDE; virtual bool IsOffscreen() OVERRIDE; virtual bool SwapBuffers() OVERRIDE; virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE; @@ -60,6 +61,12 @@ class PbufferImageTransportSurface bool backbuffer_suggested_allocation_; bool frontbuffer_suggested_allocation_; + // Whether a SwapBuffers is pending. + bool is_swap_buffers_pending_; + + // Whether we unscheduled command buffer because of pending SwapBuffers. + bool did_unschedule_; + // Size to resize to when the surface becomes visible. gfx::Size visible_size_; @@ -73,7 +80,9 @@ PbufferImageTransportSurface::PbufferImageTransportSurface( GpuCommandBufferStub* stub) : GLSurfaceAdapter(new gfx::PbufferGLSurfaceEGL(false, gfx::Size(1, 1))), backbuffer_suggested_allocation_(true), - frontbuffer_suggested_allocation_(true) { + frontbuffer_suggested_allocation_(true), + is_swap_buffers_pending_(false), + did_unschedule_(false) { helper_.reset(new ImageTransportHelper(this, manager, stub, @@ -102,6 +111,20 @@ void PbufferImageTransportSurface::Destroy() { GLSurfaceAdapter::Destroy(); } +bool PbufferImageTransportSurface::DeferDraws() { + // The command buffer hit a draw/clear command that could clobber the + // IOSurface in use by an earlier SwapBuffers. If a Swap is pending, abort + // processing of the command by returning true and unschedule until the Swap + // Ack arrives. + DCHECK(!did_unschedule_); + if (is_swap_buffers_pending_) { + did_unschedule_ = true; + helper_->SetScheduled(false); + return true; + } + return false; +} + bool PbufferImageTransportSurface::IsOffscreen() { return false; } @@ -115,6 +138,10 @@ bool PbufferImageTransportSurface::SwapBuffers() { if (!surface_handle) return false; + // Don't send the surface to the browser until we hit the fence that + // indicates the drawing to the surface has been completed. + // TODO(jbates) unscheduling should be deferred until draw commands from the + // next frame -- otherwise the GPU is potentially sitting idle. helper_->DeferToFence(base::Bind( &PbufferImageTransportSurface::SendBuffersSwapped, AsWeakPtr())); @@ -171,11 +198,16 @@ void PbufferImageTransportSurface::SendBuffersSwapped() { params.size = GetSize(); helper_->SendAcceleratedSurfaceBuffersSwapped(params); - helper_->SetScheduled(false); + DCHECK(!is_swap_buffers_pending_); + is_swap_buffers_pending_ = true; } void PbufferImageTransportSurface::OnBufferPresented(uint32 sync_point) { - helper_->SetScheduled(true); + is_swap_buffers_pending_ = false; + if (did_unschedule_) { + did_unschedule_ = false; + helper_->SetScheduled(true); + } } void PbufferImageTransportSurface::OnNewSurfaceACK( diff --git a/content/common/view_messages.h b/content/common/view_messages.h index f160752..1ec6b9b 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h @@ -837,6 +837,14 @@ IPC_MESSAGE_ROUTED4(ViewMsg_PaintAtSize, // This signals the render view that it can send another UpdateRect message. IPC_MESSAGE_ROUTED0(ViewMsg_UpdateRect_ACK) +// Tells the render view that a SwapBuffers was completed. Typically, +// SwapBuffers requests go from renderer -> GPU process -> browser. Most +// platforms still use the GfxCxt3D Echo for receiving the SwapBuffers Ack. +// Using Echo routes the ack from browser -> GPU process -> renderer, while this +// Ack goes directly from browser -> renderer. This is not used for the threaded +// compositor path. +IPC_MESSAGE_ROUTED0(ViewMsg_SwapBuffers_ACK) + // Message payload includes: // 1. A blob that should be cast to WebInputEvent // 2. An optional boolean value indicating if a RawKeyDown event is associated diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc index ddfde20..fbba3d6 100644 --- a/content/renderer/render_widget.cc +++ b/content/renderer/render_widget.cc @@ -234,6 +234,7 @@ bool RenderWidget::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(ViewMsg_WasRestored, OnWasRestored) IPC_MESSAGE_HANDLER(ViewMsg_WasSwappedOut, OnWasSwappedOut) IPC_MESSAGE_HANDLER(ViewMsg_UpdateRect_ACK, OnUpdateRectAck) + IPC_MESSAGE_HANDLER(ViewMsg_SwapBuffers_ACK, OnSwapBuffersComplete) IPC_MESSAGE_HANDLER(ViewMsg_HandleInputEvent, OnHandleInputEvent) IPC_MESSAGE_HANDLER(ViewMsg_MouseCaptureLost, OnMouseCaptureLost) IPC_MESSAGE_HANDLER(ViewMsg_SetFocus, OnSetFocus) diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index 3426e3f..af6d353 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -872,7 +872,10 @@ _FUNCTION_INFO = { 'error_value': 'GL_FRAMEBUFFER_UNSUPPORTED', 'result': ['GLenum'], }, - 'Clear': {'decoder_func': 'DoClear'}, + 'Clear': { + 'type': 'Manual', + 'cmd_args': 'GLbitfield mask' + }, 'ClearColor': {'decoder_func': 'DoClearColor'}, 'ClearDepthf': { 'decoder_func': 'DoClearDepthf', diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 953f87f..ca3a9e7 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc @@ -971,6 +971,12 @@ GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM( return result; } +void GLES2Implementation::Clear(GLbitfield mask) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << this << "] glClear(" << mask << ")"); + helper_->Clear(mask); +} + void GLES2Implementation::DrawElements( GLenum mode, GLsizei count, GLenum type, const void* indices) { GPU_CLIENT_SINGLE_THREAD_CHECK(); diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index ee673ce..5432345 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.h @@ -120,11 +120,7 @@ GLenum CheckFramebufferStatus(GLenum target) { return *result; } -void Clear(GLbitfield mask) { - GPU_CLIENT_SINGLE_THREAD_CHECK(); - GPU_CLIENT_LOG("[" << this << "] glClear(" << mask << ")"); - helper_->Clear(mask); -} +void Clear(GLbitfield mask); void ClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { GPU_CLIENT_SINGLE_THREAD_CHECK(); diff --git a/gpu/command_buffer/common/constants.h b/gpu/command_buffer/common/constants.h index 38a8c32..a2eeb74 100644 --- a/gpu/command_buffer/common/constants.h +++ b/gpu/command_buffer/common/constants.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -21,12 +21,13 @@ namespace error { kUnknownCommand, kInvalidArguments, kLostContext, - kGenericError + kGenericError, + kDeferCommandUntilLater }; // Return true if the given error code is an actual error. inline bool IsError(Error error) { - return error != kNoError; + return error != kNoError && error != kDeferCommandUntilLater; } // Provides finer grained information about why the context was lost. diff --git a/gpu/command_buffer/service/cmd_parser.cc b/gpu/command_buffer/service/cmd_parser.cc index a58d5a5..0ca1e61 100644 --- a/gpu/command_buffer/service/cmd_parser.cc +++ b/gpu/command_buffer/service/cmd_parser.cc @@ -79,7 +79,7 @@ error::Error CommandParser::ProcessCommand() { } // If get was not set somewhere else advance it. - if (get == get_) + if (get == get_ && result != error::kDeferCommandUntilLater) get_ = (get + header.size) % entry_count_; if (trace_gl_commands_) diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index bc7b9b8..0f2ef5c 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -1003,7 +1003,7 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, GLenum DoCheckFramebufferStatus(GLenum target); // Wrapper for glClear - void DoClear(GLbitfield mask); + error::Error DoClear(GLbitfield mask); // Wrappers for clear and mask settings functions. void DoClearColor( @@ -1356,6 +1356,12 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, void RenderWarning(const std::string& msg); void PerformanceWarning(const std::string& msg); + bool ShouldDeferDraws() { + return !offscreen_target_frame_buffer_.get() && + bound_draw_framebuffer_ == NULL && + surface_->DeferDraws(); + } + // Generate a member function prototype for each command in an automated and // typesafe way. #define GLES2_CMD_OP(name) \ @@ -4243,13 +4249,22 @@ error::Error GLES2DecoderImpl::HandleRegisterSharedIdsCHROMIUM( return error::kNoError; } -void GLES2DecoderImpl::DoClear(GLbitfield mask) { +error::Error GLES2DecoderImpl::DoClear(GLbitfield mask) { + if (ShouldDeferDraws()) + return error::kDeferCommandUntilLater; if (CheckBoundFramebuffersValid("glClear")) { UNSHIPPED_TRACE_EVENT_INSTANT2("test_gpu", "DoClear", "red", clear_red_, "green", clear_green_); ApplyDirtyState(); glClear(mask); } + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandleClear( + uint32 immediate_data_size, const gles2::Clear& c) { + GLbitfield mask = static_cast<GLbitfield>(c.mask); + return DoClear(mask); } void GLES2DecoderImpl::DoFramebufferRenderbuffer( @@ -5492,6 +5507,8 @@ error::Error GLES2DecoderImpl::DoDrawArrays( GLint first, GLsizei count, GLsizei primcount) { + if (ShouldDeferDraws()) + return error::kDeferCommandUntilLater; if (!validators_->draw_mode.IsValid(mode)) { SetGLError(GL_INVALID_ENUM, function_name, "mode GL_INVALID_ENUM"); return error::kNoError; @@ -5593,6 +5610,8 @@ error::Error GLES2DecoderImpl::DoDrawElements( GLenum type, int32 offset, GLsizei primcount) { + if (ShouldDeferDraws()) + return error::kDeferCommandUntilLater; if (!bound_element_array_buffer_) { SetGLError(GL_INVALID_OPERATION, function_name, "No element array buffer bound"); @@ -8204,6 +8223,10 @@ error::Error GLES2DecoderImpl::HandleShaderBinary( error::Error GLES2DecoderImpl::HandleSwapBuffers( uint32 immediate_data_size, const gles2::SwapBuffers& c) { bool is_offscreen = !!offscreen_target_frame_buffer_.get(); + if (!is_offscreen && surface_->DeferSwapBuffers()) { + return error::kDeferCommandUntilLater; + } + int this_frame_number = frame_number_++; // TRACE_EVENT for gpu tests: TRACE_EVENT_INSTANT2("test_gpu", "SwapBuffers", diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h index ab06503..dc85cc2 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h @@ -223,13 +223,6 @@ error::Error GLES2DecoderImpl::HandleCheckFramebufferStatus( return error::kNoError; } -error::Error GLES2DecoderImpl::HandleClear( - uint32 immediate_data_size, const gles2::Clear& c) { - GLbitfield mask = static_cast<GLbitfield>(c.mask); - DoClear(mask); - return error::kNoError; -} - error::Error GLES2DecoderImpl::HandleClearColor( uint32 immediate_data_size, const gles2::ClearColor& c) { GLclampf red = static_cast<GLclampf>(c.red); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h index 495b16a..bd7dbd7 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h @@ -290,15 +290,8 @@ TEST_F(GLES2DecoderTest1, CheckFramebufferStatusInvalidArgsBadSharedMemoryId) { cmd.Init(GL_FRAMEBUFFER, shared_memory_id_, kInvalidSharedMemoryOffset); EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd)); } +// TODO(gman): Clear -TEST_F(GLES2DecoderTest1, ClearValidArgs) { - EXPECT_CALL(*gl_, Clear(1)); - SpecializedSetup<Clear, 0>(true); - Clear cmd; - cmd.Init(1); - EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); - EXPECT_EQ(GL_NO_ERROR, GetGLError()); -} TEST_F(GLES2DecoderTest1, ClearColorValidArgs) { EXPECT_CALL(*gl_, ClearColor(1, 2, 3, 4)); diff --git a/gpu/command_buffer/service/gpu_scheduler.cc b/gpu/command_buffer/service/gpu_scheduler.cc index 85d4f75..de83617 100644 --- a/gpu/command_buffer/service/gpu_scheduler.cc +++ b/gpu/command_buffer/service/gpu_scheduler.cc @@ -80,6 +80,11 @@ void GpuScheduler::PutChanged() { error = parser_->ProcessCommand(); + if (error == error::kDeferCommandUntilLater) { + DCHECK(unscheduled_count_ > 0); + return; + } + // TODO(piman): various classes duplicate various pieces of state, leading // to needlessly complex update logic. It should be possible to simply // share the state across all of them. diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc index b9040ec..b51d747 100644 --- a/ui/gl/gl_surface.cc +++ b/ui/gl/gl_surface.cc @@ -84,6 +84,14 @@ bool GLSurface::Resize(const gfx::Size& size) { return false; } +bool GLSurface::DeferDraws() { + return false; +} + +bool GLSurface::DeferSwapBuffers() { + return false; +} + std::string GLSurface::GetExtensions() { // Use of GLSurfaceAdapter class means that we can't compare // GetCurrent() and this directly. @@ -166,6 +174,14 @@ bool GLSurfaceAdapter::Resize(const gfx::Size& size) { return surface_->Resize(size); } +bool GLSurfaceAdapter::DeferDraws() { + return surface_->DeferDraws(); +} + +bool GLSurfaceAdapter::DeferSwapBuffers() { + return surface_->DeferSwapBuffers(); +} + bool GLSurfaceAdapter::IsOffscreen() { return surface_->IsOffscreen(); } diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h index 5872ed0..7b0faee 100644 --- a/ui/gl/gl_surface.h +++ b/ui/gl/gl_surface.h @@ -39,6 +39,16 @@ class GL_EXPORT GLSurface : public base::RefCounted<GLSurface> { virtual bool Resize(const gfx::Size& size); + // Unschedule the GpuScheduler and return true to abort the processing of + // a GL draw call to this surface and defer it until the GpuScheduler is + // rescheduled. + virtual bool DeferDraws(); + + // Unschedule the GpuScheduler and return true to abort the processing of + // a GL SwapBuffers call to this surface and defer it until the GpuScheduler + // is rescheduled. + virtual bool DeferSwapBuffers(); + // Returns true if this surface is offscreen. virtual bool IsOffscreen() = 0; @@ -126,6 +136,8 @@ class GL_EXPORT GLSurfaceAdapter : public GLSurface { virtual bool Initialize() OVERRIDE; virtual void Destroy() OVERRIDE; virtual bool Resize(const gfx::Size& size) OVERRIDE; + virtual bool DeferDraws() OVERRIDE; + virtual bool DeferSwapBuffers() OVERRIDE; virtual bool IsOffscreen() OVERRIDE; virtual bool SwapBuffers() OVERRIDE; virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE; |