Loading core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -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); core/java/android/hardware/SyncFence.java +19 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 = () -> {}; } Loading Loading @@ -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 Loading core/java/android/view/SurfaceControl.java +54 −3 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading Loading @@ -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. * Loading Loading @@ -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); } } core/jni/android_view_SurfaceControl.cpp +66 −3 Original line number Diff line number Diff line Loading @@ -253,6 +253,11 @@ static struct { jfieldID alphaInterpretation; } gDisplayDecorationSupportInfo; static struct { jclass clazz; jmethodID invokeReleaseCallback; } gInvokeReleaseCallback; class JNamedColorSpace { public: // ColorSpace.Named.SRGB.ordinal() = 0; Loading Loading @@ -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( Loading @@ -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, Loading Loading @@ -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", Loading Loading @@ -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; } Loading Loading
core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -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);
core/java/android/hardware/SyncFence.java +19 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 = () -> {}; } Loading Loading @@ -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 Loading
core/java/android/view/SurfaceControl.java +54 −3 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading Loading @@ -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. * Loading Loading @@ -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); } }
core/jni/android_view_SurfaceControl.cpp +66 −3 Original line number Diff line number Diff line Loading @@ -253,6 +253,11 @@ static struct { jfieldID alphaInterpretation; } gDisplayDecorationSupportInfo; static struct { jclass clazz; jmethodID invokeReleaseCallback; } gInvokeReleaseCallback; class JNamedColorSpace { public: // ColorSpace.Named.SRGB.ordinal() = 0; Loading Loading @@ -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( Loading @@ -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, Loading Loading @@ -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", Loading Loading @@ -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; } Loading