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

Commit 59a60b7b authored by Huihong Luo's avatar Huihong Luo
Browse files

Round up virtual display refresh rate

This semantics guarantees the virtual display will at least have the
specified refresh rate, e.g., if 60hz is requested on a 90hz display,
the virtual dislay will get a 90hz.

Bug: 266965278
Test: atest libsurfaceflinger_unittest
Change-Id: Ie7b30c5766454d0ad25cfd437f0498594c690a2e
parent 763ee291
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -535,8 +535,8 @@ void DisplayDevice::clearDesiredActiveModeState() {
}

void DisplayDevice::adjustRefreshRate(Fps pacesetterDisplayRefreshRate) {
    using fps_approx_ops::operator==;
    if (mRequestedRefreshRate == 0_Hz) {
    using fps_approx_ops::operator<=;
    if (mRequestedRefreshRate <= 0_Hz) {
        return;
    }

@@ -547,7 +547,12 @@ void DisplayDevice::adjustRefreshRate(Fps pacesetterDisplayRefreshRate) {
    }

    unsigned divisor = static_cast<unsigned>(
            std::round(pacesetterDisplayRefreshRate.getValue() / mRequestedRefreshRate.getValue()));
            std::floor(pacesetterDisplayRefreshRate.getValue() / mRequestedRefreshRate.getValue()));
    if (divisor == 0) {
        mAdjustedRefreshRate = 0_Hz;
        return;
    }

    mAdjustedRefreshRate = pacesetterDisplayRefreshRate / divisor;
}

+1 −1
Original line number Diff line number Diff line
@@ -492,7 +492,7 @@ private:

    // Implements ISurfaceComposer
    sp<IBinder> createDisplay(const String8& displayName, bool secure,
                              float requestedRefreshRate = 0);
                              float requestedRefreshRate = 0.0f);
    void destroyDisplay(const sp<IBinder>& displayToken);
    std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const EXCLUDES(mStateLock) {
        Mutex::Autolock lock(mStateLock);
+126 −1
Original line number Diff line number Diff line
@@ -17,12 +17,60 @@
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"

#include <scheduler/Fps.h>

#include "DisplayTransactionTestHelpers.h"
#include "FpsOps.h"

namespace android {
namespace {

class CreateDisplayTest : public DisplayTransactionTest {};
class CreateDisplayTest : public DisplayTransactionTest {
public:
    void createDisplayWithRequestedRefreshRate(const String8& name, uint64_t displayId,
                                               float pacesetterDisplayRefreshRate,
                                               float requestedRefreshRate,
                                               float expectedAdjustedRefreshRate) {
        // --------------------------------------------------------------------
        // Call Expectations

        // --------------------------------------------------------------------
        // Invocation

        sp<IBinder> displayToken = mFlinger.createDisplay(name, false, requestedRefreshRate);

        // --------------------------------------------------------------------
        // Postconditions

        // The display should have been added to the current state
        ASSERT_TRUE(hasCurrentDisplayState(displayToken));
        const auto& display = getCurrentDisplayState(displayToken);
        EXPECT_TRUE(display.isVirtual());
        EXPECT_EQ(display.requestedRefreshRate, Fps::fromValue(requestedRefreshRate));
        EXPECT_EQ(name.string(), display.displayName);

        std::optional<VirtualDisplayId> vid =
                DisplayId::fromValue<VirtualDisplayId>(displayId | DisplayId::FLAG_VIRTUAL);
        ASSERT_TRUE(vid.has_value());

        sp<DisplayDevice> device =
                mFlinger.createVirtualDisplayDevice(displayToken, *vid, requestedRefreshRate);
        EXPECT_TRUE(device->isVirtual());
        device->adjustRefreshRate(Fps::fromValue(pacesetterDisplayRefreshRate));
        // verifying desired value
        EXPECT_EQ(device->getAdjustedRefreshRate(), Fps::fromValue(expectedAdjustedRefreshRate));
        // verifying rounding up
        if (requestedRefreshRate < pacesetterDisplayRefreshRate) {
            EXPECT_GE(device->getAdjustedRefreshRate(), Fps::fromValue(requestedRefreshRate));
        } else {
            EXPECT_EQ(device->getAdjustedRefreshRate(),
                      Fps::fromValue(pacesetterDisplayRefreshRate));
        }

        // --------------------------------------------------------------------
        // Cleanup conditions
    }
};

TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForNonsecureDisplay) {
    const String8 name("virtual.test");
@@ -84,5 +132,82 @@ TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForSecureDisplay) {
    EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
}

// Requesting 0 tells SF not to do anything, i.e., default to refresh as physical displays
TEST_F(CreateDisplayTest, createDisplayWithRequestedRefreshRate0) {
    const String8 displayName("virtual.test");
    const uint64_t displayId = 123ull;
    const float kPacesetterDisplayRefreshRate = 60.f;
    const float kRequestedRefreshRate = 0.f;
    const float kExpectedAdjustedRefreshRate = 0.f;
    createDisplayWithRequestedRefreshRate(displayName, displayId, kPacesetterDisplayRefreshRate,
                                          kRequestedRefreshRate, kExpectedAdjustedRefreshRate);
}

// Requesting negative refresh rate, will be ignored, same as requesting 0
TEST_F(CreateDisplayTest, createDisplayWithRequestedRefreshRateNegative) {
    const String8 displayName("virtual.test");
    const uint64_t displayId = 123ull;
    const float kPacesetterDisplayRefreshRate = 60.f;
    const float kRequestedRefreshRate = -60.f;
    const float kExpectedAdjustedRefreshRate = 0.f;
    createDisplayWithRequestedRefreshRate(displayName, displayId, kPacesetterDisplayRefreshRate,
                                          kRequestedRefreshRate, kExpectedAdjustedRefreshRate);
}

// Requesting a higher refresh rate than the pacesetter
TEST_F(CreateDisplayTest, createDisplayWithRequestedRefreshRateHigh) {
    const String8 displayName("virtual.test");
    const uint64_t displayId = 123ull;
    const float kPacesetterDisplayRefreshRate = 60.f;
    const float kRequestedRefreshRate = 90.f;
    const float kExpectedAdjustedRefreshRate = 60.f;
    createDisplayWithRequestedRefreshRate(displayName, displayId, kPacesetterDisplayRefreshRate,
                                          kRequestedRefreshRate, kExpectedAdjustedRefreshRate);
}

// Requesting the same refresh rate as the pacesetter
TEST_F(CreateDisplayTest, createDisplayWithRequestedRefreshRateSame) {
    const String8 displayName("virtual.test");
    const uint64_t displayId = 123ull;
    const float kPacesetterDisplayRefreshRate = 60.f;
    const float kRequestedRefreshRate = 60.f;
    const float kExpectedAdjustedRefreshRate = 60.f;
    createDisplayWithRequestedRefreshRate(displayName, displayId, kPacesetterDisplayRefreshRate,
                                          kRequestedRefreshRate, kExpectedAdjustedRefreshRate);
}

// Requesting a divisor (30) of the pacesetter (60) should be honored
TEST_F(CreateDisplayTest, createDisplayWithRequestedRefreshRateDivisor) {
    const String8 displayName("virtual.test");
    const uint64_t displayId = 123ull;
    const float kPacesetterDisplayRefreshRate = 60.f;
    const float kRequestedRefreshRate = 30.f;
    const float kExpectedAdjustedRefreshRate = 30.f;
    createDisplayWithRequestedRefreshRate(displayName, displayId, kPacesetterDisplayRefreshRate,
                                          kRequestedRefreshRate, kExpectedAdjustedRefreshRate);
}

// Requesting a non divisor (45) of the pacesetter (120) should round up to a divisor (60)
TEST_F(CreateDisplayTest, createDisplayWithRequestedRefreshRateNoneDivisor) {
    const String8 displayName("virtual.test");
    const uint64_t displayId = 123ull;
    const float kPacesetterDisplayRefreshRate = 120.f;
    const float kRequestedRefreshRate = 45.f;
    const float kExpectedAdjustedRefreshRate = 60.f;
    createDisplayWithRequestedRefreshRate(displayName, displayId, kPacesetterDisplayRefreshRate,
                                          kRequestedRefreshRate, kExpectedAdjustedRefreshRate);
}

// Requesting a non divisor (75) of the pacesetter (120) should round up to pacesetter (120)
TEST_F(CreateDisplayTest, createDisplayWithRequestedRefreshRateNoneDivisorMax) {
    const String8 displayName("virtual.test");
    const uint64_t displayId = 123ull;
    const float kPacesetterDisplayRefreshRate = 120.f;
    const float kRequestedRefreshRate = 75.f;
    const float kExpectedAdjustedRefreshRate = 120.f;
    createDisplayWithRequestedRefreshRate(displayName, displayId, kPacesetterDisplayRefreshRate,
                                          kRequestedRefreshRate, kExpectedAdjustedRefreshRate);
}

} // namespace
} // namespace android
+23 −2
Original line number Diff line number Diff line
@@ -48,10 +48,12 @@
#include "TestableScheduler.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/DisplayHardware/MockDisplayMode.h"
#include "mock/DisplayHardware/MockPowerAdvisor.h"
#include "mock/MockEventThread.h"
#include "mock/MockFrameTimeline.h"
#include "mock/MockFrameTracer.h"
#include "mock/MockSchedulerCallback.h"
#include "mock/system/window/MockNativeWindow.h"

namespace android {
namespace renderengine {
@@ -379,8 +381,8 @@ public:

    void commitAndComposite() { mFlinger->composite(commit(), kVsyncId); }

    auto createDisplay(const String8& displayName, bool secure) {
        return mFlinger->createDisplay(displayName, secure);
    auto createDisplay(const String8& displayName, bool secure, float requestedRefreshRate = 0.0f) {
        return mFlinger->createDisplay(displayName, secure, requestedRefreshRate);
    }

    auto destroyDisplay(const sp<IBinder>& displayToken) {
@@ -527,6 +529,24 @@ public:
        mFlinger->getDynamicDisplayInfoFromToken(displayToken, dynamicDisplayInfo);
    }

    sp<DisplayDevice> createVirtualDisplayDevice(const sp<IBinder> displayToken,
                                                 VirtualDisplayId displayId,
                                                 float requestedRefreshRate) {
        constexpr ui::Size kResolution = {1080, 1920};
        auto compositionDisplay = compositionengine::impl::
                createDisplay(mFlinger->getCompositionEngine(),
                              compositionengine::DisplayCreationArgsBuilder()
                                      .setId(displayId)
                                      .setPixels(kResolution)
                                      .setPowerAdvisor(&mPowerAdvisor)
                                      .build());
        DisplayDeviceCreationArgs creationArgs(mFlinger, mFlinger->getHwComposer(), displayToken,
                                               compositionDisplay);
        creationArgs.requestedRefreshRate = Fps::fromValue(requestedRefreshRate);
        creationArgs.nativeWindow = sp<mock::NativeWindow>::make();
        return sp<DisplayDevice>::make(creationArgs);
    }

    /* ------------------------------------------------------------------------
     * Read-only access to private data to assert post-conditions.
     */
@@ -964,6 +984,7 @@ private:
    scheduler::mock::NoOpSchedulerCallback mNoOpSchedulerCallback;
    std::unique_ptr<frametimeline::impl::TokenManager> mTokenManager;
    scheduler::TestableScheduler* mScheduler = nullptr;
    Hwc2::mock::PowerAdvisor mPowerAdvisor;
};

} // namespace android