Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9ad1fb49 authored by ramindani's avatar ramindani Committed by Rachel Lee
Browse files

[DM] Unify onModeChanged and frameRateOverride callbacks.

In case when we change the mode and frame rate override aligns
with it, we end up sending frame rate override even though it already
aligns with the mode change rate, this causes unnecessary binder
traffic. combining these into one call reduces the binder traffic
and helps with power saving.

Test: atest LocalDisplayAdapterTest
BUG: 399482301
Flag: com.android.graphics.surfaceflinger.flags.unify_refresh_rate_callbacks
Change-Id: Iaa0a417f899b1fb2278693c23ff60cc5478df86d
parent f25e3dfe
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -297,6 +297,26 @@ public abstract class DisplayEventReceiver {
            long renderPeriod, long appVsyncOffsetNanos, long presentationDeadlineNanos) {
    }

    /**
     * Called when a display mode and frame rate overrides changed event is received.
     *
     * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
     * timebase.
     * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
     * @param modeId The new mode ID
     * @param renderPeriod The render frame period, which is a multiple of the mode's vsync period
     * @param appVsyncOffsetNanos The offset from the vsync of the display refresh rate.
     * @param presentationDeadlineNanos The time in nanoseconds by which the frame should be ready
     *                             from the target vsync, if target vsync is N then the frame
     *                             should be ready by N - presentationDeadlineNanos.
     * @param overrides The mappings from uid to frame rates
     */
    public void onModeAndFrameRateOverridesChanged(long timestampNanos,
            long physicalDisplayId,  int modeId,  long renderPeriod,
            long appVsyncOffsetNanos,
            long presentationDeadlineNanos, FrameRateOverride[] overrides) {
    }

    /**
     * Called when a display mode rejection event is received.
     *
@@ -398,6 +418,15 @@ public abstract class DisplayEventReceiver {
                appVsyncOffsetNanos, presentationDeadlineNanos);
    }

    // Called from native code.
    @SuppressWarnings("unused")
    private void dispatchModeChangedWithFrameRateOverrides(long timestampNanos,
            long physicalDisplayId, int modeId, long renderPeriod, long appVsyncOffsetNanos,
            long presentationDeadlineNanos, FrameRateOverride[] overrides) {
        onModeAndFrameRateOverridesChanged(timestampNanos, physicalDisplayId, modeId,
                renderPeriod, appVsyncOffsetNanos, presentationDeadlineNanos, overrides);
    }

    // Called from native code.
    @SuppressWarnings("unused")
    private void dispatchModeRejected(long physicalDisplayId, int modeId) {
+46 −15
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ static struct {
    jmethodID dispatchHotplug;
    jmethodID dispatchHotplugConnectionError;
    jmethodID dispatchModeChanged;
    jmethodID dispatchModeChangedWithFrameRateOverrides;
    jmethodID dispatchModeRejected;
    jmethodID dispatchFrameRateOverrides;
    jmethodID dispatchHdcpLevelsChanged;
@@ -74,6 +75,22 @@ static struct {

} gDisplayEventReceiverClassInfo;

jobjectArray getFrameRateOverrides(std::vector<FrameRateOverride> overrides, JNIEnv* env) {
    const auto frameRateOverrideClass =
            gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz;
    const auto frameRateOverrideInit =
            gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.init;
    auto frameRateOverrideInitObject =
            env->NewObject(frameRateOverrideClass, frameRateOverrideInit, 0, 0);
    auto frameRateOverrideArray = env->NewObjectArray(overrides.size(), frameRateOverrideClass,
                                                      frameRateOverrideInitObject);
    for (size_t i = 0; i < overrides.size(); i++) {
        auto FrameRateOverrideObject = env->NewObject(frameRateOverrideClass, frameRateOverrideInit,
                                                      overrides[i].uid, overrides[i].frameRateHz);
        env->SetObjectArrayElement(frameRateOverrideArray, i, FrameRateOverrideObject);
    }
    return frameRateOverrideArray;
}

class NativeDisplayEventReceiver : public DisplayEventDispatcher {
public:
@@ -95,6 +112,10 @@ private:
                       VsyncEventData vsyncEventData) override;
    void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
    void dispatchHotplugConnectionError(nsecs_t timestamp, int errorCode) override;
    void dispatchModeChangedWithFrameRateOverrides(
            nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId, nsecs_t renderPeriod,
            nsecs_t appVsyncOffset, nsecs_t presentationDeadline,
            std::vector<FrameRateOverride> overrides) override;
    void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
                             nsecs_t renderPeriod, nsecs_t appVsyncOffset,
                             nsecs_t presentationDeadline) override;
@@ -278,6 +299,26 @@ void NativeDisplayEventReceiver::dispatchModeChanged(nsecs_t timestamp, Physical
    mMessageQueue->raiseAndClearException(env, "dispatchModeChanged");
}

void NativeDisplayEventReceiver::dispatchModeChangedWithFrameRateOverrides(
        nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId, nsecs_t renderPeriod,
        nsecs_t appVsyncOffset, nsecs_t presentationDeadline,
        std::vector<FrameRateOverride> overrides) {
    JNIEnv* env = AndroidRuntime::getJNIEnv();
    ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
    if (receiverObj.get()) {
        ALOGV("receiver %p ~ Invoking modeWithFrameRateOverride changed handler.", this);
        auto frameRateOverrideArray = getFrameRateOverrides(overrides, env);
        env->CallVoidMethod(receiverObj.get(),
                            gDisplayEventReceiverClassInfo
                                    .dispatchModeChangedWithFrameRateOverrides,
                            timestamp, displayId.value, modeId, renderPeriod, appVsyncOffset,
                            presentationDeadline, frameRateOverrideArray);
        ALOGV("receiver %p ~ Returned from modeWithFrameRateOverride changed handler.", this);
    }

    mMessageQueue->raiseAndClearException(env, "dispatchModeChangedWithFrameRateOverrides");
}

void NativeDisplayEventReceiver::dispatchModeRejected(PhysicalDisplayId displayId, int32_t modeId) {
    JNIEnv* env = AndroidRuntime::getJNIEnv();

@@ -299,21 +340,7 @@ void NativeDisplayEventReceiver::dispatchFrameRateOverrides(
    ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
    if (receiverObj.get()) {
        ALOGV("receiver %p ~ Invoking FrameRateOverride handler.", this);
        const auto frameRateOverrideClass =
                gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz;
        const auto frameRateOverrideInit =
                gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.init;
        auto frameRateOverrideInitObject =
                env->NewObject(frameRateOverrideClass, frameRateOverrideInit, 0, 0);
        auto frameRateOverrideArray = env->NewObjectArray(overrides.size(), frameRateOverrideClass,
                                                          frameRateOverrideInitObject);
        for (size_t i = 0; i < overrides.size(); i++) {
            auto FrameRateOverrideObject =
                    env->NewObject(frameRateOverrideClass, frameRateOverrideInit, overrides[i].uid,
                                   overrides[i].frameRateHz);
            env->SetObjectArrayElement(frameRateOverrideArray, i, FrameRateOverrideObject);
        }

        auto frameRateOverrideArray = getFrameRateOverrides(overrides, env);
        env->CallVoidMethod(receiverObj.get(),
                            gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides, timestamp,
                            displayId.value, frameRateOverrideArray);
@@ -426,6 +453,10 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) {
    gDisplayEventReceiverClassInfo.dispatchModeChanged =
            GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeChanged",
                             "(JJIJJJ)V");
    gDisplayEventReceiverClassInfo.dispatchModeChangedWithFrameRateOverrides =
            GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz,
                             "dispatchModeChangedWithFrameRateOverrides",
                             "(JJIJJJ[Landroid/view/DisplayEventReceiver$FrameRateOverride;)V");
    gDisplayEventReceiverClassInfo.dispatchModeRejected =
            GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeRejected",
                             "(JI)V");
+26 −0
Original line number Diff line number Diff line
@@ -1616,6 +1616,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
                long renderPeriod, long appVsyncOffsetNanos, long presentationDeadlineNanos);
        void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
                DisplayEventReceiver.FrameRateOverride[] overrides);
        void onModeAndFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
                int modeId,  long renderPeriod, long appVsyncOffsetNanos,
                long presentationDeadlineNanos, DisplayEventReceiver.FrameRateOverride[] overrides);
        void onHdcpLevelsChanged(long physicalDisplayId, int connectedLevel, int maxLevel);

    }
@@ -1646,6 +1649,14 @@ final class LocalDisplayAdapter extends DisplayAdapter {
                    renderPeriod, appVsyncOffsetNanos, presentationDeadlineNanos);
        }

        public void onModeAndFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
                int modeId,  long renderPeriod, long appVsyncOffsetNanos,
                long presentationDeadlineNanos,
                DisplayEventReceiver.FrameRateOverride[] overrides) {
            mListener.onModeAndFrameRateOverridesChanged(timestampNanos, physicalDisplayId, modeId,
                    renderPeriod, appVsyncOffsetNanos, presentationDeadlineNanos, overrides);
        }

        @Override
        public void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
                DisplayEventReceiver.FrameRateOverride[] overrides) {
@@ -1729,6 +1740,21 @@ final class LocalDisplayAdapter extends DisplayAdapter {
            }
        }

        @Override
        public void onModeAndFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId,
                int modeId, long renderPeriod, long appVsyncOffsetNanos,
                long presentationDeadlineNanos,
                DisplayEventReceiver.FrameRateOverride[] overrides) {
            if (DEBUG) {
                Slog.d(TAG, "onModeAndFrameRateOverridesChanged");
            }
            //TODO(b/415850294) App should not get two callbacks when
            // onModeAndFrameRateOverridesChanged is executed.
            onModeChanged(timestampNanos, physicalDisplayId, modeId, renderPeriod,
                    appVsyncOffsetNanos, presentationDeadlineNanos);
            onFrameRateOverridesChanged(timestampNanos, physicalDisplayId, overrides);
        }

        @Override
        public void onHdcpLevelsChanged(long physicalDisplayId, int connectedLevel, int maxLevel) {
            if (DEBUG) {
+62 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.display;

import static android.hardware.display.DeviceProductInfo.CONNECTION_TO_SINK_DIRECT;
import static android.view.DisplayEventReceiver.FrameRateOverride;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
@@ -939,6 +940,56 @@ public class LocalDisplayAdapterTest {
        assertThat(mListener.changedDisplays.size()).isEqualTo(1);
    }

    @Test
    public void testOnModeAndFrameRateOverridesChanged() throws Exception {
        doReturn(true).when(mFlags).isDispatchDisplayModeWithVsyncOffsetsEnabled();
        long appVsyncOffsetNanosMode1 = 100;
        long presentationDeadlineNanosMode1 = 200;
        long appVsyncOffsetNanosMode2 = 101;
        long presentationDeadlineNanosMode2 = 201;
        SurfaceControl.DisplayMode displayMode1 = createFakeDisplayMode(0, 1920, 1080, 60f,
                appVsyncOffsetNanosMode1, presentationDeadlineNanosMode1);
        SurfaceControl.DisplayMode displayMode2 = createFakeDisplayMode(1, 1920, 1080, 120f,
                appVsyncOffsetNanosMode2, presentationDeadlineNanosMode2);
        SurfaceControl.DisplayMode[] modes =
                new SurfaceControl.DisplayMode[]{displayMode1, displayMode2};
        FakeDisplay display = new FakeDisplay(PORT_A, modes, /*activeMode*/ 0,
                displayMode1.peakRefreshRate);
        setUpDisplay(display);
        updateAvailableDisplays();
        mAdapter.registerLocked();
        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
        assertThat(mListener.addedDisplays.size()).isEqualTo(1);
        assertThat(mListener.changedDisplays).isEmpty();

        DisplayDeviceInfo displayDeviceInfo = mListener.addedDisplays.get(
                0).getDisplayDeviceInfoLocked();
        assertEquals(appVsyncOffsetNanosMode1, displayDeviceInfo.appVsyncOffsetNanos);
        assertEquals(presentationDeadlineNanosMode1, displayDeviceInfo.presentationDeadlineNanos);
        Display.Mode activeMode = getModeById(displayDeviceInfo, displayDeviceInfo.modeId);
        assertThat(activeMode.matches(1920, 1080, 60f)).isTrue();

        long newAppVsyncOffsetNanos = 400;
        long newPresentationDeadlineNanos = 500;

        FrameRateOverride[] frameRateOverrides = new FrameRateOverride[1];
        mInjector.getTransmitter().sendOnModeAndFrameRateOverridesChanged(display,
                /*modeId*/ 1, (long) displayMode2.peakRefreshRate, newAppVsyncOffsetNanos,
                newPresentationDeadlineNanos, frameRateOverrides);
        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
        assertTrue(mListener.traversalRequested);

        DisplayDevice displayDevice = mListener.changedDisplays.get(0);
        displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
        displayDeviceInfo = mListener.addedDisplays.get(0).getDisplayDeviceInfoLocked();
        // Returns the values captured from the OnModeAndFrameRateOverridesChanged event.
        assertEquals(newAppVsyncOffsetNanos, displayDeviceInfo.appVsyncOffsetNanos);
        assertEquals(newPresentationDeadlineNanos, displayDeviceInfo.presentationDeadlineNanos);
        assertThat(mListener.changedDisplays.size()).isEqualTo(2);
        activeMode = getModeById(displayDeviceInfo, displayDeviceInfo.modeId);
        assertThat(activeMode.matches(1920, 1080, 120f)).isTrue();
    }

    @Test
    public void testAfterDisplayChange_HdrCapabilitiesAreUpdated() throws Exception {
        FakeDisplay display = new FakeDisplay(PORT_A);
@@ -1928,6 +1979,17 @@ public class LocalDisplayAdapterTest {
                    appVsyncOffsetNanos, presentationDeadlineNanos));
            waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
        }

        public void sendOnModeAndFrameRateOverridesChanged(FakeDisplay display, int modeId,
                long renderPeriod, long appVsyncOffsetNanos, long presentationDeadlineNanos,
                FrameRateOverride[] frameRateOverrides) throws InterruptedException {

            mHandler.post(() -> mListener.onModeAndFrameRateOverridesChanged(
                    /* timestampNanos = */ 0, display.address.getPhysicalDisplayId(), modeId,
                    renderPeriod, appVsyncOffsetNanos, presentationDeadlineNanos,
                    frameRateOverrides));
            waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
        }
    }

    private class Injector extends LocalDisplayAdapter.Injector {