summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorjbates@chromium.org <jbates@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-28 02:11:08 +0000
committerjbates@chromium.org <jbates@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-28 02:11:08 +0000
commita7266a9dc36aa68143d670eb8646f9d67237fa61 (patch)
tree783113824e460a2154aec46f401ead1f1ffd8e66 /content
parent0390d8c8d8c72dedb6bcb9ef39b96fbb8e6915b2 (diff)
downloadchromium_src-a7266a9dc36aa68143d670eb8646f9d67237fa61.zip
chromium_src-a7266a9dc36aa68143d670eb8646f9d67237fa61.tar.gz
chromium_src-a7266a9dc36aa68143d670eb8646f9d67237fa61.tar.bz2
Defer descheduling of GPU commands until draw or swap
This CL adds support to Windows and Mac. Linux doesn't gain anything, because the GPU process is blocked on the actual SwapBuffers call (whereas Windows and Mac asynchronously notify the browser to execute the Swap). The surface gets a chance to defer either Draws or Swaps. The surface can unschedule the GpuScheduler on the first attempt at a draw, for example, and reschedule it later when the draw is safe to execute (ie: when the pending SwapBuffers is acked by the browser). Platforms with triple-buffered contexts can defer all the way until a Swap, while most platforms will use the draws to defer. Review URL: https://chromiumcodereview.appspot.com/10389202 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@144648 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-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
9 files changed, 171 insertions, 30 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)