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

This commit is contained in:
John Reck
2022-03-19 01:32:25 +00:00
committed by Android (Google) Code Review
4 changed files with 140 additions and 7 deletions

View File

@@ -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);

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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;
}