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

Commit daa281da authored by Vishnu Nair's avatar Vishnu Nair
Browse files

BBQ: Recreate BBQ when SurfaceControl changes 2/2

Alternative approach to fab15e55446080bdcfc05ba315e8ef914b0a6f65 which
was racy because the disconnect callback is called without the
BQ lock and the client can continue to modify the BQ state after
disconnecting from the queue.

This approach resets the BQ and BBQ states when the SurfaceControl is
updated. This solves one concrete problem of not relying on the old
SurfaceControl to be destroyed in order to release the currently presented
buffer back to BQ.

In addition this change resets the sync state in BBQ with the rationale
the system does not want to sync on buffers presented on an older
SurfaceControl.

Bug: 197269223
Test: atest BLASTBufferQueueTest
Test: labtest ag/16407859 cf-foldable * 3 (b/197269223#comment40)
Change-Id: I137d3284c4e9216963f9c672f192afd334501ee5
parent 0e27aa3b
Loading
Loading
Loading
Loading
+16 −19
Original line number Diff line number Diff line
@@ -1959,26 +1959,29 @@ public final class ViewRootImpl implements ViewParent,
       return mBoundsLayer;
    }

    Surface getOrCreateBLASTSurface() {
    void updateBlastSurfaceIfNeeded() {
        if (!mSurfaceControl.isValid()) {
            return null;
            return;
        }

        Surface ret = null;
        if (mBlastBufferQueue == null) {
            mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
                mSurfaceSize.x, mSurfaceSize.y,
                mWindowAttributes.format);
            // We only return the Surface the first time, as otherwise
            // it hasn't changed and there is no need to update.
            ret = mBlastBufferQueue.createSurface();
        } else {
        if (mBlastBufferQueue != null && mBlastBufferQueue.isSameSurfaceControl(mSurfaceControl)) {
            mBlastBufferQueue.update(mSurfaceControl,
                mSurfaceSize.x, mSurfaceSize.y,
                mWindowAttributes.format);
            return;
        }

        return ret;
        // If the SurfaceControl has been updated, destroy and recreate the BBQ to reset the BQ and
        // BBQ states.
        if (mBlastBufferQueue != null) {
            mBlastBufferQueue.destroy();
        }
        mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
                mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);
        Surface blastSurface = mBlastBufferQueue.createSurface();
        // Only call transferFrom if the surface has changed to prevent inc the generation ID and
        // causing EGL resources to be recreated.
        mSurface.transferFrom(blastSurface);
    }

    private void setBoundsLayerCrop(Transaction t) {
@@ -7843,13 +7846,7 @@ public final class ViewRootImpl implements ViewParent,
            if (!useBLAST()) {
                mSurface.copyFrom(mSurfaceControl);
            } else {
                final Surface blastSurface = getOrCreateBLASTSurface();
                // If blastSurface == null that means it hasn't changed since the last time we
                // called. In this situation, avoid calling transferFrom as we would then
                // inc the generation ID and cause EGL resources to be recreated.
                if (blastSurface != null) {
                    mSurface.transferFrom(blastSurface);
                }
                updateBlastSurfaceIfNeeded();
            }
            if (mAttachInfo.mThreadedRenderer != null) {
                mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl);
+6 −11
Original line number Diff line number Diff line
@@ -37,16 +37,6 @@ static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring jName) {
    return reinterpret_cast<jlong>(queue.get());
}

static jlong nativeCreateAndUpdate(JNIEnv* env, jclass clazz, jstring jName, jlong surfaceControl,
                                   jlong width, jlong height, jint format) {
    ScopedUtfChars name(env, jName);
    sp<BLASTBufferQueue> queue =
            new BLASTBufferQueue(name.c_str(), reinterpret_cast<SurfaceControl*>(surfaceControl),
                                 width, height, format);
    queue->incStrong((void*)nativeCreate);
    return reinterpret_cast<jlong>(queue.get());
}

static void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
    sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
    queue->decStrong((void*)nativeCreate);
@@ -91,11 +81,15 @@ static void nativeApplyPendingTransactions(JNIEnv* env, jclass clazz, jlong ptr,
    queue->applyPendingTransactions(frameNum);
}

static bool nativeIsSameSurfaceControl(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl) {
    sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
    return queue->isSameSurfaceControl(reinterpret_cast<SurfaceControl*>(surfaceControl));
}

static const JNINativeMethod gMethods[] = {
        /* name, signature, funcPtr */
        // clang-format off
        {"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},
        {"nativeSetSyncTransaction", "(JJZ)V", (void*)nativeSetSyncTransaction},
@@ -103,6 +97,7 @@ static const JNINativeMethod gMethods[] = {
        {"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction},
        {"nativeGetLastAcquiredFrameNum", "(J)J", (void*)nativeGetLastAcquiredFrameNum},
        {"nativeApplyPendingTransactions", "(JJ)V", (void*)nativeApplyPendingTransactions},
        {"nativeIsSameSurfaceControl", "(JJ)Z", (void*)nativeIsSameSurfaceControl},
        // clang-format on
};

+10 −3
Original line number Diff line number Diff line
@@ -27,8 +27,6 @@ public final class BLASTBufferQueue {
    // Note: This field is accessed by native code.
    public long mNativeObject; // BLASTBufferQueue*

    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);
@@ -40,11 +38,13 @@ public final class BLASTBufferQueue {
                                                              long frameNumber);
    private static native long nativeGetLastAcquiredFrameNum(long ptr);
    private static native void nativeApplyPendingTransactions(long ptr, long frameNumber);
    private static native boolean nativeIsSameSurfaceControl(long ptr, long surfaceControlPtr);

    /** Create a new connection with the surface flinger. */
    public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height,
            @PixelFormat.Format int format) {
        mNativeObject = nativeCreateAndUpdate(name, sc.mNativeObject, width, height, format);
        this(name);
        update(sc, width, height, format);
    }

    public BLASTBufferQueue(String name) {
@@ -152,4 +152,11 @@ public final class BLASTBufferQueue {
    public long getLastAcquiredFrameNum() {
        return nativeGetLastAcquiredFrameNum(mNativeObject);
    }

    /**
     * @return True if the associated SurfaceControl has the same handle as {@param sc}.
     */
    public boolean isSameSurfaceControl(SurfaceControl sc) {
        return nativeIsSameSurfaceControl(mNativeObject, sc.mNativeObject);
    }
}