summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/browser/gpu/gpu_process_host.cc81
-rw-r--r--content/browser/renderer_host/render_widget_host_impl.cc10
-rw-r--r--content/browser/renderer_host/render_widget_host_impl.h6
-rw-r--r--content/browser/renderer_host/render_widget_host_view_mac.mm2
-rw-r--r--content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc17
-rw-r--r--content/common/gpu/image_transport_surface_mac.cc38
-rw-r--r--content/common/gpu/image_transport_surface_win.cc38
-rw-r--r--content/common/view_messages.h8
-rw-r--r--content/renderer/render_widget.cc1
-rwxr-xr-xgpu/command_buffer/build_gles2_cmd_buffer.py5
-rw-r--r--gpu/command_buffer/client/gles2_implementation.cc6
-rw-r--r--gpu/command_buffer/client/gles2_implementation_autogen.h6
-rw-r--r--gpu/command_buffer/common/constants.h7
-rw-r--r--gpu/command_buffer/service/cmd_parser.cc2
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc27
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_autogen.h7
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h9
-rw-r--r--gpu/command_buffer/service/gpu_scheduler.cc5
-rw-r--r--ui/gl/gl_surface.cc16
-rw-r--r--ui/gl/gl_surface.h12
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;