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

Commit bb0809e7 authored by John Reck's avatar John Reck Committed by Android (Google) Code Review
Browse files

Merge "Add setBuffer w/ release callback" into tm-dev

parents 0d73e85f f6fb6f62
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -49369,6 +49369,7 @@ package android.view {
    method @NonNull public android.view.SurfaceControl.Transaction setAlpha(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0, to=1.0) float);
    method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer);
    method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer, @Nullable android.hardware.SyncFence);
    method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer, @Nullable android.hardware.SyncFence, @Nullable java.util.function.Consumer<android.hardware.SyncFence>);
    method @NonNull public android.view.SurfaceControl.Transaction setBufferSize(@NonNull android.view.SurfaceControl, @IntRange(from=0) int, @IntRange(from=0) int);
    method @NonNull public android.view.SurfaceControl.Transaction setBufferTransform(@NonNull android.view.SurfaceControl, int);
    method @NonNull public android.view.SurfaceControl.Transaction setCrop(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect);
+19 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.opengl.EGLSync;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.SystemClock;

import libcore.util.NativeAllocationRegistry;

@@ -105,6 +106,21 @@ public final class SyncFence implements AutoCloseable, Parcelable {
        }
    }

    /**
     * Creates a SyncFence from a libui Fence*
     * DOES NOT TAKE AN ADDITIONAL REFERENCE, the caller must incref if it intends to retain
     * ownership (eg, when using sp<Fence>)
     * @hide
     */
    public SyncFence(long nativeFencePtr) {
        mNativePtr = nativeFencePtr;
        if (nativeFencePtr != 0) {
            mCloser = sRegistry.registerNativeAllocation(this, mNativePtr);
        } else {
            mCloser = () -> {};
        }
    }

    private SyncFence() {
        mCloser = () -> {};
    }
@@ -194,7 +210,9 @@ public final class SyncFence implements AutoCloseable, Parcelable {
    }

    /**
     * Returns the time that the fence signaled in the CLOCK_MONOTONIC time domain.
     * Returns the time in nanoseconds that the fence signaled in the CLOCK_MONOTONIC time domain.
     * This corresponds to {@link System#nanoTime()} but may also be compared to
     * {@link SystemClock#uptimeMillis()} after adjusting for milliseconds vs. nanoseconds.
     *
     * If the fence isn't valid, that is if {@link #isValid()} is false, then this returns
     * {@link #SIGNAL_TIME_INVALID}. Similarly, if an error occurs while trying to access the
+54 −3
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
 * Handle to an on-screen Surface managed by the system compositor. The SurfaceControl is
@@ -213,7 +214,7 @@ public final class SurfaceControl implements Parcelable {
    private static native void nativeReparent(long transactionObj, long nativeObject,
            long newParentNativeObject);
    private static native void nativeSetBuffer(long transactionObj, long nativeObject,
            HardwareBuffer buffer, long fencePtr);
            HardwareBuffer buffer, long fencePtr, Consumer<SyncFence> releaseCallback);
    private static native void nativeSetBufferTransform(long transactionObj, long nativeObject,
            int transform);
    private static native void nativeSetDataSpace(long transactionObj, long nativeObject,
@@ -3744,18 +3745,62 @@ public final class SurfaceControl implements Parcelable {
         */
        public @NonNull Transaction setBuffer(@NonNull SurfaceControl sc,
                @Nullable HardwareBuffer buffer, @Nullable SyncFence fence) {
            return setBuffer(sc, buffer, fence, null);
        }

        /**
         * Updates the HardwareBuffer displayed for the SurfaceControl.
         *
         * Note that the buffer must be allocated with {@link HardwareBuffer#USAGE_COMPOSER_OVERLAY}
         * as well as {@link HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE} as the surface control might
         * be composited using either an overlay or using the GPU.
         *
         * A presentation fence may be passed to improve performance by allowing the buffer
         * to complete rendering while it is waiting for the transaction to be applied.
         * For example, if the buffer is being produced by rendering with OpenGL ES then
         * a fence created with
         * {@link android.opengl.EGLExt#eglDupNativeFenceFDANDROID(EGLDisplay, EGLSync)} can be
         * used to allow the GPU rendering to be concurrent with the transaction. The compositor
         * will wait for the fence to be signaled before the buffer is displayed. If multiple
         * buffers are set as part of the same transaction, the presentation fences of all of them
         * must signal before any buffer is displayed. That is, the entire transaction is delayed
         * until all presentation fences have signaled, ensuring the transaction remains consistent.
         *
         * A releaseCallback may be passed to know when the buffer is safe to be reused. This
         * is recommended when attempting to render continuously using SurfaceControl transactions
         * instead of through {@link Surface}, as it provides a safe & reliable way to know when
         * a buffer can be re-used. The callback will be invoked with a {@link SyncFence} which,
         * if {@link SyncFence#isValid() valid}, must be waited on prior to using the buffer. This
         * can either be done directly with {@link SyncFence#awaitForever()} or it may be done
         * indirectly such as passing it as a release fence to
         * {@link android.media.Image#setFence(SyncFence)} when using
         * {@link android.media.ImageReader}.
         *
         * @param sc The SurfaceControl to update
         * @param buffer The buffer to be displayed
         * @param fence The presentation fence. If null or invalid, this is equivalent to
         *              {@link #setBuffer(SurfaceControl, HardwareBuffer)}
         * @param releaseCallback The callback to invoke when the buffer being set has been released
         *                        by a later transaction. That is, the point at which it is safe
         *                        to re-use the buffer.
         * @return this
         */
        public @NonNull Transaction setBuffer(@NonNull SurfaceControl sc,
                @Nullable HardwareBuffer buffer, @Nullable SyncFence fence,
                @Nullable Consumer<SyncFence> releaseCallback) {
            checkPreconditions(sc);
            if (fence != null) {
                synchronized (fence.getLock()) {
                    nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer,
                            fence.getNativeFence());
                            fence.getNativeFence(), releaseCallback);
                }
            } else {
                nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer, 0);
                nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer, 0, releaseCallback);
            }
            return this;
        }


        /**
         * Sets the buffer transform that should be applied to the current buffer.
         *
@@ -4094,4 +4139,10 @@ public final class SurfaceControl implements Parcelable {

        return -1;
    }

    // Called by native
    private static void invokeReleaseCallback(Consumer<SyncFence> callback, long nativeFencePtr) {
        SyncFence fence = new SyncFence(nativeFencePtr);
        callback.accept(fence);
    }
}
+66 −3
Original line number Diff line number Diff line
@@ -253,6 +253,11 @@ static struct {
    jfieldID alphaInterpretation;
} gDisplayDecorationSupportInfo;

static struct {
    jclass clazz;
    jmethodID invokeReleaseCallback;
} gInvokeReleaseCallback;

class JNamedColorSpace {
public:
    // ColorSpace.Named.SRGB.ordinal() = 0;
@@ -625,8 +630,59 @@ static void nativeSetGeometry(JNIEnv* env, jclass clazz, jlong transactionObj, j
    transaction->setGeometry(ctrl, source, dst, orientation);
}

class JGlobalRefHolder {
public:
    JGlobalRefHolder(JavaVM* vm, jobject object) : mVm(vm), mObject(object) {}

    virtual ~JGlobalRefHolder() {
        env()->DeleteGlobalRef(mObject);
        mObject = nullptr;
    }

    jobject object() { return mObject; }
    JavaVM* vm() { return mVm; }

    JNIEnv* env() {
        JNIEnv* env = nullptr;
        if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
            if (mVm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
                LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
            }
        }
        return env;
    }

private:
    JGlobalRefHolder(const JGlobalRefHolder&) = delete;
    void operator=(const JGlobalRefHolder&) = delete;

    JavaVM* mVm;
    jobject mObject;
};

static ReleaseBufferCallback genReleaseCallback(JNIEnv* env, jobject releaseCallback) {
    if (releaseCallback == nullptr) return nullptr;

    JavaVM* vm = nullptr;
    LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
    auto globalCallbackRef =
            std::make_shared<JGlobalRefHolder>(vm, env->NewGlobalRef(releaseCallback));
    return [globalCallbackRef](const ReleaseCallbackId&, const sp<Fence>& releaseFence,
                               std::optional<uint32_t> currentMaxAcquiredBufferCount) {
        Fence* fenceCopy = releaseFence.get();
        // We need to grab an extra ref as Java's SyncFence takes ownership
        if (fenceCopy) {
            fenceCopy->incStrong(0);
        }
        globalCallbackRef->env()->CallStaticVoidMethod(gInvokeReleaseCallback.clazz,
                                                       gInvokeReleaseCallback.invokeReleaseCallback,
                                                       globalCallbackRef->object(),
                                                       reinterpret_cast<jlong>(fenceCopy));
    };
}

static void nativeSetBuffer(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
                            jobject bufferObject, jlong fencePtr) {
                            jobject bufferObject, jlong fencePtr, jobject releaseCallback) {
    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
    sp<GraphicBuffer> graphicBuffer(GraphicBuffer::fromAHardwareBuffer(
@@ -635,7 +691,8 @@ static void nativeSetBuffer(JNIEnv* env, jclass clazz, jlong transactionObj, jlo
    if (fencePtr != 0) {
        optFence = sp<Fence>{reinterpret_cast<Fence*>(fencePtr)};
    }
    transaction->setBuffer(ctrl, graphicBuffer, optFence);
    transaction->setBuffer(ctrl, graphicBuffer, optFence, std::nullopt,
                           genReleaseCallback(env, releaseCallback));
}

static void nativeSetBufferTransform(JNIEnv* env, jclass clazz, jlong transactionObj,
@@ -2155,7 +2212,7 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
            (void*)nativeGetDisplayedContentSample },
    {"nativeSetGeometry", "(JJLandroid/graphics/Rect;Landroid/graphics/Rect;J)V",
            (void*)nativeSetGeometry },
    {"nativeSetBuffer", "(JJLandroid/hardware/HardwareBuffer;J)V",
    {"nativeSetBuffer", "(JJLandroid/hardware/HardwareBuffer;JLjava/util/function/Consumer;)V",
            (void*)nativeSetBuffer },
    {"nativeSetBufferTransform", "(JJI)V", (void*) nativeSetBufferTransform},
    {"nativeSetDataSpace", "(JJI)V",
@@ -2451,6 +2508,12 @@ int register_android_view_SurfaceControl(JNIEnv* env)
    gDisplayDecorationSupportInfo.alphaInterpretation =
            GetFieldIDOrDie(env, displayDecorationSupportClazz, "alphaInterpretation", "I");

    jclass surfaceControlClazz = FindClassOrDie(env, "android/view/SurfaceControl");
    gInvokeReleaseCallback.clazz = MakeGlobalRefOrDie(env, surfaceControlClazz);
    gInvokeReleaseCallback.invokeReleaseCallback =
            GetStaticMethodIDOrDie(env, surfaceControlClazz, "invokeReleaseCallback",
                                   "(Ljava/util/function/Consumer;J)V");

    return err;
}