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

Commit d86b03c5 authored by Ady Abraham's avatar Ady Abraham
Browse files

DMS: use vsync rate when calculating the app frame rate

This is a bug fix where without this CL, DMS does not report
the refresh rate correctly, for values that are not divisors of the
peak refresh rate, like 80hz.

Test: running swappy at 80hz
Test: presubmit (+ 1 new unit test)
Bug: 350082219
Flag: EXEMPT bugfix
Change-Id: I3c1d1832d97d931f12f5988bb6e17e25935335e2
parent acdbc9c1
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -1182,7 +1182,10 @@ public final class DisplayManagerService extends SystemService {

    private DisplayInfo getDisplayInfoForFrameRateOverride(DisplayEventReceiver.FrameRateOverride[]
            frameRateOverrides, DisplayInfo info, int callingUid) {
        // Start with the display frame rate
        float frameRateHz = info.renderFrameRate;

        // If the app has a specific override, use that instead
        for (DisplayEventReceiver.FrameRateOverride frameRateOverride : frameRateOverrides) {
            if (frameRateOverride.uid == callingUid) {
                frameRateHz = frameRateOverride.frameRateHz;
@@ -1201,18 +1204,21 @@ public final class DisplayManagerService extends SystemService {
                                DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE, callingUid);

        // Override the refresh rate only if it is a divisor of the current
        // refresh rate. This calculation needs to be in sync with the native code
        // vsync rate. This calculation needs to be in sync with the native code
        // in RefreshRateSelector::getFrameRateDivisor
        Display.Mode currentMode = info.getMode();
        float numPeriods = currentMode.getRefreshRate() / frameRateHz;
        float vsyncRate = currentMode.getVsyncRate();
        float numPeriods = vsyncRate / frameRateHz;
        float numPeriodsRound = Math.round(numPeriods);
        if (Math.abs(numPeriods - numPeriodsRound) > THRESHOLD_FOR_REFRESH_RATES_DIVISORS) {
            return info;
        }
        frameRateHz = currentMode.getRefreshRate() / numPeriodsRound;
        frameRateHz = vsyncRate / numPeriodsRound;

        DisplayInfo overriddenInfo = new DisplayInfo();
        overriddenInfo.copyFrom(info);

        // If there is a mode that matches the override, use that one
        for (Display.Mode mode : info.supportedModes) {
            if (!mode.equalsExceptRefreshRate(currentMode)) {
                continue;
@@ -1232,8 +1238,9 @@ public final class DisplayManagerService extends SystemService {
                return overriddenInfo;
            }
        }

        overriddenInfo.refreshRateOverride = frameRateHz;

        // Create a fake mode for app compat
        if (!displayModeReturnsPhysicalRefreshRate) {
            overriddenInfo.supportedModes = Arrays.copyOf(info.supportedModes,
                    info.supportedModes.length + 1);
+41 −2
Original line number Diff line number Diff line
@@ -2118,6 +2118,31 @@ public class DisplayManagerServiceTest {
        assertEquals(20f, displayInfo.getRefreshRate(), 0.01f);
    }

    /**
     * Tests that the DisplayInfo is updated correctly with a render frame rate even if it not
     * a divisor of the peak refresh rate.
     */
    @Test
    public void testDisplayInfoRenderFrameRateNonPeakDivisor() {
        DisplayManagerService displayManager =
                new DisplayManagerService(mContext, mShortMockedInjector);
        DisplayManagerService.BinderService displayManagerBinderService =
                displayManager.new BinderService();
        registerDefaultDisplays(displayManager);
        displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);

        FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
                new float[]{120f}, new float[]{240f});
        int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
                displayDevice);
        DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
        assertEquals(120f, displayInfo.getRefreshRate(), 0.01f);

        updateRenderFrameRate(displayManager, displayDevice, 80f);
        displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
        assertEquals(80f, displayInfo.getRefreshRate(), 0.01f);
    }

    /**
     * Tests that the mode reflects the render frame rate is in compat mode
     */
@@ -3387,13 +3412,26 @@ public class DisplayManagerServiceTest {
    }

    private FakeDisplayDevice createFakeDisplayDevice(DisplayManagerService displayManager,

                                                      float[] refreshRates) {
        return createFakeDisplayDevice(displayManager, refreshRates, Display.TYPE_UNKNOWN);
    }

    private FakeDisplayDevice createFakeDisplayDevice(DisplayManagerService displayManager,
                                                      float[] refreshRates,
                                                      float[] vsyncRates) {
        return createFakeDisplayDevice(displayManager, refreshRates, vsyncRates,
                Display.TYPE_UNKNOWN);
    }

    private FakeDisplayDevice createFakeDisplayDevice(DisplayManagerService displayManager,
            float[] refreshRates,
            int displayType) {
        return createFakeDisplayDevice(displayManager, refreshRates, refreshRates, displayType);
    }

    private FakeDisplayDevice createFakeDisplayDevice(DisplayManagerService displayManager,
                                                      float[] refreshRates,
                                                      float[] vsyncRates,
                                                      int displayType) {
        FakeDisplayDevice displayDevice = new FakeDisplayDevice();
        DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo();
@@ -3402,7 +3440,8 @@ public class DisplayManagerServiceTest {
        displayDeviceInfo.supportedModes = new Display.Mode[refreshRates.length];
        for (int i = 0; i < refreshRates.length; i++) {
            displayDeviceInfo.supportedModes[i] =
                    new Display.Mode(i + 1, width, height, refreshRates[i]);
                    new Display.Mode(i + 1, width, height, refreshRates[i], vsyncRates[i],
                            new float[0], new int[0]);
        }
        displayDeviceInfo.modeId = 1;
        displayDeviceInfo.type = displayType;