diff options
| -rw-r--r-- | core/api/current.txt | 9 | ||||
| -rw-r--r-- | core/java/android/hardware/SyncFence.java | 17 | ||||
| -rw-r--r-- | core/java/android/view/SurfaceControl.java | 137 | ||||
| -rw-r--r-- | core/java/android/window/flags/window_surfaces.aconfig | 10 | ||||
| -rw-r--r-- | core/jni/android_hardware_SyncFence.cpp | 5 | ||||
| -rw-r--r-- | core/jni/android_view_SurfaceControl.cpp | 89 |
6 files changed, 261 insertions, 6 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 95af71cfa074..b8464914e8d3 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -18613,6 +18613,7 @@ package android.hardware { } public final class SyncFence implements java.lang.AutoCloseable android.os.Parcelable { + ctor @FlaggedApi("com.android.window.flags.sdk_desired_present_time") public SyncFence(@NonNull android.hardware.SyncFence); method public boolean await(@NonNull java.time.Duration); method public boolean awaitForever(); method public void close(); @@ -51784,6 +51785,7 @@ package android.view { public static class SurfaceControl.Transaction implements java.io.Closeable android.os.Parcelable { ctor public SurfaceControl.Transaction(); method @NonNull public android.view.SurfaceControl.Transaction addTransactionCommittedListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.SurfaceControl.TransactionCommittedListener); + method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") @NonNull public android.view.SurfaceControl.Transaction addTransactionCompletedListener(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.SurfaceControl.TransactionStats>); method public void apply(); method @NonNull public android.view.SurfaceControl.Transaction clearFrameRate(@NonNull android.view.SurfaceControl); method @NonNull public android.view.SurfaceControl.Transaction clearTrustedPresentationCallback(@NonNull android.view.SurfaceControl); @@ -51800,9 +51802,11 @@ package android.view { method @NonNull public android.view.SurfaceControl.Transaction setCrop(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect); method @NonNull public android.view.SurfaceControl.Transaction setDamageRegion(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Region); method @NonNull public android.view.SurfaceControl.Transaction setDataSpace(@NonNull android.view.SurfaceControl, int); + method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") @NonNull public android.view.SurfaceControl.Transaction setDesiredPresentTime(long); method @NonNull public android.view.SurfaceControl.Transaction setExtendedRangeBrightness(@NonNull android.view.SurfaceControl, float, float); method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int); method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int, int); + method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") @NonNull public android.view.SurfaceControl.Transaction setFrameTimeline(long); method @Deprecated @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int); method @NonNull public android.view.SurfaceControl.Transaction setLayer(@NonNull android.view.SurfaceControl, @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) int); method @NonNull public android.view.SurfaceControl.Transaction setOpaque(@NonNull android.view.SurfaceControl, boolean); @@ -51818,6 +51822,11 @@ package android.view { method public void onTransactionCommitted(); } + @FlaggedApi("com.android.window.flags.sdk_desired_present_time") public static final class SurfaceControl.TransactionStats { + method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") public long getLatchTime(); + method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") @NonNull public android.hardware.SyncFence getPresentFence(); + } + public static final class SurfaceControl.TrustedPresentationThresholds { ctor public SurfaceControl.TrustedPresentationThresholds(@FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @IntRange(from=1) int); } diff --git a/core/java/android/hardware/SyncFence.java b/core/java/android/hardware/SyncFence.java index d6052cd4c67f..c2440fbaab1b 100644 --- a/core/java/android/hardware/SyncFence.java +++ b/core/java/android/hardware/SyncFence.java @@ -16,6 +16,7 @@ package android.hardware; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.media.Image; import android.media.ImageWriter; @@ -26,6 +27,8 @@ import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.os.SystemClock; +import com.android.window.flags.Flags; + import libcore.util.NativeAllocationRegistry; import java.io.FileDescriptor; @@ -121,6 +124,19 @@ public final class SyncFence implements AutoCloseable, Parcelable { } } + /** + * Creates a copy of the SyncFence from an existing one. + * Both fences must be closed() independently. + */ + @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME) + public SyncFence(@NonNull SyncFence other) { + this(other.mNativePtr); + + if (mNativePtr != 0) { + nIncRef(mNativePtr); + } + } + private SyncFence() { mCloser = () -> {}; } @@ -312,4 +328,5 @@ public final class SyncFence implements AutoCloseable, Parcelable { private static native int nGetFd(long nPtr); private static native boolean nWait(long nPtr, long timeout); private static native long nGetSignalTime(long nPtr); + private static native void nIncRef(long nPtr); } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index b957b31a5bb7..674f22c4166e 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -28,6 +28,7 @@ import static android.view.SurfaceControlProto.NAME; import android.Manifest; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.IntRange; @@ -71,6 +72,7 @@ import android.view.Surface.OutOfResourcesException; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import com.android.internal.util.VirtualRefBasePtr; +import com.android.window.flags.Flags; import dalvik.system.CloseGuard; @@ -277,6 +279,8 @@ public final class SurfaceControl implements Parcelable { private static native int nativeGetLayerId(long nativeObject); private static native void nativeAddTransactionCommittedListener(long nativeObject, TransactionCommittedListener listener); + private static native void nativeAddTransactionCompletedListener(long nativeObject, + Consumer<TransactionStats> listener); private static native void nativeSanitize(long transactionObject, int pid, int uid); private static native void nativeSetDestinationFrame(long transactionObj, long nativeObject, int l, int t, int r, int b); @@ -290,6 +294,10 @@ public final class SurfaceControl implements Parcelable { private static native void nativeClearTrustedPresentationCallback(long transactionObj, long nativeObject); private static native StalledTransactionInfo nativeGetStalledTransactionInfo(int pid); + private static native void nativeSetDesiredPresentTime(long transactionObj, + long desiredPresentTime); + private static native void nativeSetFrameTimeline(long transactionObj, + long vsyncId); /** * Transforms that can be applied to buffers as they are displayed to a window. @@ -2550,6 +2558,50 @@ public final class SurfaceControl implements Parcelable { } /** + * Transaction stats given to the listener registered in + * {@link SurfaceControl.Transaction#addTransactionCompletedListener} + */ + @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME) + public static final class TransactionStats { + private long mLatchTime; + private SyncFence mSyncFence; + + // called from native + private TransactionStats(long latchTime, long presentFencePtr) { + mLatchTime = latchTime; + mSyncFence = new SyncFence(presentFencePtr); + } + + /** + * Close the TransactionStats. Called by the framework when the listener returns. + * @hide + */ + public void close() { + mSyncFence.close(); + } + + /** + * Returns the timestamp of when the frame was latched by the framework and queued for + * presentation. + */ + @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME) + public long getLatchTime() { + return mLatchTime; + } + + /** + * Returns a new SyncFence that signals when the transaction has been presented. + * The caller takes ownership of the fence and is responsible for closing + * it by calling {@link SyncFence#close}. + * If a device does not support present fences, an empty fence will be returned. + */ + @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME) + public @NonNull SyncFence getPresentFence() { + return new SyncFence(mSyncFence); + } + }; + + /** * Threshold values that are sent with * {@link Transaction#setTrustedPresentationCallback(SurfaceControl, * TrustedPresentationThresholds, Executor, Consumer)} @@ -4185,12 +4237,35 @@ public final class SurfaceControl implements Parcelable { } /** - * Sets the frame timeline vsync id received from choreographer - * {@link Choreographer#getVsyncId()} that corresponds to the transaction submitted on that - * surface control. + * Sets the frame timeline to use in SurfaceFlinger. + * + * A frame timeline should be chosen based on the frame deadline the application + * can meet when rendering the frame and the application's desired presentation time. + * By setting a frame timeline, SurfaceFlinger tries to present the frame at the + * corresponding expected presentation time. + * + * To receive frame timelines, a callback must be posted to Choreographer using + * {@link Choreographer#postVsyncCallback} The vsyncId can then be extracted from the + * {@link Choreographer.FrameTimeline#getVsyncId}. + * + * @param vsyncId The vsync ID received from Choreographer, setting the frame's + * presentation target to the corresponding expected presentation time + * and deadline from the frame to be rendered. A stale or invalid value + * will be ignored. * - * @hide */ + @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME) + @NonNull + public Transaction setFrameTimeline(long vsyncId) { + if (!Flags.sdkDesiredPresentTime()) { + Log.w(TAG, "addTransactionCompletedListener was called but flag is disabled"); + return this; + } + nativeSetFrameTimelineVsync(mNativeObject, vsyncId); + return this; + } + + /** @hide */ @NonNull public Transaction setFrameTimelineVsync(long frameTimelineVsyncId) { nativeSetFrameTimelineVsync(mNativeObject, frameTimelineVsyncId); @@ -4207,6 +4282,9 @@ public final class SurfaceControl implements Parcelable { * to avoid dropping frames (overwriting transactions), and unable to use timestamps (Which * provide a more efficient solution), then this method provides a method to pace your * transaction application. + * The listener is invoked once the transaction is applied, and never again. Multiple + * listeners can be added to the same transaction, however the order the listeners will + * be called is not guaranteed. * * @param executor The executor that the callback should be invoked on. * @param listener The callback that will be invoked when the transaction has been @@ -4223,6 +4301,33 @@ public final class SurfaceControl implements Parcelable { } /** + * Request to add a TransactionCompletedListener. + * + * The listener is invoked when transaction is presented, and never again. Multiple + * listeners can be added to the same transaction, however the order the listeners will + * be called is not guaranteed. + * + * @param executor The executor that the callback should be invoked on. + * @param listener The callback that will be invoked when the transaction has been + * completed. + */ + @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME) + @NonNull + public Transaction addTransactionCompletedListener( + @NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<TransactionStats> listener) { + + if (!Flags.sdkDesiredPresentTime()) { + Log.w(TAG, "addTransactionCompletedListener was called but flag is disabled"); + return this; + } + Consumer<TransactionStats> listenerInner = stats -> executor.execute( + () -> listener.andThen(TransactionStats::close).accept(stats)); + nativeAddTransactionCompletedListener(mNativeObject, listenerInner); + return this; + } + + /** * Sets a callback to receive feedback about the presentation of a {@link SurfaceControl}. * When the {@link SurfaceControl} is presented according to the passed in * {@link TrustedPresentationThresholds}, it is said to "enter the state", and receives the @@ -4321,6 +4426,30 @@ public final class SurfaceControl implements Parcelable { } /** + * Specifies a desiredPresentTime for the transaction. The framework will try to present + * the transaction at or after the time specified. + * + * Transactions will not be presented until all of their acquire fences have signaled even + * if the app requests an earlier present time. + * + * If an earlier transaction has a desired present time of x, and a later transaction has + * a desired present time that is before x, the later transaction will not preempt the + * earlier transaction. + * + * @param desiredPresentTime The desired time (in CLOCK_MONOTONIC) for the transaction. + * @return This transaction + */ + @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME) + @NonNull + public Transaction setDesiredPresentTime(long desiredPresentTime) { + if (!Flags.sdkDesiredPresentTime()) { + Log.w(TAG, "addTransactionCompletedListener was called but flag is disabled"); + return this; + } + nativeSetDesiredPresentTime(mNativeObject, desiredPresentTime); + return this; + } + /** * Writes the transaction to parcel, clearing the transaction as if it had been applied so * it can be used to store future transactions. It's the responsibility of the parcel * reader to apply the original transaction. diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig index 56df49370379..3794c5d647a4 100644 --- a/core/java/android/window/flags/window_surfaces.aconfig +++ b/core/java/android/window/flags/window_surfaces.aconfig @@ -63,4 +63,12 @@ flag { description: "Enable trustedPresentationListener on windows public API" is_fixed_read_only: true bug: "278027319" -}
\ No newline at end of file +} + +flag { + namespace: "window_surfaces" + name: "sdk_desired_present_time" + description: "Feature flag for the new SDK API to set desired present time" + is_fixed_read_only: true + bug: "295038072" +} diff --git a/core/jni/android_hardware_SyncFence.cpp b/core/jni/android_hardware_SyncFence.cpp index b99665346f25..6e94616db825 100644 --- a/core/jni/android_hardware_SyncFence.cpp +++ b/core/jni/android_hardware_SyncFence.cpp @@ -66,6 +66,10 @@ static jlong SyncFence_getSignalTime(JNIEnv* env, jobject, jlong jPtr) { return fromJlong<Fence>(jPtr)->getSignalTime(); } +static void SyncFence_incRef(JNIEnv*, jobject, jlong jPtr) { + fromJlong<Fence>(jPtr)->incStrong((void*)SyncFence_incRef); +} + // ---------------------------------------------------------------------------- // JNI Glue // ---------------------------------------------------------------------------- @@ -80,6 +84,7 @@ static const JNINativeMethod gMethods[] = { { "nGetFd", "(J)I", (void*) SyncFence_getFd }, { "nWait", "(JJ)Z", (void*) SyncFence_wait }, { "nGetSignalTime", "(J)J", (void*) SyncFence_getSignalTime }, + { "nIncRef", "(J)V", (void*) SyncFence_incRef }, }; // clang-format on diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index db42246ca76c..55326da2c7df 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -231,6 +231,16 @@ static struct { static struct { jclass clazz; + jmethodID accept; +} gConsumerClassInfo; + +static struct { + jclass clazz; + jmethodID ctor; +} gTransactionStatsClassInfo; + +static struct { + jclass clazz; jmethodID ctor; jfieldID format; jfieldID alphaInterpretation; @@ -317,6 +327,52 @@ private: } }; +class TransactionCompletedListenerWrapper { +public: + explicit TransactionCompletedListenerWrapper(JNIEnv* env, jobject object) { + env->GetJavaVM(&mVm); + mTransactionCompletedListenerObject = env->NewGlobalRef(object); + LOG_ALWAYS_FATAL_IF(!mTransactionCompletedListenerObject, "Failed to make global ref"); + } + + ~TransactionCompletedListenerWrapper() { + getenv()->DeleteGlobalRef(mTransactionCompletedListenerObject); + } + + void callback(nsecs_t latchTime, const sp<Fence>& presentFence, + const std::vector<SurfaceControlStats>& /*stats*/) { + JNIEnv* env = getenv(); + // Adding a strong reference for java SyncFence + presentFence->incStrong(0); + + jobject stats = + env->NewObject(gTransactionStatsClassInfo.clazz, gTransactionStatsClassInfo.ctor, + latchTime, presentFence.get()); + env->CallVoidMethod(mTransactionCompletedListenerObject, gConsumerClassInfo.accept, stats); + env->DeleteLocalRef(stats); + DieIfException(env, "Uncaught exception in TransactionCompletedListener."); + } + + static void transactionCallbackThunk(void* context, nsecs_t latchTime, + const sp<Fence>& presentFence, + const std::vector<SurfaceControlStats>& stats) { + TransactionCompletedListenerWrapper* listener = + reinterpret_cast<TransactionCompletedListenerWrapper*>(context); + listener->callback(latchTime, presentFence, stats); + delete listener; + } + +private: + jobject mTransactionCompletedListenerObject; + JavaVM* mVm; + + JNIEnv* getenv() { + JNIEnv* env; + mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6); + return env; + } +}; + class WindowInfosReportedListenerWrapper : public gui::BnWindowInfosReportedListener { public: explicit WindowInfosReportedListenerWrapper(JNIEnv* env, jobject listener) { @@ -1879,10 +1935,16 @@ static void nativeSetFrameTimelineVsync(JNIEnv* env, jclass clazz, jlong transac FrameTimelineInfo ftInfo; ftInfo.vsyncId = frameTimelineVsyncId; - ftInfo.inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID; transaction->setFrameTimelineInfo(ftInfo); } +static void nativeSetDesiredPresentTime(JNIEnv* env, jclass clazz, jlong transactionObj, + jlong desiredPresentTime) { + auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); + + transaction->setDesiredPresentTime(desiredPresentTime); +} + static void nativeAddTransactionCommittedListener(JNIEnv* env, jclass clazz, jlong transactionObj, jobject transactionCommittedListenerObject) { auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); @@ -1894,6 +1956,17 @@ static void nativeAddTransactionCommittedListener(JNIEnv* env, jclass clazz, jlo context); } +static void nativeAddTransactionCompletedListener(JNIEnv* env, jclass clazz, jlong transactionObj, + jobject transactionCompletedListenerObject) { + auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); + + void* context = + new TransactionCompletedListenerWrapper(env, transactionCompletedListenerObject); + transaction->addTransactionCompletedCallback(TransactionCompletedListenerWrapper:: + transactionCallbackThunk, + context); +} + static void nativeSetTrustedPresentationCallback(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject, jlong trustedPresentationCallbackObject, @@ -2318,6 +2391,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSurfaceFlushJankData }, {"nativeAddTransactionCommittedListener", "(JLandroid/view/SurfaceControl$TransactionCommittedListener;)V", (void*) nativeAddTransactionCommittedListener }, + {"nativeAddTransactionCompletedListener", "(JLjava/util/function/Consumer;)V", + (void*) nativeAddTransactionCompletedListener }, {"nativeSetTrustedPresentationCallback", "(JJJLandroid/view/SurfaceControl$TrustedPresentationThresholds;)V", (void*) nativeSetTrustedPresentationCallback }, {"nativeClearTrustedPresentationCallback", "(JJ)V", @@ -2337,6 +2412,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { {"getNativeTrustedPresentationCallbackFinalizer", "()J", (void*)getNativeTrustedPresentationCallbackFinalizer }, {"nativeGetStalledTransactionInfo", "(I)Landroid/gui/StalledTransactionInfo;", (void*) nativeGetStalledTransactionInfo }, + {"nativeSetDesiredPresentTime", "(JJ)V", + (void*) nativeSetDesiredPresentTime }, // clang-format on }; @@ -2539,6 +2616,16 @@ int register_android_view_SurfaceControl(JNIEnv* env) gTransactionCommittedListenerClassInfo.onTransactionCommitted = GetMethodIDOrDie(env, transactionCommittedListenerClazz, "onTransactionCommitted", "()V"); + jclass consumerClazz = FindClassOrDie(env, "java/util/function/Consumer"); + gConsumerClassInfo.clazz = MakeGlobalRefOrDie(env, consumerClazz); + gConsumerClassInfo.accept = + GetMethodIDOrDie(env, consumerClazz, "accept", "(Ljava/lang/Object;)V"); + + jclass transactionStatsClazz = + FindClassOrDie(env, "android/view/SurfaceControl$TransactionStats"); + gTransactionStatsClassInfo.clazz = MakeGlobalRefOrDie(env, transactionStatsClazz); + gTransactionStatsClassInfo.ctor = + GetMethodIDOrDie(env, gTransactionStatsClassInfo.clazz, "<init>", "(JJ)V"); jclass displayDecorationSupportClazz = FindClassOrDie(env, "android/hardware/graphics/common/DisplayDecorationSupport"); |