diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index e8725f00ffdff..4c7bfd2526577 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -942,9 +942,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall // When the listener is updated, we will get at least a single position update call so we can // guarantee any changes we post will be applied. private void replacePositionUpdateListener(int surfaceWidth, int surfaceHeight, - @Nullable Transaction geometryTransaction) { + Transaction geometryTransaction) { if (mPositionListener != null) { mRenderNode.removePositionUpdateListener(mPositionListener); + geometryTransaction = mPositionListener.getTransaction().merge(geometryTransaction); } mPositionListener = new SurfaceViewPositionUpdateListener(surfaceWidth, surfaceHeight, geometryTransaction); @@ -952,7 +953,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } private boolean performSurfaceTransaction(ViewRootImpl viewRoot, Translator translator, - boolean creating, boolean sizeChanged, boolean hintChanged) { + boolean creating, boolean sizeChanged, boolean hintChanged, + Transaction geometryTransaction) { boolean realSizeChanged = false; mSurfaceLock.lock(); @@ -990,10 +992,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mSurfaceAlpha = alpha; } - // While creating the surface, we will set it's initial - // geometry. Outside of that though, we should generally - // leave it to the RenderThread. - Transaction geometryTransaction = new Transaction(); geometryTransaction.setCornerRadius(mSurfaceControl, mCornerRadius); if ((sizeChanged || hintChanged) && !creating) { setBufferSize(geometryTransaction); @@ -1016,20 +1014,18 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mSurfaceHeight); } - boolean applyChangesOnRenderThread = - sizeChanged && !creating && isHardwareAccelerated(); if (isHardwareAccelerated()) { // This will consume the passed in transaction and the transaction will be // applied on a render worker thread. replacePositionUpdateListener(mSurfaceWidth, mSurfaceHeight, - applyChangesOnRenderThread ? geometryTransaction : null); + geometryTransaction); } if (DEBUG_POSITION) { Log.d(TAG, String.format( - "%d updateSurfacePosition %s" + "%d performSurfaceTransaction %s " + "position = [%d, %d, %d, %d] surfaceSize = %dx%d", System.identityHashCode(this), - applyChangesOnRenderThread ? "RenderWorker" : "UiThread", + isHardwareAccelerated() ? "RenderWorker" : "UI Thread", mScreenRect.left, mScreenRect.top, mScreenRect.right, mScreenRect.bottom, mSurfaceWidth, mSurfaceHeight)); } @@ -1141,12 +1137,14 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall final Rect surfaceInsets = viewRoot.mWindowAttributes.surfaceInsets; mScreenRect.offset(surfaceInsets.left, surfaceInsets.top); - + // Collect all geometry changes and apply these changes on the RenderThread worker + // via the RenderNode.PositionUpdateListener. + final Transaction geometryTransaction = new Transaction(); if (creating) { updateOpaqueFlag(); final String name = "SurfaceView[" + viewRoot.getTitle().toString() + "]"; if (mUseBlastAdapter) { - createBlastSurfaceControls(viewRoot, name); + createBlastSurfaceControls(viewRoot, name, geometryTransaction); } else { mDeferredDestroySurfaceControl = createSurfaceControls(viewRoot, name); } @@ -1155,7 +1153,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } final boolean realSizeChanged = performSurfaceTransaction(viewRoot, - translator, creating, sizeChanged, hintChanged); + translator, creating, sizeChanged, hintChanged, geometryTransaction); final boolean redrawNeeded = sizeChanged || creating || hintChanged || (mVisible && !mDrawFinished); @@ -1322,7 +1320,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall // is still alive, the old buffers will continue to be presented until replaced by buffers from // the new adapter. This means we do not need to track the old surface control and destroy it // after the client has drawn to avoid any flickers. - private void createBlastSurfaceControls(ViewRootImpl viewRoot, String name) { + private void createBlastSurfaceControls(ViewRootImpl viewRoot, String name, + Transaction geometryTransaction) { if (mSurfaceControl == null) { mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) .setName(name) @@ -1363,8 +1362,9 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } mTransformHint = viewRoot.getBufferTransformHint(); mBlastSurfaceControl.setTransformHint(mTransformHint); - mBlastBufferQueue = new BLASTBufferQueue(name, mBlastSurfaceControl, mSurfaceWidth, - mSurfaceHeight, mFormat); + mBlastBufferQueue = new BLASTBufferQueue(name); + mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat, + geometryTransaction); } private void onDrawFinished() { @@ -1545,6 +1545,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall applyOrMergeTransaction(mRtTransaction, frameNumber); } } + + public Transaction getTransaction() { + return mPositionChangedTransaction; + } } private SurfaceViewPositionUpdateListener mPositionListener = null; @@ -1638,6 +1642,11 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall @Override public void setFixedSize(int width, int height) { if (mRequestedWidth != width || mRequestedHeight != height) { + if (DEBUG_POSITION) { + Log.d(TAG, String.format("%d setFixedSize %dx%d -> %dx%d", + System.identityHashCode(this), mRequestedWidth, mRequestedHeight, width, + height)); + } mRequestedWidth = width; mRequestedHeight = height; requestLayout(); @@ -1647,6 +1656,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall @Override public void setSizeFromLayout() { if (mRequestedWidth != -1 || mRequestedHeight != -1) { + if (DEBUG_POSITION) { + Log.d(TAG, String.format("%d setSizeFromLayout was %dx%d", + System.identityHashCode(this), mRequestedWidth, mRequestedHeight)); + } mRequestedWidth = mRequestedHeight = -1; requestLayout(); } diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp index 3b7328e72913a..1382a99c46739 100644 --- a/core/jni/android_graphics_BLASTBufferQueue.cpp +++ b/core/jni/android_graphics_BLASTBufferQueue.cpp @@ -67,21 +67,19 @@ private: } }; -static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName, jlong surfaceControl, - jlong width, jlong height, jint format) { - String8 str8; - if (jName) { - const jchar* str16 = env->GetStringCritical(jName, nullptr); - if (str16) { - str8 = String8(reinterpret_cast(str16), env->GetStringLength(jName)); - env->ReleaseStringCritical(jName, str16); - str16 = nullptr; - } - } - std::string name = str8.string(); +static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName) { + ScopedUtfChars name(env, jName); + sp queue = new BLASTBufferQueue(name.c_str()); + queue->incStrong((void*)nativeCreate); + return reinterpret_cast(queue.get()); +} + +static jlong nativeCreateAndUpdate(JNIEnv* env, jclass clazz, jstring jName, jlong surfaceControl, + jlong width, jlong height, jint format) { + ScopedUtfChars name(env, jName); sp queue = - new BLASTBufferQueue(name, reinterpret_cast(surfaceControl), width, - height, format); + new BLASTBufferQueue(name.c_str(), reinterpret_cast(surfaceControl), + width, height, format); queue->incStrong((void*)nativeCreate); return reinterpret_cast(queue.get()); } @@ -142,7 +140,8 @@ static jlong nativeGetLastAcquiredFrameNum(JNIEnv* env, jclass clazz, jlong ptr) static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ // clang-format off - {"nativeCreate", "(Ljava/lang/String;JJJI)J", (void*)nativeCreate}, + {"nativeCreate", "(Ljava/lang/String;)J", (void*)nativeCreate}, + {"nativeCreateAndUpdate", "(Ljava/lang/String;JJJI)J", (void*)nativeCreateAndUpdate}, {"nativeGetSurface", "(JZ)Landroid/view/Surface;", (void*)nativeGetSurface}, {"nativeDestroy", "(J)V", (void*)nativeDestroy}, {"nativeSetNextTransaction", "(JJ)V", (void*)nativeSetNextTransaction}, diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java index 2393eaf32e9a1..2faa532a241df 100644 --- a/graphics/java/android/graphics/BLASTBufferQueue.java +++ b/graphics/java/android/graphics/BLASTBufferQueue.java @@ -27,8 +27,9 @@ public final class BLASTBufferQueue { // Note: This field is accessed by native code. public long mNativeObject; // BLASTBufferQueue* - private static native long nativeCreate(String name, long surfaceControl, long width, + private static native long nativeCreateAndUpdate(String name, long surfaceControl, long width, long height, int format); + private static native long nativeCreate(String name); private static native void nativeDestroy(long ptr); private static native Surface nativeGetSurface(long ptr, boolean includeSurfaceControlHandle); private static native void nativeSetNextTransaction(long ptr, long transactionPtr); @@ -54,7 +55,11 @@ public final class BLASTBufferQueue { /** Create a new connection with the surface flinger. */ public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height, @PixelFormat.Format int format) { - mNativeObject = nativeCreate(name, sc.mNativeObject, width, height, format); + mNativeObject = nativeCreateAndUpdate(name, sc.mNativeObject, width, height, format); + } + + public BLASTBufferQueue(String name) { + mNativeObject = nativeCreate(name); } public void destroy() {