From f4abc2b701c23978e8bd5e4fc3e183e519aede4a Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Thu, 12 Nov 2015 23:40:58 -0800 Subject: [PATCH] Need to updateSurface if surface size was changed in relayoutWindow On some chips, SurfaceControl.setSize will not take effect for several frames. We have to also do a updateSurface/invalidate (which destroys and creates the EGLSurface) to get the size right. Keep track of SurfaceControl size changes in window manager, and pass that to ViewRootImpl, so that a updateSurface is done either the surface itself or its size is changed. Note that we don't use frame size change to trigger updateSurface, because frame size could be different from the surface size that window manager set. For example during drag resizing, the surface size is fullscreen although frame size changes constantly. Doing updateSurface upon frame size change could cause us to do many unnecessary updateSurface. bug: 25583942 Change-Id: I1989613a187bb6ef1c179bd2800c6a7b01fcdb3a --- core/java/android/view/ViewRootImpl.java | 16 ++++++++++++++-- core/java/android/view/WindowManagerGlobal.java | 5 +++++ .../android/server/wm/WindowManagerService.java | 5 +++++ .../android/server/wm/WindowStateAnimator.java | 2 ++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 625ed380efd54..fdea1ba157f47 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1638,6 +1638,8 @@ public final class ViewRootImpl implements ViewParent, final boolean stableInsetsChanged = !mPendingStableInsets.equals( mAttachInfo.mStableInsets); final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets); + final boolean surfaceSizeChanged = (relayoutResult + & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0; if (contentInsetsChanged) { mAttachInfo.mContentInsets.set(mPendingContentInsets); if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: " @@ -1723,10 +1725,20 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mHardwareRenderer.isEnabled()) { mAttachInfo.mHardwareRenderer.destroy(); } - } else if (surfaceGenerationId != mSurface.getGenerationId() && - mSurfaceHolder == null && mAttachInfo.mHardwareRenderer != null) { + } else if ((surfaceGenerationId != mSurface.getGenerationId() + || surfaceSizeChanged) + && mSurfaceHolder == null + && mAttachInfo.mHardwareRenderer != null) { mFullRedrawNeeded = true; try { + // Need to do updateSurface (which leads to CanvasContext::setSurface and + // re-create the EGLSurface) if either the Surface changed (as indicated by + // generation id), or WindowManager changed the surface size. The latter is + // because on some chips, changing the consumer side's BufferQueue size may + // not take effect immediately unless we create a new EGLSurface. + // Note that frame size change doesn't always imply surface size change (eg. + // drag resizing uses fullscreen surface), need to check surfaceSizeChanged + // flag from WindowManager. mAttachInfo.mHardwareRenderer.updateSurface(mSurface); } catch (OutOfResourcesException e) { handleOutOfResourcesException(e); diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index 43d643e51c32f..c08e1b5803c48 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -76,6 +76,11 @@ public final class WindowManagerGlobal { */ public static final int RELAYOUT_RES_DRAG_RESIZING = 0x8; + /** + * The window manager has changed the size of the surface from the last call. + */ + public static final int RELAYOUT_RES_SURFACE_RESIZED = 0x10; + /** * Flag for relayout: the client will be later giving * internal insets; as a result, the window will not impact other window diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index a22f8213e15d8..490f5d88011c0 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2725,6 +2725,8 @@ public class WindowManagerService extends IWindowManager.Stub WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; } + final int oldSurfaceResizeGeneration = winAnimator.mSurfaceResizeGeneration; + win.setDisplayLayoutNeeded(); win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0; configChanged = updateOrientationFromAppTokensLocked(false); @@ -2737,6 +2739,9 @@ public class WindowManagerService extends IWindowManager.Stub if (win.mAppToken != null) { win.mAppToken.updateReportedVisibilityLocked(); } + if (winAnimator.mSurfaceResizeGeneration != oldSurfaceResizeGeneration) { + result |= WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED; + } outFrame.set(win.mCompatFrame); outOverscanInsets.set(win.mOverscanInsets); outContentInsets.set(win.mContentInsets); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index decfb342acad7..4b2edf64aa518 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -99,6 +99,7 @@ class WindowStateAnimator { * we must tell them application to resize (and thus redraw itself). */ boolean mSurfaceResized; + int mSurfaceResizeGeneration; WindowSurfaceController mSurfaceController; private WindowSurfaceController mPendingDestroySurface; @@ -1183,6 +1184,7 @@ class WindowStateAnimator { recoveringMemory); if (mSurfaceResized) { + mSurfaceResizeGeneration++; mAnimator.setPendingLayoutChanges(w.getDisplayId(), WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER); w.applyDimLayerIfNeeded();