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

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

Merge "Add ability to make SyncFence from EGL"

parents 05474038 1ce46f75
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -17124,12 +17124,17 @@ package android.hardware {
    field public static final int MICROPHONE = 1; // 0x1
  }
  public final class SyncFence implements java.io.Closeable android.os.Parcelable {
    method public void close() throws java.io.IOException;
  public final class SyncFence implements java.lang.AutoCloseable android.os.Parcelable {
    method public boolean await(@NonNull java.time.Duration);
    method public boolean awaitForever();
    method public void close();
    method public int describeContents();
    method public long getSignalTime();
    method public boolean isValid();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.SyncFence> CREATOR;
    field public static final long SIGNAL_TIME_INVALID = -1L; // 0xffffffffffffffffL
    field public static final long SIGNAL_TIME_PENDING = 9223372036854775807L; // 0x7fffffffffffffffL
  }
  public final class TriggerEvent {
@@ -27879,12 +27884,17 @@ package android.opengl {
  public class EGLExt {
    ctor public EGLExt();
    method @NonNull public static android.hardware.SyncFence eglDupNativeFenceFDANDROID(@NonNull android.opengl.EGLDisplay, @NonNull android.opengl.EGLSync);
    method public static boolean eglPresentationTimeANDROID(android.opengl.EGLDisplay, android.opengl.EGLSurface, long);
    field public static final int EGL_CONTEXT_FLAGS_KHR = 12540; // 0x30fc
    field public static final int EGL_CONTEXT_MAJOR_VERSION_KHR = 12440; // 0x3098
    field public static final int EGL_CONTEXT_MINOR_VERSION_KHR = 12539; // 0x30fb
    field public static final int EGL_NO_NATIVE_FENCE_FD_ANDROID = -1; // 0xffffffff
    field public static final int EGL_OPENGL_ES3_BIT_KHR = 64; // 0x40
    field public static final int EGL_RECORDABLE_ANDROID = 12610; // 0x3142
    field public static final int EGL_SYNC_NATIVE_FENCE_ANDROID = 12612; // 0x3144
    field public static final int EGL_SYNC_NATIVE_FENCE_FD_ANDROID = 12613; // 0x3145
    field public static final int EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID = 12614; // 0x3146
  }
  public class EGLImage extends android.opengl.EGLObjectHandle {
+150 −33
Original line number Diff line number Diff line
@@ -17,12 +17,17 @@
package android.hardware;

import android.annotation.NonNull;
import android.opengl.EGLDisplay;
import android.opengl.EGLSync;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;

import java.io.Closeable;
import libcore.util.NativeAllocationRegistry;

import java.io.FileDescriptor;
import java.io.IOException;
import java.time.Duration;

/**
 * A SyncFence represents a synchronization primitive which signals when hardware buffers have
@@ -34,19 +39,57 @@ import java.io.IOException;
 * Once the fence signals, then the backing storage for the framebuffer may be safely read from,
 * such as for display or for media encoding.</p>
 *
 * @see <a href="https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkCreateFence.html">
 * VkFence</a>
 * @see android.opengl.EGLExt#eglDupNativeFenceFDANDROID(EGLDisplay, EGLSync)
 * @see android.media.Image#getFence()
 */
public final class SyncFence implements AutoCloseable, Parcelable {

    /**
     * An invalid signal time. Represents either the signal time for a SyncFence that isn't valid
     * (that is, {@link #isValid()} is false), or if an error occurred while attempting to retrieve
     * the signal time.
     */
public final class SyncFence implements Closeable, Parcelable {
    private static final String TAG = "SyncFence";
    public static final long SIGNAL_TIME_INVALID = -1;

    /**
     * Wrapped {@link android.os.ParcelFileDescriptor}.
     * A pending signal time. This is equivalent to the max value of a long, representing an
     * infinitely far point in the future.
     */
    private ParcelFileDescriptor mWrapped;
    public static final long SIGNAL_TIME_PENDING = Long.MAX_VALUE;

    private static final NativeAllocationRegistry sRegistry =
            NativeAllocationRegistry.createNonmalloced(SyncFence.class.getClassLoader(),
                    nGetDestructor(), 4);

    private long mNativePtr;

    // The destructor for this object
    // This is also used as our internal lock object. Although SyncFence doesn't claim to be
    // thread-safe, the cost of doing so to avoid issues around double-close or similar issues
    // is well worth making.
    private final Runnable mCloser;

    private SyncFence(@NonNull ParcelFileDescriptor wrapped) {
        mWrapped = wrapped;
        mNativePtr = nCreate(wrapped.detachFd());
        mCloser = sRegistry.registerNativeAllocation(this, mNativePtr);
    }

    private SyncFence(@NonNull Parcel parcel) {
        boolean valid = parcel.readBoolean();
        FileDescriptor fileDescriptor = null;
        if (valid) {
            fileDescriptor = parcel.readRawFileDescriptor();
        }
        if (fileDescriptor != null) {
            mNativePtr = nCreate(fileDescriptor.getInt$());
            mCloser = sRegistry.registerNativeAllocation(this, mNativePtr);
        } else {
            mCloser = () -> {};
        }
    }

    private SyncFence() {
        mCloser = () -> {};
    }

    /***
@@ -56,7 +99,7 @@ public final class SyncFence implements Closeable, Parcelable {
     * @hide
     */
    public static @NonNull SyncFence createEmpty() {
        return new SyncFence(ParcelFileDescriptor.adoptFd(-1));
        return new SyncFence();
    }

    /**
@@ -75,7 +118,13 @@ public final class SyncFence implements Closeable, Parcelable {
     * @hide
     */
    public @NonNull ParcelFileDescriptor getFdDup() throws IOException {
        return mWrapped.dup();
        synchronized (mCloser) {
            final int fd = mNativePtr != 0 ? nGetFd(mNativePtr) : -1;
            if (fd == -1) {
                throw new IllegalStateException("Cannot dup the FD of an invalid SyncFence");
            }
            return ParcelFileDescriptor.fromFd(fd);
        }
    }

    /**
@@ -85,29 +134,84 @@ public final class SyncFence implements Closeable, Parcelable {
     *         {@code false} otherwise.
     */
    public boolean isValid() {
        return mWrapped.getFileDescriptor().valid();
        synchronized (mCloser) {
            return mNativePtr != 0 && nIsValid(mNativePtr);
        }
    }

    /**
     * Waits for a SyncFence to signal for up to the timeout duration.
     *
     * An invalid SyncFence, that is if {@link #isValid()} is false, is treated equivalently
     * to a SyncFence that has already signaled. That is, wait() will immediately return true.
     *
     * @param timeout The timeout duration. If the duration is negative, then this waits forever.
     * @return true if the fence signaled or isn't valid, false otherwise.
     */
    public boolean await(@NonNull Duration timeout) {
        final long timeoutNanos;
        if (timeout.isNegative()) {
            timeoutNanos = -1;
        } else {
            timeoutNanos = timeout.toNanos();
        }
        return await(timeoutNanos);
    }

    /**
     * Waits forever for a SyncFence to signal.
     *
     * An invalid SyncFence, that is if {@link #isValid()} is false, is treated equivalently
     * to a SyncFence that has already signaled. That is, wait() will immediately return true.
     *
     * @return true if the fence signaled or isn't valid, false otherwise.
     */
    public boolean awaitForever() {
        return await(-1);
    }

    private boolean await(long timeoutNanos) {
        synchronized (mCloser) {
            return mNativePtr != 0 && nWait(mNativePtr, timeoutNanos);
        }
    }

    /**
     * Returns the time that the fence signaled in the CLOCK_MONOTONIC time domain.
     *
     * 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
     * signal time, then {@link #SIGNAL_TIME_INVALID} is also returned.
     *
     * If the fence hasn't yet signaled, then {@link #SIGNAL_TIME_PENDING} is returned.
     *
     * @return The time the fence signaled, {@link #SIGNAL_TIME_INVALID} if there's an error,
     *         or {@link #SIGNAL_TIME_PENDING} if the fence hasn't signaled yet.
     */
    public long getSignalTime() {
        synchronized (mCloser) {
            return mNativePtr != 0 ? nGetSignalTime(mNativePtr) : SIGNAL_TIME_INVALID;
        }
    }

    /**
     * Close the SyncFence. This implementation closes the underlying OS resources allocated
     * this stream.
     *
     * @throws IOException If an error occurs attempting to close this SyncFence.
     */
    @Override
    public void close() throws IOException {
        if (mWrapped != null) {
            try {
                mWrapped.close();
            } finally {
                // success
    public void close() {
        synchronized (mCloser) {
            if (mNativePtr == 0) {
                return;
            }
            mNativePtr = 0;
            mCloser.run();
        }
    }

    @Override
    public int describeContents() {
        return mWrapped.describeContents();
        return CONTENTS_FILE_DESCRIPTOR;
    }

    /**
@@ -119,10 +223,16 @@ public final class SyncFence implements Closeable, Parcelable {
     */
    @Override
    public void writeToParcel(@NonNull Parcel out, int flags) {
        try {
            mWrapped.writeToParcel(out, flags);
        } finally {
            // success
        synchronized (mCloser) {
            final int fd = mNativePtr != 0 ? nGetFd(mNativePtr) : -1;
            if (fd == -1) {
                out.writeBoolean(false);
            } else {
                out.writeBoolean(true);
                FileDescriptor temp = new FileDescriptor();
                temp.setInt$(fd);
                out.writeFileDescriptor(temp);
            }
        }
    }

@@ -130,7 +240,7 @@ public final class SyncFence implements Closeable, Parcelable {
            new Parcelable.Creator<SyncFence>() {
                @Override
                public SyncFence createFromParcel(Parcel in) {
            return new SyncFence(ParcelFileDescriptor.CREATOR.createFromParcel(in));
                    return new SyncFence(in);
                }

                @Override
@@ -138,4 +248,11 @@ public final class SyncFence implements Closeable, Parcelable {
                    return new SyncFence[size];
                }
            };

    private static native long nGetDestructor();
    private static native long nCreate(int fd);
    private static native boolean nIsValid(long nPtr);
    private static native int nGetFd(long nPtr);
    private static native boolean nWait(long nPtr, long timeout);
    private static native long nGetSignalTime(long nPtr);
}
+1 −0
Original line number Diff line number Diff line
@@ -188,6 +188,7 @@ cc_library_shared {
                "android_hardware_HardwareBuffer.cpp",
                "android_hardware_SensorManager.cpp",
                "android_hardware_SerialPort.cpp",
                "android_hardware_SyncFence.cpp",
                "android_hardware_UsbDevice.cpp",
                "android_hardware_UsbDeviceConnection.cpp",
                "android_hardware_UsbRequest.cpp",
+2 −0
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ extern int register_android_hardware_display_DisplayManagerGlobal(JNIEnv* env);
extern int register_android_hardware_HardwareBuffer(JNIEnv *env);
extern int register_android_hardware_SensorManager(JNIEnv *env);
extern int register_android_hardware_SerialPort(JNIEnv *env);
extern int register_android_hardware_SyncFence(JNIEnv* env);
extern int register_android_hardware_UsbDevice(JNIEnv *env);
extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env);
extern int register_android_hardware_UsbRequest(JNIEnv *env);
@@ -1601,6 +1602,7 @@ static const RegJNIRec gRegJNI[] = {
        REG_JNI(register_android_hardware_HardwareBuffer),
        REG_JNI(register_android_hardware_SensorManager),
        REG_JNI(register_android_hardware_SerialPort),
        REG_JNI(register_android_hardware_SyncFence),
        REG_JNI(register_android_hardware_UsbDevice),
        REG_JNI(register_android_hardware_UsbDeviceConnection),
        REG_JNI(register_android_hardware_UsbRequest),
+89 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "SyncFence"

#include <nativehelper/JNIHelp.h>
#include <ui/Fence.h>

#include "core_jni_helpers.h"
#include "jni.h"

using namespace android;

template <typename T>
jlong toJlong(T* ptr) {
    return static_cast<jlong>(reinterpret_cast<uintptr_t>(ptr));
}

template <typename T>
T* fromJlong(jlong jPtr) {
    return reinterpret_cast<T*>(static_cast<uintptr_t>(jPtr));
}

static void destroyFence(Fence* fence) {
    fence->decStrong(0);
}

static jlong SyncFence_getDestructor(JNIEnv*, jobject) {
    return toJlong(&destroyFence);
}

static jlong SyncFence_create(JNIEnv*, jobject, int fd) {
    Fence* fence = new Fence(fd);
    fence->incStrong(0);
    return toJlong(fence);
}

static jboolean SyncFence_isValid(JNIEnv*, jobject, jlong jPtr) {
    return fromJlong<Fence>(jPtr)->isValid();
}

static jint SyncFence_getFd(JNIEnv*, jobject, jlong jPtr) {
    return fromJlong<Fence>(jPtr)->get();
}

static jboolean SyncFence_wait(JNIEnv* env, jobject, jlong jPtr, jlong timeoutNanos) {
    Fence* fence = fromJlong<Fence>(jPtr);
    int err = fence->wait(timeoutNanos);
    return err == OK;
}

static jlong SyncFence_getSignalTime(JNIEnv* env, jobject, jlong jPtr) {
    return fromJlong<Fence>(jPtr)->getSignalTime();
}

// ----------------------------------------------------------------------------
// JNI Glue
// ----------------------------------------------------------------------------

const char* const kClassPathName = "android/hardware/SyncFence";

// clang-format off
static const JNINativeMethod gMethods[] = {
        { "nGetDestructor", "()J", (void*) SyncFence_getDestructor },
        { "nCreate", "(I)J", (void*) SyncFence_create },
        { "nIsValid", "(J)Z", (void*) SyncFence_isValid },
        { "nGetFd", "(J)I", (void*) SyncFence_getFd },
        { "nWait",  "(JJ)Z", (void*) SyncFence_wait },
        { "nGetSignalTime", "(J)J", (void*) SyncFence_getSignalTime },
};
// clang-format on

int register_android_hardware_SyncFence(JNIEnv* env) {
    int err = RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
    return err;
}
 No newline at end of file
Loading