Merge "Add setBuffer w/ release callback" into tm-dev
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user