333 lines
12 KiB
Java
333 lines
12 KiB
Java
![]() |
/**
|
||
|
* 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.
|
||
|
*/
|
||
|
|
||
|
package android.hardware;
|
||
|
|
||
|
import android.annotation.FlaggedApi;
|
||
|
import android.annotation.NonNull;
|
||
|
import android.media.Image;
|
||
|
import android.media.ImageWriter;
|
||
|
import android.opengl.EGLDisplay;
|
||
|
import android.opengl.EGLSync;
|
||
|
import android.os.Parcel;
|
||
|
import android.os.ParcelFileDescriptor;
|
||
|
import android.os.Parcelable;
|
||
|
import android.os.SystemClock;
|
||
|
|
||
|
import com.android.window.flags.Flags;
|
||
|
|
||
|
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 units have
|
||
|
* completed work on a particular resource. They initially start in an unsignaled state and make
|
||
|
* a one-time transition to either a signaled or error state. SyncFences are created by various
|
||
|
* device APIs in response to submitting tasks to the device. They cannot be created nor signaled
|
||
|
* by userspace. As a result, this means that a SyncFence will make always make forward progress.
|
||
|
*
|
||
|
* <p>SyncFence's generally come in one of two varieties. "Presentation fences" refer to
|
||
|
* a SyncFence when the writing to a buffer has finished. "Release fences" then refer
|
||
|
* to when the reading from a buffer has finished.</p>
|
||
|
*
|
||
|
* <p>For example, a GPU rendering to a framebuffer may generate a synchronization fence,
|
||
|
* e.g., an EGLSync or VkFence, which signals when rendering has completed. Once the fence signals,
|
||
|
* then the backing storage for the framebuffer may be safely read from, such as for display or
|
||
|
* for media encoding. This would be referred to as a "presentation fence."</p>
|
||
|
*
|
||
|
* <p>Similarly when using an {@link android.media.ImageWriter} it is possible that an
|
||
|
* {@link android.media.Image} returned by {@link ImageWriter#dequeueInputImage()} may already
|
||
|
* have a {@link Image#getFence() fence} set on it. This would be what is referred to as either
|
||
|
* a "release fence" or an "acqurie fence" and indicates the fence that the writer must wait
|
||
|
* on before writing to the underlying buffer. In the case of ImageWriter this is done
|
||
|
* automatically when eg {@link Image#getPlanes()} is called, however when using
|
||
|
* {@link Image#getHardwareBuffer()} it is the caller's responsibility to ensure the
|
||
|
* release fence has signaled before writing to the buffer.</p>
|
||
|
*
|
||
|
* @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 static final long SIGNAL_TIME_INVALID = -1;
|
||
|
|
||
|
/**
|
||
|
* A pending signal time. This is equivalent to the max value of a long, representing an
|
||
|
* infinitely far point in the future.
|
||
|
*/
|
||
|
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(int fileDescriptor) {
|
||
|
mNativePtr = nCreate(fileDescriptor);
|
||
|
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 = () -> {};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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 = () -> {};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates a copy of the SyncFence from an existing one.
|
||
|
* Both fences must be closed() independently.
|
||
|
*/
|
||
|
@FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME)
|
||
|
public SyncFence(@NonNull SyncFence other) {
|
||
|
this(other.mNativePtr);
|
||
|
|
||
|
if (mNativePtr != 0) {
|
||
|
nIncRef(mNativePtr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private SyncFence() {
|
||
|
mCloser = () -> {};
|
||
|
}
|
||
|
|
||
|
/***
|
||
|
* Create an empty SyncFence
|
||
|
*
|
||
|
* @return a SyncFence with invalid fence
|
||
|
* @hide
|
||
|
*/
|
||
|
public static @NonNull SyncFence createEmpty() {
|
||
|
return new SyncFence();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a new SyncFence wrapped around another {@link ParcelFileDescriptor}. By default, all
|
||
|
* method calls are delegated to the wrapped descriptor. This takes ownership of the
|
||
|
* {@link ParcelFileDescriptor}.
|
||
|
*
|
||
|
* @param wrapped The descriptor to be wrapped.
|
||
|
* @hide
|
||
|
*/
|
||
|
public static @NonNull SyncFence create(@NonNull ParcelFileDescriptor wrapped) {
|
||
|
return new SyncFence(wrapped.detachFd());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a new SyncFence wrapped around another descriptor. The returned {@link SyncFence}
|
||
|
* instance takes ownership of the file descriptor.
|
||
|
*
|
||
|
* @param fileDescriptor The descriptor to be wrapped.
|
||
|
* @hide
|
||
|
*/
|
||
|
public static @NonNull SyncFence adopt(int fileDescriptor) {
|
||
|
return new SyncFence(fileDescriptor);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return a dup'd ParcelFileDescriptor from the SyncFence ParcelFileDescriptor.
|
||
|
* @hide
|
||
|
*/
|
||
|
public @NonNull ParcelFileDescriptor getFdDup() throws IOException {
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Checks if the SyncFile object is valid.
|
||
|
*
|
||
|
* @return {@code true} if the file descriptor represents a valid, open file;
|
||
|
* {@code false} otherwise.
|
||
|
*/
|
||
|
public boolean isValid() {
|
||
|
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 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
|
||
|
* 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.
|
||
|
*/
|
||
|
@Override
|
||
|
public void close() {
|
||
|
synchronized (mCloser) {
|
||
|
if (mNativePtr == 0) {
|
||
|
return;
|
||
|
}
|
||
|
mNativePtr = 0;
|
||
|
mCloser.run();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int describeContents() {
|
||
|
return CONTENTS_FILE_DESCRIPTOR;
|
||
|
}
|
||
|
|
||
|
/** @hide */
|
||
|
public Object getLock() {
|
||
|
return mCloser;
|
||
|
}
|
||
|
|
||
|
/** @hide */
|
||
|
public long getNativeFence() {
|
||
|
return mNativePtr;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Flatten this object into a Parcel.
|
||
|
*
|
||
|
* @param out The Parcel in which the object should be written.
|
||
|
* @param flags Additional flags about how the object should be written.
|
||
|
* May be {@code 0} or {@link #PARCELABLE_WRITE_RETURN_VALUE}
|
||
|
*/
|
||
|
@Override
|
||
|
public void writeToParcel(@NonNull Parcel out, int flags) {
|
||
|
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(in);
|
||
|
}
|
||
|
|
||
|
@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);
|
||
|
private static native void nIncRef(long nPtr);
|
||
|
}
|