Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2337)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java

Issue 2201483002: Improve transition between opaque and translucent compositor views. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: cl feedback Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java
index 323781006ed24c7a9a8a9d55a05cfd984668e57a..b4d261e97f20311ec416df5a9e3807afe10a5d8f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2016 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.
@@ -9,6 +9,7 @@ import android.content.Context;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Build;
import android.view.Display;
import android.view.MotionEvent;
@@ -17,9 +18,9 @@ import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
+import android.widget.FrameLayout;
import org.chromium.base.CommandLine;
-import org.chromium.base.Log;
import org.chromium.base.TraceEvent;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
@@ -43,8 +44,7 @@ import org.chromium.ui.resources.ResourceManager;
* The is the {@link View} displaying the ui compositor results; including webpages and tabswitcher.
*/
@JNINamespace("android")
-public class CompositorView
- extends SurfaceView implements SurfaceHolder.Callback {
+public class CompositorView extends FrameLayout implements SurfaceHolder.Callback {
private static final String TAG = "CompositorView";
private static final long NANOSECONDS_PER_MILLISECOND = 1000000;
@@ -52,6 +52,17 @@ public class CompositorView
private final Rect mCacheAppRect = new Rect();
private final int[] mCacheViewPosition = new int[2];
+ private CompositorSurfaceManager mCompositorSurfaceManager;
+ private boolean mOverlayVideoEnabled;
+ private boolean mAlwaysTranslucent;
+
+ // Are we waiting to hide the outgoing surface until the foreground has something to display?
+ // If == 0, then no. If > 0, then yes. We'll hide when it transitions from one to zero.
+ private int mFramesUntilHideBackground;
+
+ // Cache of setWillNotDraw, which we keep up to date if we switch SVs.
+ private boolean mWillNotDraw;
+
private long mNativeCompositorView;
private final LayoutRenderHost mRenderHost;
private boolean mEnableTabletTabStack;
@@ -70,16 +81,11 @@ public class CompositorView
private TabContentManager mTabContentManager;
private View mRootView;
- private int mSurfaceWidth;
- private int mSurfaceHeight;
private boolean mPreloadedResources;
- // The current SurfaceView pixel format. Defaults to OPAQUE.
- private int mCurrentPixelFormat = PixelFormat.OPAQUE;
-
/**
- * Creates a {@link CompositorView}. This can be called only after the native library is
- * properly loaded.
+ * Creates a {@link CompositorView}. This can be called only after the
+ * native library is properly loaded.
David Trainor- moved to gerrit 2017/02/07 19:36:16 Move back up? 100 columns for Java.
liberato (no reviews please) 2017/02/14 17:22:24 Done.
* @param c The Context to create this {@link CompositorView} in.
* @param host The renderer host owning this view.
*/
@@ -87,8 +93,8 @@ public class CompositorView
super(c);
mRenderHost = host;
resetFlags();
+
setVisibility(View.INVISIBLE);
- setZOrderMediaOverlay(true);
}
/**
@@ -157,7 +163,7 @@ public class CompositorView
* Should be called for cleanup when the CompositorView instance is no longer used.
*/
public void shutDown() {
- getHolder().removeCallback(this);
+ mCompositorSurfaceManager.shutDown();
if (mNativeCompositorView != 0) nativeDestroy(mNativeCompositorView);
mNativeCompositorView = 0;
}
@@ -178,9 +184,23 @@ public class CompositorView
mNativeCompositorView = nativeInit(lowMemDevice,
windowAndroid.getNativePointer(), layerTitleCache, tabContentManager);
- assert !getHolder().getSurface().isValid()
- : "Surface created before native library loaded.";
- getHolder().addCallback(this);
+ // compositor_impl_android.cc will use 565 EGL surfaces if and only if we're using a low
David Trainor- moved to gerrit 2017/02/07 19:36:16 Remove extra space after "only if"
liberato (no reviews please) 2017/02/14 17:22:24 Done.
+ // memory device, and no alpha channel is desired. Otherwise, it will use 8888. Since
+ // SurfaceFlinger doesn't need the eOpaque flag to optimize out alpha blending during
+ // composition if the buffer has no alpha channel, we can avoid using the extra background
+ // surface (and the memory it requires) in the low memory case. The output buffer will
+ // either have an alpha channel or not, depending on whether the compositor needs it. We
+ // can keep the surface translucent all the times without worrying about the impact on power
+ // usage during SurfaceFlinger composition. We might also want to set |mAlwaysTranslucent|
+ // on non-low memory devices , if we are running on hardware that implements efficient alpha
David Trainor- moved to gerrit 2017/02/07 19:36:16 Remove extra space before ","
liberato (no reviews please) 2017/02/14 17:22:24 Done.
+ // blending.
+ mAlwaysTranslucent = lowMemDevice;
+
+ mCompositorSurfaceManager = new CompositorSurfaceManager(this, this);
+ // In case the background drawable was set before now, update it.
+ mCompositorSurfaceManager.setBackgroundDrawable(getBackground());
+ mCompositorSurfaceManager.setWillNotDraw(mWillNotDraw);
+ mCompositorSurfaceManager.requestSurface(getSurfacePixelFormat());
// Cover the black surface before it has valid content.
setBackgroundColor(Color.WHITE);
@@ -208,34 +228,53 @@ public class CompositorView
}
/**
+ * @see SurfaceView#getHolder
+ */
+ SurfaceHolder getHolder() {
+ return mCompositorSurfaceManager.getHolder();
+ }
+
+ /**
* Enables/disables overlay video mode. Affects alpha blending on this view.
* @param enabled Whether to enter or leave overlay video mode.
*/
public void setOverlayVideoMode(boolean enabled) {
- mCurrentPixelFormat = enabled ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
- getHolder().setFormat(mCurrentPixelFormat);
nativeSetOverlayVideoMode(mNativeCompositorView, enabled);
+
+ mOverlayVideoEnabled = enabled;
+ // Request the new surface, even if it's the same as the old one. We'll get a synthetic
+ // destroy / create / changed callback in that case, possibly before this returns.
+ mCompositorSurfaceManager.requestSurface(getSurfacePixelFormat());
+ // Note that we don't know if we'll get a surfaceCreated / surfaceDestoyed for this surface.
+ // We do know that if we do get one, then it will be for the surface that we just requested.
+ }
+
+ private int getSurfacePixelFormat() {
+ return (mOverlayVideoEnabled || mAlwaysTranslucent) ? PixelFormat.TRANSLUCENT
+ : PixelFormat.OPAQUE;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mNativeCompositorView == 0) return;
+
nativeSurfaceChanged(mNativeCompositorView, format, width, height, holder.getSurface());
mRenderHost.onPhysicalBackingSizeChanged(width, height);
- mSurfaceWidth = width;
- mSurfaceHeight = height;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (mNativeCompositorView == 0) return;
+
nativeSurfaceCreated(mNativeCompositorView);
+ mFramesUntilHideBackground = 2;
mRenderHost.onSurfaceCreated();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (mNativeCompositorView == 0) return;
+
nativeSurfaceDestroyed(mNativeCompositorView);
}
@@ -264,29 +303,7 @@ public class CompositorView
*/
@CalledByNative
private void onJellyBeanSurfaceDisconnectWorkaround(boolean inOverlayMode) {
- // There is a bug in JellyBean because of which we will not be able to
- // reconnect to the existing Surface after we launch a new GPU process.
- // We simply trick the JB Android code to allocate a new Surface.
- // It does a strict comparison between the current format and the requested
- // one, even if they are the same in practice. Furthermore, the format
- // does not matter here since the producer-side EGL config overwrites it
- // (but transparency might matter).
- switch (mCurrentPixelFormat) {
- case PixelFormat.OPAQUE:
- mCurrentPixelFormat = PixelFormat.RGBA_8888;
- break;
- case PixelFormat.RGBA_8888:
- mCurrentPixelFormat = inOverlayMode
- ? PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
- break;
- case PixelFormat.TRANSLUCENT:
- mCurrentPixelFormat = PixelFormat.RGBA_8888;
- break;
- default:
- assert false;
- Log.e(TAG, "Unknown current pixel format.");
- }
- getHolder().setFormat(mCurrentPixelFormat);
+ mCompositorSurfaceManager.recreateSurfaceForJellyBean();
}
/**
@@ -308,6 +325,20 @@ public class CompositorView
}, mFramePresentationDelay);
}
+ // If we're in the middle of a surface swap, then see if we've received a new frame yet for
+ // the new surface before hiding the outgoing surface.
+ if (mFramesUntilHideBackground > 1) {
+ // We need at least one more frame before we hide the outgoing surface. Make sure that
+ // there will be a frame.
+ mFramesUntilHideBackground--;
+ requestRender();
+ } else if (mFramesUntilHideBackground == 1) {
+ // We can hide the outgoing surface, since the incoming one has a frame. It's okay if
+ // we've don't have an unowned surface.
+ mFramesUntilHideBackground = 0;
+ mCompositorSurfaceManager.doneWithUnownedSurface();
Ted C 2017/02/06 18:44:17 Looking at the code in doneWithUnownedSurface, it
liberato (no reviews please) 2017/02/14 17:22:24 it will doneWithUnowned -> detachSurfaceLater a fe
+ }
+
mRenderHost.onSwapBuffersCompleted(pendingSwapBuffersCount);
}
@@ -351,6 +382,25 @@ public class CompositorView
TraceEvent.end("CompositorView:finalizeLayers");
}
+ @Override
+ public void setWillNotDraw(boolean willNotDraw) {
+ mWillNotDraw = willNotDraw;
+ if (mCompositorSurfaceManager != null) {
+ mCompositorSurfaceManager.setWillNotDraw(mWillNotDraw);
+ }
+ }
+
+ @Override
+ public void setBackgroundDrawable(Drawable background) {
+ // We override setBackgroundDrawable since that's the common entry point from all the
+ // setBackground* calls in View. We still call to setBackground on the SurfaceView because
+ // SetBackgroundDrawable is depricated, and the semantics are the same I think.
Ted C 2017/02/06 18:44:17 depr[e]cated
liberato (no reviews please) 2017/02/14 17:22:24 Done.
+ super.setBackgroundDrawable(background);
Ted C 2017/02/06 18:44:17 should we actually set the drawable in both places
liberato (no reviews please) 2017/02/14 17:22:24 i think that we should. i tried with / without bo
+ if (mCompositorSurfaceManager != null) {
+ mCompositorSurfaceManager.setBackgroundDrawable(background);
+ }
+ }
+
// Implemented in native
private native long nativeInit(boolean lowMemDevice, long nativeWindowAndroid,
LayerTitleCache layerTitleCache, TabContentManager tabContentManager);

Powered by Google App Engine
This is Rietveld 408576698