Loading core/java/android/provider/Settings.java +8 −0 Original line number Diff line number Diff line Loading @@ -9708,6 +9708,14 @@ public final class Settings { public static final String DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR = "render_shadows_in_compositor"; /** * If true, submit buffers using blast in SurfaceView. * (0 = false, 1 = true) * @hide */ public static final String DEVELOPMENT_USE_BLAST_ADAPTER_SV = "use_blast_adapter_sv"; /** * Whether user has enabled development settings. */ Loading core/java/android/view/Surface.java +34 −8 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.res.CompatibilityInfo.Translator; import android.graphics.BLASTBufferQueue; import android.graphics.Canvas; import android.graphics.ColorSpace; import android.graphics.HardwareRenderer; Loading Loading @@ -66,6 +67,8 @@ public class Surface implements Parcelable { private static native long nativeCreateFromSurfaceControl(long surfaceControlNativeObject); private static native long nativeGetFromSurfaceControl(long surfaceObject, long surfaceControlNativeObject); private static native long nativeGetFromBlastBufferQueue(long surfaceObject, long blastBufferQueueNativeObject); private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty) throws OutOfResourcesException; Loading Loading @@ -534,6 +537,18 @@ public class Surface implements Parcelable { } } private void updateNativeObject(long newNativeObject) { synchronized (mLock) { if (newNativeObject == mNativeObject) { return; } if (mNativeObject != 0) { nativeRelease(mNativeObject); } setNativeObjectLocked(newNativeObject); } } /** * Copy another surface to this one. This surface now holds a reference * to the same data as the original surface, and is -not- the owner. Loading @@ -557,16 +572,27 @@ public class Surface implements Parcelable { "null SurfaceControl native object. Are you using a released SurfaceControl?"); } long newNativeObject = nativeGetFromSurfaceControl(mNativeObject, surfaceControlPtr); synchronized (mLock) { if (newNativeObject == mNativeObject) { return; updateNativeObject(newNativeObject); } if (mNativeObject != 0) { nativeRelease(mNativeObject); /** * Update the surface if the BLASTBufferQueue IGraphicBufferProducer is different from this * surface's IGraphicBufferProducer. * * @param queue {@link BLASTBufferQueue} to copy from. * @hide */ public void copyFrom(BLASTBufferQueue queue) { if (queue == null) { throw new IllegalArgumentException("queue must not be null"); } setNativeObjectLocked(newNativeObject); long blastBufferQueuePtr = queue.mNativeObject; if (blastBufferQueuePtr == 0) { throw new NullPointerException("Null BLASTBufferQueue native object"); } long newNativeObject = nativeGetFromBlastBufferQueue(mNativeObject, blastBufferQueuePtr); updateNativeObject(newNativeObject); } /** Loading core/java/android/view/SurfaceView.java +173 −79 Original line number Diff line number Diff line Loading @@ -23,8 +23,10 @@ import static android.view.WindowManagerPolicyConstants.APPLICATION_PANEL_SUBLAY import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; import android.content.res.CompatibilityInfo.Translator; import android.graphics.BLASTBufferQueue; import android.graphics.BlendMode; import android.graphics.Canvas; import android.graphics.Color; Loading @@ -41,6 +43,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; import android.util.AttributeSet; import android.util.Log; import android.view.SurfaceControl.Transaction; Loading Loading @@ -232,6 +235,19 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall SurfaceControlViewHost.SurfacePackage mSurfacePackage; /** * Returns {@code true} if buffers should be submitted via blast */ private static boolean useBlastAdapter(Context context) { ContentResolver contentResolver = context.getContentResolver(); return Settings.Global.getInt(contentResolver, Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV, 0 /* default */) == 1; } private final boolean mUseBlastAdapter; private SurfaceControl mBlastSurfaceControl; private BLASTBufferQueue mBlastBufferQueue; public SurfaceView(Context context) { this(context, null); } Loading @@ -252,6 +268,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall public SurfaceView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes, boolean disableBackgroundLayer) { super(context, attrs, defStyleAttr, defStyleRes); mUseBlastAdapter = useBlastAdapter(context); mRenderNode.addPositionUpdateListener(mPositionListener); setWillNotDraw(true); Loading Loading @@ -531,7 +548,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mRequestedVisible = false; updateSurface(); releaseSurfaces(); tryReleaseSurfaces(); // We don't release this as part of releaseSurfaces as // that is also called on transient visibility changes. We can't Loading Loading @@ -875,7 +892,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall return t; } private void releaseSurfaces() { private void tryReleaseSurfaces() { mSurfaceAlpha = 1f; synchronized (mSurfaceControlLock) { Loading @@ -886,15 +903,27 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall return; } releaseSurfaces(mTmpTransaction); mTmpTransaction.apply(); } } private void releaseSurfaces(Transaction transaction) { if (mSurfaceControl != null) { mTmpTransaction.remove(mSurfaceControl); transaction.remove(mSurfaceControl); mSurfaceControl = null; } if (mBackgroundControl != null) { mTmpTransaction.remove(mBackgroundControl); transaction.remove(mBackgroundControl); mBackgroundControl = null; } mTmpTransaction.apply(); if (mBlastSurfaceControl != null) { transaction.remove(mBlastSurfaceControl); mBlastSurfaceControl = null; } if (mBlastBufferQueue != null) { mBlastBufferQueue.destroy(); mBlastBufferQueue = null; } } Loading @@ -914,7 +943,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall if (viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) { notifySurfaceDestroyed(); releaseSurfaces(); tryReleaseSurfaces(); return; } Loading Loading @@ -979,45 +1008,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mScreenRect.offset(surfaceInsets.left, surfaceInsets.top); if (creating) { mDeferredDestroySurfaceControl = mSurfaceControl; updateOpaqueFlag(); // SurfaceView hierarchy // ViewRootImpl surface // - bounds layer (crops all child surfaces to parent surface insets) // - SurfaceView surface (drawn relative to ViewRootImpl surface) // - Background color layer (drawn behind all SurfaceView surfaces) // // The bounds layer is used to crop the surface view so it does not draw into // the parent surface inset region. Since there can be multiple surface views // below or above the parent surface, one option is to create multiple bounds // layer for each z order. The other option, the one implement is to create // a single bounds layer and set z order for each child surface relative to the // parent surface. // When creating the surface view, we parent it to the bounds layer and then // set the relative z order. When the parent surface changes, we have to // make sure to update the relative z via ViewRootImpl.SurfaceChangedCallback. final String name = "SurfaceView - " + viewRoot.getTitle().toString(); mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) .setName(name) .setLocalOwnerView(this) .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0) .setBufferSize(mSurfaceWidth, mSurfaceHeight) .setFormat(mFormat) .setParent(viewRoot.getBoundsLayer()) .setFlags(mSurfaceFlags) .setCallsite("SurfaceView.updateSurface") .build(); mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession) .setName("Background for -" + name) .setLocalOwnerView(this) .setOpaque(true) .setColorLayer() .setParent(mSurfaceControl) .setCallsite("SurfaceView.updateSurface") .build(); mDeferredDestroySurfaceControl = createSurfaceControls(viewRoot); } else if (mSurfaceControl == null) { return; } Loading Loading @@ -1090,8 +1082,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius); if (sizeChanged && !creating) { mTmpTransaction.setBufferSize(mSurfaceControl, mSurfaceWidth, mSurfaceHeight); setBufferSize(mTmpTransaction); } mTmpTransaction.apply(); Loading Loading @@ -1133,19 +1124,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall notifySurfaceDestroyed(); } if (creating) { mSurface.copyFrom(mSurfaceControl); } if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.O) { // Some legacy applications use the underlying native {@link Surface} object // as a key to whether anything has changed. In these cases, updates to the // existing {@link Surface} will be ignored when the size changes. // Therefore, we must explicitly recreate the {@link Surface} in these // cases. mSurface.createFrom(mSurfaceControl); } copySurface(creating /* surfaceControlCreated */, sizeChanged); if (visible && mSurface.isValid()) { if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) { Loading Loading @@ -1189,7 +1168,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } finally { mIsCreating = false; if (mSurfaceControl != null && !mSurfaceCreated) { releaseSurfaces(); tryReleaseSurfaces(); } } } catch (Exception ex) { Loading @@ -1202,6 +1181,119 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } } /** * Copy the Surface from the SurfaceControl or the blast adapter. * * @param surfaceControlCreated true if we created the SurfaceControl and need to update our * Surface if needed. * @param bufferSizeChanged true if the BufferSize has changed and we need to recreate the * Surface for compatibility reasons. */ private void copySurface(boolean surfaceControlCreated, boolean bufferSizeChanged) { if (surfaceControlCreated) { if (mUseBlastAdapter) { mSurface.copyFrom(mBlastBufferQueue); } else { mSurface.copyFrom(mSurfaceControl); } } if (bufferSizeChanged && getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.O) { // Some legacy applications use the underlying native {@link Surface} object // as a key to whether anything has changed. In these cases, updates to the // existing {@link Surface} will be ignored when the size changes. // Therefore, we must explicitly recreate the {@link Surface} in these // cases. if (mUseBlastAdapter) { mSurface.transferFrom(mBlastBufferQueue.createSurface()); } else { mSurface.createFrom(mSurfaceControl); } } } private void setBufferSize(Transaction transaction) { if (mUseBlastAdapter) { mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight); } else { transaction.setBufferSize(mSurfaceControl, mSurfaceWidth, mSurfaceHeight); } } /** * Creates the surface control hierarchy as follows * ViewRootImpl surface * bounds layer (crops all child surfaces to parent surface insets) * * SurfaceView surface (drawn relative to ViewRootImpl surface) * * Blast surface (if enabled) * * Background color layer (drawn behind all SurfaceView surfaces) * * The bounds layer is used to crop the surface view so it does not draw into the parent * surface inset region. Since there can be multiple surface views below or above the parent * surface, one option is to create multiple bounds layer for each z order. The other option, * the one implement is to create a single bounds layer and set z order for each child surface * relative to the parent surface. * When creating the surface view, we parent it to the bounds layer and then set the relative z * order. When the parent surface changes, we have to make sure to update the relative z via * ViewRootImpl.SurfaceChangedCallback. * * @return previous SurfaceControl where the content was rendered. In the surface is switched * out, the old surface can be persevered until the new one has drawn by keeping the reference * of the old SurfaceControl alive. */ private SurfaceControl createSurfaceControls(ViewRootImpl viewRoot) { final String name = "SurfaceView - " + viewRoot.getTitle().toString(); SurfaceControl.Builder builder = new SurfaceControl.Builder(mSurfaceSession) .setName(name) .setLocalOwnerView(this) .setParent(viewRoot.getBoundsLayer()) .setCallsite("SurfaceView.updateSurface"); final SurfaceControl previousSurfaceControl; if (mUseBlastAdapter) { mSurfaceControl = builder .setContainerLayer() .build(); previousSurfaceControl = mBlastSurfaceControl; mBlastSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) .setName(name + "(BLAST)") .setLocalOwnerView(this) .setBufferSize(mSurfaceWidth, mSurfaceHeight) .setFormat(mFormat) .setParent(mSurfaceControl) .setFlags(mSurfaceFlags) .setHidden(false) .setBLASTLayer() .setCallsite("SurfaceView.updateSurface") .build(); mBlastBufferQueue = new BLASTBufferQueue( mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, true /* TODO */); } else { previousSurfaceControl = mSurfaceControl; mSurfaceControl = builder .setBufferSize(mSurfaceWidth, mSurfaceHeight) .setFlags(mSurfaceFlags) .setFormat(mFormat) .build(); mBlastSurfaceControl = null; mBlastBufferQueue = null; } mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession) .setName("Background for " + name) .setLocalOwnerView(this) .setOpaque(true) .setColorLayer() .setParent(mSurfaceControl) .setCallsite("SurfaceView.updateSurface") .build(); return previousSurfaceControl; } private void onDrawFinished() { if (DEBUG) { Log.i(TAG, System.identityHashCode(this) + " " Loading Loading @@ -1348,16 +1440,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } } private void releaseSurfaces(Transaction t) { if (mRtReleaseSurfaces) { mRtReleaseSurfaces = false; t.remove(mSurfaceControl); t.remove(mBackgroundControl); mSurfaceControl = null; mBackgroundControl = null; } } @Override public void positionLost(long frameNumber) { final ViewRootImpl viewRoot = getViewRootImpl(); Loading @@ -1380,15 +1462,21 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall if (useBLAST) { synchronized (viewRoot.getBlastTransactionLock()) { viewRoot.getBLASTSyncTransaction().hide(mSurfaceControl); if (mRtReleaseSurfaces) { mRtReleaseSurfaces = false; releaseSurfaces(viewRoot.getBLASTSyncTransaction()); } } } else { if (frameNumber > 0 && viewRoot != null && viewRoot.mSurface.isValid()) { mRtTransaction.deferTransactionUntil(mSurfaceControl, viewRoot.getRenderSurfaceControl(), frameNumber); } mRtTransaction.hide(mSurfaceControl); if (mRtReleaseSurfaces) { mRtReleaseSurfaces = false; releaseSurfaces(mRtTransaction); } // If we aren't using BLAST, we apply the transaction locally, otherwise we let // the ViewRoot apply it for us. // If the ViewRoot is null, we behave as if we aren't using BLAST so we need to Loading Loading @@ -1716,7 +1804,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall * @param p The SurfacePackage to embed. */ public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) { final SurfaceControl sc = p != null ? p.getSurfaceControl() : null; final SurfaceControl lastSc = mSurfacePackage != null ? mSurfacePackage.getSurfaceControl() : null; if (mSurfaceControl != null && lastSc != null) { Loading @@ -1733,7 +1820,14 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall SurfaceControlViewHost.SurfacePackage p) { initEmbeddedHierarchyForAccessibility(p); final SurfaceControl sc = p.getSurfaceControl(); t.reparent(sc, mSurfaceControl).show(sc); final SurfaceControl parent; if (mUseBlastAdapter) { parent = mBlastSurfaceControl; } else { parent = mSurfaceControl; } t.reparent(sc, parent).show(sc); } /** @hide */ Loading core/java/android/view/ViewRootImpl.java +2 −2 Original line number Diff line number Diff line Loading @@ -1810,7 +1810,7 @@ public final class ViewRootImpl implements ViewParent, mBlastSurfaceControl, width, height, mEnableTripleBuffering); // We only return the Surface the first time, as otherwise // it hasn't changed and there is no need to update. ret = mBlastBufferQueue.getSurface(); ret = mBlastBufferQueue.createSurface(); } else { mBlastBufferQueue.update(mBlastSurfaceControl, width, height); } Loading core/jni/android_view_Surface.cpp +47 −33 Original line number Diff line number Diff line Loading @@ -32,9 +32,10 @@ #include "android_os_Parcel.h" #include <binder/Parcel.h> #include <gui/BLASTBufferQueue.h> #include <gui/Surface.h> #include <gui/view/Surface.h> #include <gui/SurfaceControl.h> #include <gui/view/Surface.h> #include <ui/GraphicBuffer.h> #include <ui/Rect.h> Loading Loading @@ -300,6 +301,26 @@ static jlong nativeGetFromSurfaceControl(JNIEnv* env, jclass clazz, return reinterpret_cast<jlong>(surface.get()); } static jlong nativeGetFromBlastBufferQueue(JNIEnv* env, jclass clazz, jlong nativeObject, jlong blastBufferQueueNativeObj) { Surface* self(reinterpret_cast<Surface*>(nativeObject)); sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(blastBufferQueueNativeObj); const sp<IGraphicBufferProducer>& bufferProducer = queue->getIGraphicBufferProducer(); // If the underlying IGBP's are the same, we don't need to do anything. if (self != nullptr && IInterface::asBinder(self->getIGraphicBufferProducer()) == IInterface::asBinder(bufferProducer)) { return nativeObject; } sp<Surface> surface(new Surface(bufferProducer, true)); if (surface != NULL) { surface->incStrong(&sRefBaseOwner); } return reinterpret_cast<jlong>(surface.get()); } static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz, jlong nativeObject, jobject parcelObj) { Parcel* parcel = parcelForJavaObject(env, parcelObj); Loading Loading @@ -430,26 +451,18 @@ static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jf static const JNINativeMethod gSurfaceMethods[] = { {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)J", (void*)nativeCreateFromSurfaceTexture}, {"nativeRelease", "(J)V", (void*)nativeRelease }, {"nativeIsValid", "(J)Z", (void*)nativeIsValid }, {"nativeIsConsumerRunningBehind", "(J)Z", (void*)nativeIsConsumerRunningBehind }, {"nativeRelease", "(J)V", (void*)nativeRelease}, {"nativeIsValid", "(J)Z", (void*)nativeIsValid}, {"nativeIsConsumerRunningBehind", "(J)Z", (void*)nativeIsConsumerRunningBehind}, {"nativeLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)J", (void*)nativeLockCanvas}, {"nativeUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)V", (void*)nativeUnlockCanvasAndPost}, {"nativeAllocateBuffers", "(J)V", (void*)nativeAllocateBuffers }, {"nativeCreateFromSurfaceControl", "(J)J", (void*)nativeCreateFromSurfaceControl }, {"nativeGetFromSurfaceControl", "(JJ)J", (void*)nativeGetFromSurfaceControl }, {"nativeReadFromParcel", "(JLandroid/os/Parcel;)J", (void*)nativeReadFromParcel }, {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel }, {"nativeAllocateBuffers", "(J)V", (void*)nativeAllocateBuffers}, {"nativeCreateFromSurfaceControl", "(J)J", (void*)nativeCreateFromSurfaceControl}, {"nativeGetFromSurfaceControl", "(JJ)J", (void*)nativeGetFromSurfaceControl}, {"nativeReadFromParcel", "(JLandroid/os/Parcel;)J", (void*)nativeReadFromParcel}, {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel}, {"nativeGetWidth", "(J)I", (void*)nativeGetWidth}, {"nativeGetHeight", "(J)I", (void*)nativeGetHeight}, {"nativeGetNextFrameNumber", "(J)J", (void*)nativeGetNextFrameNumber}, Loading @@ -460,6 +473,7 @@ static const JNINativeMethod gSurfaceMethods[] = { {"nativeSetSharedBufferModeEnabled", "(JZ)I", (void*)nativeSetSharedBufferModeEnabled}, {"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled}, {"nativeSetFrameRate", "(JFI)I", (void*)nativeSetFrameRate}, {"nativeGetFromBlastBufferQueue", "(JJ)J", (void*)nativeGetFromBlastBufferQueue}, }; int register_android_view_Surface(JNIEnv* env) Loading Loading
core/java/android/provider/Settings.java +8 −0 Original line number Diff line number Diff line Loading @@ -9708,6 +9708,14 @@ public final class Settings { public static final String DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR = "render_shadows_in_compositor"; /** * If true, submit buffers using blast in SurfaceView. * (0 = false, 1 = true) * @hide */ public static final String DEVELOPMENT_USE_BLAST_ADAPTER_SV = "use_blast_adapter_sv"; /** * Whether user has enabled development settings. */ Loading
core/java/android/view/Surface.java +34 −8 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ActivityInfo; import android.content.res.CompatibilityInfo.Translator; import android.graphics.BLASTBufferQueue; import android.graphics.Canvas; import android.graphics.ColorSpace; import android.graphics.HardwareRenderer; Loading Loading @@ -66,6 +67,8 @@ public class Surface implements Parcelable { private static native long nativeCreateFromSurfaceControl(long surfaceControlNativeObject); private static native long nativeGetFromSurfaceControl(long surfaceObject, long surfaceControlNativeObject); private static native long nativeGetFromBlastBufferQueue(long surfaceObject, long blastBufferQueueNativeObject); private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty) throws OutOfResourcesException; Loading Loading @@ -534,6 +537,18 @@ public class Surface implements Parcelable { } } private void updateNativeObject(long newNativeObject) { synchronized (mLock) { if (newNativeObject == mNativeObject) { return; } if (mNativeObject != 0) { nativeRelease(mNativeObject); } setNativeObjectLocked(newNativeObject); } } /** * Copy another surface to this one. This surface now holds a reference * to the same data as the original surface, and is -not- the owner. Loading @@ -557,16 +572,27 @@ public class Surface implements Parcelable { "null SurfaceControl native object. Are you using a released SurfaceControl?"); } long newNativeObject = nativeGetFromSurfaceControl(mNativeObject, surfaceControlPtr); synchronized (mLock) { if (newNativeObject == mNativeObject) { return; updateNativeObject(newNativeObject); } if (mNativeObject != 0) { nativeRelease(mNativeObject); /** * Update the surface if the BLASTBufferQueue IGraphicBufferProducer is different from this * surface's IGraphicBufferProducer. * * @param queue {@link BLASTBufferQueue} to copy from. * @hide */ public void copyFrom(BLASTBufferQueue queue) { if (queue == null) { throw new IllegalArgumentException("queue must not be null"); } setNativeObjectLocked(newNativeObject); long blastBufferQueuePtr = queue.mNativeObject; if (blastBufferQueuePtr == 0) { throw new NullPointerException("Null BLASTBufferQueue native object"); } long newNativeObject = nativeGetFromBlastBufferQueue(mNativeObject, blastBufferQueuePtr); updateNativeObject(newNativeObject); } /** Loading
core/java/android/view/SurfaceView.java +173 −79 Original line number Diff line number Diff line Loading @@ -23,8 +23,10 @@ import static android.view.WindowManagerPolicyConstants.APPLICATION_PANEL_SUBLAY import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; import android.content.res.CompatibilityInfo.Translator; import android.graphics.BLASTBufferQueue; import android.graphics.BlendMode; import android.graphics.Canvas; import android.graphics.Color; Loading @@ -41,6 +43,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; import android.util.AttributeSet; import android.util.Log; import android.view.SurfaceControl.Transaction; Loading Loading @@ -232,6 +235,19 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall SurfaceControlViewHost.SurfacePackage mSurfacePackage; /** * Returns {@code true} if buffers should be submitted via blast */ private static boolean useBlastAdapter(Context context) { ContentResolver contentResolver = context.getContentResolver(); return Settings.Global.getInt(contentResolver, Settings.Global.DEVELOPMENT_USE_BLAST_ADAPTER_SV, 0 /* default */) == 1; } private final boolean mUseBlastAdapter; private SurfaceControl mBlastSurfaceControl; private BLASTBufferQueue mBlastBufferQueue; public SurfaceView(Context context) { this(context, null); } Loading @@ -252,6 +268,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall public SurfaceView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes, boolean disableBackgroundLayer) { super(context, attrs, defStyleAttr, defStyleRes); mUseBlastAdapter = useBlastAdapter(context); mRenderNode.addPositionUpdateListener(mPositionListener); setWillNotDraw(true); Loading Loading @@ -531,7 +548,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mRequestedVisible = false; updateSurface(); releaseSurfaces(); tryReleaseSurfaces(); // We don't release this as part of releaseSurfaces as // that is also called on transient visibility changes. We can't Loading Loading @@ -875,7 +892,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall return t; } private void releaseSurfaces() { private void tryReleaseSurfaces() { mSurfaceAlpha = 1f; synchronized (mSurfaceControlLock) { Loading @@ -886,15 +903,27 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall return; } releaseSurfaces(mTmpTransaction); mTmpTransaction.apply(); } } private void releaseSurfaces(Transaction transaction) { if (mSurfaceControl != null) { mTmpTransaction.remove(mSurfaceControl); transaction.remove(mSurfaceControl); mSurfaceControl = null; } if (mBackgroundControl != null) { mTmpTransaction.remove(mBackgroundControl); transaction.remove(mBackgroundControl); mBackgroundControl = null; } mTmpTransaction.apply(); if (mBlastSurfaceControl != null) { transaction.remove(mBlastSurfaceControl); mBlastSurfaceControl = null; } if (mBlastBufferQueue != null) { mBlastBufferQueue.destroy(); mBlastBufferQueue = null; } } Loading @@ -914,7 +943,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall if (viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) { notifySurfaceDestroyed(); releaseSurfaces(); tryReleaseSurfaces(); return; } Loading Loading @@ -979,45 +1008,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mScreenRect.offset(surfaceInsets.left, surfaceInsets.top); if (creating) { mDeferredDestroySurfaceControl = mSurfaceControl; updateOpaqueFlag(); // SurfaceView hierarchy // ViewRootImpl surface // - bounds layer (crops all child surfaces to parent surface insets) // - SurfaceView surface (drawn relative to ViewRootImpl surface) // - Background color layer (drawn behind all SurfaceView surfaces) // // The bounds layer is used to crop the surface view so it does not draw into // the parent surface inset region. Since there can be multiple surface views // below or above the parent surface, one option is to create multiple bounds // layer for each z order. The other option, the one implement is to create // a single bounds layer and set z order for each child surface relative to the // parent surface. // When creating the surface view, we parent it to the bounds layer and then // set the relative z order. When the parent surface changes, we have to // make sure to update the relative z via ViewRootImpl.SurfaceChangedCallback. final String name = "SurfaceView - " + viewRoot.getTitle().toString(); mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) .setName(name) .setLocalOwnerView(this) .setOpaque((mSurfaceFlags & SurfaceControl.OPAQUE) != 0) .setBufferSize(mSurfaceWidth, mSurfaceHeight) .setFormat(mFormat) .setParent(viewRoot.getBoundsLayer()) .setFlags(mSurfaceFlags) .setCallsite("SurfaceView.updateSurface") .build(); mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession) .setName("Background for -" + name) .setLocalOwnerView(this) .setOpaque(true) .setColorLayer() .setParent(mSurfaceControl) .setCallsite("SurfaceView.updateSurface") .build(); mDeferredDestroySurfaceControl = createSurfaceControls(viewRoot); } else if (mSurfaceControl == null) { return; } Loading Loading @@ -1090,8 +1082,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius); if (sizeChanged && !creating) { mTmpTransaction.setBufferSize(mSurfaceControl, mSurfaceWidth, mSurfaceHeight); setBufferSize(mTmpTransaction); } mTmpTransaction.apply(); Loading Loading @@ -1133,19 +1124,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall notifySurfaceDestroyed(); } if (creating) { mSurface.copyFrom(mSurfaceControl); } if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.O) { // Some legacy applications use the underlying native {@link Surface} object // as a key to whether anything has changed. In these cases, updates to the // existing {@link Surface} will be ignored when the size changes. // Therefore, we must explicitly recreate the {@link Surface} in these // cases. mSurface.createFrom(mSurfaceControl); } copySurface(creating /* surfaceControlCreated */, sizeChanged); if (visible && mSurface.isValid()) { if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) { Loading Loading @@ -1189,7 +1168,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } finally { mIsCreating = false; if (mSurfaceControl != null && !mSurfaceCreated) { releaseSurfaces(); tryReleaseSurfaces(); } } } catch (Exception ex) { Loading @@ -1202,6 +1181,119 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } } /** * Copy the Surface from the SurfaceControl or the blast adapter. * * @param surfaceControlCreated true if we created the SurfaceControl and need to update our * Surface if needed. * @param bufferSizeChanged true if the BufferSize has changed and we need to recreate the * Surface for compatibility reasons. */ private void copySurface(boolean surfaceControlCreated, boolean bufferSizeChanged) { if (surfaceControlCreated) { if (mUseBlastAdapter) { mSurface.copyFrom(mBlastBufferQueue); } else { mSurface.copyFrom(mSurfaceControl); } } if (bufferSizeChanged && getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.O) { // Some legacy applications use the underlying native {@link Surface} object // as a key to whether anything has changed. In these cases, updates to the // existing {@link Surface} will be ignored when the size changes. // Therefore, we must explicitly recreate the {@link Surface} in these // cases. if (mUseBlastAdapter) { mSurface.transferFrom(mBlastBufferQueue.createSurface()); } else { mSurface.createFrom(mSurfaceControl); } } } private void setBufferSize(Transaction transaction) { if (mUseBlastAdapter) { mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight); } else { transaction.setBufferSize(mSurfaceControl, mSurfaceWidth, mSurfaceHeight); } } /** * Creates the surface control hierarchy as follows * ViewRootImpl surface * bounds layer (crops all child surfaces to parent surface insets) * * SurfaceView surface (drawn relative to ViewRootImpl surface) * * Blast surface (if enabled) * * Background color layer (drawn behind all SurfaceView surfaces) * * The bounds layer is used to crop the surface view so it does not draw into the parent * surface inset region. Since there can be multiple surface views below or above the parent * surface, one option is to create multiple bounds layer for each z order. The other option, * the one implement is to create a single bounds layer and set z order for each child surface * relative to the parent surface. * When creating the surface view, we parent it to the bounds layer and then set the relative z * order. When the parent surface changes, we have to make sure to update the relative z via * ViewRootImpl.SurfaceChangedCallback. * * @return previous SurfaceControl where the content was rendered. In the surface is switched * out, the old surface can be persevered until the new one has drawn by keeping the reference * of the old SurfaceControl alive. */ private SurfaceControl createSurfaceControls(ViewRootImpl viewRoot) { final String name = "SurfaceView - " + viewRoot.getTitle().toString(); SurfaceControl.Builder builder = new SurfaceControl.Builder(mSurfaceSession) .setName(name) .setLocalOwnerView(this) .setParent(viewRoot.getBoundsLayer()) .setCallsite("SurfaceView.updateSurface"); final SurfaceControl previousSurfaceControl; if (mUseBlastAdapter) { mSurfaceControl = builder .setContainerLayer() .build(); previousSurfaceControl = mBlastSurfaceControl; mBlastSurfaceControl = new SurfaceControl.Builder(mSurfaceSession) .setName(name + "(BLAST)") .setLocalOwnerView(this) .setBufferSize(mSurfaceWidth, mSurfaceHeight) .setFormat(mFormat) .setParent(mSurfaceControl) .setFlags(mSurfaceFlags) .setHidden(false) .setBLASTLayer() .setCallsite("SurfaceView.updateSurface") .build(); mBlastBufferQueue = new BLASTBufferQueue( mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, true /* TODO */); } else { previousSurfaceControl = mSurfaceControl; mSurfaceControl = builder .setBufferSize(mSurfaceWidth, mSurfaceHeight) .setFlags(mSurfaceFlags) .setFormat(mFormat) .build(); mBlastSurfaceControl = null; mBlastBufferQueue = null; } mBackgroundControl = new SurfaceControl.Builder(mSurfaceSession) .setName("Background for " + name) .setLocalOwnerView(this) .setOpaque(true) .setColorLayer() .setParent(mSurfaceControl) .setCallsite("SurfaceView.updateSurface") .build(); return previousSurfaceControl; } private void onDrawFinished() { if (DEBUG) { Log.i(TAG, System.identityHashCode(this) + " " Loading Loading @@ -1348,16 +1440,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall } } private void releaseSurfaces(Transaction t) { if (mRtReleaseSurfaces) { mRtReleaseSurfaces = false; t.remove(mSurfaceControl); t.remove(mBackgroundControl); mSurfaceControl = null; mBackgroundControl = null; } } @Override public void positionLost(long frameNumber) { final ViewRootImpl viewRoot = getViewRootImpl(); Loading @@ -1380,15 +1462,21 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall if (useBLAST) { synchronized (viewRoot.getBlastTransactionLock()) { viewRoot.getBLASTSyncTransaction().hide(mSurfaceControl); if (mRtReleaseSurfaces) { mRtReleaseSurfaces = false; releaseSurfaces(viewRoot.getBLASTSyncTransaction()); } } } else { if (frameNumber > 0 && viewRoot != null && viewRoot.mSurface.isValid()) { mRtTransaction.deferTransactionUntil(mSurfaceControl, viewRoot.getRenderSurfaceControl(), frameNumber); } mRtTransaction.hide(mSurfaceControl); if (mRtReleaseSurfaces) { mRtReleaseSurfaces = false; releaseSurfaces(mRtTransaction); } // If we aren't using BLAST, we apply the transaction locally, otherwise we let // the ViewRoot apply it for us. // If the ViewRoot is null, we behave as if we aren't using BLAST so we need to Loading Loading @@ -1716,7 +1804,6 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall * @param p The SurfacePackage to embed. */ public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) { final SurfaceControl sc = p != null ? p.getSurfaceControl() : null; final SurfaceControl lastSc = mSurfacePackage != null ? mSurfacePackage.getSurfaceControl() : null; if (mSurfaceControl != null && lastSc != null) { Loading @@ -1733,7 +1820,14 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall SurfaceControlViewHost.SurfacePackage p) { initEmbeddedHierarchyForAccessibility(p); final SurfaceControl sc = p.getSurfaceControl(); t.reparent(sc, mSurfaceControl).show(sc); final SurfaceControl parent; if (mUseBlastAdapter) { parent = mBlastSurfaceControl; } else { parent = mSurfaceControl; } t.reparent(sc, parent).show(sc); } /** @hide */ Loading
core/java/android/view/ViewRootImpl.java +2 −2 Original line number Diff line number Diff line Loading @@ -1810,7 +1810,7 @@ public final class ViewRootImpl implements ViewParent, mBlastSurfaceControl, width, height, mEnableTripleBuffering); // We only return the Surface the first time, as otherwise // it hasn't changed and there is no need to update. ret = mBlastBufferQueue.getSurface(); ret = mBlastBufferQueue.createSurface(); } else { mBlastBufferQueue.update(mBlastSurfaceControl, width, height); } Loading
core/jni/android_view_Surface.cpp +47 −33 Original line number Diff line number Diff line Loading @@ -32,9 +32,10 @@ #include "android_os_Parcel.h" #include <binder/Parcel.h> #include <gui/BLASTBufferQueue.h> #include <gui/Surface.h> #include <gui/view/Surface.h> #include <gui/SurfaceControl.h> #include <gui/view/Surface.h> #include <ui/GraphicBuffer.h> #include <ui/Rect.h> Loading Loading @@ -300,6 +301,26 @@ static jlong nativeGetFromSurfaceControl(JNIEnv* env, jclass clazz, return reinterpret_cast<jlong>(surface.get()); } static jlong nativeGetFromBlastBufferQueue(JNIEnv* env, jclass clazz, jlong nativeObject, jlong blastBufferQueueNativeObj) { Surface* self(reinterpret_cast<Surface*>(nativeObject)); sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(blastBufferQueueNativeObj); const sp<IGraphicBufferProducer>& bufferProducer = queue->getIGraphicBufferProducer(); // If the underlying IGBP's are the same, we don't need to do anything. if (self != nullptr && IInterface::asBinder(self->getIGraphicBufferProducer()) == IInterface::asBinder(bufferProducer)) { return nativeObject; } sp<Surface> surface(new Surface(bufferProducer, true)); if (surface != NULL) { surface->incStrong(&sRefBaseOwner); } return reinterpret_cast<jlong>(surface.get()); } static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz, jlong nativeObject, jobject parcelObj) { Parcel* parcel = parcelForJavaObject(env, parcelObj); Loading Loading @@ -430,26 +451,18 @@ static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jf static const JNINativeMethod gSurfaceMethods[] = { {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)J", (void*)nativeCreateFromSurfaceTexture}, {"nativeRelease", "(J)V", (void*)nativeRelease }, {"nativeIsValid", "(J)Z", (void*)nativeIsValid }, {"nativeIsConsumerRunningBehind", "(J)Z", (void*)nativeIsConsumerRunningBehind }, {"nativeRelease", "(J)V", (void*)nativeRelease}, {"nativeIsValid", "(J)Z", (void*)nativeIsValid}, {"nativeIsConsumerRunningBehind", "(J)Z", (void*)nativeIsConsumerRunningBehind}, {"nativeLockCanvas", "(JLandroid/graphics/Canvas;Landroid/graphics/Rect;)J", (void*)nativeLockCanvas}, {"nativeUnlockCanvasAndPost", "(JLandroid/graphics/Canvas;)V", (void*)nativeUnlockCanvasAndPost}, {"nativeAllocateBuffers", "(J)V", (void*)nativeAllocateBuffers }, {"nativeCreateFromSurfaceControl", "(J)J", (void*)nativeCreateFromSurfaceControl }, {"nativeGetFromSurfaceControl", "(JJ)J", (void*)nativeGetFromSurfaceControl }, {"nativeReadFromParcel", "(JLandroid/os/Parcel;)J", (void*)nativeReadFromParcel }, {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel }, {"nativeAllocateBuffers", "(J)V", (void*)nativeAllocateBuffers}, {"nativeCreateFromSurfaceControl", "(J)J", (void*)nativeCreateFromSurfaceControl}, {"nativeGetFromSurfaceControl", "(JJ)J", (void*)nativeGetFromSurfaceControl}, {"nativeReadFromParcel", "(JLandroid/os/Parcel;)J", (void*)nativeReadFromParcel}, {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel}, {"nativeGetWidth", "(J)I", (void*)nativeGetWidth}, {"nativeGetHeight", "(J)I", (void*)nativeGetHeight}, {"nativeGetNextFrameNumber", "(J)J", (void*)nativeGetNextFrameNumber}, Loading @@ -460,6 +473,7 @@ static const JNINativeMethod gSurfaceMethods[] = { {"nativeSetSharedBufferModeEnabled", "(JZ)I", (void*)nativeSetSharedBufferModeEnabled}, {"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled}, {"nativeSetFrameRate", "(JFI)I", (void*)nativeSetFrameRate}, {"nativeGetFromBlastBufferQueue", "(JJ)J", (void*)nativeGetFromBlastBufferQueue}, }; int register_android_view_Surface(JNIEnv* env) Loading