diff options
| author | John Reck <jreck@google.com> | 2022-02-10 14:22:57 -0500 |
|---|---|---|
| committer | John Reck <jreck@google.com> | 2022-02-10 19:48:45 -0500 |
| commit | 1ce46f750abb7c29b50cc44e706941dcc6fa11cd (patch) | |
| tree | 8b96e625c76b91815e0ebf033f86aeece3f9cb7e /core/java/android/hardware/SyncFence.java | |
| parent | 4f2645ae1b04aea60aea65256b5b6f8585c8dbd4 (diff) | |
Add ability to make SyncFence from EGL
Bug: 217776226
Test: atest android.graphics.cts.EGL15Test#testEGL15AndroidNativeFence
Change-Id: I5e1356739831f63426521561c45e719fc5f419d9
Diffstat (limited to 'core/java/android/hardware/SyncFence.java')
| -rw-r--r-- | core/java/android/hardware/SyncFence.java | 183 |
1 files changed, 150 insertions, 33 deletions
diff --git a/core/java/android/hardware/SyncFence.java b/core/java/android/hardware/SyncFence.java index b0a6f51c2a39..693cda7720e4 100644 --- a/core/java/android/hardware/SyncFence.java +++ b/core/java/android/hardware/SyncFence.java @@ -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 Closeable, Parcelable { - private static final String TAG = "SyncFence"; +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 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,23 +223,36 @@ 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); + } } } public static final @NonNull Parcelable.Creator<SyncFence> CREATOR = new Parcelable.Creator<SyncFence>() { - @Override - public SyncFence createFromParcel(Parcel in) { - return new SyncFence(ParcelFileDescriptor.CREATOR.createFromParcel(in)); - } + @Override + public SyncFence createFromParcel(Parcel in) { + return new SyncFence(in); + } - @Override - public SyncFence[] newArray(int size) { - return new SyncFence[size]; - } - }; + @Override + public SyncFence[] newArray(int size) { + 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); } |
