Commit 89afd64a authored by jbates@chromium.org's avatar jbates@chromium.org

Defer CGLFlushDrawable until OSX-requested drawRect to avoid spinning when window is obscured.

Sadly, this fix regresses some black flashing bugs:
 -flicker-test2.html occasionally flashes while resizing the window.

I think this regression could be fixed if we always draw with the OpenGL context once the context is created. But that would be a third drawing path and some significant code, so let's consider it in a follow up.

BUG=127709
TEST=open https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/sdk/demos/google/particles/index.html ; open Activity Monitor and observe the chrome process CPU usage ; resize chrome window so it's smaller than the Activity Monitor window (or increase size of Activity Monitor); move Activity Monitor on top of chrome window to fully obscure it ; verify that the CPU usage of chrome does not spike upwards while the chrome window is obscured.

Review URL: https://chromiumcodereview.appspot.com/10382213

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@138327 0039d316-1c4b-4281-b951-d872f2087c98
parent a450b6be
...@@ -615,6 +615,10 @@ BackingStore* RenderWidgetHostImpl::GetBackingStore(bool force_create) { ...@@ -615,6 +615,10 @@ BackingStore* RenderWidgetHostImpl::GetBackingStore(bool force_create) {
do { do {
TRACE_EVENT0("renderer_host", "GetBackingStore::WaitForUpdate"); TRACE_EVENT0("renderer_host", "GetBackingStore::WaitForUpdate");
#if defined(OS_MACOSX)
view_->AboutToWaitForBackingStoreMsg();
#endif
// When we have asked the RenderWidget to resize, and we are still waiting // When we have asked the RenderWidget to resize, and we are still waiting
// on a response, block for a little while to see if we can't get a response // on a response, block for a little while to see if we can't get a response
// before returning the old (incorrectly sized) backing store. // before returning the old (incorrectly sized) backing store.
......
...@@ -283,6 +283,7 @@ class RenderWidgetHostViewMac : public content::RenderWidgetHostViewBase { ...@@ -283,6 +283,7 @@ class RenderWidgetHostViewMac : public content::RenderWidgetHostViewBase {
int gpu_host_id) OVERRIDE; int gpu_host_id) OVERRIDE;
virtual void AcceleratedSurfaceSuspend() OVERRIDE; virtual void AcceleratedSurfaceSuspend() OVERRIDE;
virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) OVERRIDE; virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) OVERRIDE;
virtual void AboutToWaitForBackingStoreMsg() OVERRIDE;
virtual void GetScreenInfo(WebKit::WebScreenInfo* results) OVERRIDE; virtual void GetScreenInfo(WebKit::WebScreenInfo* results) OVERRIDE;
virtual gfx::Rect GetRootWindowBounds() OVERRIDE; virtual gfx::Rect GetRootWindowBounds() OVERRIDE;
virtual gfx::GLSurfaceHandle GetCompositingSurface() OVERRIDE; virtual gfx::GLSurfaceHandle GetCompositingSurface() OVERRIDE;
...@@ -319,8 +320,12 @@ class RenderWidgetHostViewMac : public content::RenderWidgetHostViewBase { ...@@ -319,8 +320,12 @@ class RenderWidgetHostViewMac : public content::RenderWidgetHostViewBase {
const std::string& selected_text() const { return selected_text_; } const std::string& selected_text() const { return selected_text_; }
// Call setNeedsDisplay on the cocoa_view_. The IOSurface will be drawn during // Call setNeedsDisplay on the cocoa_view_. The IOSurface will be drawn during
// the next drawRect. // the next drawRect. Return true if the Ack should be sent, false if it
void CompositorSwapBuffers(uint64 surface_handle); // should be deferred until drawRect.
bool CompositorSwapBuffers(uint64 surface_handle);
// Ack pending SwapBuffers requests, if any, to unblock the GPU process. Has
// no effect if there are no pending requests.
void AckPendingSwapBuffers();
// These member variables should be private, but the associated ObjC class // These member variables should be private, but the associated ObjC class
// needs access to them and can't be made a friend. // needs access to them and can't be made a friend.
...@@ -420,6 +425,10 @@ class RenderWidgetHostViewMac : public content::RenderWidgetHostViewBase { ...@@ -420,6 +425,10 @@ class RenderWidgetHostViewMac : public content::RenderWidgetHostViewBase {
scoped_nsobject<NSWindow> pepper_fullscreen_window_; scoped_nsobject<NSWindow> pepper_fullscreen_window_;
scoped_nsobject<FullscreenWindowManager> fullscreen_window_manager_; scoped_nsobject<FullscreenWindowManager> fullscreen_window_manager_;
// List of pending swaps for deferred acking:
// pairs of (route_id, gpu_host_id).
std::list<std::pair<int32, int32> > pending_swap_buffers_acks_;
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewMac); DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewMac);
}; };
......
...@@ -276,6 +276,7 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget) ...@@ -276,6 +276,7 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget)
} }
RenderWidgetHostViewMac::~RenderWidgetHostViewMac() { RenderWidgetHostViewMac::~RenderWidgetHostViewMac() {
AckPendingSwapBuffers();
UnlockMouse(); UnlockMouse();
} }
...@@ -369,6 +370,10 @@ void RenderWidgetHostViewMac::WasHidden() { ...@@ -369,6 +370,10 @@ void RenderWidgetHostViewMac::WasHidden() {
if (is_hidden_) if (is_hidden_)
return; return;
// Send ACKs for any pending SwapBuffers (if any) since we won't be displaying
// them and the GPU process is waiting.
AckPendingSwapBuffers();
// If we receive any more paint messages while we are hidden, we want to // If we receive any more paint messages while we are hidden, we want to
// ignore them so we don't re-allocate the backing store. We will paint // ignore them so we don't re-allocate the backing store. We will paint
// everything again when we become selected again. // everything again when we become selected again.
...@@ -661,6 +666,8 @@ void RenderWidgetHostViewMac::RenderViewGone(base::TerminationStatus status, ...@@ -661,6 +666,8 @@ void RenderWidgetHostViewMac::RenderViewGone(base::TerminationStatus status,
} }
void RenderWidgetHostViewMac::Destroy() { void RenderWidgetHostViewMac::Destroy() {
AckPendingSwapBuffers();
// On Windows, popups are implemented with a popup window style, so that when // On Windows, popups are implemented with a popup window style, so that when
// an event comes in that would "cancel" it, it receives the OnCancelMode // an event comes in that would "cancel" it, it receives the OnCancelMode
// message and can kill itself. Alas, on the Mac, views cannot capture events // message and can kill itself. Alas, on the Mac, views cannot capture events
...@@ -943,22 +950,47 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceSetTransportDIB( ...@@ -943,22 +950,47 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceSetTransportDIB(
transport_dib); transport_dib);
} }
void RenderWidgetHostViewMac::CompositorSwapBuffers(uint64 surface_handle) { bool RenderWidgetHostViewMac::CompositorSwapBuffers(uint64 surface_handle) {
if (is_hidden_) if (is_hidden_)
return; return true;
if (!compositing_iosurface_.get()) if (!compositing_iosurface_.get())
compositing_iosurface_.reset(CompositingIOSurfaceMac::Create()); compositing_iosurface_.reset(CompositingIOSurfaceMac::Create());
if (!compositing_iosurface_.get()) if (!compositing_iosurface_.get())
return; return true;
compositing_iosurface_->SetIOSurface(surface_handle); compositing_iosurface_->SetIOSurface(surface_handle);
GotAcceleratedFrame();
// No need to draw the surface if we are inside a drawRect. It will be done // No need to draw the surface if we are inside a drawRect. It will be done
// later. // later.
if (!about_to_validate_and_paint_) if (!about_to_validate_and_paint_) {
compositing_iosurface_->DrawIOSurface(cocoa_view_); // Trigger a drawRect, but don't invalidate the whole window because it
GotAcceleratedFrame(); // is expensive to clear it with transparency to expose the GL underneath.
[cocoa_view_ setNeedsDisplayInRect:NSMakeRect(0, 0, 1, 1)];
// While resizing, OSX fails to call drawRect on the NSView unless the
// window size has changed. That means we won't see animations update if the
// user has the mouse button held down, but is not currently changing the
// size of the window. To work around that, display here while resizing.
if ([cocoa_view_ inLiveResize])
[cocoa_view_ displayIfNeeded];
}
return false;
}
void RenderWidgetHostViewMac::AckPendingSwapBuffers() {
TRACE_EVENT0("browser", "RenderWidgetHostViewMac::AckPendingSwapBuffers");
while (!pending_swap_buffers_acks_.empty()) {
if (pending_swap_buffers_acks_.front().first != 0) {
RenderWidgetHostImpl::AcknowledgeSwapBuffers(
pending_swap_buffers_acks_.front().first,
pending_swap_buffers_acks_.front().second);
}
pending_swap_buffers_acks_.erase(pending_swap_buffers_acks_.begin());
}
} }
void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped( void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped(
...@@ -966,13 +998,17 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped( ...@@ -966,13 +998,17 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped(
int gpu_host_id) { int gpu_host_id) {
TRACE_EVENT0("browser", TRACE_EVENT0("browser",
"RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped"); "RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped");
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
pending_swap_buffers_acks_.push_back(std::make_pair(params.route_id,
gpu_host_id));
// Compositor window is always gfx::kNullPluginWindow. // Compositor window is always gfx::kNullPluginWindow.
// TODO(jbates) http://crbug.com/105344 This will be removed when there are no // TODO(jbates) http://crbug.com/105344 This will be removed when there are no
// plugin windows. // plugin windows.
if (params.window == gfx::kNullPluginWindow) { if (params.window == gfx::kNullPluginWindow) {
CompositorSwapBuffers(params.surface_handle); if (CompositorSwapBuffers(params.surface_handle))
AckPendingSwapBuffers();
} else { } else {
// Deprecated accelerated plugin code path. // Deprecated accelerated plugin code path.
AcceleratedPluginView* view = ViewForPluginWindowHandle(params.window); AcceleratedPluginView* view = ViewForPluginWindowHandle(params.window);
...@@ -986,11 +1022,7 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped( ...@@ -986,11 +1022,7 @@ void RenderWidgetHostViewMac::AcceleratedSurfaceBuffersSwapped(
[view setHidden:NO]; [view setHidden:NO];
[view drawView]; [view drawView];
} }
} AckPendingSwapBuffers();
if (params.route_id != 0) {
RenderWidgetHostImpl::AcknowledgeSwapBuffers(params.route_id,
gpu_host_id);
} }
} }
...@@ -999,13 +1031,17 @@ void RenderWidgetHostViewMac::AcceleratedSurfacePostSubBuffer( ...@@ -999,13 +1031,17 @@ void RenderWidgetHostViewMac::AcceleratedSurfacePostSubBuffer(
int gpu_host_id) { int gpu_host_id) {
TRACE_EVENT0("browser", TRACE_EVENT0("browser",
"RenderWidgetHostViewMac::AcceleratedSurfacePostSubBuffer"); "RenderWidgetHostViewMac::AcceleratedSurfacePostSubBuffer");
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
pending_swap_buffers_acks_.push_back(std::make_pair(params.route_id,
gpu_host_id));
// Compositor window is always gfx::kNullPluginWindow. // Compositor window is always gfx::kNullPluginWindow.
// TODO(jbates) http://crbug.com/105344 This will be removed when there are no // TODO(jbates) http://crbug.com/105344 This will be removed when there are no
// plugin windows. // plugin windows.
if (params.window == gfx::kNullPluginWindow) { if (params.window == gfx::kNullPluginWindow) {
CompositorSwapBuffers(params.surface_handle); if (CompositorSwapBuffers(params.surface_handle))
AckPendingSwapBuffers();
} else { } else {
// Deprecated accelerated plugin code path. // Deprecated accelerated plugin code path.
AcceleratedPluginView* view = ViewForPluginWindowHandle(params.window); AcceleratedPluginView* view = ViewForPluginWindowHandle(params.window);
...@@ -1021,11 +1057,7 @@ void RenderWidgetHostViewMac::AcceleratedSurfacePostSubBuffer( ...@@ -1021,11 +1057,7 @@ void RenderWidgetHostViewMac::AcceleratedSurfacePostSubBuffer(
[view setHidden:NO]; [view setHidden:NO];
[view drawView]; [view drawView];
} }
} AckPendingSwapBuffers();
if (params.route_id != 0) {
RenderWidgetHostImpl::AcknowledgePostSubBuffer(
params.route_id, gpu_host_id);
} }
} }
...@@ -1043,6 +1075,10 @@ bool RenderWidgetHostViewMac::HasAcceleratedSurface( ...@@ -1043,6 +1075,10 @@ bool RenderWidgetHostViewMac::HasAcceleratedSurface(
compositing_iosurface_->io_surface_size() == desired_size); compositing_iosurface_->io_surface_size() == desired_size);
} }
void RenderWidgetHostViewMac::AboutToWaitForBackingStoreMsg() {
AckPendingSwapBuffers();
}
void RenderWidgetHostViewMac::OnAcceleratedCompositingStateChange() { void RenderWidgetHostViewMac::OnAcceleratedCompositingStateChange() {
} }
...@@ -1154,10 +1190,8 @@ void RenderWidgetHostViewMac::GotAcceleratedFrame() { ...@@ -1154,10 +1190,8 @@ void RenderWidgetHostViewMac::GotAcceleratedFrame() {
// Need to wipe the software view with transparency to expose the GL // Need to wipe the software view with transparency to expose the GL
// underlay. Invalidate the whole window to do that. // underlay. Invalidate the whole window to do that.
if (!about_to_validate_and_paint_) { if (!about_to_validate_and_paint_)
[cocoa_view_ setNeedsDisplay:YES]; [cocoa_view_ setNeedsDisplay:YES];
[cocoa_view_ displayIfNeeded];
}
// Delete software backingstore. // Delete software backingstore.
BackingStoreManager::RemoveBackingStore(render_widget_host_); BackingStoreManager::RemoveBackingStore(render_widget_host_);
...@@ -1168,6 +1202,8 @@ void RenderWidgetHostViewMac::GotSoftwareFrame() { ...@@ -1168,6 +1202,8 @@ void RenderWidgetHostViewMac::GotSoftwareFrame() {
if (last_frame_was_accelerated_) { if (last_frame_was_accelerated_) {
last_frame_was_accelerated_ = false; last_frame_was_accelerated_ = false;
AckPendingSwapBuffers();
// Forget IOSurface since we are drawing a software frame now. // Forget IOSurface since we are drawing a software frame now.
if (compositing_iosurface_.get() && if (compositing_iosurface_.get() &&
compositing_iosurface_->HasIOSurface()) { compositing_iosurface_->HasIOSurface()) {
...@@ -1895,9 +1931,6 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) { ...@@ -1895,9 +1931,6 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) {
if (renderWidgetHostView_->last_frame_was_accelerated_ && if (renderWidgetHostView_->last_frame_was_accelerated_ &&
renderWidgetHostView_->compositing_iosurface_.get()) { renderWidgetHostView_->compositing_iosurface_.get()) {
// Note that this code path is only executed when there's window damage
// (when the window is foregrounded, for example). Normally, GPU frames
// arrive and are drawn during AcceleratedSurfaceBuffersSwapped.
{ {
TRACE_EVENT0("browser", "NSRectFill"); TRACE_EVENT0("browser", "NSRectFill");
// Draw transparency to expose the GL underlay. NSRectFill is extremely // Draw transparency to expose the GL underlay. NSRectFill is extremely
...@@ -1909,6 +1942,7 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) { ...@@ -1909,6 +1942,7 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) {
} }
renderWidgetHostView_->compositing_iosurface_->DrawIOSurface(self); renderWidgetHostView_->compositing_iosurface_->DrawIOSurface(self);
renderWidgetHostView_->AckPendingSwapBuffers();
return; return;
} }
......
...@@ -125,6 +125,9 @@ bool TestRenderWidgetHostView::HasAcceleratedSurface( ...@@ -125,6 +125,9 @@ bool TestRenderWidgetHostView::HasAcceleratedSurface(
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
void TestRenderWidgetHostView::AboutToWaitForBackingStoreMsg() {
}
gfx::Rect TestRenderWidgetHostView::GetViewCocoaBounds() const { gfx::Rect TestRenderWidgetHostView::GetViewCocoaBounds() const {
return gfx::Rect(); return gfx::Rect();
} }
......
...@@ -111,6 +111,7 @@ class TestRenderWidgetHostView : public RenderWidgetHostViewBase { ...@@ -111,6 +111,7 @@ class TestRenderWidgetHostView : public RenderWidgetHostViewBase {
virtual void AcceleratedSurfaceSuspend() OVERRIDE; virtual void AcceleratedSurfaceSuspend() OVERRIDE;
virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) OVERRIDE; virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) OVERRIDE;
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
virtual void AboutToWaitForBackingStoreMsg() OVERRIDE;
virtual gfx::Rect GetViewCocoaBounds() const OVERRIDE; virtual gfx::Rect GetViewCocoaBounds() const OVERRIDE;
virtual void PluginFocusChanged(bool focused, int plugin_id) OVERRIDE; virtual void PluginFocusChanged(bool focused, int plugin_id) OVERRIDE;
virtual void StartPluginIme() OVERRIDE; virtual void StartPluginIme() OVERRIDE;
......
...@@ -180,6 +180,9 @@ class CONTENT_EXPORT RenderWidgetHostViewPort : public RenderWidgetHostView { ...@@ -180,6 +180,9 @@ class CONTENT_EXPORT RenderWidgetHostViewPort : public RenderWidgetHostView {
virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) = 0; virtual bool HasAcceleratedSurface(const gfx::Size& desired_size) = 0;
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
// Called just before GetBackingStore blocks for an updated frame.
virtual void AboutToWaitForBackingStoreMsg() = 0;
// Retrieve the bounds of the view, in cocoa view coordinates. // Retrieve the bounds of the view, in cocoa view coordinates.
// If the UI scale factor is 2, |GetViewBounds()| will return a size of e.g. // If the UI scale factor is 2, |GetViewBounds()| will return a size of e.g.
// (400, 300) in pixels, while this method will return (200, 150). // (400, 300) in pixels, while this method will return (200, 150).
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment