Add ability to make SyncFence from EGL
Bug: 217776226 Test: atest android.graphics.cts.EGL15Test#testEGL15AndroidNativeFence Change-Id: I5e1356739831f63426521561c45e719fc5f419d9
This commit is contained in:
parent
4f2645ae1b
commit
1ce46f750a
@ -17108,12 +17108,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 {
|
||||
@ -27843,12 +27848,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 {
|
||||
|
@ -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 {
|
||||
|
||||
/**
|
||||
* Wrapped {@link android.os.ParcelFileDescriptor}.
|
||||
* 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.
|
||||
*/
|
||||
private ParcelFileDescriptor mWrapped;
|
||||
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(@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);
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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
core/jni/android_hardware_SyncFence.cpp
Normal file
89
core/jni/android_hardware_SyncFence.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
@ -37,25 +37,12 @@
|
||||
#include <ui/ANativeObjectBase.h>
|
||||
|
||||
static jclass egldisplayClass;
|
||||
static jclass eglcontextClass;
|
||||
static jclass eglsurfaceClass;
|
||||
static jclass eglconfigClass;
|
||||
static jclass eglsyncClass;
|
||||
|
||||
static jmethodID egldisplayGetHandleID;
|
||||
static jmethodID eglcontextGetHandleID;
|
||||
static jmethodID eglsurfaceGetHandleID;
|
||||
static jmethodID eglconfigGetHandleID;
|
||||
|
||||
static jmethodID egldisplayConstructor;
|
||||
static jmethodID eglcontextConstructor;
|
||||
static jmethodID eglsurfaceConstructor;
|
||||
static jmethodID eglconfigConstructor;
|
||||
|
||||
static jobject eglNoContextObject;
|
||||
static jobject eglNoDisplayObject;
|
||||
static jobject eglNoSurfaceObject;
|
||||
|
||||
|
||||
static jmethodID eglsyncGetHandleID;
|
||||
|
||||
/* Cache method IDs each time the class is loaded. */
|
||||
|
||||
@ -64,37 +51,14 @@ nativeClassInit(JNIEnv *_env, jclass glImplClass)
|
||||
{
|
||||
jclass egldisplayClassLocal = _env->FindClass("android/opengl/EGLDisplay");
|
||||
egldisplayClass = (jclass) _env->NewGlobalRef(egldisplayClassLocal);
|
||||
jclass eglcontextClassLocal = _env->FindClass("android/opengl/EGLContext");
|
||||
eglcontextClass = (jclass) _env->NewGlobalRef(eglcontextClassLocal);
|
||||
jclass eglsurfaceClassLocal = _env->FindClass("android/opengl/EGLSurface");
|
||||
eglsurfaceClass = (jclass) _env->NewGlobalRef(eglsurfaceClassLocal);
|
||||
jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig");
|
||||
eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal);
|
||||
jclass eglsyncClassLocal = _env->FindClass("android/opengl/EGLSync");
|
||||
eglsyncClass = (jclass)_env->NewGlobalRef(eglsyncClassLocal);
|
||||
|
||||
egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getNativeHandle", "()J");
|
||||
eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J");
|
||||
eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getNativeHandle", "()J");
|
||||
eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J");
|
||||
|
||||
|
||||
egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(J)V");
|
||||
eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(J)V");
|
||||
eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V");
|
||||
eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(J)V");
|
||||
|
||||
|
||||
jclass eglClass = _env->FindClass("android/opengl/EGL14");
|
||||
jfieldID noContextFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;");
|
||||
jobject localeglNoContextObject = _env->GetStaticObjectField(eglClass, noContextFieldID);
|
||||
eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject);
|
||||
|
||||
jfieldID noDisplayFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;");
|
||||
jobject localeglNoDisplayObject = _env->GetStaticObjectField(eglClass, noDisplayFieldID);
|
||||
eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject);
|
||||
|
||||
jfieldID noSurfaceFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;");
|
||||
jobject localeglNoSurfaceObject = _env->GetStaticObjectField(eglClass, noSurfaceFieldID);
|
||||
eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
|
||||
eglsyncGetHandleID = _env->GetMethodID(eglsyncClassLocal, "getNativeHandle", "()J");
|
||||
}
|
||||
|
||||
static void *
|
||||
@ -108,26 +72,6 @@ fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) {
|
||||
return reinterpret_cast<void*>(_env->CallLongMethod(obj, mid));
|
||||
}
|
||||
|
||||
static jobject
|
||||
toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void * handle) {
|
||||
if (cls == eglcontextClass &&
|
||||
(EGLContext)handle == EGL_NO_CONTEXT) {
|
||||
return eglNoContextObject;
|
||||
}
|
||||
|
||||
if (cls == egldisplayClass &&
|
||||
(EGLDisplay)handle == EGL_NO_DISPLAY) {
|
||||
return eglNoDisplayObject;
|
||||
}
|
||||
|
||||
if (cls == eglsurfaceClass &&
|
||||
(EGLSurface)handle == EGL_NO_SURFACE) {
|
||||
return eglNoSurfaceObject;
|
||||
}
|
||||
|
||||
return _env->NewObject(cls, con, reinterpret_cast<jlong>(handle));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
/* EGLBoolean eglPresentationTimeANDROID ( EGLDisplay dpy, EGLSurface sur, EGLnsecsANDROID time ) */
|
||||
static jboolean
|
||||
@ -145,11 +89,21 @@ android_eglPresentationTimeANDROID
|
||||
return (jboolean)_returnValue;
|
||||
}
|
||||
|
||||
static jint android_eglDupNativeFenceFDANDROID(JNIEnv *env, jobject, jobject dpy, jobject sync) {
|
||||
EGLDisplay dpy_native = (EGLDisplay)fromEGLHandle(env, egldisplayGetHandleID, dpy);
|
||||
EGLSync sync_native = (EGLSync)fromEGLHandle(env, eglsyncGetHandleID, sync);
|
||||
|
||||
return eglDupNativeFenceFDANDROID(dpy_native, sync_native);
|
||||
}
|
||||
|
||||
static const char *classPathName = "android/opengl/EGLExt";
|
||||
|
||||
static const JNINativeMethod methods[] = {
|
||||
{"_nativeClassInit", "()V", (void*)nativeClassInit },
|
||||
{"eglPresentationTimeANDROID", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSurface;J)Z", (void *) android_eglPresentationTimeANDROID },
|
||||
{"_nativeClassInit", "()V", (void *)nativeClassInit},
|
||||
{"eglPresentationTimeANDROID", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSurface;J)Z",
|
||||
(void *)android_eglPresentationTimeANDROID},
|
||||
{"eglDupNativeFenceFDANDROIDImpl", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSync;)I",
|
||||
(void *)android_eglDupNativeFenceFDANDROID},
|
||||
};
|
||||
|
||||
int register_android_opengl_jni_EGLExt(JNIEnv *_env)
|
||||
|
@ -18,6 +18,11 @@
|
||||
|
||||
package android.opengl;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.hardware.SyncFence;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* EGL Extensions
|
||||
*/
|
||||
@ -30,6 +35,12 @@ public class EGLExt {
|
||||
public static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040;
|
||||
public static final int EGL_RECORDABLE_ANDROID = 0x3142;
|
||||
|
||||
// EGL_ANDROID_native_fence_sync
|
||||
public static final int EGL_SYNC_NATIVE_FENCE_ANDROID = 0x3144;
|
||||
public static final int EGL_SYNC_NATIVE_FENCE_FD_ANDROID = 0x3145;
|
||||
public static final int EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID = 0x3146;
|
||||
public static final int EGL_NO_NATIVE_FENCE_FD_ANDROID = -1;
|
||||
|
||||
native private static void _nativeClassInit();
|
||||
static {
|
||||
_nativeClassInit();
|
||||
@ -43,4 +54,33 @@ public class EGLExt {
|
||||
long time
|
||||
);
|
||||
|
||||
/**
|
||||
* Retrieves the SyncFence for an EGLSync created with EGL_SYNC_NATIVE_FENCE_ANDROID
|
||||
*
|
||||
* See <a href="https://www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_native_fence_sync.txt">
|
||||
* EGL_ANDROID_native_fence_sync</a> extension for more details
|
||||
* @param display The EGLDisplay connection
|
||||
* @param sync The EGLSync to fetch the SyncFence from
|
||||
* @return A SyncFence representing the native fence.
|
||||
* * If <sync> is not a valid sync object for <display>,
|
||||
* an {@link SyncFence#isValid() invalid} SyncFence is returned and an EGL_BAD_PARAMETER
|
||||
* error is generated.
|
||||
* * If the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute of <sync> is
|
||||
* EGL_NO_NATIVE_FENCE_FD_ANDROID, an {@link SyncFence#isValid() invalid} SyncFence is
|
||||
* returned and an EGL_BAD_PARAMETER error is generated.
|
||||
* * If <display> does not match the display passed to eglCreateSync
|
||||
* when <sync> was created, the behaviour is undefined.
|
||||
*/
|
||||
public static @NonNull SyncFence eglDupNativeFenceFDANDROID(@NonNull EGLDisplay display,
|
||||
@NonNull EGLSync sync) {
|
||||
int fd = eglDupNativeFenceFDANDROIDImpl(display, sync);
|
||||
Log.d("EGL", "eglDupNativeFence returned " + fd);
|
||||
if (fd >= 0) {
|
||||
return SyncFence.create(ParcelFileDescriptor.adoptFd(fd));
|
||||
} else {
|
||||
return SyncFence.createEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
private static native int eglDupNativeFenceFDANDROIDImpl(EGLDisplay display, EGLSync sync);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user