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
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 01db0cd..20f4de1 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -535,8 +535,8 @@
}
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 @@
}
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;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 834c8b6..7c5b0ce 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -492,7 +492,7 @@
// 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);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
index 6a9c970..1cc9ba4 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
@@ -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 @@
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
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index fc9e653..862a8de 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -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 @@
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 @@
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 @@
scheduler::mock::NoOpSchedulerCallback mNoOpSchedulerCallback;
std::unique_ptr<frametimeline::impl::TokenManager> mTokenManager;
scheduler::TestableScheduler* mScheduler = nullptr;
+ Hwc2::mock::PowerAdvisor mPowerAdvisor;
};
} // namespace android