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 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);
|
||||||
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);
|
||||||
|
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 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 setBufferTransform(@NonNull android.view.SurfaceControl, int);
|
||||||
method @NonNull public android.view.SurfaceControl.Transaction setCrop(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect);
|
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.Parcel;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
|
||||||
import libcore.util.NativeAllocationRegistry;
|
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() {
|
private SyncFence() {
|
||||||
mCloser = () -> {};
|
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
|
* 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
|
* {@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.CountDownLatch;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle to an on-screen Surface managed by the system compositor. The SurfaceControl is
|
* 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,
|
private static native void nativeReparent(long transactionObj, long nativeObject,
|
||||||
long newParentNativeObject);
|
long newParentNativeObject);
|
||||||
private static native void nativeSetBuffer(long transactionObj, long nativeObject,
|
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,
|
private static native void nativeSetBufferTransform(long transactionObj, long nativeObject,
|
||||||
int transform);
|
int transform);
|
||||||
private static native void nativeSetDataSpace(long transactionObj, long nativeObject,
|
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,
|
public @NonNull Transaction setBuffer(@NonNull SurfaceControl sc,
|
||||||
@Nullable HardwareBuffer buffer, @Nullable SyncFence fence) {
|
@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);
|
checkPreconditions(sc);
|
||||||
if (fence != null) {
|
if (fence != null) {
|
||||||
synchronized (fence.getLock()) {
|
synchronized (fence.getLock()) {
|
||||||
nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer,
|
nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer,
|
||||||
fence.getNativeFence());
|
fence.getNativeFence(), releaseCallback);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer, 0);
|
nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer, 0, releaseCallback);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the buffer transform that should be applied to the current buffer.
|
* Sets the buffer transform that should be applied to the current buffer.
|
||||||
*
|
*
|
||||||
@@ -4094,4 +4139,10 @@ public final class SurfaceControl implements Parcelable {
|
|||||||
|
|
||||||
return -1;
|
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;
|
jfieldID alphaInterpretation;
|
||||||
} gDisplayDecorationSupportInfo;
|
} gDisplayDecorationSupportInfo;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
jclass clazz;
|
||||||
|
jmethodID invokeReleaseCallback;
|
||||||
|
} gInvokeReleaseCallback;
|
||||||
|
|
||||||
class JNamedColorSpace {
|
class JNamedColorSpace {
|
||||||
public:
|
public:
|
||||||
// ColorSpace.Named.SRGB.ordinal() = 0;
|
// 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);
|
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,
|
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);
|
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
|
||||||
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
|
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
|
||||||
sp<GraphicBuffer> graphicBuffer(GraphicBuffer::fromAHardwareBuffer(
|
sp<GraphicBuffer> graphicBuffer(GraphicBuffer::fromAHardwareBuffer(
|
||||||
@@ -635,7 +691,8 @@ static void nativeSetBuffer(JNIEnv* env, jclass clazz, jlong transactionObj, jlo
|
|||||||
if (fencePtr != 0) {
|
if (fencePtr != 0) {
|
||||||
optFence = sp<Fence>{reinterpret_cast<Fence*>(fencePtr)};
|
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,
|
static void nativeSetBufferTransform(JNIEnv* env, jclass clazz, jlong transactionObj,
|
||||||
@@ -2155,7 +2212,7 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
|
|||||||
(void*)nativeGetDisplayedContentSample },
|
(void*)nativeGetDisplayedContentSample },
|
||||||
{"nativeSetGeometry", "(JJLandroid/graphics/Rect;Landroid/graphics/Rect;J)V",
|
{"nativeSetGeometry", "(JJLandroid/graphics/Rect;Landroid/graphics/Rect;J)V",
|
||||||
(void*)nativeSetGeometry },
|
(void*)nativeSetGeometry },
|
||||||
{"nativeSetBuffer", "(JJLandroid/hardware/HardwareBuffer;J)V",
|
{"nativeSetBuffer", "(JJLandroid/hardware/HardwareBuffer;JLjava/util/function/Consumer;)V",
|
||||||
(void*)nativeSetBuffer },
|
(void*)nativeSetBuffer },
|
||||||
{"nativeSetBufferTransform", "(JJI)V", (void*) nativeSetBufferTransform},
|
{"nativeSetBufferTransform", "(JJI)V", (void*) nativeSetBufferTransform},
|
||||||
{"nativeSetDataSpace", "(JJI)V",
|
{"nativeSetDataSpace", "(JJI)V",
|
||||||
@@ -2451,6 +2508,12 @@ int register_android_view_SurfaceControl(JNIEnv* env)
|
|||||||
gDisplayDecorationSupportInfo.alphaInterpretation =
|
gDisplayDecorationSupportInfo.alphaInterpretation =
|
||||||
GetFieldIDOrDie(env, displayDecorationSupportClazz, "alphaInterpretation", "I");
|
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;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user