Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f9438b04 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add BlastBufferQueue adapter in SurfaceView"

parents 7eb855d2 cf143d44
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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.
        */
+34 −8
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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.
@@ -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);
    }

    /**
+173 −79
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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);
    }
@@ -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);
@@ -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
@@ -875,7 +892,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
        return t;
    }

    private void releaseSurfaces() {
    private void tryReleaseSurfaces() {
        mSurfaceAlpha = 1f;

        synchronized (mSurfaceControlLock) {
@@ -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;
        }
    }

@@ -914,7 +943,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall

        if (viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
            notifySurfaceDestroyed();
            releaseSurfaces();
            tryReleaseSurfaces();
            return;
        }

@@ -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;
                }
@@ -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();
@@ -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)) {
@@ -1189,7 +1168,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
                } finally {
                    mIsCreating = false;
                    if (mSurfaceControl != null && !mSurfaceCreated) {
                        releaseSurfaces();
                        tryReleaseSurfaces();
                    }
                }
            } catch (Exception ex) {
@@ -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) + " "
@@ -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();
@@ -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
@@ -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) {
@@ -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 */
+2 −2
Original line number Diff line number Diff line
@@ -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);
        }
+47 −33
Original line number Diff line number Diff line
@@ -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>
@@ -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);
@@ -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},
@@ -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