summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorccameron <ccameron@chromium.org>2014-10-09 02:06:42 -0700
committerCommit bot <commit-bot@chromium.org>2014-10-09 09:07:13 +0000
commit95e3616034fcf2ef6d1a7caf8b289ad87ad8b6d0 (patch)
tree8352c068cf1a9e0402b0f92c57815f045780d6bb
parenta98abe65be310e50064ff84e38a7e79e45251dc5 (diff)
downloadchromium_src-95e3616034fcf2ef6d1a7caf8b289ad87ad8b6d0.zip
chromium_src-95e3616034fcf2ef6d1a7caf8b289ad87ad8b6d0.tar.gz
chromium_src-95e3616034fcf2ef6d1a7caf8b289ad87ad8b6d0.tar.bz2
Clean up GPU back-pressure with remote CALayers
If a CAOpenGLLayer is attached to a NSView that is completely occluded or isn't in the window hierarchy, then when we ask that layer to draw, it will not draw, or will draw after a long delay. This optimization can be a problem if we need to renderer to continue to produce frames, e.g, for tab capture. Fix this issue by having the frame acknowledgement from the browser to the GPU process (which currently informs the GPU process of the CGL renderer ID) inform the GPU process of the occlusion status of the NSView being drawn to. Use this information in the GPU process to force the CAOpenGLLayer to draw as soon as a new frame arrives. Add the same timeout mechanism as is in the IOSurface drawing path to limit CoreAnimation's throttling (based on GPU back-pressure) to 6 fps, to avoid having the renderer block indefinitely. This is something of a hack, but is an unfortunate necessity. Note that this change assumes that calling setNeedsDisplay and then displayIfNeeded will result in the CALayer being draw except in the case where the CALayer is backing a NSView that is not in the window hierarchy. This exception only happens during tab capture of a backgrounded tab, and the contents not drawn are actually never seen, so it is safe to skip the draw entirely. Also, wrap some Mac-only IPCs and structures #if defined(OS_MACOSX). BUG=312462 Review URL: https://codereview.chromium.org/636003002 Cr-Commit-Position: refs/heads/master@{#298828}
-rw-r--r--content/browser/compositor/browser_compositor_ca_layer_tree_mac.h3
-rw-r--r--content/browser/compositor/browser_compositor_ca_layer_tree_mac.mm6
-rw-r--r--content/browser/compositor/browser_compositor_view_mac.mm3
-rw-r--r--content/common/gpu/gpu_messages.h14
-rw-r--r--content/common/gpu/image_transport_surface.cc6
-rw-r--r--content/common/gpu/image_transport_surface.h6
-rw-r--r--content/common/gpu/image_transport_surface_calayer_mac.h17
-rw-r--r--content/common/gpu/image_transport_surface_calayer_mac.mm67
-rw-r--r--content/common/gpu/image_transport_surface_fbo_mac.h5
-rw-r--r--content/common/gpu/image_transport_surface_fbo_mac.mm2
-rw-r--r--content/common/gpu/image_transport_surface_iosurface_mac.cc3
-rw-r--r--content/common/gpu/image_transport_surface_iosurface_mac.h2
12 files changed, 89 insertions, 45 deletions
diff --git a/content/browser/compositor/browser_compositor_ca_layer_tree_mac.h b/content/browser/compositor/browser_compositor_ca_layer_tree_mac.h
index 71787c6..4092370 100644
--- a/content/browser/compositor/browser_compositor_ca_layer_tree_mac.h
+++ b/content/browser/compositor/browser_compositor_ca_layer_tree_mac.h
@@ -37,6 +37,9 @@ class BrowserCompositorCALayerTreeMac
// Return the CGL renderer ID for the surface, if one is available.
int GetRendererID() const;
+ // Return true if the renderer should not be throttled by GPU back-pressure.
+ bool IsRendererThrottlingDisabled() const;
+
// Mark a bracket in which new frames are being pumped in a restricted nested
// run loop.
void BeginPumpingFrames();
diff --git a/content/browser/compositor/browser_compositor_ca_layer_tree_mac.mm b/content/browser/compositor/browser_compositor_ca_layer_tree_mac.mm
index f746701..6a8e51c 100644
--- a/content/browser/compositor/browser_compositor_ca_layer_tree_mac.mm
+++ b/content/browser/compositor/browser_compositor_ca_layer_tree_mac.mm
@@ -116,6 +116,12 @@ int BrowserCompositorCALayerTreeMac::GetRendererID() const {
return 0;
}
+bool BrowserCompositorCALayerTreeMac::IsRendererThrottlingDisabled() const {
+ if (client_)
+ return client_->BrowserCompositorViewShouldAckImmediately();
+ return false;
+}
+
void BrowserCompositorCALayerTreeMac::BeginPumpingFrames() {
[io_surface_layer_ beginPumpingFrames];
}
diff --git a/content/browser/compositor/browser_compositor_view_mac.mm b/content/browser/compositor/browser_compositor_view_mac.mm
index b99f173..e011008 100644
--- a/content/browser/compositor/browser_compositor_view_mac.mm
+++ b/content/browser/compositor/browser_compositor_view_mac.mm
@@ -82,15 +82,18 @@ void BrowserCompositorViewMac::GotAcceleratedFrame(
int gpu_host_id, int gpu_route_id) {
BrowserCompositorCALayerTreeMac* ca_layer_tree =
BrowserCompositorCALayerTreeMac::FromAcceleratedWidget(widget);
+ bool disable_throttling = false;
int renderer_id = 0;
if (ca_layer_tree) {
ca_layer_tree->GotAcceleratedFrame(
surface_handle, surface_id, latency_info, pixel_size, scale_factor);
+ disable_throttling = ca_layer_tree->IsRendererThrottlingDisabled();
renderer_id = ca_layer_tree->GetRendererID();
}
// Acknowledge the swap, now that it has been processed.
AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
+ ack_params.disable_throttling = disable_throttling;
ack_params.renderer_id = renderer_id;
GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(gpu_host_id);
if (ui_shim) {
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h
index 4375deb..b42bc09 100644
--- a/content/common/gpu/gpu_messages.h
+++ b/content/common/gpu/gpu_messages.h
@@ -81,9 +81,17 @@ IPC_STRUCT_BEGIN(GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params)
IPC_STRUCT_MEMBER(std::vector<ui::LatencyInfo>, latency_info)
IPC_STRUCT_END()
+#if defined(OS_MACOSX)
IPC_STRUCT_BEGIN(AcceleratedSurfaceMsg_BufferPresented_Params)
+ // If the browser needs framerate throttling based on GPU back-pressure to be
+ // disabled (e.g, because the NSView isn't visible but tab capture is active),
+ // then this is set to true.
+ IPC_STRUCT_MEMBER(bool, disable_throttling)
+ // If the browser is drawing to the screen, this is the CGL renderer ID of
+ // the GL context that the brower is using.
IPC_STRUCT_MEMBER(int32, renderer_id)
IPC_STRUCT_END()
+#endif
IPC_STRUCT_BEGIN(GPUCommandBufferConsoleMessage)
IPC_STRUCT_MEMBER(int32, id)
@@ -272,12 +280,12 @@ IPC_MESSAGE_CONTROL0(GpuMsg_CollectGraphicsInfo)
// Tells the GPU process to report video_memory information for the task manager
IPC_MESSAGE_CONTROL0(GpuMsg_GetVideoMemoryUsageStats)
+#if defined(OS_MACOSX)
// Tells the GPU process that the browser process has handled the swap
-// buffers or post sub-buffer request. A non-zero sync point means
-// that we should wait for the sync point. The surface_handle identifies
-// that buffer that has finished presented, i.e. the buffer being returned.
+// buffers or post sub-buffer request.
IPC_MESSAGE_ROUTED1(AcceleratedSurfaceMsg_BufferPresented,
AcceleratedSurfaceMsg_BufferPresented_Params)
+#endif
// Tells the GPU process to wake up the GPU because we're about to draw.
IPC_MESSAGE_ROUTED0(AcceleratedSurfaceMsg_WakeUpGpu)
diff --git a/content/common/gpu/image_transport_surface.cc b/content/common/gpu/image_transport_surface.cc
index 61fe511..94991a8 100644
--- a/content/common/gpu/image_transport_surface.cc
+++ b/content/common/gpu/image_transport_surface.cc
@@ -91,8 +91,10 @@ bool ImageTransportHelper::Initialize() {
bool ImageTransportHelper::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ImageTransportHelper, message)
+#if defined(OS_MACOSX)
IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_BufferPresented,
OnBufferPresented)
+#endif
IPC_MESSAGE_HANDLER(AcceleratedSurfaceMsg_WakeUpGpu, OnWakeUpGpu);
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -177,10 +179,12 @@ gpu::gles2::GLES2Decoder* ImageTransportHelper::Decoder() {
return stub_->decoder();
}
+#if defined(OS_MACOSX)
void ImageTransportHelper::OnBufferPresented(
const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
surface_->OnBufferPresented(params);
}
+#endif
void ImageTransportHelper::OnWakeUpGpu() {
surface_->WakeUpGpu();
@@ -268,10 +272,12 @@ bool PassThroughImageTransportSurface::OnMakeCurrent(gfx::GLContext* context) {
return true;
}
+#if defined(OS_MACOSX)
void PassThroughImageTransportSurface::OnBufferPresented(
const AcceleratedSurfaceMsg_BufferPresented_Params& /* params */) {
NOTREACHED();
}
+#endif
void PassThroughImageTransportSurface::OnResize(gfx::Size size,
float scale_factor) {
diff --git a/content/common/gpu/image_transport_surface.h b/content/common/gpu/image_transport_surface.h
index d03cf5ce..111ac82 100644
--- a/content/common/gpu/image_transport_surface.h
+++ b/content/common/gpu/image_transport_surface.h
@@ -57,8 +57,10 @@ class ImageTransportSurface {
public:
ImageTransportSurface();
+#if defined(OS_MACOSX)
virtual void OnBufferPresented(
const AcceleratedSurfaceMsg_BufferPresented_Params& params) = 0;
+#endif
virtual void OnResize(gfx::Size size, float scale_factor) = 0;
virtual void SetLatencyInfo(
const std::vector<ui::LatencyInfo>& latency_info) = 0;
@@ -149,8 +151,10 @@ class ImageTransportHelper
gpu::gles2::GLES2Decoder* Decoder();
// IPC::Message handlers.
+#if defined(OS_MACOSX)
void OnBufferPresented(
const AcceleratedSurfaceMsg_BufferPresented_Params& params);
+#endif
void OnWakeUpGpu();
// Backbuffer resize callback.
@@ -187,8 +191,10 @@ class PassThroughImageTransportSurface
virtual bool OnMakeCurrent(gfx::GLContext* context) override;
// ImageTransportSurface implementation.
+#if defined(OS_MACOSX)
virtual void OnBufferPresented(
const AcceleratedSurfaceMsg_BufferPresented_Params& params) override;
+#endif
virtual void OnResize(gfx::Size size, float scale_factor) override;
virtual gfx::Size GetSize() override;
virtual void SetLatencyInfo(
diff --git a/content/common/gpu/image_transport_surface_calayer_mac.h b/content/common/gpu/image_transport_surface_calayer_mac.h
index 20ccce3..59aaf6f 100644
--- a/content/common/gpu/image_transport_surface_calayer_mac.h
+++ b/content/common/gpu/image_transport_surface_calayer_mac.h
@@ -31,7 +31,7 @@ class CALayerStorageProvider
virtual void SwapBuffers(const gfx::Size& size, float scale_factor) override;
virtual void WillWriteToBackbuffer() override;
virtual void DiscardBackbuffer() override;
- virtual void SwapBuffersAckedByBrowser() override;
+ virtual void SwapBuffersAckedByBrowser(bool disable_throttling) override;
// Interface to ImageTransportLayer:
CGLContextObj LayerShareGroupContext();
@@ -40,8 +40,11 @@ class CALayerStorageProvider
void LayerResetStorageProvider();
private:
- void DrawWithVsyncDisabled();
- void SendPendingSwapToBrowserAfterFrameDrawn();
+ void DrawImmediatelyAndUnblockBrowser();
+
+ // The browser will be blocked while there is a frame that was sent to it but
+ // hasn't drawn yet. This call will un-block the browser.
+ void UnblockBrowserIfNeeded();
ImageTransportSurfaceFBO* transport_surface_;
@@ -49,6 +52,10 @@ class CALayerStorageProvider
// animate.
const bool gpu_vsync_disabled_;
+ // Used also to determine if we should wait for CoreAnimation to call our
+ // drawInCGLContext, or if we should force it with displayIfNeeded.
+ bool throttling_disabled_;
+
// Set when a new swap occurs, and un-set when |layer_| draws that frame.
bool has_pending_draw_;
@@ -68,7 +75,9 @@ class CALayerStorageProvider
base::scoped_nsobject<CAContext> context_;
base::scoped_nsobject<ImageTransportLayer> layer_;
- base::WeakPtrFactory<CALayerStorageProvider> weak_factory_;
+ // Weak factory against which a timeout task for forcing a draw is created.
+ base::WeakPtrFactory<CALayerStorageProvider> pending_draw_weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(CALayerStorageProvider);
};
diff --git a/content/common/gpu/image_transport_surface_calayer_mac.mm b/content/common/gpu/image_transport_surface_calayer_mac.mm
index 7531297..3735460 100644
--- a/content/common/gpu/image_transport_surface_calayer_mac.mm
+++ b/content/common/gpu/image_transport_surface_calayer_mac.mm
@@ -90,11 +90,12 @@ CALayerStorageProvider::CALayerStorageProvider(
: transport_surface_(transport_surface),
gpu_vsync_disabled_(CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableGpuVsync)),
+ throttling_disabled_(false),
has_pending_draw_(false),
can_draw_returned_false_count_(0),
fbo_texture_(0),
fbo_scale_factor_(1),
- weak_factory_(this) {}
+ pending_draw_weak_factory_(this) {}
CALayerStorageProvider::~CALayerStorageProvider() {
}
@@ -141,20 +142,15 @@ bool CALayerStorageProvider::AllocateColorBufferStorage(
}
void CALayerStorageProvider::FreeColorBufferStorage() {
- // We shouldn't be asked to free a texture when we still have yet to draw it.
- DCHECK(!has_pending_draw_);
- has_pending_draw_ = false;
- can_draw_returned_false_count_ = 0;
-
// Note that |context_| still holds a reference to |layer_|, and will until
// a new frame is swapped in.
- [layer_ displayIfNeeded];
[layer_ resetStorageProvider];
layer_.reset();
share_group_context_.reset();
fbo_texture_ = 0;
fbo_pixel_size_ = gfx::Size();
+ can_draw_returned_false_count_ = 0;
}
void CALayerStorageProvider::SwapBuffers(
@@ -185,37 +181,41 @@ void CALayerStorageProvider::SwapBuffers(
[context_ setLayer:layer_];
}
- // Tell CoreAnimation to draw our frame. We will send the IPC to the browser
- // when CoreAnimation has drawn our frame.
- if (gpu_vsync_disabled_) {
- DrawWithVsyncDisabled();
+ // Tell CoreAnimation to draw our frame.
+ if (gpu_vsync_disabled_ || throttling_disabled_) {
+ DrawImmediatelyAndUnblockBrowser();
} else {
if (![layer_ isAsynchronous])
[layer_ setAsynchronous:YES];
+
+ // If CoreAnimation doesn't end up drawing our frame, un-block the browser
+ // after a timeout of 1/6th of a second has passed.
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&CALayerStorageProvider::DrawImmediatelyAndUnblockBrowser,
+ pending_draw_weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromSeconds(1) / 6);
}
}
-void CALayerStorageProvider::DrawWithVsyncDisabled() {
- DCHECK(has_pending_draw_);
+void CALayerStorageProvider::DrawImmediatelyAndUnblockBrowser() {
+ CHECK(has_pending_draw_);
+ if ([layer_ isAsynchronous])
+ [layer_ setAsynchronous:NO];
[layer_ setNeedsDisplay];
+ [layer_ displayIfNeeded];
- // Sometimes, setNeedsDisplay calls are dropped on the floor. Make this not
- // hang the renderer by re-issuing the call if the draw has not yet
- // happened.
- if (has_pending_draw_) {
- // Delay sending another draw immediately to avoid starving the run loop.
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&CALayerStorageProvider::DrawWithVsyncDisabled,
- weak_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(5));
- }
+ // Sometimes, the setNeedsDisplay+displayIfNeeded pairs have no effect. This
+ // can happen if the NSView that this layer is attached to isn't in the
+ // window hierarchy (e.g, tab capture of a backgrounded tab). In this case,
+ // the frame will never be seen, so drop it.
+ UnblockBrowserIfNeeded();
}
void CALayerStorageProvider::WillWriteToBackbuffer() {
- // TODO(ccameron): The browser may need to continue issuing swaps even when
- // they do not draw. In these cases it is necessary to either double-buffer
- // the resulting texture, or to drop frames.
+ // The browser will always throttle itself so that there is no pending draw
+ // when this output surface is written to.
+ DCHECK(!has_pending_draw_);
}
void CALayerStorageProvider::DiscardBackbuffer() {
@@ -228,7 +228,9 @@ void CALayerStorageProvider::DiscardBackbuffer() {
context_.reset();
}
-void CALayerStorageProvider::SwapBuffersAckedByBrowser() {
+void CALayerStorageProvider::SwapBuffersAckedByBrowser(
+ bool disable_throttling) {
+ throttling_disabled_ = disable_throttling;
}
CGLContextObj CALayerStorageProvider::LayerShareGroupContext() {
@@ -290,20 +292,19 @@ void CALayerStorageProvider::LayerDoDraw() {
glDisable(GL_TEXTURE_RECTANGLE_ARB);
// Allow forward progress in the context now that the swap is complete.
- DCHECK(has_pending_draw_);
- SendPendingSwapToBrowserAfterFrameDrawn();
+ UnblockBrowserIfNeeded();
}
void CALayerStorageProvider::LayerResetStorageProvider() {
// If we are providing back-pressure by waiting for a draw, that draw will
// now never come, so release the pressure now.
- SendPendingSwapToBrowserAfterFrameDrawn();
+ UnblockBrowserIfNeeded();
}
-void CALayerStorageProvider::SendPendingSwapToBrowserAfterFrameDrawn() {
+void CALayerStorageProvider::UnblockBrowserIfNeeded() {
if (!has_pending_draw_)
return;
- weak_factory_.InvalidateWeakPtrs();
+ pending_draw_weak_factory_.InvalidateWeakPtrs();
has_pending_draw_ = false;
transport_surface_->SendSwapBuffers(
SurfaceHandleFromCAContextID([context_ contextId]),
diff --git a/content/common/gpu/image_transport_surface_fbo_mac.h b/content/common/gpu/image_transport_surface_fbo_mac.h
index 44eeec7..b0747f5 100644
--- a/content/common/gpu/image_transport_surface_fbo_mac.h
+++ b/content/common/gpu/image_transport_surface_fbo_mac.h
@@ -53,8 +53,9 @@ class ImageTransportSurfaceFBO
virtual void DiscardBackbuffer() = 0;
// Called once for every SwapBuffers call when the IPC for the present has
- // been processed by the browser.
- virtual void SwapBuffersAckedByBrowser() = 0;
+ // been processed by the browser. |disable_throttling| is set if the
+ // browser suspects that GPU back-pressure should be disabled.
+ virtual void SwapBuffersAckedByBrowser(bool disable_throttling) = 0;
};
ImageTransportSurfaceFBO(GpuChannelManager* manager,
diff --git a/content/common/gpu/image_transport_surface_fbo_mac.mm b/content/common/gpu/image_transport_surface_fbo_mac.mm
index 4fea7bc..36cf2c3 100644
--- a/content/common/gpu/image_transport_surface_fbo_mac.mm
+++ b/content/common/gpu/image_transport_surface_fbo_mac.mm
@@ -164,7 +164,7 @@ void* ImageTransportSurfaceFBO::GetDisplay() {
void ImageTransportSurfaceFBO::OnBufferPresented(
const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
context_->share_group()->SetRendererID(params.renderer_id);
- storage_provider_->SwapBuffersAckedByBrowser();
+ storage_provider_->SwapBuffersAckedByBrowser(params.disable_throttling);
}
void ImageTransportSurfaceFBO::OnResize(gfx::Size size,
diff --git a/content/common/gpu/image_transport_surface_iosurface_mac.cc b/content/common/gpu/image_transport_surface_iosurface_mac.cc
index 6ef1fc6..121a3a2 100644
--- a/content/common/gpu/image_transport_surface_iosurface_mac.cc
+++ b/content/common/gpu/image_transport_surface_iosurface_mac.cc
@@ -124,7 +124,8 @@ void IOSurfaceStorageProvider::WillWriteToBackbuffer() {
void IOSurfaceStorageProvider::DiscardBackbuffer() {
}
-void IOSurfaceStorageProvider::SwapBuffersAckedByBrowser() {
+void IOSurfaceStorageProvider::SwapBuffersAckedByBrowser(
+ bool disable_throttling) {
DCHECK(!pending_swapped_surfaces_.empty());
pending_swapped_surfaces_.pop_front();
}
diff --git a/content/common/gpu/image_transport_surface_iosurface_mac.h b/content/common/gpu/image_transport_surface_iosurface_mac.h
index e8ffd05..9d7ab31 100644
--- a/content/common/gpu/image_transport_surface_iosurface_mac.h
+++ b/content/common/gpu/image_transport_surface_iosurface_mac.h
@@ -31,7 +31,7 @@ class IOSurfaceStorageProvider
virtual void SwapBuffers(const gfx::Size& size, float scale_factor) override;
virtual void WillWriteToBackbuffer() override;
virtual void DiscardBackbuffer() override;
- virtual void SwapBuffersAckedByBrowser() override;
+ virtual void SwapBuffersAckedByBrowser(bool disable_throttling) override;
private:
ImageTransportSurfaceFBO* transport_surface_;