From 4bc7cdf68bdd9d3248e802e3f2f430d05879744f Mon Sep 17 00:00:00 2001 From: Kriti Dang Date: Fri, 8 Jan 2021 11:49:56 +0100 Subject: Hdr format settings [Backend] Added new API to SurfaceControl to override the HDR formats supported by device in SurfaceFlinger. This API is used in the CTS Tests to verify HDR capabilities and enabling/disabling of HDR formats. Bug: 172905874 Test: atest CtsDisplayTestCases Change-Id: Icb13cdd638d315c0e23ece8aa61242470404a428 --- services/surfaceflinger/DisplayDevice.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index f4a2a3f03a..b7b2cc691b 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -354,8 +354,20 @@ int DisplayDevice::getSupportedPerFrameMetadata() const { return mCompositionDisplay->getDisplayColorProfile()->getSupportedPerFrameMetadata(); } -const HdrCapabilities& DisplayDevice::getHdrCapabilities() const { - return mCompositionDisplay->getDisplayColorProfile()->getHdrCapabilities(); +void DisplayDevice::overrideHdrTypes(const std::vector& hdrTypes) { + mOverrideHdrTypes = hdrTypes; +} + +HdrCapabilities DisplayDevice::getHdrCapabilities() const { + const HdrCapabilities& capabilities = + mCompositionDisplay->getDisplayColorProfile()->getHdrCapabilities(); + std::vector hdrTypes = capabilities.getSupportedHdrTypes(); + if (!mOverrideHdrTypes.empty()) { + hdrTypes = mOverrideHdrTypes; + } + return HdrCapabilities(hdrTypes, capabilities.getDesiredMaxLuminance(), + capabilities.getDesiredMaxAverageLuminance(), + capabilities.getDesiredMinLuminance()); } std::atomic DisplayDeviceState::sNextSequenceId(1); -- cgit v1.2.3-59-g8ed1b From 50121d58d0ff7cee786aea0997678d2208dfdecf Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Fri, 23 Apr 2021 13:01:16 -0700 Subject: SF: Use RenderSurfaceCreationArgsBuilder Fix -Wmissing-field-initializers errors silenced via pragmas. Bug: 129481165 Test: m libcompositionengine_test Change-Id: I6b254be239b173af599c4423f190472af218dbb9 --- .../compositionengine/RenderSurfaceCreationArgs.h | 39 ++++++++-------------- .../CompositionEngine/tests/DisplayTest.cpp | 15 ++++++--- .../CompositionEngine/tests/RenderSurfaceTest.cpp | 22 +++++------- services/surfaceflinger/DisplayDevice.cpp | 15 +++++---- 4 files changed, 42 insertions(+), 49 deletions(-) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h index a8d372c562..4110346aa3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h @@ -24,21 +24,17 @@ struct ANativeWindow; -namespace android { - -namespace compositionengine { - -class Display; +namespace android::compositionengine { /** * A parameter object for creating RenderSurface instances */ struct RenderSurfaceCreationArgs { // The initial width of the surface - int32_t displayWidth; + int32_t displayWidth = -1; // The initial height of the surface - int32_t displayHeight; + int32_t displayHeight = -1; // The ANativeWindow for the buffer queue for this surface sp nativeWindow; @@ -46,22 +42,16 @@ struct RenderSurfaceCreationArgs { // The DisplaySurface for this surface sp displaySurface; - size_t maxTextureCacheSize; + // The maximum size of the renderengine::ExternalTexture cache + size_t maxTextureCacheSize = 0; + +private: + friend class RenderSurfaceCreationArgsBuilder; + + // Not defaulted to disable aggregate initialization. + RenderSurfaceCreationArgs() {} }; -/** - * A helper for setting up a RenderSurfaceCreationArgs value in-line. - * Prefer this builder over raw structure initialization. - * - * Instead of: - * - * RenderSurfaceCreationArgs{1000, 1000, nativeWindow, displaySurface} - * - * Prefer: - * - * RenderSurfaceCreationArgsBuilder().setDisplayWidth(1000).setDisplayHeight(1000) - * .setNativeWindow(nativeWindow).setDisplaySurface(displaySurface).Build(); - */ class RenderSurfaceCreationArgsBuilder { public: RenderSurfaceCreationArgs build() { return std::move(mArgs); } @@ -75,11 +65,11 @@ public: return *this; } RenderSurfaceCreationArgsBuilder& setNativeWindow(sp nativeWindow) { - mArgs.nativeWindow = nativeWindow; + mArgs.nativeWindow = std::move(nativeWindow); return *this; } RenderSurfaceCreationArgsBuilder& setDisplaySurface(sp displaySurface) { - mArgs.displaySurface = displaySurface; + mArgs.displaySurface = std::move(displaySurface); return *this; } @@ -92,5 +82,4 @@ private: RenderSurfaceCreationArgs mArgs; }; -} // namespace compositionengine -} // namespace android +} // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index b31e64ac0d..492db431da 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -522,7 +522,11 @@ using DisplayCreateRenderSurfaceTest = PartialMockDisplayTestCommon; TEST_F(DisplayCreateRenderSurfaceTest, setsRenderSurface) { EXPECT_CALL(*mNativeWindow, disconnect(NATIVE_WINDOW_API_EGL)).WillRepeatedly(Return(NO_ERROR)); EXPECT_TRUE(mDisplay->getRenderSurface() == nullptr); - mDisplay->createRenderSurface(RenderSurfaceCreationArgs{640, 480, mNativeWindow, nullptr}); + mDisplay->createRenderSurface(RenderSurfaceCreationArgsBuilder() + .setDisplayWidth(640) + .setDisplayHeight(480) + .setNativeWindow(mNativeWindow) + .build()); EXPECT_TRUE(mDisplay->getRenderSurface() != nullptr); } @@ -1030,9 +1034,12 @@ struct DisplayFunctionalTest : public testing::Test { ); impl::RenderSurface* mRenderSurface = new impl::RenderSurface{mCompositionEngine, *mDisplay, - RenderSurfaceCreationArgs{DEFAULT_DISPLAY_WIDTH, - DEFAULT_DISPLAY_HEIGHT, mNativeWindow, - mDisplaySurface}}; + RenderSurfaceCreationArgsBuilder() + .setDisplayWidth(DEFAULT_DISPLAY_WIDTH) + .setDisplayHeight(DEFAULT_DISPLAY_HEIGHT) + .setNativeWindow(mNativeWindow) + .setDisplaySurface(mDisplaySurface) + .build()}; }; TEST_F(DisplayFunctionalTest, postFramebufferCriticalCallsAreOrdered) { diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index 8579d8c444..431cc93514 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -14,12 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#include "renderengine/ExternalTexture.h" -#include "ui/GraphicBuffer.h" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wextra" - #include #include @@ -32,7 +26,9 @@ #include #include #include +#include #include +#include namespace android::compositionengine { namespace { @@ -67,9 +63,12 @@ public: sp mNativeWindow = new StrictMock(); sp mDisplaySurface = new StrictMock(); impl::RenderSurface mSurface{mCompositionEngine, mDisplay, - RenderSurfaceCreationArgs{DEFAULT_DISPLAY_WIDTH, - DEFAULT_DISPLAY_HEIGHT, mNativeWindow, - mDisplaySurface}}; + RenderSurfaceCreationArgsBuilder() + .setDisplayWidth(DEFAULT_DISPLAY_WIDTH) + .setDisplayHeight(DEFAULT_DISPLAY_HEIGHT) + .setNativeWindow(mNativeWindow) + .setDisplaySurface(mDisplaySurface) + .build()}; }; /* @@ -367,11 +366,8 @@ TEST_F(RenderSurfaceTest, flipForwardsSignal) { mSurface.flip(); - EXPECT_EQ(501, mSurface.getPageFlipCount()); + EXPECT_EQ(501u, mSurface.getPageFlipCount()); } } // namespace } // namespace android::compositionengine - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 8692ee60dc..d8a7514c2f 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -70,13 +70,14 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) mIsPrimary(args.isPrimary) { mCompositionDisplay->editState().isSecure = args.isSecure; mCompositionDisplay->createRenderSurface( - compositionengine:: - RenderSurfaceCreationArgs{ANativeWindow_getWidth(args.nativeWindow.get()), - ANativeWindow_getHeight(args.nativeWindow.get()), - args.nativeWindow, args.displaySurface, - static_cast( - SurfaceFlinger:: - maxFrameBufferAcquiredBuffers)}); + compositionengine::RenderSurfaceCreationArgsBuilder() + .setDisplayWidth(ANativeWindow_getWidth(args.nativeWindow.get())) + .setDisplayHeight(ANativeWindow_getHeight(args.nativeWindow.get())) + .setNativeWindow(std::move(args.nativeWindow)) + .setDisplaySurface(std::move(args.displaySurface)) + .setMaxTextureCacheSize( + static_cast(SurfaceFlinger::maxFrameBufferAcquiredBuffers)) + .build()); if (!mFlinger->mDisableClientCompositionCache && SurfaceFlinger::maxFrameBufferAcquiredBuffers > 0) { -- cgit v1.2.3-59-g8ed1b From dd8bf2d69562aed676dac27a9180d9b81a477e4b Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Sat, 8 May 2021 16:36:33 -0700 Subject: Support toggling layer caching at runtime The use-case for this is dynamically enabling and disabling layer caching when a bad layer state is encountered that is difficult to reproduce. Bug: 187448777 Test: adb shell service call SurfaceFlinger 1040 i32 1 Test: libcompositionengine_test Change-Id: Id441a0894ff5a4c654db9fd706ceb1c0d1c343f0 --- .../include/compositionengine/Output.h | 3 ++ .../include/compositionengine/impl/Output.h | 8 ++--- .../include/compositionengine/mock/Output.h | 1 + .../CompositionEngine/src/Output.cpp | 27 ++++++++------- .../CompositionEngine/tests/OutputTest.cpp | 26 +++++++++++++-- services/surfaceflinger/DisplayDevice.cpp | 4 +++ services/surfaceflinger/DisplayDevice.h | 3 ++ services/surfaceflinger/SurfaceFlinger.cpp | 38 ++++++++++++++++++++-- services/surfaceflinger/SurfaceFlinger.h | 1 + 9 files changed, 89 insertions(+), 22 deletions(-) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 497621397c..9fba7aa558 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -163,6 +163,9 @@ public: // Enables (or disables) composition on this output virtual void setCompositionEnabled(bool) = 0; + // Enables (or disables) layer caching on this output + virtual void setLayerCachingEnabled(bool) = 0; + // Sets the projection state to use virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, const Rect& orientedDisplaySpaceRect) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index eeb20fc1d1..2893c3f910 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -28,21 +29,18 @@ namespace android::compositionengine::impl { -namespace planner { -class Planner; -} // namespace planner - // The implementation class contains the common implementation, but does not // actually contain the final output state. class Output : public virtual compositionengine::Output { public: - Output(); + Output() = default; ~Output() override; // compositionengine::Output overrides bool isValid() const override; std::optional getDisplayId() const override; void setCompositionEnabled(bool) override; + void setLayerCachingEnabled(bool) override; void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, const Rect& orientedDisplaySpaceRect) override; void setDisplaySize(const ui::Size&) override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 5aa53e54dd..749675d8fd 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -36,6 +36,7 @@ public: MOCK_CONST_METHOD0(getDisplayId, std::optional()); MOCK_METHOD1(setCompositionEnabled, void(bool)); + MOCK_METHOD1(setLayerCachingEnabled, void(bool)); MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&)); MOCK_METHOD1(setDisplaySize, void(const ui::Size&)); MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool)); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 297e687fcb..796fe7dbf0 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -55,18 +55,6 @@ Output::~Output() = default; namespace impl { -Output::Output() { - const bool enableLayerCaching = [] { - const bool enable = - android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false); - return base::GetBoolProperty(std::string("debug.sf.enable_layer_caching"), enable); - }(); - - if (enableLayerCaching) { - mPlanner = std::make_unique(); - } -} - namespace { template @@ -135,6 +123,21 @@ void Output::setCompositionEnabled(bool enabled) { dirtyEntireOutput(); } +void Output::setLayerCachingEnabled(bool enabled) { + if (enabled == (mPlanner != nullptr)) { + return; + } + + if (enabled) { + mPlanner = std::make_unique(); + if (mRenderSurface) { + mPlanner->setDisplaySize(mRenderSurface->getSize()); + } + } else { + mPlanner.reset(); + } +} + void Output::setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, const Rect& orientedDisplaySpaceRect) { auto& outputState = editState(); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 27980a01ac..11736d1e07 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -237,6 +237,28 @@ TEST_F(OutputTest, setCompositionEnabledSetsDisabledAndDirtiesEntireOutput) { EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } +/* + * Output::setLayerCachingEnabled() + */ + +TEST_F(OutputTest, setLayerCachingEnabled_enablesCaching) { + const auto kSize = ui::Size(1, 1); + EXPECT_CALL(*mRenderSurface, getSize()).WillRepeatedly(ReturnRef(kSize)); + mOutput->setLayerCachingEnabled(false); + mOutput->setLayerCachingEnabled(true); + + EXPECT_TRUE(mOutput->plannerEnabled()); +} + +TEST_F(OutputTest, setLayerCachingEnabled_disablesCaching) { + const auto kSize = ui::Size(1, 1); + EXPECT_CALL(*mRenderSurface, getSize()).WillRepeatedly(ReturnRef(kSize)); + mOutput->setLayerCachingEnabled(true); + mOutput->setLayerCachingEnabled(false); + + EXPECT_FALSE(mOutput->plannerEnabled()); +} + /* * Output::setProjection() */ @@ -972,9 +994,7 @@ TEST_F(OutputPrepareFrameTest, delegatesToChooseCompositionStrategyAndRenderSurf mOutput.editState().usesDeviceComposition = true; EXPECT_CALL(mOutput, chooseCompositionStrategy()).Times(1); - if (mOutput.plannerEnabled()) { - EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u)); - } + EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)); mOutput.prepareFrame(); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index d8a7514c2f..339701188a 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -139,6 +139,10 @@ void DisplayDevice::setPowerMode(hal::PowerMode mode) { getCompositionDisplay()->setCompositionEnabled(mPowerMode != hal::PowerMode::OFF); } +void DisplayDevice::enableLayerCaching(bool enable) { + getCompositionDisplay()->setLayerCachingEnabled(enable); +} + hal::PowerMode DisplayDevice::getPowerMode() const { return mPowerMode; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 68846d35bd..bf249cdb25 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -157,6 +157,9 @@ public: void setPowerMode(hardware::graphics::composer::hal::PowerMode mode); bool isPoweredOn() const; + // Enables layer caching on this DisplayDevice + void enableLayerCaching(bool enable); + ui::Dataspace getCompositionDataSpace() const; /* ------------------------------------------------------------------------ diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5bd43e133f..1e39d05a16 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -381,6 +381,12 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mColorSpaceAgnosticDataspace = static_cast(color_space_agnostic_dataspace(Dataspace::UNKNOWN)); + mLayerCachingEnabled = [] { + const bool enable = + android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false); + return base::GetBoolProperty(std::string("debug.sf.enable_layer_caching"), enable); + }(); + useContextPriority = use_context_priority(true); using Values = SurfaceFlingerProperties::primary_display_orientation_values; @@ -2641,6 +2647,7 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, builder.setGpuVirtualDisplayIdGenerator(mGpuVirtualDisplayIdGenerator); builder.setName(state.displayName); const auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); + compositionDisplay->setLayerCachingEnabled(mLayerCachingEnabled); sp displaySurface; sp producer; @@ -5186,9 +5193,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { code == IBinder::SYSPROPS_TRANSACTION) { return OK; } - // Numbers from 1000 to 1038 are currently used for backdoors. The code + // Numbers from 1000 to 1040 are currently used for backdoors. The code // in onTransact verifies that the user is root, and has access to use SF. - if (code >= 1000 && code <= 1039) { + if (code >= 1000 && code <= 1040) { ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code); return OK; } @@ -5572,6 +5579,33 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId); return NO_ERROR; } + // Toggle caching feature + // First argument is an int32 - nonzero enables caching and zero disables caching + // Second argument is an optional uint64 - if present, then limits enabling/disabling + // caching to a particular physical display + case 1040: { + n = data.readInt32(); + std::optional inputId = std::nullopt; + if (uint64_t inputDisplayId; data.readUint64(&inputDisplayId) == NO_ERROR) { + inputId = DisplayId::fromValue(inputDisplayId); + if (!inputId || getPhysicalDisplayToken(*inputId)) { + ALOGE("No display with id: %" PRIu64, inputDisplayId); + return NAME_NOT_FOUND; + } + } + { + Mutex::Autolock lock(mStateLock); + mLayerCachingEnabled = n != 0; + for (const auto& [_, display] : mDisplays) { + if (!inputId || *inputId == display->getPhysicalId()) { + display->enableLayerCaching(mLayerCachingEnabled); + } + } + } + invalidateHwcGeometry(); + repaintEverything(); + return NO_ERROR; + } } } return err; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 0a6a8e79f7..4009bafea1 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1244,6 +1244,7 @@ private: int mDebugRegion = 0; bool mDebugDisableHWC = false; bool mDebugDisableTransformHint = false; + bool mLayerCachingEnabled = false; volatile nsecs_t mDebugInTransaction = 0; bool mForceFullDamage = false; bool mPropagateBackpressureClientComposition = false; -- cgit v1.2.3-59-g8ed1b From ed3290f819fdb1fc0c9b16403bd0b19de59285b9 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 17 May 2021 15:12:14 -0700 Subject: SF: default display is active display For devices with multiple internal displays, choose the internal display the is powered on (if any) to be the default display that would be used mainly for vsync tracking. Bug: 187539899 Test: SF unit tests Change-Id: Icc305cdeec1c8a04729f00ff795dfbb806d8f72c --- libs/renderengine/gl/GLESRenderEngine.h | 2 +- .../include/renderengine/RenderEngine.h | 4 +- .../include/renderengine/mock/RenderEngine.h | 2 +- libs/renderengine/skia/SkiaGLRenderEngine.cpp | 2 +- libs/renderengine/skia/SkiaGLRenderEngine.h | 2 +- .../renderengine/threaded/RenderEngineThreaded.cpp | 6 +- libs/renderengine/threaded/RenderEngineThreaded.h | 2 +- services/surfaceflinger/DisplayDevice.cpp | 4 +- services/surfaceflinger/DisplayDevice.h | 3 + services/surfaceflinger/Scheduler/Scheduler.cpp | 2 +- services/surfaceflinger/Scheduler/Scheduler.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 92 ++++++++++++++-------- services/surfaceflinger/SurfaceFlinger.h | 25 +++++- .../tests/unittests/SchedulerTest.cpp | 4 +- 14 files changed, 101 insertions(+), 51 deletions(-) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index 915dba364f..95d58abe28 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -71,7 +71,7 @@ public: void cleanupPostRender() override; int getContextPriority() override; bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; } - void onPrimaryDisplaySizeChanged(ui::Size size) override {} + void onActiveDisplaySizeChanged(ui::Size size) override {} EGLDisplay getEGLDisplay() const { return mEGLDisplay; } // Creates an output image for rendering to diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index ac0affb2ee..9fdf4d1d98 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -129,9 +129,9 @@ public: // Attempt to switch RenderEngine into and out of protectedContext mode virtual bool useProtectedContext(bool useProtectedContext) = 0; - // Notify RenderEngine of changes to the dimensions of the primary display + // Notify RenderEngine of changes to the dimensions of the active display // so that it can configure its internal caches accordingly. - virtual void onPrimaryDisplaySizeChanged(ui::Size size) = 0; + virtual void onActiveDisplaySizeChanged(ui::Size size) = 0; // Renders layers for a particular display via GPU composition. This method // should be called for every display that needs to be rendered via the GPU. diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index 0175af3a85..c0b1c6fbc0 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -54,7 +54,7 @@ public: MOCK_METHOD0(cleanFramebufferCache, void()); MOCK_METHOD0(getContextPriority, int()); MOCK_METHOD0(supportsBackgroundBlur, bool()); - MOCK_METHOD1(onPrimaryDisplaySizeChanged, void(ui::Size)); + MOCK_METHOD1(onActiveDisplaySizeChanged, void(ui::Size)); protected: // mock renderengine still needs to implement these, but callers should never need to call them. diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index c7356ea728..a963819d51 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -1401,7 +1401,7 @@ int SkiaGLRenderEngine::getContextPriority() { return value; } -void SkiaGLRenderEngine::onPrimaryDisplaySizeChanged(ui::Size size) { +void SkiaGLRenderEngine::onActiveDisplaySizeChanged(ui::Size size) { // This cache multiplier was selected based on review of cache sizes relative // to the screen resolution. Looking at the worst case memory needed by blur (~1.5x), // shadows (~1x), and general data structures (e.g. vertex buffers) we selected this as a diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index b30355bb67..48aa27603f 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -67,7 +67,7 @@ public: bool useProtectedContext(bool useProtectedContext) override; bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; } void assertShadersCompiled(int numShaders) override; - void onPrimaryDisplaySizeChanged(ui::Size size) override; + void onActiveDisplaySizeChanged(ui::Size size) override; int reportShadersCompiled() override; protected: diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index ea3871f235..c09ea9c32f 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -354,14 +354,14 @@ bool RenderEngineThreaded::supportsBackgroundBlur() { return mRenderEngine->supportsBackgroundBlur(); } -void RenderEngineThreaded::onPrimaryDisplaySizeChanged(ui::Size size) { +void RenderEngineThreaded::onActiveDisplaySizeChanged(ui::Size size) { // This function is designed so it can run asynchronously, so we do not need to wait // for the futures. { std::lock_guard lock(mThreadMutex); mFunctionCalls.push([size](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::onPrimaryDisplaySizeChanged"); - instance.onPrimaryDisplaySizeChanged(size); + ATRACE_NAME("REThreaded::onActiveDisplaySizeChanged"); + instance.onActiveDisplaySizeChanged(size); }); } mCondition.notify_one(); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 9b523b2140..71d46c1bb7 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -65,7 +65,7 @@ public: void cleanFramebufferCache() override; int getContextPriority() override; bool supportsBackgroundBlur() override; - void onPrimaryDisplaySizeChanged(ui::Size size) override; + void onActiveDisplaySizeChanged(ui::Size size) override; protected: void mapExternalTextureBuffer(const sp& buffer, bool isRenderable) override; diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index c391901faa..517f848f10 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -217,7 +217,7 @@ ui::Dataspace DisplayDevice::getCompositionDataSpace() const { } void DisplayDevice::setLayerStack(ui::LayerStack stack) { - mCompositionDisplay->setLayerStackFilter(stack, isPrimary()); + mCompositionDisplay->setLayerStackFilter(stack, isInternal()); } void DisplayDevice::setFlags(uint32_t flags) { @@ -266,7 +266,7 @@ ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() { std::string DisplayDevice::getDebugName() const { const char* type = "virtual"; if (mConnectionType) { - type = *mConnectionType == ui::DisplayConnectionType::Internal ? "internal" : "external"; + type = isInternal() ? "internal" : "external"; } return base::StringPrintf("DisplayDevice{%s, %s%s, \"%s\"}", to_string(getId()).c_str(), type, diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index b068dafb19..885c5c5818 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -79,6 +79,9 @@ public: bool isVirtual() const { return !mConnectionType; } bool isPrimary() const { return mIsPrimary; } + bool isInternal() const { + return !isVirtual() && mConnectionType == ui::DisplayConnectionType::Internal; + } // isSecure indicates whether this display can be trusted to display // secure surfaces. diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 6d6e3c23d6..384e4e9f35 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -893,7 +893,7 @@ void Scheduler::onDisplayRefreshed(nsecs_t timestamp) { } } -void Scheduler::onPrimaryDisplayAreaChanged(uint32_t displayArea) { +void Scheduler::onActiveDisplayAreaChanged(uint32_t displayArea) { mLayerHistory->setDisplayArea(displayArea); } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 30a32537ad..7a2fdb5209 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -165,7 +165,7 @@ public: void onDisplayRefreshed(nsecs_t timestamp); // Notifies the scheduler when the display size has changed. Called from SF's main thread - void onPrimaryDisplayAreaChanged(uint32_t displayArea); + void onActiveDisplayAreaChanged(uint32_t displayArea); size_t getEventThreadConnectionCount(ConnectionHandle handle); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7dfb8c2e19..47f6d7900a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -632,9 +632,7 @@ void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) { mVirtualDisplayIdGenerators.gpu.releaseId(*id); } -std::vector SurfaceFlinger::getPhysicalDisplayIds() const { - Mutex::Autolock lock(mStateLock); - +std::vector SurfaceFlinger::getPhysicalDisplayIdsLocked() const { const auto internalDisplayId = getInternalDisplayIdLocked(); if (!internalDisplayId) { return {}; @@ -837,7 +835,7 @@ void SurfaceFlinger::init() { } } - getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize()); + onActiveDisplaySizeChanged(display); // Inform native graphics APIs whether the present timestamp is supported: @@ -2335,7 +2333,7 @@ void SurfaceFlinger::postComposition() { mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence); mTransactionCallbackInvoker.sendCallbacks(); - if (display && display->isPrimary() && display->getPowerMode() == hal::PowerMode::ON && + if (display && display->isInternal() && display->getPowerMode() == hal::PowerMode::ON && mPreviousPresentFences[0].fenceTime->isValid()) { mScheduler->addPresentFence(mPreviousPresentFences[0].fenceTime); } @@ -2785,11 +2783,6 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, if (!state.isVirtual()) { dispatchDisplayHotplugEvent(display->getPhysicalId(), true); } - - if (display->isPrimary()) { - mScheduler->onPrimaryDisplayAreaChanged(display->getWidth() * display->getHeight()); - getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize()); - } } void SurfaceFlinger::processDisplayRemoved(const wp& displayToken) { @@ -2854,16 +2847,8 @@ void SurfaceFlinger::processDisplayChanged(const wp& displayToken, // TODO(b/175678251) Call a listener instead. if (currentState.physical->hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) { - mRefreshRateConfigs->updateDisplayModes(currentState.physical->supportedModes, - currentState.physical->activeMode->getId()); - mVsyncConfiguration->reset(); - const Fps refreshRate = currentState.physical->activeMode->getFps(); - updatePhaseConfiguration(refreshRate); - mRefreshRateStats->setRefreshRate(refreshRate); - - if (mRefreshRateOverlay) { - mRefreshRateOverlay->reset(); - } + updateInternalDisplayVsyncLocked(currentState.physical->supportedModes, + currentState.physical->activeMode->getId()); } } return; @@ -2889,8 +2874,8 @@ void SurfaceFlinger::processDisplayChanged(const wp& displayToken, currentState.height != drawingState.height) { display->setDisplaySize(currentState.width, currentState.height); - if (display->isPrimary()) { - mScheduler->onPrimaryDisplayAreaChanged(currentState.width * currentState.height); + if (isDisplayActiveLocked(display)) { + onActiveDisplaySizeChanged(display); } if (mRefreshRateOverlay) { @@ -2899,6 +2884,17 @@ void SurfaceFlinger::processDisplayChanged(const wp& displayToken, } } } +void SurfaceFlinger::updateInternalDisplayVsyncLocked(const DisplayModes& modes, + DisplayModeId currentModeId) { + mRefreshRateConfigs->updateDisplayModes(modes, currentModeId); + mVsyncConfiguration->reset(); + const Fps refreshRate = mRefreshRateConfigs->getCurrentRefreshRate().getFps(); + updatePhaseConfiguration(refreshRate); + mRefreshRateStats->setRefreshRate(refreshRate); + if (mRefreshRateOverlay) { + mRefreshRateOverlay->reset(); + } +} void SurfaceFlinger::processDisplayChangesLocked() { // here we take advantage of Vector's copy-on-write semantics to @@ -4555,6 +4551,11 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: } const auto vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); if (currentMode == hal::PowerMode::OFF) { + const auto activeDisplay = getDisplayDeviceLocked(mActiveDisplayToken); + if (display->isInternal() && (!activeDisplay || !activeDisplay->isPoweredOn())) { + mActiveDisplayToken = display->getDisplayToken(); + onActiveDisplayChangedLocked(getDisplayDeviceLocked(mActiveDisplayToken)); + } // Keep uclamp in a separate syscall and set it before changing to RT due to b/190237315. // We can merge the syscall later. if (SurfaceFlinger::setSchedAttr(true) != NO_ERROR) { @@ -4564,7 +4565,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: ALOGW("Couldn't set SCHED_FIFO on display on: %s\n", strerror(errno)); } getHwComposer().setPowerMode(displayId, mode); - if (display->isPrimary() && mode != hal::PowerMode::DOZE_SUSPEND) { + if (display->isInternal() && mode != hal::PowerMode::DOZE_SUSPEND) { getHwComposer().setVsyncEnabled(displayId, mHWCVsyncPendingState); mScheduler->onScreenAcquired(mAppConnectionHandle); mScheduler->resyncToHardwareVsync(true, vsyncPeriod); @@ -4581,7 +4582,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: if (SurfaceFlinger::setSchedAttr(false) != NO_ERROR) { ALOGW("Couldn't set uclamp.min on display off: %s\n", strerror(errno)); } - if (display->isPrimary() && currentMode != hal::PowerMode::DOZE_SUSPEND) { + if (display->isInternal() && currentMode != hal::PowerMode::DOZE_SUSPEND) { mScheduler->disableHardwareVsync(true); mScheduler->onScreenReleased(mAppConnectionHandle); } @@ -4595,13 +4596,13 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: } else if (mode == hal::PowerMode::DOZE || mode == hal::PowerMode::ON) { // Update display while dozing getHwComposer().setPowerMode(displayId, mode); - if (display->isPrimary() && currentMode == hal::PowerMode::DOZE_SUSPEND) { + if (display->isInternal() && currentMode == hal::PowerMode::DOZE_SUSPEND) { mScheduler->onScreenAcquired(mAppConnectionHandle); mScheduler->resyncToHardwareVsync(true, vsyncPeriod); } } else if (mode == hal::PowerMode::DOZE_SUSPEND) { // Leave display going to doze - if (display->isPrimary()) { + if (display->isInternal()) { mScheduler->disableHardwareVsync(true); mScheduler->onScreenReleased(mAppConnectionHandle); } @@ -4611,7 +4612,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: getHwComposer().setPowerMode(displayId, mode); } - if (display->isPrimary()) { + if (display->isInternal()) { mTimeStats->setPowerMode(mode); mRefreshRateStats->setPowerMode(mode); mScheduler->setDisplayPowerState(mode == hal::PowerMode::ON); @@ -5675,7 +5676,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r const auto display = [&]() -> sp { uint64_t value; if (data.readUint64(&value) != NO_ERROR) { - return getInternalDisplayToken(); + return getDefaultDisplayDevice()->getDisplayToken().promote(); } if (const auto id = DisplayId::fromValue(value)) { @@ -6440,8 +6441,10 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( const std::optional& policy, bool overridePolicy) { Mutex::Autolock lock(mStateLock); - LOG_ALWAYS_FATAL_IF(!display->isPrimary() && overridePolicy, - "Can only set override policy on the primary display"); + const bool isDefaultDisplay = display == getDefaultDisplayDeviceLocked(); + + LOG_ALWAYS_FATAL_IF(!isDefaultDisplay && overridePolicy, + "Can only set override policy on the default display"); LOG_ALWAYS_FATAL_IF(!policy && !overridePolicy, "Can only clear the override policy"); if (mDebugDisplayModeSetByBackdoor) { @@ -6449,11 +6452,11 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( return NO_ERROR; } - if (!display->isPrimary()) { - // TODO(b/144711714): For non-primary displays we should be able to set an active mode + if (!isDefaultDisplay) { + // TODO(b/144711714): For non-default displays we should be able to set an active mode // as well. For now, just call directly to initiateModeChange but ideally // it should go thru setDesiredActiveMode, similar to primary display. - ALOGV("%s for non-primary display", __func__); + ALOGV("%s for non-default display", __func__); const auto displayId = display->getPhysicalId(); hal::VsyncPeriodChangeConstraints constraints; @@ -6571,7 +6574,7 @@ status_t SurfaceFlinger::getDesiredDisplayModeSpecs(const sp& displayTo return NAME_NOT_FOUND; } - if (display->isPrimary()) { + if (display == getDefaultDisplayDeviceLocked()) { scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy(); *outDefaultMode = policy.defaultMode.value(); @@ -6965,6 +6968,27 @@ void SurfaceFlinger::notifyRegionSamplingThread() { mRegionSamplingThread->onCompositionComplete(mEventQueue->nextExpectedInvalidate()); } +void SurfaceFlinger::onActiveDisplaySizeChanged(const sp& activeDisplay) { + mScheduler->onActiveDisplayAreaChanged(activeDisplay->getWidth() * activeDisplay->getHeight()); + getRenderEngine().onActiveDisplaySizeChanged(activeDisplay->getSize()); +} + +void SurfaceFlinger::onActiveDisplayChangedLocked(const sp& activeDisplay) { + ATRACE_CALL(); + + if (!activeDisplay) { + ALOGE("%s: activeDisplay is null", __func__); + return; + } + updateInternalDisplayVsyncLocked(activeDisplay->getSupportedModes(), + activeDisplay->getActiveMode()->getId()); + onActiveDisplaySizeChanged(activeDisplay); + if (mRefreshRateOverlay) { + mRefreshRateOverlay->setViewport(activeDisplay->getSize()); + mRefreshRateOverlay->changeRefreshRate(activeDisplay->getActiveMode()->getFps()); + } +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b7f3db0d72..257d48de21 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -609,7 +609,10 @@ private: sp createConnection() override; sp createDisplay(const String8& displayName, bool secure) override; void destroyDisplay(const sp& displayToken) override; - std::vector getPhysicalDisplayIds() const override; + std::vector getPhysicalDisplayIds() const override EXCLUDES(mStateLock) { + Mutex::Autolock lock(mStateLock); + return getPhysicalDisplayIdsLocked(); + } sp getPhysicalDisplayToken(PhysicalDisplayId displayId) const override; status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo, const Vector& state, @@ -951,6 +954,11 @@ private: } sp getDefaultDisplayDeviceLocked() REQUIRES(mStateLock) { + if (const auto display = getDisplayDeviceLocked(mActiveDisplayToken)) { + return display; + } + // The active display is outdated, fall back to the internal display + mActiveDisplayToken.clear(); if (const auto token = getInternalDisplayTokenLocked()) { return getDisplayDeviceLocked(token); } @@ -976,12 +984,18 @@ private: return findDisplay([id](const auto& display) { return display.getId() == id; }); } + std::vector getPhysicalDisplayIdsLocked() const REQUIRES(mStateLock); + // mark a region of a layer stack dirty. this updates the dirty // region of all screens presenting this layer stack. void invalidateLayerStack(const sp& layer, const Region& dirty); sp getDisplayWithInputByLayer(Layer* layer) const REQUIRES(mStateLock); + bool isDisplayActiveLocked(const sp& display) REQUIRES(mStateLock) { + return display->getDisplayToken() == mActiveDisplayToken; + } + /* * H/W composer */ @@ -1104,6 +1118,10 @@ private: REQUIRES(mStateLock); void releaseVirtualDisplay(VirtualDisplayId); + void onActiveDisplayChangedLocked(const sp& activeDisplay) REQUIRES(mStateLock); + + void onActiveDisplaySizeChanged(const sp& activeDisplay); + /* * Debugging & dumpsys */ @@ -1183,6 +1201,9 @@ private: std::chrono::nanoseconds presentLatency); int getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const; + void updateInternalDisplayVsyncLocked(const DisplayModes& modes, DisplayModeId currentModeId) + REQUIRES(mStateLock); + sp mStartPropertySetThread; surfaceflinger::Factory& mFactory; @@ -1471,6 +1492,8 @@ private: void scheduleRegionSamplingThread(); void notifyRegionSamplingThread(); + + wp mActiveDisplayToken GUARDED_BY(mStateLock); }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 0023aa0ab3..eef0ea9b33 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -171,7 +171,7 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSup mScheduler->setDisplayPowerState(kPowerStateNormal); constexpr uint32_t kDisplayArea = 999'999; - mScheduler->onPrimaryDisplayAreaChanged(kDisplayArea); + mScheduler->onActiveDisplayAreaChanged(kDisplayArea); EXPECT_CALL(mSchedulerCallback, changeRefreshRate(_, _)).Times(0); mScheduler->chooseRefreshRateForContent(); @@ -235,7 +235,7 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { mScheduler->setDisplayPowerState(kPowerStateNormal); constexpr uint32_t kDisplayArea = 999'999; - mScheduler->onPrimaryDisplayAreaChanged(kDisplayArea); + mScheduler->onActiveDisplayAreaChanged(kDisplayArea); EXPECT_CALL(mSchedulerCallback, changeRefreshRate(Is120Hz(), _)).Times(1); mScheduler->chooseRefreshRateForContent(); -- cgit v1.2.3-59-g8ed1b From 690f461b0141225696e89f73b406331c005f0716 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 1 Jul 2021 23:24:03 -0700 Subject: SF: Move desired active mode management to DisplayDevice SF would set the desired active mode on the specific DisplayDevice the mode was requested and use it to swicth the active display mode. Change-Id: Ib4f01ec63b2087ab2a81490051d1e029afc71854 Test: SF unit tests Test: refresh rate switching is working on device with more than one display Bug: 187539899 Change-Id: Ie0e5ffe364f81775c2101ffd0cf2c596051947fa --- services/surfaceflinger/DisplayDevice.cpp | 61 ++++- services/surfaceflinger/DisplayDevice.h | 36 ++- services/surfaceflinger/MainThreadGuard.h | 35 +++ services/surfaceflinger/Scheduler/EventThread.cpp | 15 +- services/surfaceflinger/Scheduler/EventThread.h | 6 +- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 1 + services/surfaceflinger/Scheduler/Scheduler.cpp | 73 ++--- services/surfaceflinger/Scheduler/Scheduler.h | 16 +- services/surfaceflinger/SurfaceFlinger.cpp | 300 +++++++++------------ services/surfaceflinger/SurfaceFlinger.h | 44 ++- services/surfaceflinger/tests/unittests/Android.bp | 1 + .../unittests/DisplayDevice_InitiateModeChange.cpp | 173 ++++++++++++ .../tests/unittests/EventThreadTest.cpp | 31 ++- .../tests/unittests/SchedulerTest.cpp | 15 +- .../tests/unittests/TestableScheduler.h | 5 +- .../tests/unittests/TestableSurfaceFlinger.h | 2 +- .../tests/unittests/mock/MockEventThread.h | 2 +- 17 files changed, 524 insertions(+), 292 deletions(-) create mode 100644 services/surfaceflinger/MainThreadGuard.h create mode 100644 services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 60f2408ada..4445eea604 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -22,6 +22,8 @@ #undef LOG_TAG #define LOG_TAG "DisplayDevice" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + #include #include #include @@ -66,6 +68,8 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) mSequenceId(args.sequenceId), mConnectionType(args.connectionType), mCompositionDisplay{args.compositionDisplay}, + mActiveModeFPSTrace("ActiveModeFPS -" + to_string(getId())), + mActiveModeFPSHwcTrace("ActiveModeFPS_HWC -" + to_string(getId())), mPhysicalOrientation(args.physicalOrientation), mSupportedModes(std::move(args.supportedModes)), mIsPrimary(args.isPrimary), @@ -156,6 +160,7 @@ bool DisplayDevice::isPoweredOn() const { void DisplayDevice::setActiveMode(DisplayModeId id) { const auto mode = getMode(id); LOG_FATAL_IF(!mode, "Cannot set active mode which is not supported."); + ATRACE_INT(mActiveModeFPSTrace.c_str(), mode->getFps().getIntValue()); mActiveMode = mode; if (mRefreshRateConfigs) { mRefreshRateConfigs->setCurrentModeId(mActiveMode->getId()); @@ -165,17 +170,19 @@ void DisplayDevice::setActiveMode(DisplayModeId id) { } } -status_t DisplayDevice::initiateModeChange(DisplayModeId modeId, +status_t DisplayDevice::initiateModeChange(const ActiveModeInfo& info, const hal::VsyncPeriodChangeConstraints& constraints, - hal::VsyncPeriodChangeTimeline* outTimeline) const { - const auto mode = getMode(modeId); - if (!mode) { + hal::VsyncPeriodChangeTimeline* outTimeline) { + if (!info.mode || info.mode->getPhysicalDisplayId() != getPhysicalId()) { ALOGE("Trying to initiate a mode change to invalid mode %s on display %s", - std::to_string(modeId.value()).c_str(), to_string(getId()).c_str()); + info.mode ? std::to_string(info.mode->getId().value()).c_str() : "null", + to_string(getId()).c_str()); return BAD_VALUE; } - return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), mode->getHwcId(), constraints, - outTimeline); + mUpcomingActiveMode = info; + ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), info.mode->getFps().getIntValue()); + return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), info.mode->getHwcId(), + constraints, outTimeline); } const DisplayModePtr& DisplayDevice::getActiveMode() const { @@ -435,6 +442,46 @@ void DisplayDevice::onInvalidate() { } } +bool DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info) { + ATRACE_CALL(); + + LOG_ALWAYS_FATAL_IF(!info.mode, "desired mode not provided"); + LOG_ALWAYS_FATAL_IF(getPhysicalId() != info.mode->getPhysicalDisplayId(), "DisplayId mismatch"); + + ALOGV("%s(%s)", __func__, to_string(*info.mode).c_str()); + + std::scoped_lock lock(mActiveModeLock); + if (mDesiredActiveModeChanged) { + // If a mode change is pending, just cache the latest request in mDesiredActiveMode + const Scheduler::ModeEvent prevConfig = mDesiredActiveMode.event; + mDesiredActiveMode = info; + mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig; + return false; + } + + // Check if we are already at the desired mode + if (getActiveMode()->getId() == info.mode->getId()) { + return false; + } + + // Initiate a mode change. + mDesiredActiveModeChanged = true; + mDesiredActiveMode = info; + return true; +} + +std::optional DisplayDevice::getDesiredActiveMode() const { + std::scoped_lock lock(mActiveModeLock); + if (mDesiredActiveModeChanged) return mDesiredActiveMode; + return std::nullopt; +} + +void DisplayDevice::clearDesiredActiveModeState() { + std::scoped_lock lock(mActiveModeLock); + mDesiredActiveMode.event = Scheduler::ModeEvent::None; + mDesiredActiveModeChanged = false; +} + std::atomic DisplayDeviceState::sNextSequenceId(1); } // namespace android diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index e7067eb231..afd12b59a3 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -39,6 +39,8 @@ #include #include +#include "MainThreadGuard.h" + #include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/DisplayMode.h" #include "DisplayHardware/Hal.h" @@ -46,6 +48,8 @@ #include "Scheduler/RefreshRateConfigs.h" +#include "TracedOrdinal.h" + namespace android { class Fence; @@ -181,10 +185,28 @@ public: * Display mode management. */ const DisplayModePtr& getActiveMode() const; - void setActiveMode(DisplayModeId); - status_t initiateModeChange(DisplayModeId modeId, + + struct ActiveModeInfo { + DisplayModePtr mode; + scheduler::RefreshRateConfigEvent event = scheduler::RefreshRateConfigEvent::None; + + bool operator!=(const ActiveModeInfo& other) const { + return mode != other.mode || event != other.event; + } + }; + + bool setDesiredActiveMode(const ActiveModeInfo&) EXCLUDES(mActiveModeLock); + std::optional getDesiredActiveMode() const EXCLUDES(mActiveModeLock); + void clearDesiredActiveModeState() EXCLUDES(mActiveModeLock); + ActiveModeInfo getUpcomingActiveMode() const REQUIRES(SF_MAIN_THREAD) { + return mUpcomingActiveMode; + } + + void setActiveMode(DisplayModeId) REQUIRES(SF_MAIN_THREAD); + status_t initiateModeChange(const ActiveModeInfo&, const hal::VsyncPeriodChangeConstraints& constraints, - hal::VsyncPeriodChangeTimeline* outTimeline) const; + hal::VsyncPeriodChangeTimeline* outTimeline) + REQUIRES(SF_MAIN_THREAD); // Return the immutable list of supported display modes. The HWC may report different modes // after a hotplug reconnect event, in which case the DisplayDevice object will be recreated. @@ -236,6 +258,8 @@ private: const std::shared_ptr mCompositionDisplay; std::string mDisplayName; + std::string mActiveModeFPSTrace; + std::string mActiveModeFPSHwcTrace; const ui::Rotation mPhysicalOrientation; ui::Rotation mOrientation = ui::ROTATION_0; @@ -260,6 +284,12 @@ private: std::shared_ptr mRefreshRateConfigs; std::unique_ptr mRefreshRateOverlay; + + mutable std::mutex mActiveModeLock; + ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock); + TracedOrdinal mDesiredActiveModeChanged + GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false}; + ActiveModeInfo mUpcomingActiveMode GUARDED_BY(SF_MAIN_THREAD); }; struct DisplayDeviceState { diff --git a/services/surfaceflinger/MainThreadGuard.h b/services/surfaceflinger/MainThreadGuard.h new file mode 100644 index 0000000000..c1aa118492 --- /dev/null +++ b/services/surfaceflinger/MainThreadGuard.h @@ -0,0 +1,35 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace android { +namespace { + +// Helps to ensure that some functions runs on SF's main thread by using the +// clang thread safety annotations. +class CAPABILITY("mutex") MainThreadGuard { +} SF_MAIN_THREAD; + +struct SCOPED_CAPABILITY MainThreadScopedGuard { +public: + explicit MainThreadScopedGuard(MainThreadGuard& mutex) ACQUIRE(mutex) {} + ~MainThreadScopedGuard() RELEASE() {} +}; +} // namespace +} // namespace android diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 2321e2d082..2bdcaf6ad0 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -118,12 +118,12 @@ DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t times return event; } -DisplayEventReceiver::Event makeModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId, - nsecs_t vsyncPeriod) { +DisplayEventReceiver::Event makeModeChanged(DisplayModePtr mode) { DisplayEventReceiver::Event event; - event.header = {DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE, displayId, systemTime()}; - event.modeChange.modeId = modeId.value(); - event.modeChange.vsyncPeriod = vsyncPeriod; + event.header = {DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE, mode->getPhysicalDisplayId(), + systemTime()}; + event.modeChange.modeId = mode->getId().value(); + event.modeChange.vsyncPeriod = mode->getVsyncPeriod(); return event; } @@ -375,11 +375,10 @@ void EventThread::onHotplugReceived(PhysicalDisplayId displayId, bool connected) mCondition.notify_all(); } -void EventThread::onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId, - nsecs_t vsyncPeriod) { +void EventThread::onModeChanged(DisplayModePtr mode) { std::lock_guard lock(mMutex); - mPendingEvents.push_back(makeModeChanged(displayId, modeId, vsyncPeriod)); + mPendingEvents.push_back(makeModeChanged(mode)); mCondition.notify_all(); } diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 1e6793f77c..9265a25b86 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -124,8 +124,7 @@ public: virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0; // called when SF changes the active mode and apps needs to be notified about the change - virtual void onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId, - nsecs_t vsyncPeriod) = 0; + virtual void onModeChanged(DisplayModePtr) = 0; // called when SF updates the Frame Rate Override list virtual void onFrameRateOverridesChanged(PhysicalDisplayId displayId, @@ -174,8 +173,7 @@ public: void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override; - void onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId, - nsecs_t vsyncPeriod) override; + void onModeChanged(DisplayModePtr) override; void onFrameRateOverridesChanged(PhysicalDisplayId displayId, std::vector overrides) override; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 5fc19daf85..4a9a1fd9fc 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -71,6 +71,7 @@ public: int32_t getModeGroup() const { return mode->getGroup(); } std::string getName() const { return to_string(getFps()); } Fps getFps() const { return mode->getFps(); } + DisplayModePtr getMode() const { return mode; } // Checks whether the fps of this RefreshRate struct is within a given min and max refresh // rate passed in. Margin of error is applied to the boundaries for approximation. diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 861f3acaac..f808981d0f 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -371,23 +371,22 @@ void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDis thread->onFrameRateOverridesChanged(displayId, std::move(overrides)); } -void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId, - DisplayModeId modeId, nsecs_t vsyncPeriod) { +void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { { std::lock_guard lock(mFeatureStateLock); // Cache the last reported modes for primary display. - mFeatures.cachedModeChangedParams = {handle, displayId, modeId, vsyncPeriod}; + mFeatures.cachedModeChangedParams = {handle, mode}; // Invalidate content based refresh rate selection so it could be calculated // again for the new refresh rate. mFeatures.contentRequirements.clear(); } - onNonPrimaryDisplayModeChanged(handle, displayId, modeId, vsyncPeriod); + onNonPrimaryDisplayModeChanged(handle, mode); } void Scheduler::dispatchCachedReportedMode() { // Check optional fields first. - if (!mFeatures.modeId.has_value()) { + if (!mFeatures.mode) { ALOGW("No mode ID found, not dispatching cached mode."); return; } @@ -396,35 +395,24 @@ void Scheduler::dispatchCachedReportedMode() { return; } - const auto modeId = *mFeatures.modeId; - const auto vsyncPeriod = [&] { - std::scoped_lock lock(mRefreshRateConfigsLock); - return mRefreshRateConfigs->getRefreshRateFromModeId(modeId).getVsyncPeriod(); - }(); - // If there is no change from cached mode, there is no need to dispatch an event - if (modeId == mFeatures.cachedModeChangedParams->modeId && - vsyncPeriod == mFeatures.cachedModeChangedParams->vsyncPeriod) { + if (mFeatures.mode == mFeatures.cachedModeChangedParams->mode) { return; } - mFeatures.cachedModeChangedParams->modeId = modeId; - mFeatures.cachedModeChangedParams->vsyncPeriod = vsyncPeriod; + mFeatures.cachedModeChangedParams->mode = mFeatures.mode; onNonPrimaryDisplayModeChanged(mFeatures.cachedModeChangedParams->handle, - mFeatures.cachedModeChangedParams->displayId, - mFeatures.cachedModeChangedParams->modeId, - mFeatures.cachedModeChangedParams->vsyncPeriod); + mFeatures.cachedModeChangedParams->mode); } -void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId, - DisplayModeId modeId, nsecs_t vsyncPeriod) { +void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { android::EventThread* thread; { std::lock_guard lock(mConnectionsLock); RETURN_IF_INVALID_HANDLE(handle); thread = mConnections[handle].thread.get(); } - thread->onModeChanged(displayId, modeId, vsyncPeriod); + thread->onModeChanged(mode); } size_t Scheduler::getEventThreadConnectionCount(ConnectionHandle handle) { @@ -642,19 +630,17 @@ void Scheduler::chooseRefreshRateForContent() { scheduler::LayerHistory::Summary summary = mLayerHistory->summarize(*refreshRateConfigs, systemTime()); scheduler::RefreshRateConfigs::GlobalSignals consideredSignals; - DisplayModeId newModeId; + DisplayModePtr newMode; bool frameRateChanged; bool frameRateOverridesChanged; { std::lock_guard lock(mFeatureStateLock); mFeatures.contentRequirements = summary; - newModeId = calculateRefreshRateModeId(&consideredSignals); - auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newModeId); - frameRateOverridesChanged = - updateFrameRateOverrides(consideredSignals, newRefreshRate.getFps()); + newMode = calculateRefreshRateModeId(&consideredSignals); + frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); - if (mFeatures.modeId == newModeId) { + if (mFeatures.mode == newMode) { // We don't need to change the display mode, but we might need to send an event // about a mode change, since it was suppressed due to a previous idleConsidered if (!consideredSignals.idle) { @@ -662,12 +648,12 @@ void Scheduler::chooseRefreshRateForContent() { } frameRateChanged = false; } else { - mFeatures.modeId = newModeId; + mFeatures.mode = newMode; frameRateChanged = true; } } if (frameRateChanged) { - auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newModeId); + auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); mSchedulerCallback.changeRefreshRate(newRefreshRate, consideredSignals.idle ? ModeEvent::None : ModeEvent::Changed); @@ -820,7 +806,7 @@ bool Scheduler::updateFrameRateOverrides( template bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { - DisplayModeId newModeId; + DisplayModePtr newMode; bool refreshRateChanged = false; bool frameRateOverridesChanged; scheduler::RefreshRateConfigs::GlobalSignals consideredSignals; @@ -831,23 +817,22 @@ bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { return false; } *currentState = newState; - newModeId = calculateRefreshRateModeId(&consideredSignals); - const RefreshRate& newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newModeId); - frameRateOverridesChanged = - updateFrameRateOverrides(consideredSignals, newRefreshRate.getFps()); - if (mFeatures.modeId == newModeId) { + newMode = calculateRefreshRateModeId(&consideredSignals); + frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); + if (mFeatures.mode == newMode) { // We don't need to change the display mode, but we might need to send an event // about a mode change, since it was suppressed due to a previous idleConsidered if (!consideredSignals.idle) { dispatchCachedReportedMode(); } } else { - mFeatures.modeId = newModeId; + mFeatures.mode = newMode; refreshRateChanged = true; } } if (refreshRateChanged) { - const RefreshRate& newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newModeId); + const RefreshRate& newRefreshRate = + refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); mSchedulerCallback.changeRefreshRate(newRefreshRate, consideredSignals.idle ? ModeEvent::None @@ -859,7 +844,7 @@ bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { return consideredSignals.touch; } -DisplayModeId Scheduler::calculateRefreshRateModeId( +DisplayModePtr Scheduler::calculateRefreshRateModeId( scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals) { ATRACE_CALL(); if (consideredSignals) *consideredSignals = {}; @@ -870,7 +855,7 @@ DisplayModeId Scheduler::calculateRefreshRateModeId( if (mDisplayPowerTimer && (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset)) { - return refreshRateConfigs->getMaxRefreshRateByPolicy().getModeId(); + return refreshRateConfigs->getMaxRefreshRateByPolicy().getMode(); } const bool touchActive = mTouchTimer && mFeatures.touch == TouchState::Active; @@ -879,16 +864,16 @@ DisplayModeId Scheduler::calculateRefreshRateModeId( return refreshRateConfigs ->getBestRefreshRate(mFeatures.contentRequirements, {.touch = touchActive, .idle = idle}, consideredSignals) - .getModeId(); + .getMode(); } -std::optional Scheduler::getPreferredModeId() { +DisplayModePtr Scheduler::getPreferredDisplayMode() { std::lock_guard lock(mFeatureStateLock); // Make sure that the default mode ID is first updated, before returned. - if (mFeatures.modeId.has_value()) { - mFeatures.modeId = calculateRefreshRateModeId(); + if (mFeatures.mode) { + mFeatures.mode = calculateRefreshRateModeId(); } - return mFeatures.modeId; + return mFeatures.mode; } void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index dc17f903c2..4b6905bc6d 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -87,10 +87,8 @@ public: sp getEventConnection(ConnectionHandle); void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected); - void onPrimaryDisplayModeChanged(ConnectionHandle, PhysicalDisplayId, DisplayModeId, - nsecs_t vsyncPeriod) EXCLUDES(mFeatureStateLock); - void onNonPrimaryDisplayModeChanged(ConnectionHandle, PhysicalDisplayId, DisplayModeId, - nsecs_t vsyncPeriod); + void onPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr) EXCLUDES(mFeatureStateLock); + void onNonPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr); void onScreenAcquired(ConnectionHandle); void onScreenReleased(ConnectionHandle); @@ -157,7 +155,7 @@ public: void dumpVsync(std::string&) const; // Get the appropriate refresh for current conditions. - std::optional getPreferredModeId(); + DisplayModePtr getPreferredDisplayMode(); // Notifies the scheduler about a refresh rate timeline change. void onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline); @@ -245,7 +243,7 @@ private: // This function checks whether individual features that are affecting the refresh rate // selection were initialized, prioritizes them, and calculates the DisplayModeId // for the suggested refresh rate. - DisplayModeId calculateRefreshRateModeId( + DisplayModePtr calculateRefreshRateModeId( scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr) REQUIRES(mFeatureStateLock); @@ -308,7 +306,7 @@ private: TouchState touch = TouchState::Inactive; TimerState displayPowerTimer = TimerState::Expired; - std::optional modeId; + DisplayModePtr mode; LayerHistory::Summary contentRequirements; bool isDisplayPowerStateNormal = true; @@ -316,9 +314,7 @@ private: // Used to cache the last parameters of onPrimaryDisplayModeChanged struct ModeChangedParams { ConnectionHandle handle; - PhysicalDisplayId displayId; - DisplayModeId modeId; - nsecs_t vsyncPeriod; + DisplayModePtr mode; }; std::optional cachedModeChangedParams; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 0892d6590c..f7ba9e2239 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -145,6 +145,13 @@ return (expr); \ }() +#define MAIN_THREAD_GUARD(expr) \ + [&] { \ + LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \ + MainThreadScopedGuard lock(SF_MAIN_THREAD); \ + return (expr); \ + }() + #undef NO_THREAD_SAFETY_ANALYSIS #define NO_THREAD_SAFETY_ANALYSIS \ _Pragma("GCC error \"Prefer MAIN_THREAD macros or {Conditional,Timed,Unnecessary}Lock.\"") @@ -1073,41 +1080,28 @@ status_t SurfaceFlinger::getDisplayStats(const sp&, DisplayStatInfo* st void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) { ATRACE_CALL(); - const auto display = getDefaultDisplayDeviceLocked(); + + if (!info.mode) { + ALOGW("requested display mode is null"); + return; + } + auto display = getDisplayDeviceLocked(info.mode->getPhysicalDisplayId()); if (!display) { - ALOGW("%s: default display is null", __func__); + ALOGW("%s: display is no longer valid", __func__); return; } - auto refreshRate = display->refreshRateConfigs().getRefreshRateFromModeId(info.modeId); - ALOGV("%s(%s)", __func__, refreshRate.getName().c_str()); - - std::lock_guard lock(mActiveModeLock); - if (mDesiredActiveModeChanged) { - // If a mode change is pending, just cache the latest request in mDesiredActiveMode - const Scheduler::ModeEvent prevConfig = mDesiredActiveMode.event; - mDesiredActiveMode = info; - mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig; - } else { - // Check if we are already at the desired mode - if (display->getActiveMode()->getId() == refreshRate.getModeId()) { - return; - } - - // Initiate a mode change. - mDesiredActiveModeChanged = true; - mDesiredActiveMode = info; - + if (display->setDesiredActiveMode(info)) { // This will trigger HWC refresh without resetting the idle timer. repaintEverythingForHWC(); // Start receiving vsync samples now, so that we can detect a period // switch. - mScheduler->resyncToHardwareVsync(true, refreshRate.getVsyncPeriod()); + mScheduler->resyncToHardwareVsync(true, info.mode->getVsyncPeriod()); // As we called to set period, we will call to onRefreshRateChangeCompleted once // VsyncController model is locked. modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated); - updatePhaseConfiguration(refreshRate.getFps()); + updatePhaseConfiguration(info.mode->getFps()); mScheduler->setModeChangePending(true); } } @@ -1161,58 +1155,43 @@ void SurfaceFlinger::setActiveModeInternal() { return; } - const auto upcomingMode = display->getMode(mUpcomingActiveMode.modeId); - if (!upcomingMode) { - ALOGW("Upcoming active mode is no longer supported. Mode ID = %d", - mUpcomingActiveMode.modeId.value()); - // TODO(b/159590486) Handle the error better. Some parts of SurfaceFlinger may - // have been already updated with the upcoming active mode. - return; - } - - if (display->getActiveMode()->getSize() != upcomingMode->getSize()) { + const auto upcomingModeInfo = MAIN_THREAD_GUARD(display->getUpcomingActiveMode()); + if (display->getActiveMode()->getSize() != upcomingModeInfo.mode->getSize()) { auto& state = mCurrentState.displays.editValueFor(display->getDisplayToken()); // We need to generate new sequenceId in order to recreate the display (and this // way the framebuffer). state.sequenceId = DisplayDeviceState{}.sequenceId; - state.physical->activeMode = upcomingMode; + state.physical->activeMode = upcomingModeInfo.mode; processDisplayChangesLocked(); // processDisplayChangesLocked will update all necessary components so we're done here. return; } - std::lock_guard lock(mActiveModeLock); - display->setActiveMode(mUpcomingActiveMode.modeId); - - const Fps refreshRate = upcomingMode->getFps(); + // We just created this display so we can call even if we are not on + // the main thread + MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD); + display->setActiveMode(upcomingModeInfo.mode->getId()); + const Fps refreshRate = upcomingModeInfo.mode->getFps(); mRefreshRateStats->setRefreshRate(refreshRate); - updatePhaseConfiguration(refreshRate); - ATRACE_INT("ActiveConfigFPS", refreshRate.getValue()); - if (mUpcomingActiveMode.event != Scheduler::ModeEvent::None) { - const nsecs_t vsyncPeriod = refreshRate.getPeriodNsecs(); - const auto physicalId = display->getPhysicalId(); - mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, physicalId, - mUpcomingActiveMode.modeId, vsyncPeriod); + if (upcomingModeInfo.event != Scheduler::ModeEvent::None) { + mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, upcomingModeInfo.mode); } } -void SurfaceFlinger::clearDesiredActiveModeState() { - std::lock_guard lock(mActiveModeLock); - mDesiredActiveMode.event = Scheduler::ModeEvent::None; - mDesiredActiveModeChanged = false; - mScheduler->setModeChangePending(false); +void SurfaceFlinger::clearDesiredActiveModeState(const sp& display) { + display->clearDesiredActiveModeState(); + if (isDisplayActiveLocked(display)) { + mScheduler->setModeChangePending(false); + } } -void SurfaceFlinger::desiredActiveModeChangeDone() { - const auto modeId = getDesiredActiveMode()->modeId; - - clearDesiredActiveModeState(); - - const auto refreshRate = getDefaultDisplayDeviceLocked()->getMode(modeId)->getFps(); +void SurfaceFlinger::desiredActiveModeChangeDone(const sp& display) { + const auto refreshRate = display->getDesiredActiveMode()->mode->getFps(); + clearDesiredActiveModeState(display); mScheduler->resyncToHardwareVsync(true, refreshRate.getPeriodNsecs()); updatePhaseConfiguration(refreshRate); } @@ -1220,63 +1199,75 @@ void SurfaceFlinger::desiredActiveModeChangeDone() { void SurfaceFlinger::performSetActiveMode() { ATRACE_CALL(); ALOGV("%s", __FUNCTION__); - // Store the local variable to release the lock. - const auto desiredActiveMode = getDesiredActiveMode(); - if (!desiredActiveMode) { - // No desired active mode pending to be applied - return; - } - const auto display = getDefaultDisplayDeviceLocked(); - const auto desiredMode = display->getMode(desiredActiveMode->modeId); - if (!desiredMode) { - ALOGW("Desired display mode is no longer supported. Mode ID = %d", - desiredActiveMode->modeId.value()); - clearDesiredActiveModeState(); - return; - } - const auto refreshRate = desiredMode->getFps(); - ALOGV("%s changing active mode to %d(%s)", __FUNCTION__, desiredMode->getId().value(), - to_string(refreshRate).c_str()); + for (const auto& iter : mDisplays) { + const auto& display = iter.second; + if (!display || !display->isInternal()) { + continue; + } - if (!display || display->getActiveMode()->getId() == desiredActiveMode->modeId) { - // display is not valid or we are already in the requested mode - // on both cases there is nothing left to do - desiredActiveModeChangeDone(); - return; - } + // Store the local variable to release the lock. + const auto desiredActiveMode = display->getDesiredActiveMode(); + if (!desiredActiveMode) { + // No desired active mode pending to be applied + continue; + } - // Desired active mode was set, it is different than the mode currently in use, however - // allowed modes might have changed by the time we process the refresh. - // Make sure the desired mode is still allowed - if (!isDisplayModeAllowed(desiredActiveMode->modeId)) { - desiredActiveModeChangeDone(); - return; - } + if (!isDisplayActiveLocked(display)) { + // display is no longer the active display, so abort the mode change + clearDesiredActiveModeState(display); + continue; + } - mUpcomingActiveMode = *desiredActiveMode; + const auto desiredMode = display->getMode(desiredActiveMode->mode->getId()); + if (!desiredMode) { + ALOGW("Desired display mode is no longer supported. Mode ID = %d", + desiredActiveMode->mode->getId().value()); + clearDesiredActiveModeState(display); + continue; + } - ATRACE_INT("ActiveModeFPS_HWC", refreshRate.getValue()); + const auto refreshRate = desiredMode->getFps(); + ALOGV("%s changing active mode to %d(%s) for display %s", __func__, + desiredMode->getId().value(), to_string(refreshRate).c_str(), + to_string(display->getId()).c_str()); - // TODO(b/142753666) use constrains - hal::VsyncPeriodChangeConstraints constraints; - constraints.desiredTimeNanos = systemTime(); - constraints.seamlessRequired = false; + if (display->getActiveMode()->getId() == desiredActiveMode->mode->getId()) { + // display is not valid or we are already in the requested mode + // on both cases there is nothing left to do + desiredActiveModeChangeDone(display); + continue; + } - hal::VsyncPeriodChangeTimeline outTimeline; - const auto status = - display->initiateModeChange(mUpcomingActiveMode.modeId, constraints, &outTimeline); - if (status != NO_ERROR) { - // initiateModeChange may fail if a hotplug event is just about - // to be sent. We just log the error in this case. - ALOGW("initiateModeChange failed: %d", status); - return; - } + // Desired active mode was set, it is different than the mode currently in use, however + // allowed modes might have changed by the time we process the refresh. + // Make sure the desired mode is still allowed + const auto displayModeAllowed = + display->refreshRateConfigs().isModeAllowed(desiredActiveMode->mode->getId()); + if (!displayModeAllowed) { + desiredActiveModeChangeDone(display); + continue; + } - mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline); + // TODO(b/142753666) use constrains + hal::VsyncPeriodChangeConstraints constraints; + constraints.desiredTimeNanos = systemTime(); + constraints.seamlessRequired = false; + hal::VsyncPeriodChangeTimeline outTimeline; + + const auto status = MAIN_THREAD_GUARD( + display->initiateModeChange(*desiredActiveMode, constraints, &outTimeline)); + if (status != NO_ERROR) { + // initiateModeChange may fail if a hotplug event is just about + // to be sent. We just log the error in this case. + ALOGW("initiateModeChange failed: %d", status); + continue; + } + mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline); - // Scheduler will submit an empty frame to HWC if needed. - mSetActiveModePending = true; + // Scheduler will submit an empty frame to HWC if needed. + mSetActiveModePending = true; + } } void SurfaceFlinger::disableExpensiveRendering() { @@ -1743,15 +1734,6 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { *compositorTiming = getBE().mCompositorTiming; } -bool SurfaceFlinger::isDisplayModeAllowed(DisplayModeId modeId) const { - const auto display = getDefaultDisplayDeviceLocked(); - if (display) { - return display->refreshRateConfigs().isModeAllowed(modeId); - } - ALOGW("%s: default display is null", __func__); - return false; -} - void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate, Scheduler::ModeEvent event) { const auto display = getDefaultDisplayDeviceLocked(); @@ -1761,13 +1743,13 @@ void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate, ATRACE_CALL(); // Don't do any updating if the current fps is the same as the new one. - if (!isDisplayModeAllowed(refreshRate.getModeId())) { + if (!display->refreshRateConfigs().isModeAllowed(refreshRate.getModeId())) { ALOGV("Skipping mode %d as it is not part of allowed modes", refreshRate.getModeId().value()); return; } - setDesiredActiveMode({refreshRate.getModeId(), event}); + setDesiredActiveMode({refreshRate.getMode(), event}); } void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, @@ -2711,7 +2693,7 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN}); if (!state.isVirtual()) { - display->setActiveMode(state.physical->activeMode->getId()); + MAIN_THREAD_GUARD(display->setActiveMode(state.physical->activeMode->getId())); display->setDeviceProductInfo(state.physical->deviceProductInfo); } @@ -3135,7 +3117,6 @@ void SurfaceFlinger::initScheduler(const sp& display) { ALOGW("Can't re-init scheduler"); return; } - const auto displayId = display->getId(); const auto currRefreshRate = display->getActiveMode()->getFps(); mRefreshRateStats = std::make_unique(*mTimeStats, currRefreshRate, hal::PowerMode::OFF); @@ -3173,9 +3154,7 @@ void SurfaceFlinger::initScheduler(const sp& display) { // This is a bit hacky, but this avoids a back-pointer into the main SF // classes from EventThread, and there should be no run-time binder cost // anyway since there are no connected apps at this point. - mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, - *PhysicalDisplayId::tryCast(displayId), - display->getActiveMode()->getId(), vsyncPeriod); + mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, display->getActiveMode()); static auto ignorePresentFences = base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false); mScheduler->setIgnorePresentFences( @@ -5788,16 +5767,19 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { // Update the overlay on the main thread to avoid race conditions with // mRefreshRateConfigs->getCurrentRefreshRate() static_cast(schedule([=] { - const auto desiredActiveMode = getDesiredActiveMode(); - const std::optional desiredModeId = - desiredActiveMode ? std::make_optional(desiredActiveMode->modeId) : std::nullopt; - - const bool timerExpired = mKernelIdleTimerEnabled && expired; const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); if (!display) { ALOGW("%s: default display is null", __func__); return; } + + const auto desiredActiveMode = display->getDesiredActiveMode(); + const std::optional desiredModeId = desiredActiveMode + ? std::make_optional(desiredActiveMode->mode->getId()) + : std::nullopt; + + const bool timerExpired = mKernelIdleTimerEnabled && expired; + if (display->onKernelTimerChanged(desiredModeId, timerExpired)) { mEventQueue->invalidate(); } @@ -6432,12 +6414,6 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( const std::optional& policy, bool overridePolicy) { Mutex::Autolock lock(mStateLock); - const bool isDefaultDisplay = display == getDefaultDisplayDeviceLocked(); - - LOG_ALWAYS_FATAL_IF(!isDefaultDisplay && overridePolicy, - "Can only set override policy on the default display"); - LOG_ALWAYS_FATAL_IF(!policy && !overridePolicy, "Can only clear the override policy"); - if (mDebugDisplayModeSetByBackdoor) { // ignore this request as mode is overridden by backdoor return NO_ERROR; @@ -6453,32 +6429,6 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( return NO_ERROR; } - if (!isDefaultDisplay) { - // TODO(b/144711714): For non-default displays we should be able to set an active mode - // as well. For now, just call directly to initiateModeChange but ideally - // it should go thru setDesiredActiveMode, similar to primary display. - ALOGV("%s for non-default display", __func__); - const auto displayId = display->getPhysicalId(); - - hal::VsyncPeriodChangeConstraints constraints; - constraints.desiredTimeNanos = systemTime(); - constraints.seamlessRequired = false; - - hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0}; - if (display->initiateModeChange(policy->defaultMode, constraints, &timeline) != NO_ERROR) { - return BAD_VALUE; - } - if (timeline.refreshRequired) { - repaintEverythingForHWC(); - } - - display->setActiveMode(policy->defaultMode); - const nsecs_t vsyncPeriod = display->getMode(policy->defaultMode)->getVsyncPeriod(); - mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, displayId, - policy->defaultMode, vsyncPeriod); - return NO_ERROR; - } - scheduler::RefreshRateConfigs::Policy currentPolicy = display->refreshRateConfigs().getCurrentPolicy(); @@ -6487,25 +6437,32 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( // TODO(b/140204874): Leave the event in until we do proper testing with all apps that might // be depending in this callback. const auto activeMode = display->getActiveMode(); - const nsecs_t vsyncPeriod = activeMode->getVsyncPeriod(); - const auto physicalId = display->getPhysicalId(); - mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, physicalId, activeMode->getId(), - vsyncPeriod); - toggleKernelIdleTimer(); - - auto modeId = mScheduler->getPreferredModeId() ? *mScheduler->getPreferredModeId() - : currentPolicy.defaultMode; - auto preferredRefreshRate = display->refreshRateConfigs().getRefreshRateFromModeId(modeId); + if (isDisplayActiveLocked(display)) { + mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode); + toggleKernelIdleTimer(); + } else { + mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode); + } + + const DisplayModePtr preferredDisplayMode = [&] { + const auto schedulerMode = mScheduler->getPreferredDisplayMode(); + if (schedulerMode && schedulerMode->getPhysicalDisplayId() == display->getPhysicalId()) { + return schedulerMode; + } + + return display->getMode(currentPolicy.defaultMode); + }(); + ALOGV("trying to switch to Scheduler preferred mode %d (%s)", - preferredRefreshRate.getModeId().value(), preferredRefreshRate.getName().c_str()); + preferredDisplayMode->getId().value(), to_string(preferredDisplayMode->getFps()).c_str()); - if (isDisplayModeAllowed(preferredRefreshRate.getModeId())) { + if (display->refreshRateConfigs().isModeAllowed(preferredDisplayMode->getId())) { ALOGV("switching to Scheduler preferred display mode %d", - preferredRefreshRate.getModeId().value()); - setDesiredActiveMode({preferredRefreshRate.getModeId(), Scheduler::ModeEvent::Changed}); + preferredDisplayMode->getId().value()); + setDesiredActiveMode({preferredDisplayMode, Scheduler::ModeEvent::Changed}); } else { LOG_ALWAYS_FATAL("Desired display mode not allowed: %d", - preferredRefreshRate.getModeId().value()); + preferredDisplayMode->getId().value()); } return NO_ERROR; @@ -6967,6 +6924,7 @@ void SurfaceFlinger::onActiveDisplayChangedLocked(const sp& activ return; } updateInternalDisplayVsyncLocked(activeDisplay); + mScheduler->setModeChangePending(false); mScheduler->setRefreshRateConfigs(activeDisplay->holdRefreshRateConfigs()); onActiveDisplaySizeChanged(activeDisplay); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b35ec3df7f..6755bfa597 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -453,14 +453,7 @@ private: mCounterByLayerHandle GUARDED_BY(mLock); }; - struct ActiveModeInfo { - DisplayModeId modeId; - Scheduler::ModeEvent event = Scheduler::ModeEvent::None; - - bool operator!=(const ActiveModeInfo& other) const { - return modeId != other.modeId || event != other.event; - } - }; + using ActiveModeInfo = DisplayDevice::ActiveModeInfo; enum class BootStage { BOOTLOADER, @@ -778,9 +771,9 @@ private: // Calls to setActiveMode on the main thread if there is a pending mode change // that needs to be applied. void performSetActiveMode() REQUIRES(mStateLock); - void clearDesiredActiveModeState() REQUIRES(mStateLock) EXCLUDES(mActiveModeLock); + void clearDesiredActiveModeState(const sp&) REQUIRES(mStateLock); // Called when active mode is no longer is progress - void desiredActiveModeChangeDone() REQUIRES(mStateLock); + void desiredActiveModeChangeDone(const sp&) REQUIRES(mStateLock); // Called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp& display, hal::PowerMode mode) REQUIRES(mStateLock); @@ -950,6 +943,18 @@ private: return it == mDisplays.end() ? nullptr : it->second; } + sp getDisplayDeviceLocked(PhysicalDisplayId id) const + REQUIRES(mStateLock) { + return const_cast(this)->getDisplayDeviceLocked(id); + } + + sp getDisplayDeviceLocked(PhysicalDisplayId id) REQUIRES(mStateLock) { + if (const auto token = getPhysicalDisplayTokenLocked(id)) { + return getDisplayDeviceLocked(token); + } + return nullptr; + } + sp getDefaultDisplayDeviceLocked() const REQUIRES(mStateLock) { return const_cast(this)->getDefaultDisplayDeviceLocked(); } @@ -1053,8 +1058,6 @@ private: // the desired refresh rate. void changeRefreshRateLocked(const RefreshRate&, Scheduler::ModeEvent) REQUIRES(mStateLock); - bool isDisplayModeAllowed(DisplayModeId) const REQUIRES(mStateLock); - struct FenceWithFenceTime { sp fence = Fence::NO_FENCE; std::shared_ptr fenceTime = FenceTime::NO_FENCE; @@ -1188,13 +1191,6 @@ private: /* * Misc */ - - std::optional getDesiredActiveMode() EXCLUDES(mActiveModeLock) { - std::lock_guard lock(mActiveModeLock); - if (mDesiredActiveModeChanged) return mDesiredActiveMode; - return std::nullopt; - } - std::vector getDisplayColorModes(PhysicalDisplayId displayId) REQUIRES(mStateLock); @@ -1407,17 +1403,7 @@ private: nsecs_t mScheduledPresentTime = 0; hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE; - std::mutex mActiveModeLock; - // This bit is set once we start setting the mode. We read from this bit during the - // process. If at the end, this bit is different than mDesiredActiveMode, we restart - // the process. - ActiveModeInfo mUpcomingActiveMode; // Always read and written on the main thread. - // This bit can be set at any point in time when the system wants the new mode. - ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock); - // below flags are set by main thread only - TracedOrdinal mDesiredActiveModeChanged - GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false}; bool mSetActiveModePending = false; bool mLumaSampling = true; diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index bd6fe1d713..8bd6e62278 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -54,6 +54,7 @@ cc_test { "DisplayIdGeneratorTest.cpp", "DisplayTransactionTest.cpp", "DisplayDevice_GetBestColorModeTest.cpp", + "DisplayDevice_InitiateModeChange.cpp", "DisplayDevice_SetProjectionTest.cpp", "EventThreadTest.cpp", "FpsReporterTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp new file mode 100644 index 0000000000..d4cfbbbe0c --- /dev/null +++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp @@ -0,0 +1,173 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "LibSurfaceFlingerUnittests" + +#include "DisplayTransactionTestHelpers.h" + +#include +#include + +namespace android { +namespace { + +using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector; + +class InitiateModeChangeTest : public DisplayTransactionTest { +public: + using Event = scheduler::RefreshRateConfigEvent; + + void SetUp() override { + injectFakeBufferQueueFactory(); + injectFakeNativeWindowSurfaceFactory(); + + PrimaryDisplayVariant::setupHwcHotplugCallExpectations(this); + PrimaryDisplayVariant::setupFramebufferConsumerBufferQueueCallExpectations(this); + PrimaryDisplayVariant::setupFramebufferProducerBufferQueueCallExpectations(this); + PrimaryDisplayVariant::setupNativeWindowSurfaceCreationCallExpectations(this); + PrimaryDisplayVariant::setupHwcGetActiveConfigCallExpectations(this); + + mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED); + + mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this) + .setSupportedModes({kDisplayMode60, kDisplayMode90, kDisplayMode120}) + .setActiveMode(kDisplayModeId60) + .inject(); + } + +protected: + sp mDisplay; + + const DisplayModeId kDisplayModeId60 = DisplayModeId(0); + const DisplayModePtr kDisplayMode60 = + DisplayMode::Builder(hal::HWConfigId(kDisplayModeId60.value())) + .setId(kDisplayModeId60) + .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) + .setVsyncPeriod(int32_t(16'666'667)) + .setGroup(0) + .setHeight(1000) + .setWidth(1000) + .build(); + + const DisplayModeId kDisplayModeId90 = DisplayModeId(1); + const DisplayModePtr kDisplayMode90 = + DisplayMode::Builder(hal::HWConfigId(kDisplayModeId90.value())) + .setId(kDisplayModeId90) + .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) + .setVsyncPeriod(int32_t(11'111'111)) + .setGroup(0) + .setHeight(1000) + .setWidth(1000) + .build(); + + const DisplayModeId kDisplayModeId120 = DisplayModeId(2); + const DisplayModePtr kDisplayMode120 = + DisplayMode::Builder(hal::HWConfigId(kDisplayModeId120.value())) + .setId(kDisplayModeId120) + .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) + .setVsyncPeriod(int32_t(8'333'333)) + .setGroup(0) + .setHeight(1000) + .setWidth(1000) + .build(); +}; + +TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setCurrentMode) { + EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode60, Event::None})); + EXPECT_EQ(std::nullopt, mDisplay->getDesiredActiveMode()); +} + +TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setNewMode) { + EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None})); + ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); + EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode); + EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); + + // Setting another mode should be cached but return false + EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode120, Event::None})); + ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); + EXPECT_EQ(kDisplayMode120, mDisplay->getDesiredActiveMode()->mode); + EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); +} + +TEST_F(InitiateModeChangeTest, clearDesiredActiveModeState) { + EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None})); + ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); + + mDisplay->clearDesiredActiveModeState(); + ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode()); +} + +TEST_F(InitiateModeChangeTest, initiateModeChange) NO_THREAD_SAFETY_ANALYSIS { + EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None})); + ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); + EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode); + EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); + + hal::VsyncPeriodChangeConstraints constraints{ + .desiredTimeNanos = systemTime(), + .seamlessRequired = false, + }; + hal::VsyncPeriodChangeTimeline timeline; + EXPECT_EQ(OK, + mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints, + &timeline)); + EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode); + EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event); + + mDisplay->clearDesiredActiveModeState(); + ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode()); +} + +TEST_F(InitiateModeChangeTest, getUpcomingActiveMode_desiredActiveModeChanged) +NO_THREAD_SAFETY_ANALYSIS { + EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None})); + ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); + EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode); + EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); + + hal::VsyncPeriodChangeConstraints constraints{ + .desiredTimeNanos = systemTime(), + .seamlessRequired = false, + }; + hal::VsyncPeriodChangeTimeline timeline; + EXPECT_EQ(OK, + mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints, + &timeline)); + EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode); + EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event); + + EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode120, Event::None})); + ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); + EXPECT_EQ(kDisplayMode120, mDisplay->getDesiredActiveMode()->mode); + EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); + + EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode); + EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event); + + EXPECT_EQ(OK, + mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints, + &timeline)); + EXPECT_EQ(kDisplayMode120, mDisplay->getUpcomingActiveMode().mode); + EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event); + + mDisplay->clearDesiredActiveModeState(); + ASSERT_EQ(std::nullopt, mDisplay->getDesiredActiveMode()); +} + +} // namespace +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 62acc6b549..28d0222829 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -546,17 +546,34 @@ TEST_F(EventThreadTest, postHotplugExternalConnect) { } TEST_F(EventThreadTest, postConfigChangedPrimary) { - mThread->onModeChanged(INTERNAL_DISPLAY_ID, DisplayModeId(7), 16666666); + const auto mode = DisplayMode::Builder(hal::HWConfigId(0)) + .setPhysicalDisplayId(INTERNAL_DISPLAY_ID) + .setId(DisplayModeId(7)) + .setVsyncPeriod(16666666) + .build(); + + mThread->onModeChanged(mode); expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7, 16666666); } TEST_F(EventThreadTest, postConfigChangedExternal) { - mThread->onModeChanged(EXTERNAL_DISPLAY_ID, DisplayModeId(5), 16666666); + const auto mode = DisplayMode::Builder(hal::HWConfigId(0)) + .setPhysicalDisplayId(EXTERNAL_DISPLAY_ID) + .setId(DisplayModeId(5)) + .setVsyncPeriod(16666666) + .build(); + + mThread->onModeChanged(mode); expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5, 16666666); } TEST_F(EventThreadTest, postConfigChangedPrimary64bit) { - mThread->onModeChanged(DISPLAY_ID_64BIT, DisplayModeId(7), 16666666); + const auto mode = DisplayMode::Builder(hal::HWConfigId(0)) + .setPhysicalDisplayId(DISPLAY_ID_64BIT) + .setId(DisplayModeId(7)) + .setVsyncPeriod(16666666) + .build(); + mThread->onModeChanged(mode); expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7, 16666666); } @@ -565,7 +582,13 @@ TEST_F(EventThreadTest, suppressConfigChanged) { sp suppressConnection = createConnection(suppressConnectionEventRecorder); - mThread->onModeChanged(INTERNAL_DISPLAY_ID, DisplayModeId(9), 16666666); + const auto mode = DisplayMode::Builder(hal::HWConfigId(0)) + .setPhysicalDisplayId(INTERNAL_DISPLAY_ID) + .setId(DisplayModeId(9)) + .setVsyncPeriod(16666666) + .build(); + + mThread->onModeChanged(mode); expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9, 16666666); auto args = suppressConnectionEventRecorder.waitForCall(); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 6cea4c2512..e2b3993211 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -199,20 +199,21 @@ TEST_F(SchedulerTest, testDispatchCachedReportedMode) { // onModeChange is called. mScheduler->clearOptionalFieldsInFeatures(); EXPECT_NO_FATAL_FAILURE(mScheduler->dispatchCachedReportedMode()); - EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0); + EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0); } TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) { - DisplayModeId modeId = DisplayModeId(111); - nsecs_t vsyncPeriod = 111111; + const auto mode = DisplayMode::Builder(hal::HWConfigId(0)) + .setId(DisplayModeId(111)) + .setPhysicalDisplayId(PHYSICAL_DISPLAY_ID) + .setVsyncPeriod(111111) + .build(); // If the handle is incorrect, the function should return before // onModeChange is called. Scheduler::ConnectionHandle invalidHandle = {.id = 123}; - EXPECT_NO_FATAL_FAILURE(mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle, - PHYSICAL_DISPLAY_ID, modeId, - vsyncPeriod)); - EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0); + EXPECT_NO_FATAL_FAILURE(mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle, mode)); + EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0); } TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) { diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 3b129d51b1..a99dabe420 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -100,9 +100,8 @@ public: mFeatures.cachedModeChangedParams.reset(); } - void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId, - DisplayModeId modeId, nsecs_t vsyncPeriod) { - return Scheduler::onNonPrimaryDisplayModeChanged(handle, displayId, modeId, vsyncPeriod); + void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { + return Scheduler::onNonPrimaryDisplayModeChanged(handle, mode); } ~TestableScheduler() { diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index c82599bfb0..ad284e3c71 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -724,7 +724,7 @@ public: return *this; } - sp inject() { + sp inject() NO_THREAD_SAFETY_ANALYSIS { const auto displayId = mCreationArgs.compositionDisplay->getDisplayId(); DisplayDeviceState state; diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 485b4acdce..d25973e1ce 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -33,7 +33,7 @@ public: MOCK_METHOD0(onScreenReleased, void()); MOCK_METHOD0(onScreenAcquired, void()); MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool)); - MOCK_METHOD3(onModeChanged, void(PhysicalDisplayId, DisplayModeId, nsecs_t)); + MOCK_METHOD1(onModeChanged, void(DisplayModePtr)); MOCK_METHOD2(onFrameRateOverridesChanged, void(PhysicalDisplayId, std::vector)); MOCK_CONST_METHOD1(dump, void(std::string&)); -- cgit v1.2.3-59-g8ed1b From 29fa146d8d745cee950a1ed82ddb500fc6d6c771 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Tue, 27 Apr 2021 15:51:50 -0700 Subject: SF: Consolidate layer-to-output filtering Add ui::LayerFilter for less repetitive CE plumbing. Make ui::LayerStack a type, and (unlike the alias) use it everywhere. Remove redundant state in CE's DisplayCreationArgs. Bug: 182939859 Test: Display cutout is excluded in screenshots. Test: libcompositionengine_test Test: libsurfaceflinger_unittest Test: SurfaceFlinger_test Test: libgui_test Change-Id: Ib854d354af7aef7168001c34297e875b71d53622 --- cmds/surfacereplayer/replayer/Replayer.cpp | 4 +- libs/gui/LayerState.cpp | 18 +-- libs/gui/SurfaceComposerClient.cpp | 4 +- libs/gui/include/gui/LayerState.h | 17 ++- libs/gui/include/gui/SurfaceComposerClient.h | 4 +- libs/gui/tests/BLASTBufferQueue_test.cpp | 12 +- libs/ui/include/ui/DisplayState.h | 7 +- libs/ui/include/ui/LayerStack.h | 78 +++++++++++ .../compositionengine/DisplayCreationArgs.h | 16 --- .../compositionengine/LayerFECompositionState.h | 7 +- .../include/compositionengine/Output.h | 21 +-- .../include/compositionengine/impl/Display.h | 3 +- .../include/compositionengine/impl/DumpHelpers.h | 14 +- .../include/compositionengine/impl/Output.h | 8 +- .../impl/OutputCompositionState.h | 8 +- .../include/compositionengine/mock/Output.h | 7 +- .../CompositionEngine/src/Display.cpp | 11 +- .../CompositionEngine/src/DumpHelpers.cpp | 16 ++- .../CompositionEngine/src/Output.cpp | 25 ++-- .../src/OutputCompositionState.cpp | 4 +- .../CompositionEngine/tests/DisplayTest.cpp | 59 +++----- .../CompositionEngine/tests/OutputTest.cpp | 149 ++++++++++----------- services/surfaceflinger/DisplayDevice.cpp | 4 +- services/surfaceflinger/DisplayDevice.h | 6 +- services/surfaceflinger/Layer.cpp | 71 +++++----- services/surfaceflinger/Layer.h | 33 +++-- services/surfaceflinger/LayerVector.cpp | 4 +- services/surfaceflinger/RefreshRateOverlay.cpp | 2 +- services/surfaceflinger/RefreshRateOverlay.h | 3 +- services/surfaceflinger/SurfaceFlinger.cpp | 98 ++++++-------- services/surfaceflinger/SurfaceInterceptor.cpp | 12 +- services/surfaceflinger/SurfaceInterceptor.h | 5 +- services/surfaceflinger/tests/Credentials_test.cpp | 2 +- services/surfaceflinger/tests/EffectLayer_test.cpp | 2 +- services/surfaceflinger/tests/IPC_test.cpp | 6 +- .../surfaceflinger/tests/LayerTransactionTest.h | 4 +- .../LayerTypeAndRenderTypeTransaction_test.cpp | 3 +- services/surfaceflinger/tests/LayerUpdate_test.cpp | 2 +- services/surfaceflinger/tests/MirrorLayer_test.cpp | 2 +- .../tests/MultiDisplayLayerBounds_test.cpp | 13 +- services/surfaceflinger/tests/RelativeZ_test.cpp | 2 +- .../surfaceflinger/tests/ScreenCapture_test.cpp | 8 +- .../tests/SurfaceInterceptor_test.cpp | 4 +- .../tests/TransactionTestHarnesses.h | 2 +- .../tests/WindowInfosListener_test.cpp | 4 +- .../tests/fakehwc/SFFakeHwc_test.cpp | 22 +-- .../tests/unittests/CompositionTest.cpp | 8 +- .../tests/unittests/DisplayTransactionTest.cpp | 8 +- .../unittests/DisplayTransactionTestHelpers.h | 8 +- .../SurfaceFlinger_HandleTransactionLockedTest.cpp | 4 +- .../SurfaceFlinger_OnInitializeDisplaysTest.cpp | 12 +- .../SurfaceFlinger_SetDisplayStateTest.cpp | 16 ++- 52 files changed, 414 insertions(+), 448 deletions(-) create mode 100644 libs/ui/include/ui/LayerStack.h (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index cfd42fec30..3f7c7d6a7b 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -528,7 +528,7 @@ void Replayer::setTransparentRegionHint(SurfaceComposerClient::Transaction& t, void Replayer::setLayerStack(SurfaceComposerClient::Transaction& t, layer_id id, const LayerStackChange& lsc) { ALOGV("Layer %d: Setting LayerStack -- layer_stack=%d", id, lsc.layer_stack()); - t.setLayerStack(mLayers[id], lsc.layer_stack()); + t.setLayerStack(mLayers[id], ui::LayerStack::fromValue(lsc.layer_stack())); } void Replayer::setHiddenFlag(SurfaceComposerClient::Transaction& t, @@ -566,7 +566,7 @@ void Replayer::setDisplaySurface(SurfaceComposerClient::Transaction& t, void Replayer::setDisplayLayerStack(SurfaceComposerClient::Transaction& t, display_id id, const LayerStackChange& lsc) { - t.setDisplayLayerStack(mDisplays[id], lsc.layer_stack()); + t.setDisplayLayerStack(mDisplays[id], ui::LayerStack::fromValue(lsc.layer_stack())); } void Replayer::setDisplaySize(SurfaceComposerClient::Transaction& t, diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 23895c0c9f..95a2f602b9 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -41,7 +41,6 @@ layer_state_t::layer_state_t() z(0), w(0), h(0), - layerStack(0), alpha(0), flags(0), mask(0), @@ -86,7 +85,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeInt32, z); SAFE_PARCEL(output.writeUint32, w); SAFE_PARCEL(output.writeUint32, h); - SAFE_PARCEL(output.writeUint32, layerStack); + SAFE_PARCEL(output.writeUint32, layerStack.id); SAFE_PARCEL(output.writeFloat, alpha); SAFE_PARCEL(output.writeUint32, flags); SAFE_PARCEL(output.writeUint32, mask); @@ -187,7 +186,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readInt32, &z); SAFE_PARCEL(input.readUint32, &w); SAFE_PARCEL(input.readUint32, &h); - SAFE_PARCEL(input.readUint32, &layerStack); + SAFE_PARCEL(input.readUint32, &layerStack.id); SAFE_PARCEL(input.readFloat, &alpha); SAFE_PARCEL(input.readUint32, &flags); @@ -314,21 +313,14 @@ status_t ComposerState::read(const Parcel& input) { return state.read(input); } -DisplayState::DisplayState() - : what(0), - layerStack(0), - flags(0), - layerStackSpaceRect(Rect::EMPTY_RECT), - orientedDisplaySpaceRect(Rect::EMPTY_RECT), - width(0), - height(0) {} +DisplayState::DisplayState() = default; status_t DisplayState::write(Parcel& output) const { SAFE_PARCEL(output.writeStrongBinder, token); SAFE_PARCEL(output.writeStrongBinder, IInterface::asBinder(surface)); SAFE_PARCEL(output.writeUint32, what); - SAFE_PARCEL(output.writeUint32, layerStack); SAFE_PARCEL(output.writeUint32, flags); + SAFE_PARCEL(output.writeUint32, layerStack.id); SAFE_PARCEL(output.writeUint32, toRotationInt(orientation)); SAFE_PARCEL(output.write, layerStackSpaceRect); SAFE_PARCEL(output.write, orientedDisplaySpaceRect); @@ -344,8 +336,8 @@ status_t DisplayState::read(const Parcel& input) { surface = interface_cast(tmpBinder); SAFE_PARCEL(input.readUint32, &what); - SAFE_PARCEL(input.readUint32, &layerStack); SAFE_PARCEL(input.readUint32, &flags); + SAFE_PARCEL(input.readUint32, &layerStack.id); uint32_t tmpUint = 0; SAFE_PARCEL(input.readUint32, &tmpUint); orientation = ui::toRotation(tmpUint); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index f620f5ae07..c3d632fa01 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1087,7 +1087,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayerStack( - const sp& sc, uint32_t layerStack) { + const sp& sc, ui::LayerStack layerStack) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; @@ -1751,7 +1751,7 @@ status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp } void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp& token, - uint32_t layerStack) { + ui::LayerStack layerStack) { DisplayState& s(getDisplayState(token)); s.layerStack = layerStack; s.what |= DisplayState::eLayerStackChanged; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index b27d9cf2bc..427f2a5ce0 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -143,7 +144,7 @@ struct layer_state_t { int32_t z; uint32_t w; uint32_t h; - uint32_t layerStack; + ui::LayerStack layerStack = ui::DEFAULT_LAYER_STACK; float alpha; uint32_t flags; uint32_t mask; @@ -262,11 +263,12 @@ struct DisplayState { DisplayState(); void merge(const DisplayState& other); - uint32_t what; + uint32_t what = 0; + uint32_t flags = 0; sp token; sp surface; - uint32_t layerStack; - uint32_t flags; + + ui::LayerStack layerStack = ui::DEFAULT_LAYER_STACK; // These states define how layers are projected onto the physical display. // @@ -280,10 +282,11 @@ struct DisplayState { // will be additionally rotated by 90 degrees around the origin clockwise and translated by (W, // 0). ui::Rotation orientation = ui::ROTATION_0; - Rect layerStackSpaceRect; - Rect orientedDisplaySpaceRect; + Rect layerStackSpaceRect = Rect::EMPTY_RECT; + Rect orientedDisplaySpaceRect = Rect::EMPTY_RECT; - uint32_t width, height; + uint32_t width = 0; + uint32_t height = 0; status_t write(Parcel& output) const; status_t read(const Parcel& input); diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 869cef6cdc..ec68ca9798 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -456,7 +456,7 @@ public: int backgroundBlurRadius); Transaction& setBlurRegions(const sp& sc, const std::vector& regions); - Transaction& setLayerStack(const sp& sc, uint32_t layerStack); + Transaction& setLayerStack(const sp&, ui::LayerStack); Transaction& setMetadata(const sp& sc, uint32_t key, const Parcel& p); /// Reparents the current layer to the new parent handle. The new parent must not be null. @@ -566,7 +566,7 @@ public: status_t setDisplaySurface(const sp& token, const sp& bufferProducer); - void setDisplayLayerStack(const sp& token, uint32_t layerStack); + void setDisplayLayerStack(const sp& token, ui::LayerStack); void setDisplayFlags(const sp& token, uint32_t flags); diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 9082d275a2..26d902d849 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -128,7 +128,7 @@ protected: mDisplayToken = mClient->getInternalDisplayToken(); ASSERT_NE(nullptr, mDisplayToken.get()); Transaction t; - t.setDisplayLayerStack(mDisplayToken, 0); + t.setDisplayLayerStack(mDisplayToken, ui::DEFAULT_LAYER_STACK); t.apply(); t.clear(); @@ -142,7 +142,7 @@ protected: mDisplayHeight, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState, /*parent*/ nullptr); - t.setLayerStack(mSurfaceControl, 0) + t.setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK) .setLayer(mSurfaceControl, std::numeric_limits::max()) .show(mSurfaceControl) .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB) @@ -490,7 +490,7 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { ISurfaceComposerClient::eFXSurfaceEffect); ASSERT_NE(nullptr, bg.get()); Transaction t; - t.setLayerStack(bg, 0) + t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK) .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight)) .setColor(bg, half3{0, 0, 0}) .setLayer(bg, 0) @@ -545,7 +545,7 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToBufferSize) { ISurfaceComposerClient::eFXSurfaceEffect); ASSERT_NE(nullptr, bg.get()); Transaction t; - t.setLayerStack(bg, 0) + t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK) .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight)) .setColor(bg, half3{0, 0, 0}) .setLayer(bg, 0) @@ -612,7 +612,7 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToWindowSize) { ISurfaceComposerClient::eFXSurfaceEffect); ASSERT_NE(nullptr, bg.get()); Transaction t; - t.setLayerStack(bg, 0) + t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK) .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight)) .setColor(bg, half3{0, 0, 0}) .setLayer(bg, 0) @@ -733,7 +733,7 @@ TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { ISurfaceComposerClient::eFXSurfaceBufferState); ASSERT_NE(nullptr, bgSurface.get()); Transaction t; - t.setLayerStack(bgSurface, 0) + t.setLayerStack(bgSurface, ui::DEFAULT_LAYER_STACK) .show(bgSurface) .setDataspace(bgSurface, ui::Dataspace::V0_SRGB) .setLayer(bgSurface, std::numeric_limits::max() - 1) diff --git a/libs/ui/include/ui/DisplayState.h b/libs/ui/include/ui/DisplayState.h index 70a0d50611..98ee35652a 100644 --- a/libs/ui/include/ui/DisplayState.h +++ b/libs/ui/include/ui/DisplayState.h @@ -16,21 +16,18 @@ #pragma once +#include #include #include -#include #include namespace android::ui { -using LayerStack = uint32_t; -constexpr LayerStack NO_LAYER_STACK = static_cast(-1); - // Transactional state of physical or virtual display. Note that libgui defines // android::DisplayState as a superset of android::ui::DisplayState. struct DisplayState { - LayerStack layerStack = NO_LAYER_STACK; + LayerStack layerStack; Rotation orientation = ROTATION_0; Size layerStackSpaceRect; }; diff --git a/libs/ui/include/ui/LayerStack.h b/libs/ui/include/ui/LayerStack.h new file mode 100644 index 0000000000..d6ffeb7fad --- /dev/null +++ b/libs/ui/include/ui/LayerStack.h @@ -0,0 +1,78 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace android::ui { + +// A LayerStack identifies a Z-ordered group of layers. A layer can only be associated to a single +// LayerStack, but a LayerStack can be associated to multiple displays, mirroring the same content. +struct LayerStack { + uint32_t id = UINT32_MAX; + + template + static constexpr LayerStack fromValue(T v) { + if (ftl::cast_safety(v) == ftl::CastSafety::kSafe) { + return {static_cast(v)}; + } + + ALOGW("Invalid layer stack %s", ftl::to_string(v).c_str()); + return {}; + } +}; + +constexpr LayerStack INVALID_LAYER_STACK; +constexpr LayerStack DEFAULT_LAYER_STACK{0u}; + +inline bool operator==(LayerStack lhs, LayerStack rhs) { + return lhs.id == rhs.id; +} + +inline bool operator!=(LayerStack lhs, LayerStack rhs) { + return !(lhs == rhs); +} + +inline bool operator>(LayerStack lhs, LayerStack rhs) { + return lhs.id > rhs.id; +} + +// A LayerFilter determines if a layer is included for output to a display. +struct LayerFilter { + LayerStack layerStack; + + // True if the layer is only output to internal displays, i.e. excluded from screenshots, screen + // recordings, and mirroring to virtual or external displays. Used for display cutout overlays. + bool toInternalDisplay = false; + + // Returns true if the input filter can be output to this filter. + bool includes(LayerFilter other) const { + // The layer stacks must match. + if (other.layerStack == INVALID_LAYER_STACK || other.layerStack != layerStack) { + return false; + } + + // The output must be to an internal display if the input filter has that constraint. + return !other.toInternalDisplay || toInternalDisplay; + } +}; + +} // namespace android::ui diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h index 526e7daa80..98c4af487e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h @@ -36,18 +36,12 @@ class CompositionEngine; struct DisplayCreationArgs { DisplayId id; - // Unset for virtual displays - std::optional connectionType; - // Size of the display in pixels ui::Size pixels = ui::kInvalidSize; // True if this display should be considered secure bool isSecure = false; - // Gives the initial layer stack id to be used for the display - uint32_t layerStackId = ~0u; - // Optional pointer to the power advisor interface, if one is needed for // this display. Hwc2::PowerAdvisor* powerAdvisor = nullptr; @@ -69,11 +63,6 @@ public: return *this; } - DisplayCreationArgsBuilder& setConnectionType(ui::DisplayConnectionType connectionType) { - mArgs.connectionType = connectionType; - return *this; - } - DisplayCreationArgsBuilder& setPixels(ui::Size pixels) { mArgs.pixels = pixels; return *this; @@ -84,11 +73,6 @@ public: return *this; } - DisplayCreationArgsBuilder& setLayerStackId(uint32_t layerStackId) { - mArgs.layerStackId = layerStackId; - return *this; - } - DisplayCreationArgsBuilder& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) { mArgs.powerAdvisor = powerAdvisor; return *this; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index a45be8a7a2..ecb4e6d79d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -93,11 +94,9 @@ struct LayerFECompositionState { /* * Visibility state */ - // the layer stack this layer belongs to - std::optional layerStackId; - // If true, this layer should be only visible on the internal display - bool internalOnly{false}; + // The filter that determines which outputs include this layer + ui::LayerFilter outputFilter; // If false, this layer should not be considered visible bool isVisible{true}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 15a86af037..28baef8726 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -180,9 +181,8 @@ public: // output. virtual ui::Transform::RotationFlags getTransformHint() const = 0; - // Sets the layer stack filtering settings for this output. See - // belongsInOutput for full details. - virtual void setLayerStackFilter(uint32_t layerStackId, bool isInternal) = 0; + // Sets the filter for this output. See Output::includesLayer. + virtual void setLayerFilter(ui::LayerFilter) = 0; // Sets the output color mode virtual void setColorProfile(const ColorProfile&) = 0; @@ -224,17 +224,10 @@ public: // If repaintEverything is true, this will be the full display bounds. virtual Region getDirtyRegion(bool repaintEverything) const = 0; - // Tests whether a given layerStackId belongs in this output. - // A layer belongs to the output if its layerStackId matches the of the output layerStackId, - // unless the layer should display on the primary output only and this is not the primary output - - // A layer belongs to the output if its layerStackId matches. Additionally - // if the layer should only show in the internal (primary) display only and - // this output allows that. - virtual bool belongsInOutput(std::optional layerStackId, bool internalOnly) const = 0; - - // Determines if a layer belongs to the output. - virtual bool belongsInOutput(const sp&) const = 0; + // Returns whether the output includes a layer, based on their respective filters. + // See Output::setLayerFilter. + virtual bool includesLayer(ui::LayerFilter) const = 0; + virtual bool includesLayer(const sp&) const = 0; // Returns a pointer to the output layer corresponding to the given layer on // this output, or nullptr if the layer does not have one diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index bb540ea7ee..b407267560 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -83,9 +83,8 @@ public: std::unique_ptr createOutputLayer(const sp&) const; private: - bool mIsVirtual = false; - bool mIsDisconnected = false; DisplayId mId; + bool mIsDisconnected = false; Hwc2::PowerAdvisor* mPowerAdvisor = nullptr; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h index 6b9597b2d5..7521324756 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -52,13 +53,14 @@ void dumpVal(std::string& out, const char* name, const std::string& valueName, E dumpVal(out, name, valueName, static_cast>(value)); } -void dumpVal(std::string& out, const char* name, const FloatRect& rect); -void dumpVal(std::string& out, const char* name, const Rect& rect); -void dumpVal(std::string& out, const char* name, const Region& region); -void dumpVal(std::string& out, const char* name, const ui::Transform&); -void dumpVal(std::string& out, const char* name, const ui::Size&); +void dumpVal(std::string& out, const char* name, ui::LayerFilter); +void dumpVal(std::string& out, const char* name, ui::Size); -void dumpVal(std::string& out, const char* name, const mat4& tr); +void dumpVal(std::string& out, const char* name, const FloatRect&); +void dumpVal(std::string& out, const char* name, const Rect&); +void dumpVal(std::string& out, const char* name, const Region&); +void dumpVal(std::string& out, const char* name, const ui::Transform&); +void dumpVal(std::string& out, const char* name, const mat4&); void dumpVal(std::string& out, const char* name, const StretchEffect&); } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 14f2163f52..cb9426c73d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -23,6 +23,7 @@ #include #include #include + #include #include #include @@ -45,7 +46,7 @@ public: void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, const Rect& orientedDisplaySpaceRect) override; void setDisplaySize(const ui::Size&) override; - void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override; + void setLayerFilter(ui::LayerFilter) override; ui::Transform::RotationFlags getTransformHint() const override; void setColorTransform(const compositionengine::CompositionRefreshArgs&) override; @@ -65,8 +66,9 @@ public: void setRenderSurface(std::unique_ptr) override; Region getDirtyRegion(bool repaintEverything) const override; - bool belongsInOutput(std::optional, bool) const override; - bool belongsInOutput(const sp&) const override; + + bool includesLayer(ui::LayerFilter) const override; + bool includesLayer(const sp&) const override; compositionengine::OutputLayer* getOutputLayerForLayer(const sp&) const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index f34cb94079..44f754f936 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -32,6 +32,7 @@ #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" #include +#include #include #include #include @@ -59,11 +60,8 @@ struct OutputCompositionState { // If true, the current frame reused the buffer from a previous client composition bool reusedClientComposition{false}; - // If true, this output displays layers that are internal-only - bool layerStackInternal{false}; - - // The layer stack to display on this display - uint32_t layerStackId{~0u}; + // The conditions for including a layer on this output + ui::LayerFilter layerFilter; // The common space for all layers in the layer stack. layerStackSpace.content is the Rect // which gets projected on the display. The orientation of this space is always ROTATION_0. diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 216019fd1d..58627da828 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -40,9 +40,12 @@ public: MOCK_METHOD1(setLayerCachingTexturePoolEnabled, void(bool)); MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&)); MOCK_METHOD1(setDisplaySize, void(const ui::Size&)); - MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool)); MOCK_CONST_METHOD0(getTransformHint, ui::Transform::RotationFlags()); + MOCK_METHOD(void, setLayerFilter, (ui::LayerFilter)); + MOCK_METHOD(bool, includesLayer, (ui::LayerFilter), (const)); + MOCK_METHOD(bool, includesLayer, (const sp&), (const)); + MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&)); MOCK_METHOD1(setColorProfile, void(const ColorProfile&)); MOCK_METHOD2(setDisplayBrightness, void(float, float)); @@ -63,8 +66,6 @@ public: MOCK_METHOD0(editState, OutputCompositionState&()); MOCK_CONST_METHOD1(getDirtyRegion, Region(bool)); - MOCK_CONST_METHOD2(belongsInOutput, bool(std::optional, bool)); - MOCK_CONST_METHOD1(belongsInOutput, bool(const sp&)); MOCK_CONST_METHOD1(getOutputLayerForLayer, compositionengine::OutputLayer*(const sp&)); diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 2f2c686805..2cc5faef33 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -51,12 +51,9 @@ Display::~Display() = default; void Display::setConfiguration(const compositionengine::DisplayCreationArgs& args) { mId = args.id; - mIsVirtual = !args.connectionType; mPowerAdvisor = args.powerAdvisor; editState().isSecure = args.isSecure; editState().displaySpace.bounds = Rect(args.pixels); - setLayerStackFilter(args.layerStackId, - args.connectionType == ui::DisplayConnectionType::Internal); setName(args.name); } @@ -73,7 +70,7 @@ bool Display::isSecure() const { } bool Display::isVirtual() const { - return mIsVirtual; + return VirtualDisplayId::tryCast(mId).has_value(); } std::optional Display::getDisplayId() const { @@ -117,8 +114,8 @@ void Display::setColorProfile(const ColorProfile& colorProfile) { return; } - if (mIsVirtual) { - ALOGW("%s: Invalid operation on virtual display", __FUNCTION__); + if (isVirtual()) { + ALOGW("%s: Invalid operation on virtual display", __func__); return; } @@ -136,7 +133,7 @@ void Display::dump(std::string& out) const { StringAppendF(&out, " Composition Display State: [\"%s\"]", getName().c_str()); out.append("\n "); - dumpVal(out, "isVirtual", mIsVirtual); + dumpVal(out, "isVirtual", isVirtual()); dumpVal(out, "DisplayId", to_string(mId)); out.append("\n"); diff --git a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp index 5565396922..01c368de88 100644 --- a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp +++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp @@ -63,6 +63,18 @@ void dumpVal(std::string& out, const char* name, const std::string& valueName, i dumpVal(out, name, valueName.c_str(), value); } +void dumpVal(std::string& out, const char* name, ui::LayerFilter filter) { + out.append(name); + out.append("={"); + dumpVal(out, "layerStack", filter.layerStack.id); + dumpVal(out, "toInternalDisplay", filter.toInternalDisplay); + out.push_back('}'); +} + +void dumpVal(std::string& out, const char* name, ui::Size size) { + StringAppendF(&out, "%s=[%d %d] ", name, size.width, size.height); +} + void dumpVal(std::string& out, const char* name, const FloatRect& rect) { StringAppendF(&out, "%s=[%f %f %f %f] ", name, rect.left, rect.top, rect.right, rect.bottom); } @@ -80,10 +92,6 @@ void dumpVal(std::string& out, const char* name, const ui::Transform& transform) out.append(" "); } -void dumpVal(std::string& out, const char* name, const ui::Size& size) { - StringAppendF(&out, "%s=[%d %d] ", name, size.width, size.height); -} - void dumpVal(std::string& out, const char* name, const mat4& tr) { StringAppendF(&out, "%s=[" diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 6ac488be29..5e40802e93 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -227,11 +227,8 @@ ui::Transform::RotationFlags Output::getTransformHint() const { return static_cast(getState().transform.getOrientation()); } -void Output::setLayerStackFilter(uint32_t layerStackId, bool isInternal) { - auto& outputState = editState(); - outputState.layerStackId = layerStackId; - outputState.layerStackInternal = isInternal; - +void Output::setLayerFilter(ui::LayerFilter filter) { + editState().layerFilter = filter; dirtyEntireOutput(); } @@ -380,17 +377,13 @@ Region Output::getDirtyRegion(bool repaintEverything) const { return dirty; } -bool Output::belongsInOutput(std::optional layerStackId, bool internalOnly) const { - // The layerStackId's must match, and also the layer must not be internal - // only when not on an internal output. - const auto& outputState = getState(); - return layerStackId && (*layerStackId == outputState.layerStackId) && - (!internalOnly || outputState.layerStackInternal); +bool Output::includesLayer(ui::LayerFilter filter) const { + return getState().layerFilter.includes(filter); } -bool Output::belongsInOutput(const sp& layerFE) const { +bool Output::includesLayer(const sp& layerFE) const { const auto* layerFEState = layerFE->getCompositionState(); - return layerFEState && belongsInOutput(layerFEState->layerStackId, layerFEState->internalOnly); + return layerFEState && includesLayer(layerFEState->outputFilter); } std::unique_ptr Output::createOutputLayer( @@ -496,8 +489,8 @@ void Output::ensureOutputLayerIfVisible(sp& layerFE, layerFE->prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry); } - // Only consider the layers on the given layer stack - if (!belongsInOutput(layerFE)) { + // Only consider the layers on this output + if (!includesLayer(layerFE)) { return; } @@ -1122,7 +1115,7 @@ std::optional Output::composeSurfaces( // bounds its framebuffer cache but Skia RenderEngine has no current policy. The best fix is // probably to encapsulate the output buffer into a structure that dispatches resource cleanup // over to RenderEngine, in which case this flag can be removed from the drawLayers interface. - const bool useFramebufferCache = outputState.layerStackInternal; + const bool useFramebufferCache = outputState.layerFilter.toInternalDisplay; status_t status = renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, tex, useFramebufferCache, std::move(fd), &readyFence); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp index ee30ad8583..acc92162ac 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp @@ -28,9 +28,7 @@ void OutputCompositionState::dump(std::string& out) const { dumpVal(out, "usesDeviceComposition", usesDeviceComposition); dumpVal(out, "flipClientTarget", flipClientTarget); dumpVal(out, "reusedClientComposition", reusedClientComposition); - - dumpVal(out, "layerStack", layerStackId); - dumpVal(out, "layerStackInternal", layerStackInternal); + dumpVal(out, "layerFilter", layerFilter); out.append("\n "); diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 72b16e0741..543dde1ca0 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -61,7 +61,6 @@ constexpr HalVirtualDisplayId HAL_VIRTUAL_DISPLAY_ID{456u}; constexpr GpuVirtualDisplayId GPU_VIRTUAL_DISPLAY_ID{789u}; constexpr ui::Size DEFAULT_RESOLUTION{1920, 1080}; -constexpr uint32_t DEFAULT_LAYER_STACK = 42; struct Layer { Layer() { @@ -161,13 +160,11 @@ struct DisplayTestCommon : public testing::Test { EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false)); } - DisplayCreationArgs getDisplayCreationArgsForPhysicalHWCDisplay() { + DisplayCreationArgs getDisplayCreationArgsForPhysicalDisplay() { return DisplayCreationArgsBuilder() .setId(DEFAULT_DISPLAY_ID) - .setConnectionType(ui::DisplayConnectionType::Internal) .setPixels(DEFAULT_RESOLUTION) .setIsSecure(true) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) .build(); } @@ -177,7 +174,6 @@ struct DisplayTestCommon : public testing::Test { .setId(GPU_VIRTUAL_DISPLAY_ID) .setPixels(DEFAULT_RESOLUTION) .setIsSecure(false) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) .build(); } @@ -193,14 +189,13 @@ struct PartialMockDisplayTestCommon : public DisplayTestCommon { using Display = DisplayTestCommon::PartialMockDisplay; std::shared_ptr mDisplay = createPartialMockDisplay(mCompositionEngine, - getDisplayCreationArgsForPhysicalHWCDisplay()); + getDisplayCreationArgsForPhysicalDisplay()); }; struct FullDisplayImplTestCommon : public DisplayTestCommon { using Display = DisplayTestCommon::FullImplDisplay; std::shared_ptr mDisplay = - createDisplay(mCompositionEngine, - getDisplayCreationArgsForPhysicalHWCDisplay()); + createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay()); }; struct DisplayWithLayersTestCommon : public FullDisplayImplTestCommon { @@ -218,8 +213,7 @@ struct DisplayWithLayersTestCommon : public FullDisplayImplTestCommon { LayerNoHWC2Layer mLayer3; StrictMock hwc2LayerUnknown; std::shared_ptr mDisplay = - createDisplay(mCompositionEngine, - getDisplayCreationArgsForPhysicalHWCDisplay()); + createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay()); }; /* @@ -232,7 +226,7 @@ struct DisplayCreationTest : public DisplayTestCommon { TEST_F(DisplayCreationTest, createPhysicalInternalDisplay) { auto display = - impl::createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalHWCDisplay()); + impl::createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay()); EXPECT_TRUE(display->isSecure()); EXPECT_FALSE(display->isVirtual()); EXPECT_EQ(DEFAULT_DISPLAY_ID, display->getId()); @@ -252,13 +246,11 @@ TEST_F(DisplayCreationTest, createGpuVirtualDisplay) { using DisplaySetConfigurationTest = PartialMockDisplayTestCommon; -TEST_F(DisplaySetConfigurationTest, configuresInternalSecurePhysicalDisplay) { +TEST_F(DisplaySetConfigurationTest, configuresPhysicalDisplay) { mDisplay->setConfiguration(DisplayCreationArgsBuilder() .setId(DEFAULT_DISPLAY_ID) - .setConnectionType(ui::DisplayConnectionType::Internal) .setPixels(DEFAULT_RESOLUTION) .setIsSecure(true) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) .setName(getDisplayNameFromCurrentTest()) .build()); @@ -266,28 +258,11 @@ TEST_F(DisplaySetConfigurationTest, configuresInternalSecurePhysicalDisplay) { EXPECT_EQ(DEFAULT_DISPLAY_ID, mDisplay->getId()); EXPECT_TRUE(mDisplay->isSecure()); EXPECT_FALSE(mDisplay->isVirtual()); - EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); - EXPECT_TRUE(mDisplay->getState().layerStackInternal); EXPECT_FALSE(mDisplay->isValid()); -} -TEST_F(DisplaySetConfigurationTest, configuresExternalInsecurePhysicalDisplay) { - mDisplay->setConfiguration(DisplayCreationArgsBuilder() - .setId(DEFAULT_DISPLAY_ID) - .setConnectionType(ui::DisplayConnectionType::External) - .setPixels(DEFAULT_RESOLUTION) - .setIsSecure(false) - .setLayerStackId(DEFAULT_LAYER_STACK) - .setPowerAdvisor(&mPowerAdvisor) - .setName(getDisplayNameFromCurrentTest()) - .build()); - - EXPECT_EQ(DEFAULT_DISPLAY_ID, mDisplay->getId()); - EXPECT_FALSE(mDisplay->isSecure()); - EXPECT_FALSE(mDisplay->isVirtual()); - EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); - EXPECT_FALSE(mDisplay->getState().layerStackInternal); - EXPECT_FALSE(mDisplay->isValid()); + const auto& filter = mDisplay->getState().layerFilter; + EXPECT_EQ(ui::INVALID_LAYER_STACK, filter.layerStack); + EXPECT_FALSE(filter.toInternalDisplay); } TEST_F(DisplaySetConfigurationTest, configuresHalVirtualDisplay) { @@ -295,7 +270,6 @@ TEST_F(DisplaySetConfigurationTest, configuresHalVirtualDisplay) { .setId(HAL_VIRTUAL_DISPLAY_ID) .setPixels(DEFAULT_RESOLUTION) .setIsSecure(false) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) .setName(getDisplayNameFromCurrentTest()) .build()); @@ -303,9 +277,11 @@ TEST_F(DisplaySetConfigurationTest, configuresHalVirtualDisplay) { EXPECT_EQ(HAL_VIRTUAL_DISPLAY_ID, mDisplay->getId()); EXPECT_FALSE(mDisplay->isSecure()); EXPECT_TRUE(mDisplay->isVirtual()); - EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); - EXPECT_FALSE(mDisplay->getState().layerStackInternal); EXPECT_FALSE(mDisplay->isValid()); + + const auto& filter = mDisplay->getState().layerFilter; + EXPECT_EQ(ui::INVALID_LAYER_STACK, filter.layerStack); + EXPECT_FALSE(filter.toInternalDisplay); } TEST_F(DisplaySetConfigurationTest, configuresGpuVirtualDisplay) { @@ -313,7 +289,6 @@ TEST_F(DisplaySetConfigurationTest, configuresGpuVirtualDisplay) { .setId(GPU_VIRTUAL_DISPLAY_ID) .setPixels(DEFAULT_RESOLUTION) .setIsSecure(false) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) .setName(getDisplayNameFromCurrentTest()) .build()); @@ -321,9 +296,11 @@ TEST_F(DisplaySetConfigurationTest, configuresGpuVirtualDisplay) { EXPECT_EQ(GPU_VIRTUAL_DISPLAY_ID, mDisplay->getId()); EXPECT_FALSE(mDisplay->isSecure()); EXPECT_TRUE(mDisplay->isVirtual()); - EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId); - EXPECT_FALSE(mDisplay->getState().layerStackInternal); EXPECT_FALSE(mDisplay->isValid()); + + const auto& filter = mDisplay->getState().layerFilter; + EXPECT_EQ(ui::INVALID_LAYER_STACK, filter.layerStack); + EXPECT_FALSE(filter.toInternalDisplay); } /* @@ -998,10 +975,8 @@ struct DisplayFunctionalTest : public testing::Test { Display>(mCompositionEngine, DisplayCreationArgsBuilder() .setId(DEFAULT_DISPLAY_ID) - .setConnectionType(ui::DisplayConnectionType::Internal) .setPixels(DEFAULT_RESOLUTION) .setIsSecure(true) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&mPowerAdvisor) .build()); diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index c3185e9e7e..e7fad594a6 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -403,17 +403,18 @@ TEST_F(OutputTest, setDisplaySpaceSizeUpdatesOutputStateAndDirtiesEntireOutput) } /* - * Output::setLayerStackFilter() + * Output::setLayerFilter() */ -TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) { - const uint32_t layerStack = 123u; - mOutput->setLayerStackFilter(layerStack, true); +TEST_F(OutputTest, setLayerFilterSetsFilterAndDirtiesEntireOutput) { + constexpr ui::LayerFilter kFilter{ui::LayerStack{123u}, true}; + mOutput->setLayerFilter(kFilter); - EXPECT_TRUE(mOutput->getState().layerStackInternal); - EXPECT_EQ(layerStack, mOutput->getState().layerStackId); + const auto& state = mOutput->getState(); + EXPECT_EQ(kFilter.layerStack, state.layerFilter.layerStack); + EXPECT_TRUE(state.layerFilter.toInternalDisplay); - EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); + EXPECT_THAT(state.dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } /* @@ -593,100 +594,90 @@ TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingFalse) { } /* - * Output::belongsInOutput() + * Output::includesLayer() */ -TEST_F(OutputTest, belongsInOutputFiltersAsExpected) { - const uint32_t layerStack1 = 123u; - const uint32_t layerStack2 = 456u; +TEST_F(OutputTest, layerFiltering) { + const ui::LayerStack layerStack1{123u}; + const ui::LayerStack layerStack2{456u}; - // If the output accepts layerStack1 and internal-only layers.... - mOutput->setLayerStackFilter(layerStack1, true); + // If the output is associated to layerStack1 and to an internal display... + mOutput->setLayerFilter({layerStack1, true}); - // A layer with no layerStack does not belong to it, internal-only or not. - EXPECT_FALSE(mOutput->belongsInOutput(std::nullopt, false)); - EXPECT_FALSE(mOutput->belongsInOutput(std::nullopt, true)); + // It excludes layers with no layer stack, internal-only or not. + EXPECT_FALSE(mOutput->includesLayer({ui::INVALID_LAYER_STACK, false})); + EXPECT_FALSE(mOutput->includesLayer({ui::INVALID_LAYER_STACK, true})); - // Any layer with layerStack1 belongs to it, internal-only or not. - EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, false)); - EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, true)); - EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, true)); - EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, false)); + // It includes layers on layerStack1, internal-only or not. + EXPECT_TRUE(mOutput->includesLayer({layerStack1, false})); + EXPECT_TRUE(mOutput->includesLayer({layerStack1, true})); + EXPECT_FALSE(mOutput->includesLayer({layerStack2, true})); + EXPECT_FALSE(mOutput->includesLayer({layerStack2, false})); - // If the output accepts layerStack21 but not internal-only layers... - mOutput->setLayerStackFilter(layerStack1, false); + // If the output is associated to layerStack1 but not to an internal display... + mOutput->setLayerFilter({layerStack1, false}); - // Only non-internal layers with layerStack1 belong to it. - EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, false)); - EXPECT_FALSE(mOutput->belongsInOutput(layerStack1, true)); - EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, true)); - EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, false)); + // It includes layers on layerStack1, unless they are internal-only. + EXPECT_TRUE(mOutput->includesLayer({layerStack1, false})); + EXPECT_FALSE(mOutput->includesLayer({layerStack1, true})); + EXPECT_FALSE(mOutput->includesLayer({layerStack2, true})); + EXPECT_FALSE(mOutput->includesLayer({layerStack2, false})); } -TEST_F(OutputTest, belongsInOutputHandlesLayerWithNoCompositionState) { +TEST_F(OutputTest, layerFilteringWithoutCompositionState) { NonInjectedLayer layer; sp layerFE(layer.layerFE); - // If the layer has no composition state, it does not belong to any output. + // Layers without composition state are excluded. EXPECT_CALL(*layer.layerFE, getCompositionState).WillOnce(Return(nullptr)); - EXPECT_FALSE(mOutput->belongsInOutput(layerFE)); + EXPECT_FALSE(mOutput->includesLayer(layerFE)); } -TEST_F(OutputTest, belongsInOutputFiltersLayersAsExpected) { +TEST_F(OutputTest, layerFilteringWithCompositionState) { NonInjectedLayer layer; sp layerFE(layer.layerFE); - const uint32_t layerStack1 = 123u; - const uint32_t layerStack2 = 456u; + const ui::LayerStack layerStack1{123u}; + const ui::LayerStack layerStack2{456u}; - // If the output accepts layerStack1 and internal-only layers.... - mOutput->setLayerStackFilter(layerStack1, true); + // If the output is associated to layerStack1 and to an internal display... + mOutput->setLayerFilter({layerStack1, true}); - // A layer with no layerStack does not belong to it, internal-only or not. - layer.layerFEState.layerStackId = std::nullopt; - layer.layerFEState.internalOnly = false; - EXPECT_FALSE(mOutput->belongsInOutput(layerFE)); + // It excludes layers with no layer stack, internal-only or not. + layer.layerFEState.outputFilter = {ui::INVALID_LAYER_STACK, false}; + EXPECT_FALSE(mOutput->includesLayer(layerFE)); - layer.layerFEState.layerStackId = std::nullopt; - layer.layerFEState.internalOnly = true; - EXPECT_FALSE(mOutput->belongsInOutput(layerFE)); + layer.layerFEState.outputFilter = {ui::INVALID_LAYER_STACK, true}; + EXPECT_FALSE(mOutput->includesLayer(layerFE)); - // Any layer with layerStack1 belongs to it, internal-only or not. - layer.layerFEState.layerStackId = layerStack1; - layer.layerFEState.internalOnly = false; - EXPECT_TRUE(mOutput->belongsInOutput(layerFE)); + // It includes layers on layerStack1, internal-only or not. + layer.layerFEState.outputFilter = {layerStack1, false}; + EXPECT_TRUE(mOutput->includesLayer(layerFE)); - layer.layerFEState.layerStackId = layerStack1; - layer.layerFEState.internalOnly = true; - EXPECT_TRUE(mOutput->belongsInOutput(layerFE)); + layer.layerFEState.outputFilter = {layerStack1, true}; + EXPECT_TRUE(mOutput->includesLayer(layerFE)); - layer.layerFEState.layerStackId = layerStack2; - layer.layerFEState.internalOnly = true; - EXPECT_FALSE(mOutput->belongsInOutput(layerFE)); + layer.layerFEState.outputFilter = {layerStack2, true}; + EXPECT_FALSE(mOutput->includesLayer(layerFE)); - layer.layerFEState.layerStackId = layerStack2; - layer.layerFEState.internalOnly = false; - EXPECT_FALSE(mOutput->belongsInOutput(layerFE)); + layer.layerFEState.outputFilter = {layerStack2, false}; + EXPECT_FALSE(mOutput->includesLayer(layerFE)); - // If the output accepts layerStack1 but not internal-only layers... - mOutput->setLayerStackFilter(layerStack1, false); + // If the output is associated to layerStack1 but not to an internal display... + mOutput->setLayerFilter({layerStack1, false}); - // Only non-internal layers with layerStack1 belong to it. - layer.layerFEState.layerStackId = layerStack1; - layer.layerFEState.internalOnly = false; - EXPECT_TRUE(mOutput->belongsInOutput(layerFE)); + // It includes layers on layerStack1, unless they are internal-only. + layer.layerFEState.outputFilter = {layerStack1, false}; + EXPECT_TRUE(mOutput->includesLayer(layerFE)); - layer.layerFEState.layerStackId = layerStack1; - layer.layerFEState.internalOnly = true; - EXPECT_FALSE(mOutput->belongsInOutput(layerFE)); + layer.layerFEState.outputFilter = {layerStack1, true}; + EXPECT_FALSE(mOutput->includesLayer(layerFE)); - layer.layerFEState.layerStackId = layerStack2; - layer.layerFEState.internalOnly = true; - EXPECT_FALSE(mOutput->belongsInOutput(layerFE)); + layer.layerFEState.outputFilter = {layerStack2, true}; + EXPECT_FALSE(mOutput->includesLayer(layerFE)); - layer.layerFEState.layerStackId = layerStack2; - layer.layerFEState.internalOnly = false; - EXPECT_FALSE(mOutput->belongsInOutput(layerFE)); + layer.layerFEState.outputFilter = {layerStack2, false}; + EXPECT_FALSE(mOutput->includesLayer(layerFE)); } /* @@ -1268,14 +1259,15 @@ struct OutputEnsureOutputLayerIfVisibleTest : public testing::Test { struct OutputPartialMock : public OutputPartialMockBase { // Sets up the helper functions called by the function under test to use // mock implementations. - MOCK_CONST_METHOD1(belongsInOutput, bool(const sp&)); + MOCK_METHOD(bool, includesLayer, (const sp&), + (const, override)); MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex, OutputLayer*(size_t)); MOCK_METHOD2(ensureOutputLayer, compositionengine::OutputLayer*(std::optional, const sp&)); }; OutputEnsureOutputLayerIfVisibleTest() { - EXPECT_CALL(mOutput, belongsInOutput(sp(mLayer.layerFE))) + EXPECT_CALL(mOutput, includesLayer(sp(mLayer.layerFE))) .WillRepeatedly(Return(true)); EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u)); EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u)) @@ -1326,8 +1318,8 @@ const Region OutputEnsureOutputLayerIfVisibleTest::kLowerHalfBoundsNoRotation = const Region OutputEnsureOutputLayerIfVisibleTest::kFullBounds90Rotation = Region(Rect(0, 0, 200, 100)); -TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerBelongs) { - EXPECT_CALL(mOutput, belongsInOutput(sp(mLayer.layerFE))).WillOnce(Return(false)); +TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLayerIncluded) { + EXPECT_CALL(mOutput, includesLayer(sp(mLayer.layerFE))).WillOnce(Return(false)); EXPECT_CALL(*mLayer.layerFE, prepareCompositionState(compositionengine::LayerFE::StateSubset::BasicGeometry)); @@ -1337,8 +1329,8 @@ TEST_F(OutputEnsureOutputLayerIfVisibleTest, performsGeomLatchBeforeCheckingIfLa } TEST_F(OutputEnsureOutputLayerIfVisibleTest, - skipsLatchIfAlreadyLatchedBeforeCheckingIfLayerBelongs) { - EXPECT_CALL(mOutput, belongsInOutput(sp(mLayer.layerFE))).WillOnce(Return(false)); + skipsLatchIfAlreadyLatchedBeforeCheckingIfLayerIncluded) { + EXPECT_CALL(mOutput, includesLayer(sp(mLayer.layerFE))).WillOnce(Return(false)); ensureOutputLayerIfVisible(); } @@ -3188,8 +3180,7 @@ TEST_F(OutputComposeSurfacesTest, r1.geometry.boundaries = FloatRect{1, 2, 3, 4}; r2.geometry.boundaries = FloatRect{5, 6, 7, 8}; - const constexpr uint32_t kInternalLayerStack = 1234; - mOutput.setLayerStackFilter(kInternalLayerStack, true); + mOutput.setLayerFilter({ui::LayerStack{1234u}, true}); EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false)); EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true)); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 4445eea604..802a17d981 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -232,7 +232,7 @@ ui::Dataspace DisplayDevice::getCompositionDataSpace() const { } void DisplayDevice::setLayerStack(ui::LayerStack stack) { - mCompositionDisplay->setLayerStackFilter(stack, isInternal()); + mCompositionDisplay->setLayerFilter({stack, isInternal()}); if (mRefreshRateOverlay) { mRefreshRateOverlay->setLayerStack(stack); } @@ -349,7 +349,7 @@ bool DisplayDevice::needsFiltering() const { } ui::LayerStack DisplayDevice::getLayerStack() const { - return mCompositionDisplay->getState().layerStackId; + return mCompositionDisplay->getState().layerFilter.layerStack; } ui::Transform::RotationFlags DisplayDevice::getTransformHint() const { diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 7db87d9123..43a6bd540a 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -86,9 +86,7 @@ public: bool isVirtual() const { return !mConnectionType; } bool isPrimary() const { return mIsPrimary; } - bool isInternal() const { - return !isVirtual() && mConnectionType == ui::DisplayConnectionType::Internal; - } + bool isInternal() const { return mConnectionType == ui::DisplayConnectionType::Internal; } // isSecure indicates whether this display can be trusted to display // secure surfaces. @@ -311,7 +309,7 @@ struct DisplayDeviceState { int32_t sequenceId = sNextSequenceId++; std::optional physical; sp surface; - ui::LayerStack layerStack = ui::NO_LAYER_STACK; + ui::LayerStack layerStack; uint32_t flags = 0; Rect layerStackSpaceRect; Rect orientedDisplaySpaceRect; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 28c8213fc9..51568547b4 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -107,7 +107,7 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.requestedCrop = mDrawingState.crop; mDrawingState.z = 0; mDrawingState.color.a = 1.0f; - mDrawingState.layerStack = 0; + mDrawingState.layerStack = ui::DEFAULT_LAYER_STACK; mDrawingState.sequence = 0; mDrawingState.requested_legacy = mDrawingState.active_legacy; mDrawingState.width = UINT32_MAX; @@ -391,7 +391,6 @@ void Layer::setupRoundedCornersCropCoordinates(Rect win, void Layer::prepareBasicGeometryCompositionState() { const auto& drawingState{getDrawingState()}; - const uint32_t layerStack = getLayerStack(); const auto alpha = static_cast(getAlpha()); const bool opaque = isOpaque(drawingState); const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f; @@ -403,9 +402,7 @@ void Layer::prepareBasicGeometryCompositionState() { } auto* compositionState = editCompositionState(); - compositionState->layerStackId = - (layerStack != ~0u) ? std::make_optional(layerStack) : std::nullopt; - compositionState->internalOnly = getPrimaryDisplayOnly(); + compositionState->outputFilter = getOutputFilter(); compositionState->isVisible = isVisible(); compositionState->isOpaque = opaque && !usesRoundedCorners && alpha == 1.f; compositionState->shadowRadius = mEffectiveShadowRadius; @@ -1005,7 +1002,7 @@ bool Layer::setMetadata(const LayerMetadata& data) { return true; } -bool Layer::setLayerStack(uint32_t layerStack) { +bool Layer::setLayerStack(ui::LayerStack layerStack) { if (mDrawingState.layerStack == layerStack) return false; mDrawingState.sequence++; mDrawingState.layerStack = layerStack; @@ -1052,12 +1049,11 @@ bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) { return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE; }; -uint32_t Layer::getLayerStack() const { - auto p = mDrawingParent.promote(); - if (p == nullptr) { - return getDrawingState().layerStack; +ui::LayerStack Layer::getLayerStack() const { + if (const auto parent = mDrawingParent.promote()) { + return parent->getLayerStack(); } - return p->getLayerStack(); + return getDrawingState().layerStack; } bool Layer::setShadowRadius(float shadowRadius) { @@ -1371,7 +1367,7 @@ LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const { info.mVisibleRegion = getVisibleRegion(display); info.mSurfaceDamageRegion = surfaceDamageRegion; - info.mLayerStack = getLayerStack(); + info.mLayerStack = getLayerStack().id; info.mX = ds.transform.tx(); info.mY = ds.transform.ty(); info.mZ = ds.z; @@ -2087,7 +2083,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy, [&]() { return layerInfo->mutable_transparent_region(); }); - layerInfo->set_layer_stack(getLayerStack()); + layerInfo->set_layer_stack(getLayerStack().id); layerInfo->set_z(state.z); LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), @@ -2134,7 +2130,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet if (traceFlags & SurfaceTracing::TRACE_INPUT) { WindowInfo info; if (useDrawing) { - info = fillInputInfo({nullptr}); + info = fillInputInfo(nullptr); } else { info = state.inputInfo; } @@ -2163,7 +2159,7 @@ Rect Layer::getInputBounds() const { return getCroppedBufferSize(getDrawingState()); } -void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& toPhysicalDisplay) { +void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& displayTransform) { // Transform layer size to screen space and inset it by surface insets. // If this is a portal window, set the touchableRegion to the layerBounds. Rect layerBounds = info.portalToDisplayId == ADISPLAY_ID_NONE @@ -2183,13 +2179,13 @@ void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& toPhysical return; } - ui::Transform layerToDisplay = getInputTransform(); + const ui::Transform layerTransform = getInputTransform(); // Transform that takes window coordinates to unrotated display coordinates - ui::Transform t = toPhysicalDisplay * layerToDisplay; + ui::Transform t = displayTransform * layerTransform; int32_t xSurfaceInset = info.surfaceInset; int32_t ySurfaceInset = info.surfaceInset; // Bring screenBounds into unrotated space - Rect screenBounds = toPhysicalDisplay.transform(Rect{mScreenBounds}); + Rect screenBounds = displayTransform.transform(Rect{mScreenBounds}); const float xScale = t.getScaleX(); const float yScale = t.getScaleY(); @@ -2268,33 +2264,33 @@ void Layer::fillTouchOcclusionMode(WindowInfo& info) { } } -WindowInfo Layer::fillInputInfo(const sp& display) { +WindowInfo Layer::fillInputInfo(const DisplayDevice* display) { if (!hasInputInfo()) { mDrawingState.inputInfo.name = getName(); mDrawingState.inputInfo.ownerUid = mOwnerUid; mDrawingState.inputInfo.ownerPid = mOwnerPid; mDrawingState.inputInfo.inputFeatures = WindowInfo::Feature::NO_INPUT_CHANNEL; mDrawingState.inputInfo.flags = WindowInfo::Flag::NOT_TOUCH_MODAL; - mDrawingState.inputInfo.displayId = getLayerStack(); + mDrawingState.inputInfo.displayId = getLayerStack().id; } WindowInfo info = mDrawingState.inputInfo; info.id = sequence; - info.displayId = getLayerStack(); + info.displayId = getLayerStack().id; - // Transform that goes from "logical(rotated)" display to physical/unrotated display. - // This is for when inputflinger operates in physical display-space. - ui::Transform toPhysicalDisplay; + // Transform that maps from LayerStack space to display space, e.g. rotated to unrotated. + // Used when InputFlinger operates in display space. + ui::Transform displayTransform; if (display) { - toPhysicalDisplay = display->getTransform(); + displayTransform = display->getTransform(); // getOrientation() without masking can contain more-significant bits (eg. ROT_INVALID). - static constexpr uint32_t ALL_ROTATIONS_MASK = + constexpr uint32_t kAllRotationsMask = ui::Transform::ROT_90 | ui::Transform::ROT_180 | ui::Transform::ROT_270; - info.displayOrientation = toPhysicalDisplay.getOrientation() & ALL_ROTATIONS_MASK; + info.displayOrientation = displayTransform.getOrientation() & kAllRotationsMask; info.displayWidth = display->getWidth(); info.displayHeight = display->getHeight(); } - fillInputFrameInfo(info, toPhysicalDisplay); + fillInputFrameInfo(info, displayTransform); // For compatibility reasons we let layers which can receive input // receive input before they have actually submitted a buffer. Because @@ -2310,15 +2306,11 @@ WindowInfo Layer::fillInputInfo(const sp& display) { auto cropLayer = mDrawingState.touchableRegionCrop.promote(); if (info.replaceTouchableRegionWithCrop) { - if (cropLayer == nullptr) { - info.touchableRegion = Region(toPhysicalDisplay.transform(Rect{mScreenBounds})); - } else { - info.touchableRegion = - Region(toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds})); - } + const Rect bounds(cropLayer ? cropLayer->mScreenBounds : mScreenBounds); + info.touchableRegion = Region(displayTransform.transform(bounds)); } else if (cropLayer != nullptr) { info.touchableRegion = info.touchableRegion.intersect( - toPhysicalDisplay.transform(Rect{cropLayer->mScreenBounds})); + displayTransform.transform(Rect{cropLayer->mScreenBounds})); } // Inherit the trusted state from the parent hierarchy, but don't clobber the trusted state @@ -2329,9 +2321,8 @@ WindowInfo Layer::fillInputInfo(const sp& display) { // If the layer is a clone, we need to crop the input region to cloned root to prevent // touches from going outside the cloned area. if (isClone()) { - sp clonedRoot = getClonedRoot(); - if (clonedRoot != nullptr) { - Rect rect = toPhysicalDisplay.transform(Rect{clonedRoot->mScreenBounds}); + if (const sp clonedRoot = getClonedRoot()) { + const Rect rect = displayTransform.transform(Rect{clonedRoot->mScreenBounds}); info.touchableRegion = info.touchableRegion.intersect(rect); } } @@ -2527,14 +2518,14 @@ scheduler::Seamlessness Layer::FrameRate::convertChangeFrameRateStrategy(int8_t } } -bool Layer::getPrimaryDisplayOnly() const { +bool Layer::isInternalDisplayOverlay() const { const State& s(mDrawingState); if (s.flags & layer_state_t::eLayerSkipScreenshot) { return true; } sp parent = mDrawingParent.promote(); - return parent == nullptr ? false : parent->getPrimaryDisplayOnly(); + return parent && parent->isInternalDisplayOverlay(); } void Layer::setClonedChild(const sp& clonedChild) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 41bdebdf10..982f246b00 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -151,12 +151,7 @@ public: Geometry requested_legacy; int32_t z; - // The identifier of the layer stack this layer belongs to. A layer can - // only be associated to a single layer stack. A layer stack is a - // z-ordered group of layers which can be associated to one or more - // displays. Using the same layer stack on different displays is a way - // to achieve mirroring. - uint32_t layerStack; + ui::LayerStack layerStack; uint32_t flags; uint8_t reserved[2]; @@ -403,8 +398,8 @@ public: virtual bool setTransparentRegionHint(const Region& transparent); virtual bool setTrustedOverlay(bool); virtual bool setFlags(uint32_t flags, uint32_t mask); - virtual bool setLayerStack(uint32_t layerStack); - virtual uint32_t getLayerStack() const; + virtual bool setLayerStack(ui::LayerStack); + virtual ui::LayerStack getLayerStack() const; virtual bool setMetadata(const LayerMetadata& data); virtual void setChildrenDrawingParent(const sp&); virtual bool reparent(const sp& newParentHandle); @@ -645,11 +640,6 @@ public: uint32_t getTransactionFlags(uint32_t flags); uint32_t setTransactionFlags(uint32_t flags); - // Deprecated, please use compositionengine::Output::belongsInOutput() - // instead. - // TODO(lpique): Move the remaining callers (screencap) to the new function. - bool belongsToDisplay(uint32_t layerStack) const { return getLayerStack() == layerStack; } - FloatRect getBounds(const Region& activeTransparentRegion) const; FloatRect getBounds() const; @@ -681,6 +671,14 @@ public: */ bool isHiddenByPolicy() const; + // True if the layer should be skipped in screenshots, screen recordings, + // and mirroring to external or virtual displays. + bool isInternalDisplayOverlay() const; + + ui::LayerFilter getOutputFilter() const { + return {getLayerStack(), isInternalDisplayOverlay()}; + } + bool isRemovedFromCurrentState() const; LayerProto* writeToProto(LayersProto& layersProto, uint32_t traceFlags, const DisplayDevice*); @@ -697,8 +695,6 @@ public: gui::WindowInfo::Type getWindowType() const { return mWindowType; } - bool getPrimaryDisplayOnly() const; - void updateMirrorInfo(); /* @@ -848,7 +844,8 @@ public: bool getPremultipledAlpha() const; void setInputInfo(const gui::WindowInfo& info); - gui::WindowInfo fillInputInfo(const sp& display); + gui::WindowInfo fillInputInfo(const DisplayDevice*); + /** * Returns whether this layer has an explicitly set input-info. */ @@ -1069,8 +1066,8 @@ private: // hasInputInfo() or no-op if no such parent is found. void fillTouchOcclusionMode(gui::WindowInfo& info); - // Fills in the frame and transform info for the gui::WindowInfo - void fillInputFrameInfo(gui::WindowInfo& info, const ui::Transform& toPhysicalDisplay); + // Fills in the frame and transform info for the gui::WindowInfo. + void fillInputFrameInfo(gui::WindowInfo&, const ui::Transform& displayTransform); // Cached properties computed from drawing state // Effective transform taking into account parent transforms and any parent scaling, which is diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp index aee820a88c..f52e60deda 100644 --- a/services/surfaceflinger/LayerVector.cpp +++ b/services/surfaceflinger/LayerVector.cpp @@ -45,8 +45,8 @@ int LayerVector::do_compare(const void* lhs, const void* rhs) const const auto& lState = l->getDrawingState(); const auto& rState = r->getDrawingState(); - uint32_t ls = lState.layerStack; - uint32_t rs = rState.layerStack; + const auto ls = lState.layerStack; + const auto rs = rState.layerStack; if (ls != rs) return (ls > rs) ? 1 : -1; diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 2adfe14ef7..40d4c61401 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -281,7 +281,7 @@ void RefreshRateOverlay::setViewport(ui::Size viewport) { mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } -void RefreshRateOverlay::setLayerStack(uint32_t stack) { +void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) { mLayer->setLayerStack(stack); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index fd1e2df96d..63ae383c8c 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -41,7 +42,7 @@ class RefreshRateOverlay { public: RefreshRateOverlay(SurfaceFlinger&, uint32_t lowFps, uint32_t highFps, bool showSpinner); - void setLayerStack(uint32_t stack); + void setLayerStack(ui::LayerStack); void setViewport(ui::Size); void changeRefreshRate(const Fps&); void onInvalidate(); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 99d9bb3463..417bffc998 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2295,7 +2295,7 @@ void SurfaceFlinger::postComposition() { int32_t maxArea = 0; mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) { const auto layerFe = layer->getCompositionEngineLayerFE(); - if (layer->isVisible() && compositionDisplay->belongsInOutput(layerFe)) { + if (layer->isVisible() && compositionDisplay->includesLayer(layerFe)) { const Dataspace transfer = static_cast(layer->getDataSpace() & Dataspace::TRANSFER_MASK); const bool isHdr = (transfer == Dataspace::TRANSFER_ST2084 || @@ -2426,8 +2426,8 @@ void SurfaceFlinger::computeLayerBounds() { const auto& displayDevice = pair.second; const auto display = displayDevice->getCompositionDisplay(); for (const auto& layer : mDrawingState.layersSortedByZ) { - // only consider the layers on the given layer stack - if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) { + // Only consider the layers on this display. + if (!display->includesLayer(layer->getOutputFilter())) { continue; } @@ -2732,14 +2732,12 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, compositionengine::DisplayCreationArgsBuilder builder; if (const auto& physical = state.physical) { builder.setId(physical->id); - builder.setConnectionType(physical->type); } else { builder.setId(acquireVirtualDisplay(resolution, pixelFormat)); } builder.setPixels(resolution); builder.setIsSecure(state.isSecure); - builder.setLayerStackId(state.layerStack); builder.setPowerAdvisor(&mPowerAdvisor); builder.setName(state.displayName); auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); @@ -2942,16 +2940,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { // Update transform hint if (transactionFlags & (eTransformHintUpdateNeeded | eDisplayTransactionNeeded)) { - // The transform hint might have changed for some layers - // (either because a display has changed, or because a layer - // as changed). - // - // Walk through all the layers in currentLayers, - // and update their transform hint. - // - // If a layer is visible only on a single display, then that - // display is used to calculate the hint, otherwise we use the - // default display. + // Layers and/or displays have changed, so update the transform hint for each layer. // // NOTE: we do this here, rather than when presenting the display so that // the hint is set before we acquire a buffer from the surface texture. @@ -2962,30 +2951,29 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { // (soon to become the drawing state list). // sp hintDisplay; - uint32_t currentlayerStack = 0; - bool first = true; + ui::LayerStack layerStack; + mCurrentState.traverse([&](Layer* layer) REQUIRES(mStateLock) { // NOTE: we rely on the fact that layers are sorted by // layerStack first (so we don't have to traverse the list // of displays for every layer). - uint32_t layerStack = layer->getLayerStack(); - if (first || currentlayerStack != layerStack) { - currentlayerStack = layerStack; - // figure out if this layerstack is mirrored - // (more than one display) if so, pick the default display, - // if not, pick the only display it's on. + if (const auto filter = layer->getOutputFilter(); layerStack != filter.layerStack) { + layerStack = filter.layerStack; hintDisplay = nullptr; + + // Find the display that includes the layer. for (const auto& [token, display] : mDisplays) { - if (display->getCompositionDisplay() - ->belongsInOutput(layer->getLayerStack(), - layer->getPrimaryDisplayOnly())) { - if (hintDisplay) { - hintDisplay = nullptr; - break; - } else { - hintDisplay = display; - } + if (!display->getCompositionDisplay()->includesLayer(filter)) { + continue; } + + // Pick the primary display if another display mirrors the layer. + if (hintDisplay) { + hintDisplay = nullptr; + break; + } + + hintDisplay = display; } } @@ -2999,13 +2987,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) { hintDisplay = getDefaultDisplayDeviceLocked(); } - // could be null if there is no display available at all to get - // the transform hint from. - if (hintDisplay) { - layer->updateTransformHint(hintDisplay->getTransformHint()); - } - - first = false; + layer->updateTransformHint(hintDisplay->getTransformHint()); }); } @@ -3069,9 +3051,12 @@ void SurfaceFlinger::notifyWindowInfos() { mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (!layer->needsInputInfo()) return; - sp display = enablePerWindowInputRotation() - ? ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)) - : nullptr; + + const DisplayDevice* display = nullptr; + if (enablePerWindowInputRotation()) { + display = ON_MAIN_THREAD(getDisplayWithInputByLayer(layer)).get(); + } + // When calculating the screen bounds we ignore the transparent region since it may // result in an unwanted offset. windowInfos.push_back(layer->fillInputInfo(display)); @@ -3243,7 +3228,7 @@ void SurfaceFlinger::commitOffscreenLayers() { void SurfaceFlinger::invalidateLayerStack(const sp& layer, const Region& dirty) { for (const auto& [token, displayDevice] : ON_MAIN_THREAD(mDisplays)) { auto display = displayDevice->getCompositionDisplay(); - if (display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) { + if (display->includesLayer(layer->getOutputFilter())) { display->editState().dirtyRegion.orSelf(dirty); } } @@ -4464,7 +4449,7 @@ void SurfaceFlinger::onInitializeDisplays() { d.what = DisplayState::eDisplayProjectionChanged | DisplayState::eLayerStackChanged; d.token = token; - d.layerStack = 0; + d.layerStack = ui::DEFAULT_LAYER_STACK; d.orientation = ui::ROTATION_0; d.orientedDisplaySpaceRect.makeInvalid(); d.layerStackSpaceRect.makeInvalid(); @@ -4495,23 +4480,22 @@ void SurfaceFlinger::initializeDisplays() { } sp SurfaceFlinger::getDisplayWithInputByLayer(Layer* layer) const { - sp display; - for (const auto& pair : mDisplays) { - const auto& displayDevice = pair.second; - if (!displayDevice->receivesInput() || - !displayDevice->getCompositionDisplay() - ->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) { + const auto filter = layer->getOutputFilter(); + sp inputDisplay; + + for (const auto& [_, display] : mDisplays) { + if (!display->receivesInput() || !display->getCompositionDisplay()->includesLayer(filter)) { continue; } // Don't return immediately so that we can log duplicates. - if (display) { - ALOGE("Multiple display devices claim to accept input for the same layerstack: %d", - layer->getLayerStack()); + if (inputDisplay) { + ALOGE("Multiple displays claim to accept input for the same layer stack: %u", + filter.layerStack.id); continue; } - display = displayDevice; + inputDisplay = display; } - return display; + return inputDisplay; } void SurfaceFlinger::setPowerModeInternal(const sp& display, hal::PowerMode mode) { @@ -6417,12 +6401,12 @@ void SurfaceFlinger::traverseLayersInLayerStack(ui::LayerStack layerStack, const // We loop through the first level of layers without traversing, // as we need to determine which layers belong to the requested display. for (const auto& layer : mDrawingState.layersSortedByZ) { - if (!layer->belongsToDisplay(layerStack)) { + if (layer->getLayerStack() != layerStack) { continue; } // relative layers are traversed in Layer::traverseInZOrder layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { - if (layer->getPrimaryDisplayOnly()) { + if (layer->isInternalDisplayOverlay()) { return; } if (!layer->isVisible()) { diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index 9be3abefab..0782fef8ea 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -323,11 +323,10 @@ void SurfaceInterceptor::addFlagsLocked(Transaction* transaction, int32_t layerI } void SurfaceInterceptor::addLayerStackLocked(Transaction* transaction, int32_t layerId, - uint32_t layerStack) -{ + ui::LayerStack layerStack) { SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); LayerStackChange* layerStackChange(change->mutable_layer_stack()); - layerStackChange->set_layer_stack(layerStack); + layerStackChange->set_layer_stack(layerStack.id); } void SurfaceInterceptor::addCropLocked(Transaction* transaction, int32_t layerId, @@ -568,12 +567,11 @@ void SurfaceInterceptor::addDisplaySurfaceLocked(Transaction* transaction, int32 } } -void SurfaceInterceptor::addDisplayLayerStackLocked(Transaction* transaction, - int32_t sequenceId, uint32_t layerStack) -{ +void SurfaceInterceptor::addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId, + ui::LayerStack layerStack) { DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId)); LayerStackChange* layerStackChange(dispChange->mutable_layer_stack()); - layerStackChange->set_layer_stack(layerStack); + layerStackChange->set_layer_stack(layerStack.id); } void SurfaceInterceptor::addDisplayFlagsLocked(Transaction* transaction, int32_t sequenceId, diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h index 7b331b9f5f..970c3e5c27 100644 --- a/services/surfaceflinger/SurfaceInterceptor.h +++ b/services/surfaceflinger/SurfaceInterceptor.h @@ -160,7 +160,7 @@ private: void addTransparentRegionLocked(Transaction* transaction, int32_t layerId, const Region& transRegion); void addFlagsLocked(Transaction* transaction, int32_t layerId, uint8_t flags, uint8_t mask); - void addLayerStackLocked(Transaction* transaction, int32_t layerId, uint32_t layerStack); + void addLayerStackLocked(Transaction* transaction, int32_t layerId, ui::LayerStack); void addCropLocked(Transaction* transaction, int32_t layerId, const Rect& rect); void addCornerRadiusLocked(Transaction* transaction, int32_t layerId, float cornerRadius); void addBackgroundBlurRadiusLocked(Transaction* transaction, int32_t layerId, @@ -183,8 +183,7 @@ private: DisplayChange* createDisplayChangeLocked(Transaction* transaction, int32_t sequenceId); void addDisplaySurfaceLocked(Transaction* transaction, int32_t sequenceId, const sp& surface); - void addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId, - uint32_t layerStack); + void addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId, ui::LayerStack); void addDisplayFlagsLocked(Transaction* transaction, int32_t sequenceId, uint32_t flags); void addDisplaySizeLocked(Transaction* transaction, int32_t sequenceId, uint32_t w, uint32_t h); diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index fa3f0e7239..d33bc1080c 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -93,7 +93,7 @@ protected: ASSERT_TRUE(mBGSurfaceControl->isValid()); Transaction t; - t.setDisplayLayerStack(mDisplay, 0); + t.setDisplayLayerStack(mDisplay, ui::DEFAULT_LAYER_STACK); ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX - 3).show(mBGSurfaceControl).apply()); } diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp index af00ec7fc9..1361ded67d 100644 --- a/services/surfaceflinger/tests/EffectLayer_test.cpp +++ b/services/surfaceflinger/tests/EffectLayer_test.cpp @@ -33,7 +33,7 @@ protected: mParentLayer = createColorLayer("Parent layer", Color::RED); asTransaction([&](Transaction& t) { - t.setDisplayLayerStack(display, 0); + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer); t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque); }); diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp index 9fa3d4c417..8d7e175cec 100644 --- a/services/surfaceflinger/tests/IPC_test.cpp +++ b/services/surfaceflinger/tests/IPC_test.cpp @@ -159,7 +159,7 @@ public: {0, 0, static_cast(width), static_cast(height)}, Color::RED); - transaction->setLayerStack(mSurfaceControl, 0) + transaction->setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK) .setLayer(mSurfaceControl, std::numeric_limits::max()) .setBuffer(mSurfaceControl, gb) .setAcquireFence(mSurfaceControl, fence) @@ -232,7 +232,7 @@ public: mDisplayHeight = mode.resolution.getHeight(); Transaction setupTransaction; - setupTransaction.setDisplayLayerStack(mPrimaryDisplay, 0); + setupTransaction.setDisplayLayerStack(mPrimaryDisplay, ui::DEFAULT_LAYER_STACK); setupTransaction.apply(); } @@ -310,7 +310,7 @@ TEST_F(IPCTest, MergeBasic) { Color::RED); Transaction transaction; - transaction.setLayerStack(sc, 0) + transaction.setLayerStack(sc, ui::DEFAULT_LAYER_STACK) .setLayer(sc, std::numeric_limits::max() - 1) .setBuffer(sc, gb) .setAcquireFence(sc, fence) diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index 0bc8fe7aa0..6bd7920a62 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -266,7 +266,7 @@ protected: sp mDisplay; uint32_t mDisplayWidth; uint32_t mDisplayHeight; - uint32_t mDisplayLayerStack; + ui::LayerStack mDisplayLayerStack = ui::DEFAULT_LAYER_STACK; Rect mDisplayRect = Rect::INVALID_RECT; // leave room for ~256 layers @@ -294,8 +294,6 @@ private: // vsyncs. mBufferPostDelay = static_cast(1e6 / mode.refreshRate) * 3; - mDisplayLayerStack = 0; - mBlackBgSurface = createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect); diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp index 43d957cf7a..407625313c 100644 --- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp @@ -643,7 +643,8 @@ TEST_P(LayerTypeAndRenderTypeTransactionTest, SetLayerStackBasic) { ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32)); - Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply(); + const auto layerStack = ui::LayerStack::fromValue(mDisplayLayerStack.id + 1); + Transaction().setLayerStack(layer, layerStack).apply(); { SCOPED_TRACE("non-existing layer stack"); getScreenCapture()->expectColor(mDisplayRect, Color::BLACK); diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp index ee4d367f3d..e1a7ecc03b 100644 --- a/services/surfaceflinger/tests/LayerUpdate_test.cpp +++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp @@ -63,7 +63,7 @@ protected: TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31); asTransaction([&](Transaction& t) { - t.setDisplayLayerStack(display, 0); + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl); diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp index d02786504e..3ec6da9ff4 100644 --- a/services/surfaceflinger/tests/MirrorLayer_test.cpp +++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp @@ -36,7 +36,7 @@ protected: mParentLayer = createColorLayer("Parent layer", Color::RED); mChildLayer = createColorLayer("Child layer", Color::GREEN, mParentLayer.get()); asTransaction([&](Transaction& t) { - t.setDisplayLayerStack(display, 0); + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer); t.setCrop(mChildLayer, Rect(0, 0, 400, 400)).show(mChildLayer); t.setPosition(mChildLayer, 50, 50); diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp index 08de01cdfb..1ed6c65afb 100644 --- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp +++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp @@ -52,7 +52,7 @@ protected: mColorLayer = 0; } - void createDisplay(const ui::Size& layerStackSize, uint32_t layerStack) { + void createDisplay(const ui::Size& layerStackSize, ui::LayerStack layerStack) { mVirtualDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), false /*secure*/); asTransaction([&](Transaction& t) { @@ -63,7 +63,7 @@ protected: }); } - void createColorLayer(uint32_t layerStack) { + void createColorLayer(ui::LayerStack layerStack) { mColorLayer = createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect); @@ -90,8 +90,9 @@ protected: }; TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) { - createDisplay(mMainDisplayState.layerStackSpaceRect, 1 /* layerStack */); - createColorLayer(1 /* layerStack */); + constexpr ui::LayerStack kLayerStack{1u}; + createDisplay(mMainDisplayState.layerStackSpaceRect, kLayerStack); + createColorLayer(kLayerStack); asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); }); @@ -113,8 +114,8 @@ TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInMirroredVirtualDisplay) { // Assumption here is that the new mirrored display has the same layer stack rect as the // primary display that it is mirroring. - createDisplay(mMainDisplayState.layerStackSpaceRect, 0 /* layerStack */); - createColorLayer(0 /* layerStack */); + createDisplay(mMainDisplayState.layerStackSpaceRect, ui::DEFAULT_LAYER_STACK); + createColorLayer(ui::DEFAULT_LAYER_STACK); asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); }); diff --git a/services/surfaceflinger/tests/RelativeZ_test.cpp b/services/surfaceflinger/tests/RelativeZ_test.cpp index fde6e6eff8..50a4092ddb 100644 --- a/services/surfaceflinger/tests/RelativeZ_test.cpp +++ b/services/surfaceflinger/tests/RelativeZ_test.cpp @@ -43,7 +43,7 @@ protected: mForegroundLayer = createColorLayer("Foreground layer", Color::GREEN); asTransaction([&](Transaction& t) { - t.setDisplayLayerStack(display, 0); + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); t.setLayer(mBackgroundLayer, INT32_MAX - 2).show(mBackgroundLayer); t.setLayer(mForegroundLayer, INT32_MAX - 1).show(mForegroundLayer); }); diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp index ab2064efd0..95301b3a37 100644 --- a/services/surfaceflinger/tests/ScreenCapture_test.cpp +++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp @@ -53,7 +53,7 @@ protected: TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); asTransaction([&](Transaction& t) { - t.setDisplayLayerStack(display, 0); + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl); @@ -563,7 +563,7 @@ TEST_F(ScreenCaptureTest, CaptureSecureLayer) { Transaction() .show(redLayer) .show(secureLayer) - .setLayerStack(redLayer, 0) + .setLayerStack(redLayer, ui::DEFAULT_LAYER_STACK) .setLayer(redLayer, INT32_MAX) .apply(); @@ -655,7 +655,7 @@ TEST_F(ScreenCaptureTest, CaptureDisplayPrimaryDisplayOnly) { Transaction() .show(layer) .hide(mFGSurfaceControl) - .setLayerStack(layer, 0) + .setLayerStack(layer, ui::DEFAULT_LAYER_STACK) .setLayer(layer, INT32_MAX) .setColor(layer, {layerColor.r / 255, layerColor.g / 255, layerColor.b / 255}) .setCrop(layer, bounds) @@ -702,7 +702,7 @@ TEST_F(ScreenCaptureTest, CaptureDisplayChildPrimaryDisplayOnly) { .show(layer) .show(childLayer) .hide(mFGSurfaceControl) - .setLayerStack(layer, 0) + .setLayerStack(layer, ui::DEFAULT_LAYER_STACK) .setLayer(layer, INT32_MAX) .setColor(layer, {layerColor.r / 255, layerColor.g / 255, layerColor.b / 255}) .setColor(childLayer, {childColor.r / 255, childColor.g / 255, childColor.b / 255}) diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index a42405989f..ee16f40b6d 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -283,7 +283,7 @@ void SurfaceInterceptorTest::setupBackgroundSurface() { ASSERT_TRUE(mFGSurfaceControl->isValid()); Transaction t; - t.setDisplayLayerStack(display, 0); + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX - 3) .show(mBGSurfaceControl) @@ -380,7 +380,7 @@ void SurfaceInterceptorTest::transparentRegionHintUpdate(Transaction& t) { } void SurfaceInterceptorTest::layerStackUpdate(Transaction& t) { - t.setLayerStack(mBGSurfaceControl, STACK_UPDATE); + t.setLayerStack(mBGSurfaceControl, ui::LayerStack::fromValue(STACK_UPDATE)); } void SurfaceInterceptorTest::hiddenFlagUpdate(Transaction& t) { diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h index 89f608645d..60cffb19df 100644 --- a/services/surfaceflinger/tests/TransactionTestHarnesses.h +++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h @@ -65,7 +65,7 @@ public: SurfaceComposerClient::Transaction t; t.setDisplaySurface(vDisplay, producer); - t.setDisplayLayerStack(vDisplay, 0); + t.setDisplayLayerStack(vDisplay, ui::DEFAULT_LAYER_STACK); t.setDisplayProjection(vDisplay, displayState.orientation, Rect(displayState.layerStackSpaceRect), Rect(resolution)); t.apply(); diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp index 89228d55e5..de116f29ca 100644 --- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp +++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp @@ -84,7 +84,7 @@ TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) { ISurfaceComposerClient::eFXSurfaceBufferState); Transaction() - .setLayerStack(surfaceControl, 0) + .setLayerStack(surfaceControl, ui::DEFAULT_LAYER_STACK) .show(surfaceControl) .setLayer(surfaceControl, INT32_MAX - 1) .setInputWindowInfo(surfaceControl, windowInfo) @@ -112,7 +112,7 @@ TEST_F(WindowInfosListenerTest, WindowInfoChanged) { ISurfaceComposerClient::eFXSurfaceBufferState); Transaction() - .setLayerStack(surfaceControl, 0) + .setLayerStack(surfaceControl, ui::DEFAULT_LAYER_STACK) .show(surfaceControl) .setLayer(surfaceControl, INT32_MAX - 1) .setInputWindowInfo(surfaceControl, windowInfo) diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index a9e935df22..b3b4ec15cd 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -363,7 +363,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -426,7 +426,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -479,7 +479,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -534,7 +534,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -586,7 +586,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -651,7 +651,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -703,7 +703,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -750,7 +750,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -797,7 +797,7 @@ protected: { TransactionScope ts(*mFakeComposerClient); - ts.setDisplayLayerStack(display, 0); + ts.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl); } @@ -1195,7 +1195,7 @@ protected: fillSurfaceRGBA8(mFGSurfaceControl, RED); Transaction t; - t.setDisplayLayerStack(display, 0); + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); t.setLayer(mBGSurfaceControl, INT32_MAX - 2); t.show(mBGSurfaceControl); @@ -1342,7 +1342,7 @@ protected: ALOGD("TransactionTest::SetLayerStack"); { TransactionScope ts(*sFakeComposer); - ts.setLayerStack(mFGSurfaceControl, 1); + ts.setLayerStack(mFGSurfaceControl, ui::LayerStack{1}); } // Foreground layer should have disappeared. diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 98c18890cf..0253c4cbbf 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -82,7 +82,7 @@ constexpr int DEFAULT_DISPLAY_WIDTH = 1920; constexpr int DEFAULT_DISPLAY_HEIGHT = 1024; constexpr int DEFAULT_TEXTURE_ID = 6000; -constexpr int DEFAULT_LAYER_STACK = 7000; +constexpr ui::LayerStack LAYER_STACK{7000u}; constexpr int DEFAULT_DISPLAY_MAX_LUMINANCE = 500; @@ -287,10 +287,8 @@ struct BaseDisplayVariant { auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() .setId(DEFAULT_DISPLAY_ID) - .setConnectionType(ui::DisplayConnectionType::Internal) .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) .setIsSecure(Derived::IS_SECURE) - .setLayerStackId(DEFAULT_LAYER_STACK) .setPowerAdvisor(&test->mPowerAdvisor) .setName(std::string("Injected display for ") + test_info->test_case_name() + "." + test_info->name()) @@ -309,7 +307,7 @@ struct BaseDisplayVariant { .setPowerMode(Derived::INIT_POWER_MODE) .inject(); Mock::VerifyAndClear(test->mNativeWindow); - test->mDisplay->setLayerStack(DEFAULT_LAYER_STACK); + test->mDisplay->setLayerStack(LAYER_STACK); } template @@ -834,7 +832,7 @@ struct BaseLayerVariant { template static void initLayerDrawingStateAndComputeBounds(CompositionTest* test, sp layer) { auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer); - layerDrawingState.layerStack = DEFAULT_LAYER_STACK; + layerDrawingState.layerStack = LAYER_STACK; layerDrawingState.width = 100; layerDrawingState.height = 100; layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1], diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 60b0f5334c..5a21e7be5b 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -139,20 +139,18 @@ sp DisplayTransactionTest::injectDefaultInternalDisplay( EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)); EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(AnyNumber()); - constexpr auto kConnectionType = ui::DisplayConnectionType::Internal; - constexpr bool kIsPrimary = true; - auto compositionDisplay = compositionengine::impl::createDisplay(mFlinger.getCompositionEngine(), compositionengine::DisplayCreationArgsBuilder() .setId(DEFAULT_DISPLAY_ID) - .setConnectionType(kConnectionType) .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) .setPowerAdvisor(&mPowerAdvisor) .build()); - auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay, kConnectionType, + constexpr bool kIsPrimary = true; + auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay, + ui::DisplayConnectionType::Internal, DEFAULT_DISPLAY_HWC_DISPLAY_ID, kIsPrimary); injector.setNativeWindow(mNativeWindow); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index de058a4f68..0f1cc6765d 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -267,11 +267,6 @@ struct DisplayVariant { .setPixels({WIDTH, HEIGHT}) .setPowerAdvisor(&test->mPowerAdvisor); - const auto connectionType = CONNECTION_TYPE::value; - if (connectionType) { - ceDisplayArgs.setConnectionType(*connectionType); - } - auto compositionDisplay = compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), ceDisplayArgs.build()); @@ -279,7 +274,7 @@ struct DisplayVariant { auto injector = TestableSurfaceFlinger::FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay, - connectionType, + CONNECTION_TYPE::value, HWC_DISPLAY_ID_OPT::value, static_cast(PRIMARY)); @@ -388,7 +383,6 @@ struct HwcDisplayVariant { auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() .setId(DisplayVariant::DISPLAY_ID::get()) - .setConnectionType(PhysicalDisplay::CONNECTION_TYPE) .setPixels({DisplayVariant::WIDTH, DisplayVariant::HEIGHT}) .setIsSecure(static_cast(DisplayVariant::SECURE)) .setPowerAdvisor(&test->mPowerAdvisor) diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp index 313ab032f9..ef53aed091 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp @@ -534,8 +534,8 @@ TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) { TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackChanges) { using Case = NonHwcVirtualDisplayCase; - constexpr uint32_t oldLayerStack = 0u; - constexpr uint32_t newLayerStack = 123u; + constexpr ui::LayerStack oldLayerStack = ui::DEFAULT_LAYER_STACK; + constexpr ui::LayerStack newLayerStack{123u}; // -------------------------------------------------------------------- // Preconditions diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp index ef8b1493ae..bafa910270 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp @@ -63,15 +63,11 @@ TEST_F(OnInitializeDisplaysTest, onInitializeDisplaysSetsUpPrimaryDisplay) { // The primary display should have a current state ASSERT_TRUE(hasCurrentDisplayState(primaryDisplay.token())); const auto& primaryDisplayState = getCurrentDisplayState(primaryDisplay.token()); - // The layer stack state should be set to zero - EXPECT_EQ(0u, primaryDisplayState.layerStack); - // The orientation state should be set to zero - EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation); - // The orientedDisplaySpaceRect state should be set to INVALID + // The primary display state should be reset + EXPECT_EQ(ui::DEFAULT_LAYER_STACK, primaryDisplayState.layerStack); + EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation); EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.orientedDisplaySpaceRect); - - // The layerStackSpaceRect state should be set to INVALID EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.layerStackSpaceRect); // The width and height should both be zero @@ -99,4 +95,4 @@ TEST_F(OnInitializeDisplaysTest, onInitializeDisplaysSetsUpPrimaryDisplay) { } } // namespace -} // namespace android \ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp index fc40818ad1..7d9e22b23e 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp @@ -25,6 +25,8 @@ namespace android { namespace { +constexpr ui::LayerStack LAYER_STACK{456u}; + class SetDisplayStateLockedTest : public DisplayTransactionTest {}; TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingWithUnknownDisplay) { @@ -38,7 +40,7 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingWithUnknownDis DisplayState state; state.what = DisplayState::eLayerStackChanged; state.token = displayToken; - state.layerStack = 456; + state.layerStack = LAYER_STACK; // -------------------------------------------------------------------- // Invocation @@ -167,13 +169,13 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfLayerStackDi display.inject(); // The display has a layer stack set - display.mutableCurrentDisplayState().layerStack = 456u; + display.mutableCurrentDisplayState().layerStack = LAYER_STACK; // The incoming request sets the same layer stack DisplayState state; state.what = DisplayState::eLayerStackChanged; state.token = display.token(); - state.layerStack = 456u; + state.layerStack = LAYER_STACK; // -------------------------------------------------------------------- // Invocation @@ -187,7 +189,7 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfLayerStackDi EXPECT_EQ(0u, flags); // The current display state is unchanged - EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack); + EXPECT_EQ(LAYER_STACK, display.getCurrentDisplayState().layerStack); } TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfLayerStackChanged) { @@ -201,13 +203,13 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfLayerStac display.inject(); // The display has a layer stack set - display.mutableCurrentDisplayState().layerStack = 654u; + display.mutableCurrentDisplayState().layerStack = ui::LayerStack{LAYER_STACK.id + 1}; // The incoming request sets a different layer stack DisplayState state; state.what = DisplayState::eLayerStackChanged; state.token = display.token(); - state.layerStack = 456u; + state.layerStack = LAYER_STACK; // -------------------------------------------------------------------- // Invocation @@ -221,7 +223,7 @@ TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfLayerStac EXPECT_EQ(eDisplayTransactionNeeded, flags); // The desired display state has been set to the new value. - EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack); + EXPECT_EQ(LAYER_STACK, display.getCurrentDisplayState().layerStack); } TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfFlagsNotChanged) { -- cgit v1.2.3-59-g8ed1b From b108a6d8dd4cf8585dd4a9c98b3baa84251a1e07 Mon Sep 17 00:00:00 2001 From: Angel Aguayo Date: Fri, 6 Aug 2021 21:34:57 +0000 Subject: Changed DisplayDevice.cpp to adhere to new getters in ProjectionSpace Test: m -j Bug: 15475032 Change-Id: I34e396a2a9e55bc3f2f59853204ed4e250185f19 --- services/surfaceflinger/DisplayDevice.cpp | 18 ++++++++++-------- services/surfaceflinger/DisplayDevice.h | 4 ++-- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 802a17d981..2f8a90f857 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -116,11 +116,11 @@ void DisplayDevice::disconnect() { } int DisplayDevice::getWidth() const { - return mCompositionDisplay->getState().displaySpace.bounds.getWidth(); + return mCompositionDisplay->getState().displaySpace.getBounds().width; } int DisplayDevice::getHeight() const { - return mCompositionDisplay->getState().displaySpace.bounds.getHeight(); + return mCompositionDisplay->getState().displaySpace.getBounds().height; } void DisplayDevice::setDisplayName(const std::string& displayName) { @@ -262,13 +262,15 @@ void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpace if (!orientedDisplaySpaceRect.isValid()) { // The destination frame can be invalid if it has never been set, // in that case we assume the whole display size. - orientedDisplaySpaceRect = getCompositionDisplay()->getState().displaySpace.bounds; + orientedDisplaySpaceRect = + getCompositionDisplay()->getState().displaySpace.getBoundsAsRect(); } if (layerStackSpaceRect.isEmpty()) { // The layerStackSpaceRect can be invalid if it has never been set, in that case // we assume the whole framebuffer size. - layerStackSpaceRect = getCompositionDisplay()->getState().framebufferSpace.bounds; + layerStackSpaceRect = + getCompositionDisplay()->getState().framebufferSpace.getBoundsAsRect(); if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) { std::swap(layerStackSpaceRect.right, layerStackSpaceRect.bottom); } @@ -336,8 +338,8 @@ bool DisplayDevice::isSecure() const { return mCompositionDisplay->isSecure(); } -const Rect& DisplayDevice::getBounds() const { - return mCompositionDisplay->getState().displaySpace.bounds; +const Rect DisplayDevice::getBounds() const { + return mCompositionDisplay->getState().displaySpace.getBoundsAsRect(); } const Region& DisplayDevice::getUndefinedRegion() const { @@ -361,11 +363,11 @@ const ui::Transform& DisplayDevice::getTransform() const { } const Rect& DisplayDevice::getLayerStackSpaceRect() const { - return mCompositionDisplay->getState().layerStackSpace.content; + return mCompositionDisplay->getState().layerStackSpace.getContent(); } const Rect& DisplayDevice::getOrientedDisplaySpaceRect() const { - return mCompositionDisplay->getState().orientedDisplaySpace.content; + return mCompositionDisplay->getState().orientedDisplaySpace.getContent(); } bool DisplayDevice::hasWideColorGamut() const { diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 43a6bd540a..9de578f0dc 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -156,8 +156,8 @@ public: // Return true if intent is supported by the display. bool hasRenderIntent(ui::RenderIntent intent) const; - const Rect& getBounds() const; - const Rect& bounds() const { return getBounds(); } + const Rect getBounds() const; + const Rect bounds() const { return getBounds(); } void setDisplayName(const std::string& displayName); const std::string& getDisplayName() const { return mDisplayName; } -- cgit v1.2.3-59-g8ed1b From 48f8cb998c61fcad3db9ca7bbebc9e424844e6e2 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 26 Aug 2021 14:05:36 -0700 Subject: Report gui::DisplayInfo to clients with window info changes InputFlinger needs to know specifications about displays such as orientation and projection from SurfaceFlinger to support the MotionEvent#getRaw API, which returns coordinates in logical display space at the moment. Since dispatcher gets window information from SF, we need to send the display information that affects input dispatching at the same time as updating window information to ensure those two pieces of information remain in sync. Instead of sending display information along with each window, we attempt to reduce the amount of information sent through binder by sending DisplayInfo separately to WindowInfos. The newly added DisplayInfo struct should only be used by InputFlinger to support raw coordinates for now, with the goal of removing it altogether in the future. Bug: 179274888 Test: atest libgui_test inputflinger_tests Test: manual, ensure input works Change-Id: I87429ca4ced5f105f49a117c676cba29f8a5c4da --- libs/gui/Android.bp | 8 ++- libs/gui/DisplayInfo.cpp | 70 ++++++++++++++++++++++ libs/gui/WindowInfo.cpp | 17 ++---- libs/gui/WindowInfosListenerReporter.cpp | 5 +- libs/gui/android/gui/DisplayInfo.aidl | 19 ++++++ libs/gui/android/gui/IWindowInfosListener.aidl | 3 +- libs/gui/include/gui/DisplayInfo.h | 46 ++++++++++++++ libs/gui/include/gui/WindowInfo.h | 7 --- libs/gui/include/gui/WindowInfosListener.h | 4 +- libs/gui/include/gui/WindowInfosListenerReporter.h | 4 +- libs/gui/tests/Android.bp | 7 ++- libs/gui/tests/DisplayInfo_test.cpp | 49 +++++++++++++++ libs/gui/tests/WindowInfo_test.cpp | 5 -- .../inputflinger/dispatcher/InputDispatcher.cpp | 52 ++++++++++++---- services/inputflinger/dispatcher/InputDispatcher.h | 7 ++- services/surfaceflinger/DisplayDevice.cpp | 28 +++++++++ services/surfaceflinger/DisplayDevice.h | 4 ++ services/surfaceflinger/Layer.cpp | 33 +--------- services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 17 +++++- .../surfaceflinger/WindowInfosListenerInvoker.cpp | 4 +- .../surfaceflinger/WindowInfosListenerInvoker.h | 3 +- .../tests/WindowInfosListener_test.cpp | 4 +- 23 files changed, 311 insertions(+), 87 deletions(-) create mode 100644 libs/gui/DisplayInfo.cpp create mode 100644 libs/gui/android/gui/DisplayInfo.aidl create mode 100644 libs/gui/include/gui/DisplayInfo.h create mode 100644 libs/gui/tests/DisplayInfo_test.cpp (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 326da3a7b5..2d1f5a1694 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -65,11 +65,13 @@ cc_library_static { host_supported: true, srcs: [ ":guiconstants_aidl", + "android/gui/DisplayInfo.aidl", "android/gui/FocusRequest.aidl", "android/gui/InputApplicationInfo.aidl", "android/gui/IWindowInfosListener.aidl", "android/gui/IWindowInfosReportedListener.aidl", "android/gui/WindowInfo.aidl", + "DisplayInfo.cpp", "WindowInfo.cpp", ], @@ -90,7 +92,7 @@ cc_library_static { ], aidl: { - export_aidl_headers: true + export_aidl_headers: true, }, include_dirs: [ @@ -135,8 +137,8 @@ cc_library_static { ], aidl: { - export_aidl_headers: true - } + export_aidl_headers: true, + }, } cc_library_shared { diff --git a/libs/gui/DisplayInfo.cpp b/libs/gui/DisplayInfo.cpp new file mode 100644 index 0000000000..52d9540eeb --- /dev/null +++ b/libs/gui/DisplayInfo.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "DisplayInfo" + +#include +#include +#include + +#include + +namespace android::gui { + +// --- DisplayInfo --- + +status_t DisplayInfo::readFromParcel(const android::Parcel* parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + + float dsdx, dtdx, tx, dtdy, dsdy, ty; + SAFE_PARCEL(parcel->readInt32, &displayId); + SAFE_PARCEL(parcel->readInt32, &logicalWidth); + SAFE_PARCEL(parcel->readInt32, &logicalHeight); + SAFE_PARCEL(parcel->readFloat, &dsdx); + SAFE_PARCEL(parcel->readFloat, &dtdx); + SAFE_PARCEL(parcel->readFloat, &tx); + SAFE_PARCEL(parcel->readFloat, &dtdy); + SAFE_PARCEL(parcel->readFloat, &dsdy); + SAFE_PARCEL(parcel->readFloat, &ty); + + transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1}); + + return OK; +} + +status_t DisplayInfo::writeToParcel(android::Parcel* parcel) const { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + + SAFE_PARCEL(parcel->writeInt32, displayId); + SAFE_PARCEL(parcel->writeInt32, logicalWidth); + SAFE_PARCEL(parcel->writeInt32, logicalHeight); + SAFE_PARCEL(parcel->writeFloat, transform.dsdx()); + SAFE_PARCEL(parcel->writeFloat, transform.dtdx()); + SAFE_PARCEL(parcel->writeFloat, transform.tx()); + SAFE_PARCEL(parcel->writeFloat, transform.dtdy()); + SAFE_PARCEL(parcel->writeFloat, transform.dsdy()); + SAFE_PARCEL(parcel->writeFloat, transform.ty()); + + return OK; +} + +} // namespace android::gui diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index b2ef7aabc9..5f3a726336 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -54,12 +54,11 @@ bool WindowInfo::operator==(const WindowInfo& info) const { info.frameLeft == frameLeft && info.frameTop == frameTop && info.frameRight == frameRight && info.frameBottom == frameBottom && info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor && - info.transform == transform && info.displayOrientation == displayOrientation && - info.displayWidth == displayWidth && info.displayHeight == displayHeight && - info.touchableRegion.hasSameRects(touchableRegion) && info.visible == visible && - info.trustedOverlay == trustedOverlay && info.focusable == focusable && - info.touchOcclusionMode == touchOcclusionMode && info.hasWallpaper == hasWallpaper && - info.paused == paused && info.ownerPid == ownerPid && info.ownerUid == ownerUid && + info.transform == transform && info.touchableRegion.hasSameRects(touchableRegion) && + info.visible == visible && info.trustedOverlay == trustedOverlay && + info.focusable == focusable && info.touchOcclusionMode == touchOcclusionMode && + info.hasWallpaper == hasWallpaper && info.paused == paused && + info.ownerPid == ownerPid && info.ownerUid == ownerUid && info.packageName == packageName && info.inputFeatures == inputFeatures && info.displayId == displayId && info.portalToDisplayId == portalToDisplayId && info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop && @@ -97,9 +96,6 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeFloat(transform.dtdy()) ?: parcel->writeFloat(transform.dsdy()) ?: parcel->writeFloat(transform.ty()) ?: - parcel->writeUint32(displayOrientation) ?: - parcel->writeInt32(displayWidth) ?: - parcel->writeInt32(displayHeight) ?: parcel->writeBool(visible) ?: parcel->writeBool(focusable) ?: parcel->writeBool(hasWallpaper) ?: @@ -155,9 +151,6 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { parcel->readFloat(&dtdy) ?: parcel->readFloat(&dsdy) ?: parcel->readFloat(&ty) ?: - parcel->readUint32(&displayOrientation) ?: - parcel->readInt32(&displayWidth) ?: - parcel->readInt32(&displayHeight) ?: parcel->readBool(&visible) ?: parcel->readBool(&focusable) ?: parcel->readBool(&hasWallpaper) ?: diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp index c00a4389ad..c32b9ab398 100644 --- a/libs/gui/WindowInfosListenerReporter.cpp +++ b/libs/gui/WindowInfosListenerReporter.cpp @@ -19,6 +19,7 @@ namespace android { +using gui::DisplayInfo; using gui::IWindowInfosReportedListener; using gui::WindowInfo; using gui::WindowInfosListener; @@ -65,7 +66,7 @@ status_t WindowInfosListenerReporter::removeWindowInfosListener( } binder::Status WindowInfosListenerReporter::onWindowInfosChanged( - const std::vector& windowInfos, + const std::vector& windowInfos, const std::vector& displayInfos, const sp& windowInfosReportedListener) { std::unordered_set, ISurfaceComposer::SpHash> windowInfosListeners; @@ -78,7 +79,7 @@ binder::Status WindowInfosListenerReporter::onWindowInfosChanged( } for (auto listener : windowInfosListeners) { - listener->onWindowInfosChanged(windowInfos); + listener->onWindowInfosChanged(windowInfos, displayInfos); } if (windowInfosReportedListener) { diff --git a/libs/gui/android/gui/DisplayInfo.aidl b/libs/gui/android/gui/DisplayInfo.aidl new file mode 100644 index 0000000000..30c088525d --- /dev/null +++ b/libs/gui/android/gui/DisplayInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2021, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + +parcelable DisplayInfo cpp_header "gui/DisplayInfo.h"; diff --git a/libs/gui/android/gui/IWindowInfosListener.aidl b/libs/gui/android/gui/IWindowInfosListener.aidl index d4553ca82d..a5b2762318 100644 --- a/libs/gui/android/gui/IWindowInfosListener.aidl +++ b/libs/gui/android/gui/IWindowInfosListener.aidl @@ -16,11 +16,12 @@ package android.gui; +import android.gui.DisplayInfo; import android.gui.IWindowInfosReportedListener; import android.gui.WindowInfo; /** @hide */ oneway interface IWindowInfosListener { - void onWindowInfosChanged(in WindowInfo[] windowInfos, in @nullable IWindowInfosReportedListener windowInfosReportedListener); + void onWindowInfosChanged(in WindowInfo[] windowInfos, in DisplayInfo[] displayInfos, in @nullable IWindowInfosReportedListener windowInfosReportedListener); } diff --git a/libs/gui/include/gui/DisplayInfo.h b/libs/gui/include/gui/DisplayInfo.h new file mode 100644 index 0000000000..74f33a2a87 --- /dev/null +++ b/libs/gui/include/gui/DisplayInfo.h @@ -0,0 +1,46 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +namespace android::gui { + +/* + * Describes information about a display that can have windows in it. + * + * This should only be used by InputFlinger to support raw coordinates in logical display space. + */ +struct DisplayInfo : public Parcelable { + int32_t displayId = ADISPLAY_ID_NONE; + + // Logical display dimensions. + int32_t logicalWidth = 0; + int32_t logicalHeight = 0; + + // The display transform. This takes display coordinates to logical display coordinates. + ui::Transform transform; + + status_t writeToParcel(android::Parcel*) const override; + + status_t readFromParcel(const android::Parcel*) override; +}; + +} // namespace android::gui \ No newline at end of file diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index f090c63228..7b7c923a58 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -168,13 +168,6 @@ struct WindowInfo : public Parcelable { // Transform applied to individual windows. ui::Transform transform; - // Display orientation as ui::Transform::RotationFlags. Used for compatibility raw coordinates. - uint32_t displayOrientation = ui::Transform::ROT_0; - - // Display size in its natural rotation. Used to rotate raw coordinates for compatibility. - int32_t displayWidth = 0; - int32_t displayHeight = 0; - /* * This is filled in by the WM relative to the frame and then translated * to absolute coordinates by SurfaceFlinger once the frame is computed. diff --git a/libs/gui/include/gui/WindowInfosListener.h b/libs/gui/include/gui/WindowInfosListener.h index 8a70b9bb57..a18a498c5e 100644 --- a/libs/gui/include/gui/WindowInfosListener.h +++ b/libs/gui/include/gui/WindowInfosListener.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include @@ -23,6 +24,7 @@ namespace android::gui { class WindowInfosListener : public virtual RefBase { public: - virtual void onWindowInfosChanged(const std::vector& /*windowInfos*/) = 0; + virtual void onWindowInfosChanged(const std::vector&, + const std::vector&) = 0; }; } // namespace android::gui \ No newline at end of file diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h index 7cb96e0a30..157a804264 100644 --- a/libs/gui/include/gui/WindowInfosListenerReporter.h +++ b/libs/gui/include/gui/WindowInfosListenerReporter.h @@ -21,7 +21,6 @@ #include #include #include -#include #include namespace android { @@ -30,7 +29,8 @@ class ISurfaceComposer; class WindowInfosListenerReporter : public gui::BnWindowInfosListener { public: static sp getInstance(); - binder::Status onWindowInfosChanged(const std::vector& windowInfos, + binder::Status onWindowInfosChanged(const std::vector&, + const std::vector&, const sp&) override; status_t addWindowInfosListener(const sp& windowInfosListener, diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 3d26c3d858..6dd1073879 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -27,6 +27,7 @@ cc_test { "BufferQueue_test.cpp", "CpuConsumer_test.cpp", "EndToEndNativeInputTest.cpp", + "DisplayInfo_test.cpp", "DisplayedContentSampling_test.cpp", "FillBuffer.cpp", "GLTest.cpp", @@ -62,7 +63,7 @@ cc_test { "libinput", "libui", "libutils", - "libnativewindow" + "libnativewindow", ], header_libs: ["libsurfaceflinger_headers"], @@ -117,7 +118,7 @@ cc_test { "libgui", "libui", "libutils", - "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui. + "libbufferhubqueue", // TODO(b/70046255): Remove these once BufferHub is integrated into libgui. "libpdx_default_transport", ], @@ -146,5 +147,5 @@ cc_test { "liblog", "libui", "libutils", - ] + ], } diff --git a/libs/gui/tests/DisplayInfo_test.cpp b/libs/gui/tests/DisplayInfo_test.cpp new file mode 100644 index 0000000000..df3329cd52 --- /dev/null +++ b/libs/gui/tests/DisplayInfo_test.cpp @@ -0,0 +1,49 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include + +namespace android { + +using gui::DisplayInfo; + +namespace test { + +TEST(DisplayInfo, Parcelling) { + DisplayInfo info; + info.displayId = 42; + info.logicalWidth = 99; + info.logicalHeight = 78; + info.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1}); + + Parcel p; + info.writeToParcel(&p); + p.setDataPosition(0); + + DisplayInfo info2; + info2.readFromParcel(&p); + ASSERT_EQ(info.displayId, info2.displayId); + ASSERT_EQ(info.logicalWidth, info2.logicalWidth); + ASSERT_EQ(info.logicalHeight, info2.logicalHeight); + ASSERT_EQ(info.transform, info2.transform); +} + +} // namespace test +} // namespace android diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index a4f436cdba..dcdf76fe35 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -60,9 +60,6 @@ TEST(WindowInfo, Parcelling) { i.globalScaleFactor = 0.3; i.alpha = 0.7; i.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1}); - i.displayOrientation = ui::Transform::ROT_0; - i.displayWidth = 1000; - i.displayHeight = 2000; i.visible = false; i.focusable = false; i.hasWallpaper = false; @@ -100,8 +97,6 @@ TEST(WindowInfo, Parcelling) { ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor); ASSERT_EQ(i.alpha, i2.alpha); ASSERT_EQ(i.transform, i2.transform); - ASSERT_EQ(i.displayWidth, i2.displayWidth); - ASSERT_EQ(i.displayHeight, i2.displayHeight); ASSERT_EQ(i.visible, i2.visible); ASSERT_EQ(i.focusable, i2.focusable); ASSERT_EQ(i.hasWallpaper, i2.hasWallpaper); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 59cb419d2b..84f5a185d1 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -54,6 +54,7 @@ using android::base::HwTimeoutMultiplier; using android::base::Result; using android::base::StringPrintf; +using android::gui::DisplayInfo; using android::gui::FocusRequest; using android::gui::TouchOcclusionMode; using android::gui::WindowInfo; @@ -2444,9 +2445,15 @@ void InputDispatcher::addWindowTargetLocked(const sp& windowHa inputTarget.inputChannel = inputChannel; inputTarget.flags = targetFlags; inputTarget.globalScaleFactor = windowInfo->globalScaleFactor; - inputTarget.displayOrientation = windowInfo->displayOrientation; - inputTarget.displaySize = - int2(windowHandle->getInfo()->displayWidth, windowHandle->getInfo()->displayHeight); + const auto& displayInfoIt = mDisplayInfos.find(windowInfo->displayId); + if (displayInfoIt != mDisplayInfos.end()) { + const auto& displayInfo = displayInfoIt->second; + inputTarget.displayOrientation = displayInfo.transform.getOrientation(); + inputTarget.displaySize = int2(displayInfo.logicalWidth, displayInfo.logicalHeight); + } else { + ALOGI_IF(isPerWindowInputRotationEnabled(), + "DisplayInfo not found for window on display: %d", windowInfo->displayId); + } inputTargets.push_back(inputTarget); it = inputTargets.end() - 1; } @@ -4484,6 +4491,7 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( void InputDispatcher::setInputWindows( const std::unordered_map>>& handlesPerDisplay) { + // TODO(b/198444055): Remove setInputWindows from InputDispatcher. { // acquire lock std::scoped_lock _l(mLock); for (const auto& [displayId, handles] : handlesPerDisplay) { @@ -5013,9 +5021,17 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { } if (!mWindowHandlesByDisplay.empty()) { - for (auto& it : mWindowHandlesByDisplay) { - const std::vector> windowHandles = it.second; - dump += StringPrintf(INDENT "Display: %" PRId32 "\n", it.first); + for (const auto& [displayId, windowHandles] : mWindowHandlesByDisplay) { + dump += StringPrintf(INDENT "Display: %" PRId32 "\n", displayId); + if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) { + const auto& displayInfo = it->second; + dump += StringPrintf(INDENT2 "logicalSize=%dx%d\n", displayInfo.logicalWidth, + displayInfo.logicalHeight); + displayInfo.transform.dump(dump, "transform", INDENT4); + } else { + dump += INDENT2 "No DisplayInfo found!\n"; + } + if (!windowHandles.empty()) { dump += INDENT2 "Windows:\n"; for (size_t i = 0; i < windowHandles.size(); i++) { @@ -5047,13 +5063,12 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { windowInfo->inputFeatures.string().c_str()); dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64 "ms, trustedOverlay=%s, hasToken=%s, " - "touchOcclusionMode=%s, displayOrientation=%d\n", + "touchOcclusionMode=%s\n", windowInfo->ownerPid, windowInfo->ownerUid, millis(windowInfo->dispatchingTimeout), toString(windowInfo->trustedOverlay), toString(windowInfo->token != nullptr), - toString(windowInfo->touchOcclusionMode).c_str(), - windowInfo->displayOrientation); + toString(windowInfo->touchOcclusionMode).c_str()); windowInfo->transform.dump(dump, "transform", INDENT4); } } else { @@ -6099,16 +6114,29 @@ void InputDispatcher::displayRemoved(int32_t displayId) { mLooper->wake(); } -void InputDispatcher::onWindowInfosChanged(const std::vector& windowInfos) { +void InputDispatcher::onWindowInfosChanged(const std::vector& windowInfos, + const std::vector& displayInfos) { // The listener sends the windows as a flattened array. Separate the windows by display for // more convenient parsing. std::unordered_map>> handlesPerDisplay; - for (const auto& info : windowInfos) { handlesPerDisplay.emplace(info.displayId, std::vector>()); handlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info)); } - setInputWindows(handlesPerDisplay); + + { // acquire lock + std::scoped_lock _l(mLock); + mDisplayInfos.clear(); + for (const auto& displayInfo : displayInfos) { + mDisplayInfos.emplace(displayInfo.displayId, displayInfo); + } + + for (const auto& [displayId, handles] : handlesPerDisplay) { + setInputWindowsLocked(handles, displayId); + } + } + // Wake up poll loop since it may need to make new input dispatching choices. + mLooper->wake(); } } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 6df333a154..afe4366c32 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -143,7 +143,8 @@ public: void displayRemoved(int32_t displayId) override; - void onWindowInfosChanged(const std::vector& windowInfos) override; + void onWindowInfosChanged(const std::vector&, + const std::vector&) override; private: enum class DropReason { @@ -337,8 +338,10 @@ private: float mMaximumObscuringOpacityForTouch GUARDED_BY(mLock); android::os::BlockUntrustedTouchesMode mBlockUntrustedTouchesMode GUARDED_BY(mLock); - std::unordered_map>> + std::unordered_map>> mWindowHandlesByDisplay GUARDED_BY(mLock); + std::unordered_map mDisplayInfos + GUARDED_BY(mLock); void setInputWindowsLocked( const std::vector>& inputWindowHandles, int32_t displayId) REQUIRES(mLock); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 802a17d981..fd93b2d8f7 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -139,6 +139,34 @@ uint32_t DisplayDevice::getPageFlipCount() const { return mCompositionDisplay->getRenderSurface()->getPageFlipCount(); } +std::pair DisplayDevice::getInputInfo() const { + gui::DisplayInfo info; + info.displayId = getLayerStack().id; + + // The physical orientation is set when the orientation of the display panel is + // different than the default orientation of the device. Other services like + // InputFlinger do not know about this, so we do not need to expose the physical + // orientation of the panel outside of SurfaceFlinger. + const ui::Rotation inversePhysicalOrientation = ui::ROTATION_0 - mPhysicalOrientation; + auto width = getWidth(); + auto height = getHeight(); + if (inversePhysicalOrientation == ui::ROTATION_90 || + inversePhysicalOrientation == ui::ROTATION_270) { + std::swap(width, height); + } + const ui::Transform undoPhysicalOrientation(ui::Transform::toRotationFlags( + inversePhysicalOrientation), + width, height); + const auto& displayTransform = undoPhysicalOrientation * getTransform(); + // Send the inverse display transform to input so it can convert display coordinates to + // logical display. + info.transform = displayTransform.inverse(); + + info.logicalWidth = getLayerStackSpaceRect().width(); + info.logicalHeight = getLayerStackSpaceRect().height(); + return {info, displayTransform}; +} + // ---------------------------------------------------------------------------- void DisplayDevice::setPowerMode(hal::PowerMode mode) { mPowerMode = mode; diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 43a6bd540a..7762054b4a 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -167,6 +167,10 @@ public: return mDeviceProductInfo; } + // Get the DisplayInfo that will be sent to InputFlinger, and the display transform that should + // be applied to all the input windows on the display. + std::pair getInputInfo() const; + /* ------------------------------------------------------------------------ * Display power mode management. */ diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 804cf9a3a0..2376b83c57 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2131,7 +2131,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet if (traceFlags & SurfaceTracing::TRACE_INPUT) { WindowInfo info; if (useDrawing) { - info = fillInputInfo(nullptr); + info = fillInputInfo(ui::Transform()); } else { info = state.inputInfo; } @@ -2265,7 +2265,7 @@ void Layer::fillTouchOcclusionMode(WindowInfo& info) { } } -WindowInfo Layer::fillInputInfo(const DisplayDevice* display) { +WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) { if (!hasInputInfo()) { mDrawingState.inputInfo.name = getName(); mDrawingState.inputInfo.ownerUid = mOwnerUid; @@ -2279,35 +2279,6 @@ WindowInfo Layer::fillInputInfo(const DisplayDevice* display) { info.id = sequence; info.displayId = getLayerStack().id; - // Transform that maps from LayerStack space to display space, e.g. rotated to non-rotated. - // Used when InputFlinger operates in display space. - ui::Transform displayTransform; - if (display) { - // The physical orientation is set when the orientation of the display panel is different - // than the default orientation of the device. Other services like InputFlinger do not know - // about this, so we do not need to expose the physical orientation of the panel outside of - // SurfaceFlinger. - const ui::Rotation inversePhysicalOrientation = - ui::ROTATION_0 - display->getPhysicalOrientation(); - auto width = display->getWidth(); - auto height = display->getHeight(); - if (inversePhysicalOrientation == ui::ROTATION_90 || - inversePhysicalOrientation == ui::ROTATION_270) { - std::swap(width, height); - } - const ui::Transform undoPhysicalOrientation(ui::Transform::toRotationFlags( - inversePhysicalOrientation), - width, height); - displayTransform = undoPhysicalOrientation * display->getTransform(); - - // Send the inverse of the display orientation so that input can transform points back to - // the rotated display space. - const ui::Rotation inverseOrientation = ui::ROTATION_0 - display->getOrientation(); - info.displayOrientation = ui::Transform::toRotationFlags(inverseOrientation); - - info.displayWidth = width; - info.displayHeight = height; - } fillInputFrameInfo(info, displayTransform); // For compatibility reasons we let layers which can receive input diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 4200be4898..3c3c7d0b88 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -851,7 +851,7 @@ public: bool getPremultipledAlpha() const; void setInputInfo(const gui::WindowInfo& info); - gui::WindowInfo fillInputInfo(const DisplayDevice*); + gui::WindowInfo fillInputInfo(const ui::Transform& displayTransform); /** * Returns whether this layer has an explicitly set input-info. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 21b889e264..12389d1663 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -169,6 +169,7 @@ using namespace android::sysprop; using android::hardware::power::Boost; using base::StringAppendF; +using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; using ui::ColorMode; @@ -3053,6 +3054,16 @@ bool enablePerWindowInputRotation() { void SurfaceFlinger::notifyWindowInfos() { std::vector windowInfos; + std::vector displayInfos; + std::unordered_map displayTransforms; + + if (enablePerWindowInputRotation()) { + for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { + const auto& [info, transform] = display->getInputInfo(); + displayInfos.emplace_back(info); + displayTransforms.emplace(display.get(), transform); + } + } mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (!layer->needsInputInfo()) return; @@ -3064,9 +3075,11 @@ void SurfaceFlinger::notifyWindowInfos() { // When calculating the screen bounds we ignore the transparent region since it may // result in an unwanted offset. - windowInfos.push_back(layer->fillInputInfo(display)); + const auto it = displayTransforms.find(display); + windowInfos.push_back( + layer->fillInputInfo(it != displayTransforms.end() ? it->second : ui::Transform())); }); - mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, + mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos, mInputWindowCommands.syncInputWindows); } diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index dc2aa58c9a..b93d127ab8 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -21,6 +21,7 @@ namespace android { +using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; @@ -67,6 +68,7 @@ void WindowInfosListenerInvoker::binderDied(const wp& who) { } void WindowInfosListenerInvoker::windowInfosChanged(const std::vector& windowInfos, + const std::vector& displayInfos, bool shouldSync) { std::unordered_set, ISurfaceComposer::SpHash> windowInfosListeners; @@ -81,7 +83,7 @@ void WindowInfosListenerInvoker::windowInfosChanged(const std::vectoronWindowInfosChanged(windowInfos, + listener->onWindowInfosChanged(windowInfos, displayInfos, shouldSync ? mWindowInfosReportedListener : nullptr); } } diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index 5e5796fe2d..ecd797a631 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -33,7 +33,8 @@ public: void addWindowInfosListener(const sp& windowInfosListener); void removeWindowInfosListener(const sp& windowInfosListener); - void windowInfosChanged(const std::vector& windowInfos, bool shouldSync); + void windowInfosChanged(const std::vector&, + const std::vector&, bool shouldSync); protected: void binderDied(const wp& who) override; diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp index de116f29ca..0069111e09 100644 --- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp +++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp @@ -22,6 +22,7 @@ namespace android { using Transaction = SurfaceComposerClient::Transaction; +using gui::DisplayInfo; using gui::WindowInfo; class WindowInfosListenerTest : public ::testing::Test { @@ -40,7 +41,8 @@ protected: struct SyncWindowInfosListener : public gui::WindowInfosListener { public: - void onWindowInfosChanged(const std::vector& windowInfos) override { + void onWindowInfosChanged(const std::vector& windowInfos, + const std::vector&) override { windowInfosPromise.set_value(windowInfos); } -- cgit v1.2.3-59-g8ed1b From e0e0cde7fa7d4dc34fb68c862f4a255d7d3252c7 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Fri, 30 Jul 2021 10:42:05 -0700 Subject: SF: Decouple MessageQueue Define an ICompositor interface against which MessageQueue (which ought to be an implementation detail of Scheduler) is implemented. Change the equivocal invalidate/refresh nomenclature to commit/composite. Schedule sampling only after composite. Bug: 185535769 Test: libsurfaceflinger_unittest Change-Id: I0c18f312459bae48531449f24f7b53c104fc5812 --- services/surfaceflinger/BufferLayer.cpp | 2 +- services/surfaceflinger/BufferQueueLayer.cpp | 8 +- services/surfaceflinger/BufferStateLayer.cpp | 4 +- .../compositionengine/CompositionRefreshArgs.h | 4 +- .../CompositionEngine/src/Output.cpp | 2 +- services/surfaceflinger/DisplayDevice.cpp | 4 +- services/surfaceflinger/DisplayDevice.h | 2 +- services/surfaceflinger/RefreshRateOverlay.cpp | 2 +- services/surfaceflinger/RefreshRateOverlay.h | 2 +- services/surfaceflinger/RegionSamplingThread.cpp | 2 +- services/surfaceflinger/Scheduler/MessageQueue.cpp | 93 ++++++------ services/surfaceflinger/Scheduler/MessageQueue.h | 81 +++++----- services/surfaceflinger/Scheduler/Scheduler.cpp | 14 +- services/surfaceflinger/Scheduler/Scheduler.h | 6 +- services/surfaceflinger/SurfaceFlinger.cpp | 166 +++++++-------------- services/surfaceflinger/SurfaceFlinger.h | 68 ++++----- .../SurfaceFlingerDefaultFactory.cpp | 4 +- .../surfaceflinger/SurfaceFlingerDefaultFactory.h | 2 +- services/surfaceflinger/SurfaceFlingerFactory.h | 7 +- .../tests/unittests/CompositionTest.cpp | 10 +- .../tests/unittests/MessageQueueTest.cpp | 101 ++++++------- .../tests/unittests/SetFrameRateTest.cpp | 18 +-- .../unittests/SurfaceFlinger_CreateDisplayTest.cpp | 10 +- .../SurfaceFlinger_DestroyDisplayTest.cpp | 4 +- .../tests/unittests/SurfaceFlinger_HotplugTest.cpp | 10 +- .../SurfaceFlinger_OnInitializeDisplaysTest.cpp | 5 +- .../SurfaceFlinger_SetPowerModeInternalTest.cpp | 2 +- .../tests/unittests/TestableSurfaceFlinger.h | 20 ++- .../tests/unittests/TransactionApplicationTest.cpp | 14 +- .../tests/unittests/mock/MockMessageQueue.h | 9 +- .../tests/unittests/mock/MockSchedulerCallback.h | 4 +- 31 files changed, 304 insertions(+), 376 deletions(-) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index ef05fe2138..160b2ea5c0 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -486,7 +486,7 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, // try again later if (!fenceHasSignaled()) { ATRACE_NAME("!fenceHasSignaled()"); - mFlinger->signalLayerUpdate(); + mFlinger->onLayerUpdate(); return false; } diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 8bbe43865a..bf38177d99 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -228,7 +228,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t if (updateResult == BufferQueue::PRESENT_LATER) { // Producer doesn't want buffer to be displayed yet. Signal a // layer update so we check again at the next opportunity. - mFlinger->signalLayerUpdate(); + mFlinger->onLayerUpdate(); return BAD_VALUE; } else if (updateResult == BufferLayerConsumer::BUFFER_REJECTED) { // If the buffer has been rejected, remove it from the shadow queue @@ -309,7 +309,7 @@ status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t // Decrement the queued-frames count. Signal another event if we // have more frames pending. if ((queuedBuffer && more_frames_pending) || mAutoRefresh) { - mFlinger->signalLayerUpdate(); + mFlinger->onLayerUpdate(); } return NO_ERROR; @@ -412,7 +412,7 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { mFlinger->mInterceptor->saveBufferUpdate(layerId, item.mGraphicBuffer->getWidth(), item.mGraphicBuffer->getHeight(), item.mFrameNumber); - mFlinger->signalLayerUpdate(); + mFlinger->onLayerUpdate(); mConsumer->onBufferAvailable(item); } @@ -458,7 +458,7 @@ void BufferQueueLayer::onSidebandStreamChanged() { bool sidebandStreamChanged = false; if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, true)) { // mSidebandStreamChanged was changed to true - mFlinger->signalLayerUpdate(); + mFlinger->onLayerUpdate(); } } diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 4eeaba154f..f0099c268d 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -595,7 +595,7 @@ bool BufferStateLayer::setSidebandStream(const sp& sidebandStream) setTransactionFlags(eTransactionNeeded); if (!mSidebandStreamChanged.exchange(true)) { // mSidebandStreamChanged was false - mFlinger->signalLayerUpdate(); + mFlinger->onLayerUpdate(); } return true; } @@ -713,7 +713,7 @@ bool BufferStateLayer::onPreComposition(nsecs_t refreshStartTime) { void BufferStateLayer::setAutoRefresh(bool autoRefresh) { if (!mAutoRefresh.exchange(autoRefresh)) { - mFlinger->signalLayerUpdate(); + mFlinger->onLayerUpdate(); } } diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h index 95d553d02f..93586eddd8 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h @@ -85,8 +85,8 @@ struct CompositionRefreshArgs { // to prevent an early presentation of a frame. std::shared_ptr previousPresentFence; - // The predicted next invalidation time - std::optional nextInvalidateTime; + // If set, a frame has been scheduled for that time. + std::optional scheduledFrameTime; }; } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 048d7c2b4a..fad1fa74dd 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -1314,7 +1314,7 @@ void Output::postFramebuffer() { void Output::renderCachedSets(const CompositionRefreshArgs& refreshArgs) { if (mPlanner) { - mPlanner->renderCachedSets(getState(), refreshArgs.nextInvalidateTime); + mPlanner->renderCachedSets(getState(), refreshArgs.scheduledFrameTime); } } diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 3397118c05..fd09ae4066 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -466,9 +466,9 @@ bool DisplayDevice::onKernelTimerChanged(std::optional desiredMod return false; } -void DisplayDevice::onInvalidate() { +void DisplayDevice::animateRefreshRateOverlay() { if (mRefreshRateOverlay) { - mRefreshRateOverlay->onInvalidate(); + mRefreshRateOverlay->animate(); } } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 4a731bddf1..4b9718f608 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -234,7 +234,7 @@ public: void enableRefreshRateOverlay(bool enable, bool showSpinner); bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; } bool onKernelTimerChanged(std::optional, bool timerExpired); - void onInvalidate(); + void animateRefreshRateOverlay(); void onVsync(nsecs_t timestamp); nsecs_t getVsyncPeriodFromHWC() const; diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index ec81e6317c..2502d66a67 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -284,7 +284,7 @@ void RefreshRateOverlay::changeRefreshRate(const Fps& fps) { t.apply(); } -void RefreshRateOverlay::onInvalidate() { +void RefreshRateOverlay::animate() { if (!mCurrentFps.has_value()) return; const auto& buffers = getOrCreateBuffers(*mCurrentFps); diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index 354510a9d7..65d446c751 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -46,7 +46,7 @@ public: void setLayerStack(ui::LayerStack); void setViewport(ui::Size); void changeRefreshRate(const Fps&); - void onInvalidate(); + void animate(); private: class SevenSegmentDrawer { diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index aa2fec56ad..9465b197b2 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -150,7 +150,7 @@ void RegionSamplingThread::checkForStaleLuma() { if (mSampleRequestTime.has_value()) { ATRACE_INT(lumaSamplingStepTag, static_cast(samplingStep::waitForSamplePhase)); mSampleRequestTime.reset(); - mFlinger.scheduleRegionSamplingThread(); + mFlinger.scheduleSample(); } } diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp index 4d51125156..043a536216 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.cpp +++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp @@ -27,49 +27,55 @@ #include "EventThread.h" #include "FrameTimeline.h" #include "MessageQueue.h" -#include "SurfaceFlinger.h" namespace android::impl { -void MessageQueue::Handler::dispatchRefresh() { - if ((mEventMask.fetch_or(eventMaskRefresh) & eventMaskRefresh) == 0) { - mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH)); +void MessageQueue::Handler::dispatchComposite() { + if ((mEventMask.fetch_or(kComposite) & kComposite) == 0) { + mQueue.mLooper->sendMessage(this, Message(kComposite)); } } -void MessageQueue::Handler::dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp) { - if ((mEventMask.fetch_or(eventMaskInvalidate) & eventMaskInvalidate) == 0) { +void MessageQueue::Handler::dispatchCommit(int64_t vsyncId, nsecs_t expectedVsyncTime) { + if ((mEventMask.fetch_or(kCommit) & kCommit) == 0) { mVsyncId = vsyncId; - mExpectedVSyncTime = expectedVSyncTimestamp; - mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE)); + mExpectedVsyncTime = expectedVsyncTime; + mQueue.mLooper->sendMessage(this, Message(kCommit)); } } -bool MessageQueue::Handler::invalidatePending() { - constexpr auto pendingMask = eventMaskInvalidate | eventMaskRefresh; - return (mEventMask.load() & pendingMask) != 0; +bool MessageQueue::Handler::isFramePending() const { + constexpr auto kPendingMask = kCommit | kComposite; + return (mEventMask.load() & kPendingMask) != 0; } void MessageQueue::Handler::handleMessage(const Message& message) { + const nsecs_t frameTime = systemTime(); switch (message.what) { - case INVALIDATE: - mEventMask.fetch_and(~eventMaskInvalidate); - mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime); - break; - case REFRESH: - mEventMask.fetch_and(~eventMaskRefresh); - mQueue.mFlinger->onMessageReceived(message.what, mVsyncId, mExpectedVSyncTime); + case kCommit: + mEventMask.fetch_and(~kCommit); + if (!mQueue.mCompositor.commit(frameTime, mVsyncId, mExpectedVsyncTime)) { + return; + } + // Composite immediately, rather than after pending tasks through scheduleComposite. + [[fallthrough]]; + case kComposite: + mEventMask.fetch_and(~kComposite); + mQueue.mCompositor.composite(frameTime); + mQueue.mCompositor.sample(); break; } } -// --------------------------------------------------------------------------- +MessageQueue::MessageQueue(ICompositor& compositor) + : MessageQueue(compositor, sp::make(*this)) {} -void MessageQueue::init(const sp& flinger) { - mFlinger = flinger; - mLooper = new Looper(true); - mHandler = new Handler(*this); -} +constexpr bool kAllowNonCallbacks = true; + +MessageQueue::MessageQueue(ICompositor& compositor, sp handler) + : mCompositor(compositor), + mLooper(sp::make(kAllowNonCallbacks)), + mHandler(std::move(handler)) {} // TODO(b/169865816): refactor VSyncInjections to use MessageQueue directly // and remove the EventThread from MessageQueue @@ -110,11 +116,13 @@ void MessageQueue::vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, ns { std::lock_guard lock(mVsync.mutex); mVsync.lastCallbackTime = std::chrono::nanoseconds(vsyncTime); - mVsync.scheduled = false; + mVsync.scheduledFrameTime.reset(); } - mHandler->dispatchInvalidate(mVsync.tokenManager->generateTokenForPredictions( - {targetWakeupTime, readyTime, vsyncTime}), - vsyncTime); + + const auto vsyncId = mVsync.tokenManager->generateTokenForPredictions( + {targetWakeupTime, readyTime, vsyncTime}); + + mHandler->dispatchCommit(vsyncId, vsyncTime); } void MessageQueue::initVsync(scheduler::VSyncDispatch& dispatch, @@ -135,8 +143,8 @@ void MessageQueue::setDuration(std::chrono::nanoseconds workDuration) { ATRACE_CALL(); std::lock_guard lock(mVsync.mutex); mVsync.workDuration = workDuration; - if (mVsync.scheduled) { - mVsync.expectedWakeupTime = mVsync.registration->schedule( + if (mVsync.scheduledFrameTime) { + mVsync.scheduledFrameTime = mVsync.registration->schedule( {mVsync.workDuration.get().count(), /*readyDuration=*/0, mVsync.lastCallbackTime.count()}); } @@ -168,7 +176,7 @@ void MessageQueue::postMessage(sp&& handler) { mLooper->sendMessage(handler, Message()); } -void MessageQueue::invalidate() { +void MessageQueue::scheduleCommit() { ATRACE_CALL(); { @@ -181,15 +189,14 @@ void MessageQueue::invalidate() { } std::lock_guard lock(mVsync.mutex); - mVsync.scheduled = true; - mVsync.expectedWakeupTime = + mVsync.scheduledFrameTime = mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(), .readyDuration = 0, .earliestVsync = mVsync.lastCallbackTime.count()}); } -void MessageQueue::refresh() { - mHandler->dispatchRefresh(); +void MessageQueue::scheduleComposite() { + mHandler->dispatchComposite(); } void MessageQueue::injectorCallback() { @@ -198,24 +205,22 @@ void MessageQueue::injectorCallback() { while ((n = DisplayEventReceiver::getEvents(&mInjector.tube, buffer, 8)) > 0) { for (int i = 0; i < n; i++) { if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { - mHandler->dispatchInvalidate(buffer[i].vsync.vsyncId, - buffer[i].vsync.expectedVSyncTimestamp); + mHandler->dispatchCommit(buffer[i].vsync.vsyncId, + buffer[i].vsync.expectedVSyncTimestamp); break; } } } } -std::optional MessageQueue::nextExpectedInvalidate() { - if (mHandler->invalidatePending()) { - return std::chrono::steady_clock::now(); +auto MessageQueue::getScheduledFrameTime() const -> std::optional { + if (mHandler->isFramePending()) { + return Clock::now(); } std::lock_guard lock(mVsync.mutex); - if (mVsync.scheduled) { - LOG_ALWAYS_FATAL_IF(!mVsync.expectedWakeupTime.has_value(), "callback was never scheduled"); - const auto expectedWakeupTime = std::chrono::nanoseconds(*mVsync.expectedWakeupTime); - return std::optional(expectedWakeupTime); + if (const auto time = mVsync.scheduledFrameTime) { + return Clock::time_point(std::chrono::nanoseconds(*time)); } return std::nullopt; diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h index 58ce9b9a2f..2c908a6983 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.h +++ b/services/surfaceflinger/Scheduler/MessageQueue.h @@ -33,7 +33,14 @@ namespace android { -class SurfaceFlinger; +struct ICompositor { + virtual bool commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) = 0; + virtual void composite(nsecs_t frameTime) = 0; + virtual void sample() = 0; + +protected: + ~ICompositor() = default; +}; template class Task : public MessageHandler { @@ -56,65 +63,65 @@ inline auto makeTask(F&& f) { class MessageQueue { public: - enum { - INVALIDATE = 0, - REFRESH = 1, - }; - virtual ~MessageQueue() = default; - virtual void init(const sp& flinger) = 0; virtual void initVsync(scheduler::VSyncDispatch&, frametimeline::TokenManager&, std::chrono::nanoseconds workDuration) = 0; virtual void setDuration(std::chrono::nanoseconds workDuration) = 0; virtual void setInjector(sp) = 0; virtual void waitMessage() = 0; virtual void postMessage(sp&&) = 0; - virtual void invalidate() = 0; - virtual void refresh() = 0; - virtual std::optional nextExpectedInvalidate() = 0; -}; + virtual void scheduleCommit() = 0; + virtual void scheduleComposite() = 0; -// --------------------------------------------------------------------------- + using Clock = std::chrono::steady_clock; + virtual std::optional getScheduledFrameTime() const = 0; +}; namespace impl { class MessageQueue : public android::MessageQueue { protected: class Handler : public MessageHandler { - enum : uint32_t { - eventMaskInvalidate = 0x1, - eventMaskRefresh = 0x2, - eventMaskTransaction = 0x4 - }; + static constexpr uint32_t kCommit = 0b1; + static constexpr uint32_t kComposite = 0b10; + MessageQueue& mQueue; - std::atomic mEventMask; - std::atomic mVsyncId; - std::atomic mExpectedVSyncTime; + std::atomic mEventMask = 0; + std::atomic mVsyncId = 0; + std::atomic mExpectedVsyncTime = 0; public: - explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) {} + explicit Handler(MessageQueue& queue) : mQueue(queue) {} void handleMessage(const Message& message) override; - virtual void dispatchRefresh(); - virtual void dispatchInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTimestamp); - virtual bool invalidatePending(); + + bool isFramePending() const; + + virtual void dispatchCommit(int64_t vsyncId, nsecs_t expectedVsyncTime); + void dispatchComposite(); }; friend class Handler; - sp mFlinger; - sp mLooper; + // For tests. + MessageQueue(ICompositor&, sp); + + void vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime); + +private: + ICompositor& mCompositor; + const sp mLooper; + const sp mHandler; struct Vsync { frametimeline::TokenManager* tokenManager = nullptr; std::unique_ptr registration; - std::mutex mutex; + mutable std::mutex mutex; TracedOrdinal workDuration GUARDED_BY(mutex) = {"VsyncWorkDuration-sf", std::chrono::nanoseconds(0)}; std::chrono::nanoseconds lastCallbackTime GUARDED_BY(mutex) = std::chrono::nanoseconds{0}; - bool scheduled GUARDED_BY(mutex) = false; - std::optional expectedWakeupTime GUARDED_BY(mutex); + std::optional scheduledFrameTime GUARDED_BY(mutex); TracedOrdinal value = {"VSYNC-sf", 0}; }; @@ -127,14 +134,11 @@ protected: Vsync mVsync; Injector mInjector; - sp mHandler; - - void vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime); void injectorCallback(); public: - ~MessageQueue() override = default; - void init(const sp& flinger) override; + explicit MessageQueue(ICompositor&); + void initVsync(scheduler::VSyncDispatch&, frametimeline::TokenManager&, std::chrono::nanoseconds workDuration) override; void setDuration(std::chrono::nanoseconds workDuration) override; @@ -143,13 +147,10 @@ public: void waitMessage() override; void postMessage(sp&&) override; - // sends INVALIDATE message at next VSYNC - void invalidate() override; - - // sends REFRESH message at next VSYNC - void refresh() override; + void scheduleCommit() override; + void scheduleComposite() override; - std::optional nextExpectedInvalidate() override; + std::optional getScheduledFrameTime() const override; }; } // namespace impl diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 12e741bbc2..c6a19de9c6 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -870,7 +870,7 @@ DisplayModePtr Scheduler::getPreferredDisplayMode() { void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) { if (timeline.refreshRequired) { - mSchedulerCallback.scheduleRefresh(FrameHint::kNone); + mSchedulerCallback.scheduleComposite(FrameHint::kNone); } std::lock_guard lock(mVsyncTimelineLock); @@ -882,12 +882,12 @@ void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimel } } -void Scheduler::onDisplayRefreshed(nsecs_t timestamp) { - const bool refresh = [=] { +void Scheduler::onPostComposition(nsecs_t presentTime) { + const bool recomposite = [=] { std::lock_guard lock(mVsyncTimelineLock); if (mLastVsyncPeriodChangeTimeline && mLastVsyncPeriodChangeTimeline->refreshRequired) { - if (timestamp < mLastVsyncPeriodChangeTimeline->refreshTimeNanos) { - // We need to schedule another refresh as refreshTimeNanos is still in the future. + if (presentTime < mLastVsyncPeriodChangeTimeline->refreshTimeNanos) { + // We need to composite again as refreshTimeNanos is still in the future. return true; } @@ -896,8 +896,8 @@ void Scheduler::onDisplayRefreshed(nsecs_t timestamp) { return false; }(); - if (refresh) { - mSchedulerCallback.scheduleRefresh(FrameHint::kNone); + if (recomposite) { + mSchedulerCallback.scheduleComposite(FrameHint::kNone); } } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 3f3debe33b..0a33dbbe92 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -59,7 +59,7 @@ struct ISchedulerCallback { // Indicates frame activity, i.e. whether commit and/or composite is taking place. enum class FrameHint { kNone, kActive }; - virtual void scheduleRefresh(FrameHint) = 0; + virtual void scheduleComposite(FrameHint) = 0; virtual void setVsyncEnabled(bool) = 0; virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&, scheduler::RefreshRateConfigEvent) = 0; @@ -162,8 +162,8 @@ public: // Notifies the scheduler about a refresh rate timeline change. void onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline); - // Notifies the scheduler when the display was refreshed - void onDisplayRefreshed(nsecs_t timestamp); + // Notifies the scheduler post composition. + void onPostComposition(nsecs_t presentTime); // Notifies the scheduler when the display size has changed. Called from SF's main thread void onActiveDisplayAreaChanged(uint32_t displayArea); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e90af3a64a..bb65bae06b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -371,7 +371,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) mTimeStats(std::make_shared()), mFrameTracer(mFactory.createFrameTracer()), mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, getpid())), - mEventQueue(mFactory.createMessageQueue()), + mEventQueue(mFactory.createMessageQueue(*this)), mCompositionEngine(mFactory.createCompositionEngine()), mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)), mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()), @@ -506,10 +506,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI SurfaceFlinger::~SurfaceFlinger() = default; -void SurfaceFlinger::onFirstRef() { - mEventQueue->init(this); -} - void SurfaceFlinger::binderDied(const wp&) { // the window manager died on us. prepare its eulogy. mBootFinished = false; @@ -1104,7 +1100,7 @@ void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) { } if (display->setDesiredActiveMode(info)) { - scheduleRefresh(FrameHint::kNone); + scheduleComposite(FrameHint::kNone); // Start receiving vsync samples now, so that we can detect a period // switch. @@ -1704,31 +1700,26 @@ sp SurfaceFlinger::createDisplayEventConnection( return mScheduler->createDisplayEventConnection(handle, eventRegistration); } -void SurfaceFlinger::scheduleInvalidate(FrameHint hint) { +void SurfaceFlinger::scheduleCommit(FrameHint hint) { if (hint == FrameHint::kActive) { mScheduler->resetIdleTimer(); } mPowerAdvisor.notifyDisplayUpdateImminent(); - mEventQueue->invalidate(); + mEventQueue->scheduleCommit(); } -void SurfaceFlinger::scheduleRefresh(FrameHint hint) { - mForceRefresh = true; - scheduleInvalidate(hint); +void SurfaceFlinger::scheduleComposite(FrameHint hint) { + mMustComposite = true; + scheduleCommit(hint); } void SurfaceFlinger::scheduleRepaint() { mGeometryDirty = true; - scheduleRefresh(FrameHint::kActive); -} - -void SurfaceFlinger::signalLayerUpdate() { - scheduleInvalidate(FrameHint::kActive); + scheduleComposite(FrameHint::kActive); } -void SurfaceFlinger::signalRefresh() { - mRefreshPending = true; - mEventQueue->refresh(); +void SurfaceFlinger::scheduleSample() { + static_cast(schedule([this] { sample(); })); } nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const { @@ -1834,7 +1825,7 @@ void SurfaceFlinger::onComposerHalSeamlessPossible(hal::HWDisplayId) { void SurfaceFlinger::onComposerHalRefresh(hal::HWDisplayId) { Mutex::Autolock lock(mStateLock); - scheduleRefresh(FrameHint::kNone); + scheduleComposite(FrameHint::kNone); } void SurfaceFlinger::setVsyncEnabled(bool enabled) { @@ -1889,40 +1880,26 @@ nsecs_t SurfaceFlinger::calculateExpectedPresentTime(DisplayStatInfo stats) cons : stats.vsyncTime + stats.vsyncPeriod; } -void SurfaceFlinger::onMessageReceived(int32_t what, int64_t vsyncId, nsecs_t expectedVSyncTime) { - switch (what) { - case MessageQueue::INVALIDATE: { - onMessageInvalidate(vsyncId, expectedVSyncTime); - break; - } - case MessageQueue::REFRESH: { - onMessageRefresh(); - break; - } - } -} - -void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTime) { - const nsecs_t frameStart = systemTime(); +bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) { // calculate the expected present time once and use the cached // value throughout this frame to make sure all layers are // seeing this same value. - if (expectedVSyncTime >= frameStart) { - mExpectedPresentTime = expectedVSyncTime; + if (expectedVsyncTime >= frameTime) { + mExpectedPresentTime = expectedVsyncTime; } else { - const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(frameStart); + const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(frameTime); mExpectedPresentTime = calculateExpectedPresentTime(stats); } const nsecs_t lastScheduledPresentTime = mScheduledPresentTime; - mScheduledPresentTime = expectedVSyncTime; + mScheduledPresentTime = expectedVsyncTime; const auto vsyncIn = [&] { if (!ATRACE_ENABLED()) return 0.f; return (mExpectedPresentTime - systemTime()) / 1e6f; }(); - ATRACE_FORMAT("onMessageInvalidate %" PRId64 " vsyncIn %.2fms%s", vsyncId, vsyncIn, - mExpectedPresentTime == expectedVSyncTime ? "" : " (adjusted)"); + ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, vsyncId, vsyncIn, + mExpectedPresentTime == expectedVsyncTime ? "" : " (adjusted)"); // When Backpressure propagation is enabled we want to give a small grace period // for the present fence to fire instead of just giving up on this frame to handle cases @@ -1969,11 +1946,11 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT } // If we are in the middle of a mode change and the fence hasn't - // fired yet just wait for the next invalidate + // fired yet just wait for the next commit. if (mSetActiveModePending) { if (framePending) { - mEventQueue->invalidate(); - return; + mEventQueue->scheduleCommit(); + return false; } // We received the present fence from the HWC, so we assume it successfully updated @@ -1984,8 +1961,8 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT if (framePending) { if ((hwcFrameMissed && !gpuFrameMissed) || mPropagateBackpressureClientComposition) { - signalLayerUpdate(); - return; + scheduleCommit(FrameHint::kNone); + return false; } } @@ -1997,11 +1974,12 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT if (mRefreshRateOverlaySpinner) { Mutex::Autolock lock(mStateLock); if (const auto display = getDefaultDisplayDeviceLocked()) { - display->onInvalidate(); + display->animateRefreshRateOverlay(); } } - bool refreshNeeded = mForceRefresh.exchange(false); + // Composite if transactions were committed, or if requested by HWC. + bool mustComposite = mMustComposite.exchange(false); { mTracePostComposition = mTracing.flagIsSet(SurfaceTracing::TRACE_COMPOSITION) || mTracing.flagIsSet(SurfaceTracing::TRACE_SYNC) || @@ -2009,10 +1987,12 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT const bool tracePreComposition = mTracingEnabled && !mTracePostComposition; ConditionalLockGuard lock(mTracingLock, tracePreComposition); - mFrameTimeline->setSfWakeUp(vsyncId, frameStart, Fps::fromPeriodNsecs(stats.vsyncPeriod)); + mFrameTimeline->setSfWakeUp(vsyncId, frameTime, Fps::fromPeriodNsecs(stats.vsyncPeriod)); + + mustComposite |= flushAndCommitTransactions(); + mustComposite |= latchBuffers(); - refreshNeeded |= flushAndCommitTransactions(); - refreshNeeded |= handleMessageInvalidate(); + updateLayerGeometry(); if (tracePreComposition) { if (mVisibleRegionsDirty) { @@ -2035,25 +2015,7 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT updateCursorAsync(); updateInputFlinger(); - if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) { - // Signal a refresh if a transaction modified the window state, - // a new buffer was latched, or if HWC has requested a full - // repaint - if (mFrameStartTime <= 0) { - // We should only use the time of the first invalidate - // message that signals a refresh as the beginning of the - // frame. Otherwise the real frame time will be - // underestimated. - mFrameStartTime = frameStart; - } - - // Run the refresh immediately after invalidate as there is no point going thru the message - // queue again, and to ensure that we actually refresh the screen instead of handling - // other messages that were queued us already in the MessageQueue. - mRefreshPending = true; - onMessageRefresh(); - } - notifyRegionSamplingThread(); + return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER); } bool SurfaceFlinger::flushAndCommitTransactions() { @@ -2068,6 +2030,9 @@ bool SurfaceFlinger::flushAndCommitTransactions() { commitTransactions(); } + // Invoke OnCommit callbacks. + mTransactionCallbackInvoker.sendCallbacks(); + if (transactionFlushNeeded()) { setTransactionFlags(eTransactionFlushNeeded); } @@ -2075,11 +2040,9 @@ bool SurfaceFlinger::flushAndCommitTransactions() { return shouldCommit; } -void SurfaceFlinger::onMessageRefresh() { +void SurfaceFlinger::composite(nsecs_t frameTime) { ATRACE_CALL(); - mRefreshPending = false; - compositionengine::CompositionRefreshArgs refreshArgs; const auto& displays = ON_MAIN_THREAD(mDisplays); refreshArgs.outputs.reserve(displays.size()); @@ -2123,18 +2086,16 @@ void SurfaceFlinger::onMessageRefresh() { const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration; refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration; refreshArgs.previousPresentFence = mPreviousPresentFences[0].fenceTime; - refreshArgs.nextInvalidateTime = mEventQueue->nextExpectedInvalidate(); + refreshArgs.scheduledFrameTime = mEventQueue->getScheduledFrameTime(); // Store the present time just before calling to the composition engine so we could notify // the scheduler. const auto presentTime = systemTime(); mCompositionEngine->present(refreshArgs); - mTimeStats->recordFrameDuration(mFrameStartTime, systemTime()); - // Reset the frame start time now that we've recorded this frame. - mFrameStartTime = 0; + mTimeStats->recordFrameDuration(frameTime, systemTime()); - mScheduler->onDisplayRefreshed(presentTime); + mScheduler->onPostComposition(presentTime); postFrame(); postComposition(); @@ -2177,17 +2138,12 @@ void SurfaceFlinger::onMessageRefresh() { mVisibleRegionsDirty = false; if (mCompositionEngine->needsAnotherUpdate()) { - signalLayerUpdate(); + scheduleCommit(FrameHint::kNone); } } -bool SurfaceFlinger::handleMessageInvalidate() { +void SurfaceFlinger::updateLayerGeometry() { ATRACE_CALL(); - // Send on commit callbacks - mTransactionCallbackInvoker.sendCallbacks(); - - bool refreshNeeded = handlePageFlip(); - if (mVisibleRegionsDirty) { computeLayerBounds(); @@ -2199,7 +2155,6 @@ bool SurfaceFlinger::handleMessageInvalidate() { invalidateLayerStack(layer, visibleReg); } mLayersPendingRefresh.clear(); - return refreshNeeded; } void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime, @@ -3301,11 +3256,10 @@ void SurfaceFlinger::invalidateLayerStack(const sp& layer, const Re } } -bool SurfaceFlinger::handlePageFlip() { +bool SurfaceFlinger::latchBuffers() { ATRACE_CALL(); - ALOGV("handlePageFlip"); - nsecs_t latchTime = systemTime(); + const nsecs_t latchTime = systemTime(); bool visibleRegions = false; bool frameQueued = false; @@ -3374,7 +3328,7 @@ bool SurfaceFlinger::handlePageFlip() { // queued frame that shouldn't be displayed during this vsync period, wake // up during the next vsync period to check again. if (frameQueued && (mLayersWithQueuedFrames.empty() || !newDataLatched)) { - signalLayerUpdate(); + scheduleCommit(FrameHint::kNone); } // enter boot animation on first buffer latch @@ -3453,7 +3407,7 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule const sp& applyToken) { const uint32_t old = mTransactionFlags.fetch_or(mask); modulateVsync(&VsyncModulator::setTransactionSchedule, schedule, applyToken); - if ((old & mask) == 0) scheduleInvalidate(FrameHint::kActive); + if ((old & mask) == 0) scheduleCommit(FrameHint::kActive); return old; } @@ -4572,7 +4526,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: mVisibleRegionsDirty = true; mHasPoweredOff = true; - scheduleRefresh(FrameHint::kActive); + scheduleComposite(FrameHint::kActive); } else if (mode == hal::PowerMode::OFF) { // Turn off the display if (SurfaceFlinger::setSchedFifo(false) != NO_ERROR) { @@ -5430,8 +5384,8 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } scheduleRepaint(); return NO_ERROR; - case 1004: // Force refresh ahead of next VSYNC. - scheduleRefresh(FrameHint::kActive); + case 1004: // Force composite ahead of next VSYNC. + scheduleComposite(FrameHint::kActive); return NO_ERROR; case 1005: { // Force commit ahead of next VSYNC. Mutex::Autolock lock(mStateLock); @@ -5439,8 +5393,8 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r eTraversalNeeded); return NO_ERROR; } - case 1006: // Force refresh immediately. - signalRefresh(); + case 1006: // Force composite immediately. + mEventQueue->scheduleComposite(); return NO_ERROR; case 1007: // Unused. return NAME_NOT_FOUND; @@ -5834,7 +5788,7 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { const bool timerExpired = mKernelIdleTimerEnabled && expired; if (display->onKernelTimerChanged(desiredModeId, timerExpired)) { - mEventQueue->invalidate(); + mEventQueue->scheduleCommit(); } })); } @@ -6265,12 +6219,6 @@ status_t SurfaceFlinger::captureScreenCommon( bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission(); static_cast(schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable { - if (mRefreshPending) { - ALOGW("Skipping screenshot for now"); - captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, regionSampling, - grayscale, captureListener); - return; - } ScreenCaptureResults captureResults; std::unique_ptr renderArea = renderAreaFuture.get(); if (!renderArea) { @@ -6617,6 +6565,10 @@ void SurfaceFlinger::onLayerDestroyed(Layer* layer) { } } +void SurfaceFlinger::onLayerUpdate() { + scheduleCommit(FrameHint::kActive); +} + // WARNING: ONLY CALL THIS FROM LAYER DTOR // Here we add children in the current state to offscreen layers and remove the // layer itself from the offscreen layer list. Since @@ -6941,16 +6893,12 @@ sp SurfaceFlinger::handleLayerCreatedLocked(const sp& handle) { return layer; } -void SurfaceFlinger::scheduleRegionSamplingThread() { - static_cast(schedule([&] { notifyRegionSamplingThread(); })); -} - -void SurfaceFlinger::notifyRegionSamplingThread() { +void SurfaceFlinger::sample() { if (!mLumaSampling || !mRegionSamplingThread) { return; } - mRegionSamplingThread->onCompositionComplete(mEventQueue->nextExpectedInvalidate()); + mRegionSamplingThread->onCompositionComplete(mEventQueue->getScheduledFrameTime()); } void SurfaceFlinger::onActiveDisplaySizeChanged(const sp& activeDisplay) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 1217d6369b..43f7b36090 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -57,6 +57,7 @@ #include "Fps.h" #include "FrameTracker.h" #include "LayerVector.h" +#include "Scheduler/MessageQueue.h" #include "Scheduler/RefreshRateConfigs.h" #include "Scheduler/RefreshRateStats.h" #include "Scheduler/Scheduler.h" @@ -177,6 +178,7 @@ class SurfaceFlinger : public BnSurfaceComposer, public PriorityDumper, private IBinder::DeathRecipient, private HWC2::ComposerCallback, + private ICompositor, private ISchedulerCallback { public: struct SkipInitializationTag {}; @@ -287,11 +289,13 @@ public: [[nodiscard]] std::future schedule(F&&); // Schedule commit of transactions on the main thread ahead of the next VSYNC. - void scheduleInvalidate(FrameHint); - // As above, but also force refresh regardless if transactions were committed. - void scheduleRefresh(FrameHint) override; + void scheduleCommit(FrameHint); + // As above, but also force composite regardless if transactions were committed. + void scheduleComposite(FrameHint) override; // As above, but also force dirty geometry to repaint. void scheduleRepaint(); + // Schedule sampling independently from commit or composite. + void scheduleSample(); surfaceflinger::Factory& getFactory() { return mFactory; } @@ -305,11 +309,6 @@ public: // utility function to delete a texture on the main thread void deleteTextureAsync(uint32_t texture); - // called on the main thread by MessageQueue when an internal message - // is received - // TODO: this should be made accessible only to MessageQueue - void onMessageReceived(int32_t what, int64_t vsyncId, nsecs_t expectedVSyncTime); - renderengine::RenderEngine& getRenderEngine() const; bool authenticateSurfaceTextureLocked( @@ -317,6 +316,7 @@ public: void onLayerFirstRef(Layer*); void onLayerDestroyed(Layer*); + void onLayerUpdate(); void removeHierarchyFromOffscreenLayers(Layer* layer); void removeFromOffscreenLayers(Layer* layer); @@ -734,9 +734,6 @@ private: // Implements IBinder::DeathRecipient. void binderDied(const wp& who) override; - // Implements RefBase. - void onFirstRef() override; - // HWC2::ComposerCallback overrides: void onComposerHalVsync(hal::HWDisplayId, int64_t timestamp, std::optional) override; @@ -746,6 +743,19 @@ private: const hal::VsyncPeriodChangeTimeline&) override; void onComposerHalSeamlessPossible(hal::HWDisplayId) override; + // ICompositor overrides: + + // Commits transactions for layers and displays. Returns whether any state has been invalidated, + // i.e. whether a frame should be composited for each display. + bool commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) override; + + // Composites a frame for each display. CompositionEngine performs GPU and/or HAL composition + // via RenderEngine and the Composer HAL, respectively. + void composite(nsecs_t frameTime) override; + + // Samples the composited frame via RegionSamplingThread. + void sample() override; + /* * ISchedulerCallback */ @@ -766,13 +776,6 @@ private: // Show spinner with refresh rate overlay bool mRefreshRateOverlaySpinner = false; - /* - * Message handling - */ - // Can only be called from the main thread or with mStateLock held - void signalLayerUpdate(); - void signalRefresh(); - // Called on the main thread in response to initializeDisplays() void onInitializeDisplays() REQUIRES(mStateLock); // Sets the desired active mode bit. It obtains the lock, and sets mDesiredActiveMode. @@ -797,10 +800,6 @@ private: const std::optional& policy, bool overridePolicy) EXCLUDES(mStateLock); - // Handle the INVALIDATE message queue event, latching new buffers and applying - // incoming transactions - void onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTime); - // Returns whether transactions were committed. bool flushAndCommitTransactions() EXCLUDES(mStateLock); @@ -808,12 +807,10 @@ private: void commitTransactionsLocked(uint32_t transactionFlags) REQUIRES(mStateLock); void doCommitTransactions() REQUIRES(mStateLock); - // Handle the REFRESH message queue event, sending the current frame down to RenderEngine and - // the Composer HAL for presentation - void onMessageRefresh(); + // Returns whether a new buffer has been latched. + bool latchBuffers(); - // Returns whether a new buffer has been latched (see handlePageFlip()) - bool handleMessageInvalidate(); + void updateLayerGeometry(); void updateInputFlinger(); void notifyWindowInfos(); @@ -824,11 +821,6 @@ private: void updatePhaseConfiguration(const Fps&) REQUIRES(mStateLock); void setVsyncConfig(const VsyncModulator::VsyncConfig&, nsecs_t vsyncPeriod); - /* handlePageFlip - latch a new buffer if available and compute the dirty - * region. Returns whether a new buffer has been latched, i.e., whether it - * is necessary to perform a refresh during this vsync. - */ - bool handlePageFlip(); /* * Transactions @@ -1250,7 +1242,7 @@ private: bool mLayersRemoved = false; bool mLayersAdded = false; - std::atomic_bool mForceRefresh = false; + std::atomic_bool mMustComposite = false; std::atomic_bool mGeometryDirty = false; // constant members (no synchronization needed for access) @@ -1350,10 +1342,6 @@ private: mutable Mutex mDestroyedLayerLock; Vector mDestroyedLayers; - nsecs_t mRefreshStartTime = 0; - - std::atomic mRefreshPending = false; - // We maintain a pool of pre-generated texture names to hand out to avoid // layer creation needing to run on the main thread (which it would // otherwise need to do to access RenderEngine). @@ -1446,9 +1434,6 @@ private: Hwc2::impl::PowerAdvisor mPowerAdvisor; - // This should only be accessed on the main thread. - nsecs_t mFrameStartTime = 0; - void enableRefreshRateOverlay(bool enable) REQUIRES(mStateLock); // Flag used to set override desired display mode from backdoor @@ -1502,9 +1487,6 @@ private: std::atomic mActiveDisplayTransformHint; - void scheduleRegionSamplingThread(); - void notifyRegionSamplingThread(); - bool isRefreshRateOverlayEnabled() const REQUIRES(mStateLock) { return std::any_of(mDisplays.begin(), mDisplays.end(), [](std::pair, sp> display) { diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp index 89d1c4d327..9a2f9107c3 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp @@ -51,8 +51,8 @@ std::unique_ptr DefaultFactory::createHWComposer(const std::string& return std::make_unique(serviceName); } -std::unique_ptr DefaultFactory::createMessageQueue() { - return std::make_unique(); +std::unique_ptr DefaultFactory::createMessageQueue(ICompositor& compositor) { + return std::make_unique(compositor); } std::unique_ptr DefaultFactory::createVsyncConfiguration( diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h index b8bf2baa33..2be09ee788 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h @@ -27,7 +27,7 @@ public: virtual ~DefaultFactory(); std::unique_ptr createHWComposer(const std::string& serviceName) override; - std::unique_ptr createMessageQueue() override; + std::unique_ptr createMessageQueue(ICompositor&) override; std::unique_ptr createVsyncConfiguration( Fps currentRefreshRate) override; std::unique_ptr createScheduler( diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index 13c95ddd15..bca533b794 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -31,11 +31,11 @@ namespace android { typedef int32_t PixelFormat; class BufferQueueLayer; -class BufferStateLayer; class BufferLayerConsumer; -class EffectLayer; +class BufferStateLayer; class ContainerLayer; class DisplayDevice; +class EffectLayer; class FrameTracer; class GraphicBuffer; class HWComposer; @@ -50,6 +50,7 @@ class SurfaceInterceptor; class TimeStats; struct DisplayDeviceCreationArgs; +struct ICompositor; struct ISchedulerCallback; struct LayerCreationArgs; @@ -76,7 +77,7 @@ class NativeWindowSurface; class Factory { public: virtual std::unique_ptr createHWComposer(const std::string& serviceName) = 0; - virtual std::unique_ptr createMessageQueue() = 0; + virtual std::unique_ptr createMessageQueue(ICompositor&) = 0; virtual std::unique_ptr createVsyncConfiguration( Fps currentRefreshRate) = 0; virtual std::unique_ptr createScheduler( diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 5135ff952f..a0812912d4 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -202,8 +202,7 @@ void CompositionTest::displayRefreshCompositionDirtyGeometry() { // -------------------------------------------------------------------- // Invocation - mFlinger.onMessageReceived(MessageQueue::INVALIDATE); - mFlinger.onMessageReceived(MessageQueue::REFRESH); + mFlinger.commitAndComposite(); LayerCase::cleanup(this); } @@ -215,8 +214,7 @@ void CompositionTest::displayRefreshCompositionDirtyFrame() { // -------------------------------------------------------------------- // Invocation - mFlinger.onMessageReceived(MessageQueue::INVALIDATE); - mFlinger.onMessageReceived(MessageQueue::REFRESH); + mFlinger.commitAndComposite(); LayerCase::cleanup(this); } @@ -537,7 +535,7 @@ struct BaseLayerProperties { ASSERT_EQ(NO_ERROR, err); Mock::VerifyAndClear(test->mRenderEngine); - EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1); + EXPECT_CALL(*test->mMessageQueue, scheduleCommit()).Times(1); enqueueBuffer(test, layer); Mock::VerifyAndClearExpectations(test->mMessageQueue); @@ -883,7 +881,7 @@ struct BaseLayerVariant { test->mFlinger.mutableDrawingState().layersSortedByZ.clear(); // Layer should be unregistered with scheduler. - test->mFlinger.onMessageReceived(MessageQueue::INVALIDATE); + test->mFlinger.commit(); EXPECT_EQ(0, test->mFlinger.scheduler()->layerHistorySize()); } }; diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp index dbd51fed78..17d1dd6b09 100644 --- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp @@ -31,62 +31,51 @@ using namespace testing; using CallbackToken = scheduler::VSyncDispatch::CallbackToken; +struct NoOpCompositor final : ICompositor { + bool commit(nsecs_t, int64_t, nsecs_t) override { return false; } + void composite(nsecs_t) override {} + void sample() override {} +} gNoOpCompositor; + class TestableMessageQueue : public impl::MessageQueue { -public: - class MockHandler : public MessageQueue::Handler { - public: - explicit MockHandler(MessageQueue& queue) : MessageQueue::Handler(queue) {} - ~MockHandler() override = default; - MOCK_METHOD2(dispatchInvalidate, void(int64_t vsyncId, nsecs_t expectedVSyncTimestamp)); + struct MockHandler : MessageQueue::Handler { + using MessageQueue::Handler::Handler; + + MOCK_METHOD(void, dispatchCommit, (int64_t, nsecs_t), (override)); }; - TestableMessageQueue() = default; - ~TestableMessageQueue() override = default; + explicit TestableMessageQueue(sp handler) + : impl::MessageQueue(gNoOpCompositor, handler), mHandler(std::move(handler)) {} - void initHandler(const sp& handler) { mHandler = handler; } +public: + TestableMessageQueue() : TestableMessageQueue(sp::make(*this)) {} - void triggerVsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime) { - vsyncCallback(vsyncTime, targetWakeupTime, readyTime); - } -}; + using impl::MessageQueue::vsyncCallback; -class MockVSyncDispatch : public scheduler::VSyncDispatch { -public: - MockVSyncDispatch() = default; - ~MockVSyncDispatch() override = default; + const sp mHandler; +}; +struct MockVSyncDispatch : scheduler::VSyncDispatch { MOCK_METHOD2(registerCallback, - CallbackToken(std::function const&, std::string)); + CallbackToken(const std::function&, std::string)); MOCK_METHOD1(unregisterCallback, void(CallbackToken)); MOCK_METHOD2(schedule, scheduler::ScheduleResult(CallbackToken, ScheduleTiming)); MOCK_METHOD1(cancel, scheduler::CancelResult(CallbackToken token)); MOCK_CONST_METHOD1(dump, void(std::string&)); }; -class MockTokenManager : public frametimeline::TokenManager { -public: - MockTokenManager() = default; - ~MockTokenManager() override = default; - +struct MockTokenManager : frametimeline::TokenManager { MOCK_METHOD1(generateTokenForPredictions, int64_t(frametimeline::TimelineItem&& prediction)); MOCK_CONST_METHOD1(getPredictionsForToken, std::optional(int64_t)); }; -class MessageQueueTest : public testing::Test { -public: - MessageQueueTest() = default; - ~MessageQueueTest() override = default; - +struct MessageQueueTest : testing::Test { void SetUp() override { - EXPECT_NO_FATAL_FAILURE(mEventQueue.initHandler(mHandler)); - EXPECT_CALL(mVSyncDispatch, registerCallback(_, "sf")).WillOnce(Return(mCallbackToken)); EXPECT_NO_FATAL_FAILURE(mEventQueue.initVsync(mVSyncDispatch, mTokenManager, mDuration)); EXPECT_CALL(mVSyncDispatch, unregisterCallback(mCallbackToken)).Times(1); } - sp mHandler = - new TestableMessageQueue::MockHandler(mEventQueue); MockVSyncDispatch mVSyncDispatch; MockTokenManager mTokenManager; TestableMessageQueue mEventQueue; @@ -100,45 +89,49 @@ namespace { /* ------------------------------------------------------------------------ * Test cases */ -TEST_F(MessageQueueTest, invalidate) { +TEST_F(MessageQueueTest, commit) { const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(), .readyDuration = 0, .earliestVsync = 0}; - EXPECT_FALSE(mEventQueue.nextExpectedInvalidate().has_value()); + EXPECT_FALSE(mEventQueue.getScheduledFrameTime()); EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234)); - EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate()); - EXPECT_TRUE(mEventQueue.nextExpectedInvalidate().has_value()); - EXPECT_EQ(1234, mEventQueue.nextExpectedInvalidate().value().time_since_epoch().count()); + EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit()); + + ASSERT_TRUE(mEventQueue.getScheduledFrameTime()); + EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count()); } -TEST_F(MessageQueueTest, invalidateTwice) { +TEST_F(MessageQueueTest, commitTwice) { InSequence s; const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(), .readyDuration = 0, .earliestVsync = 0}; EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234)); - EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate()); - EXPECT_TRUE(mEventQueue.nextExpectedInvalidate().has_value()); - EXPECT_EQ(1234, mEventQueue.nextExpectedInvalidate().value().time_since_epoch().count()); + EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit()); + + ASSERT_TRUE(mEventQueue.getScheduledFrameTime()); + EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count()); EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(4567)); - EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate()); - EXPECT_TRUE(mEventQueue.nextExpectedInvalidate().has_value()); - EXPECT_EQ(4567, mEventQueue.nextExpectedInvalidate().value().time_since_epoch().count()); + EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit()); + + ASSERT_TRUE(mEventQueue.getScheduledFrameTime()); + EXPECT_EQ(4567, mEventQueue.getScheduledFrameTime()->time_since_epoch().count()); } -TEST_F(MessageQueueTest, invalidateTwiceWithCallback) { +TEST_F(MessageQueueTest, commitTwiceWithCallback) { InSequence s; const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(), .readyDuration = 0, .earliestVsync = 0}; EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(1234)); - EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate()); - EXPECT_TRUE(mEventQueue.nextExpectedInvalidate().has_value()); - EXPECT_EQ(1234, mEventQueue.nextExpectedInvalidate().value().time_since_epoch().count()); + EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit()); + + ASSERT_TRUE(mEventQueue.getScheduledFrameTime()); + EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count()); const auto startTime = 100; const auto endTime = startTime + mDuration.count(); @@ -148,10 +141,10 @@ TEST_F(MessageQueueTest, invalidateTwiceWithCallback) { generateTokenForPredictions( frametimeline::TimelineItem(startTime, endTime, presentTime))) .WillOnce(Return(vsyncId)); - EXPECT_CALL(*mHandler, dispatchInvalidate(vsyncId, presentTime)).Times(1); - EXPECT_NO_FATAL_FAILURE(mEventQueue.triggerVsyncCallback(presentTime, startTime, endTime)); + EXPECT_CALL(*mEventQueue.mHandler, dispatchCommit(vsyncId, presentTime)).Times(1); + EXPECT_NO_FATAL_FAILURE(mEventQueue.vsyncCallback(presentTime, startTime, endTime)); - EXPECT_FALSE(mEventQueue.nextExpectedInvalidate().has_value()); + EXPECT_FALSE(mEventQueue.getScheduledFrameTime()); const auto timingAfterCallback = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(), @@ -159,10 +152,10 @@ TEST_F(MessageQueueTest, invalidateTwiceWithCallback) { .earliestVsync = presentTime}; EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timingAfterCallback)).WillOnce(Return(0)); - EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate()); + EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit()); } -TEST_F(MessageQueueTest, invalidateWithDurationChange) { +TEST_F(MessageQueueTest, commitWithDurationChange) { EXPECT_NO_FATAL_FAILURE(mEventQueue.setDuration(mDifferentDuration)); const auto timing = @@ -171,7 +164,7 @@ TEST_F(MessageQueueTest, invalidateWithDurationChange) { .earliestVsync = 0}; EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timing)).WillOnce(Return(0)); - EXPECT_NO_FATAL_FAILURE(mEventQueue.invalidate()); + EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleCommit()); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 84fa1e290a..6c3b2fdc6c 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -176,7 +176,7 @@ namespace { * Test cases */ TEST_P(SetFrameRateTest, SetAndGet) { - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); @@ -187,7 +187,7 @@ TEST_P(SetFrameRateTest, SetAndGet) { } TEST_P(SetFrameRateTest, SetAndGetParent) { - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); @@ -212,7 +212,7 @@ TEST_P(SetFrameRateTest, SetAndGetParent) { } TEST_P(SetFrameRateTest, SetAndGetParentAllVote) { - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); @@ -251,7 +251,7 @@ TEST_P(SetFrameRateTest, SetAndGetParentAllVote) { } TEST_P(SetFrameRateTest, SetAndGetChild) { - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); @@ -276,7 +276,7 @@ TEST_P(SetFrameRateTest, SetAndGetChild) { } TEST_P(SetFrameRateTest, SetAndGetChildAllVote) { - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); @@ -315,7 +315,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildAllVote) { } TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) { - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); @@ -345,7 +345,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) { } TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) { - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); @@ -376,7 +376,7 @@ TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) { } TEST_P(SetFrameRateTest, SetAndGetParentNotInTree) { - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); @@ -475,7 +475,7 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { } TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) { - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); const auto& layerFactory = GetParam(); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp index 2362a31827..8c3034178f 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp @@ -51,8 +51,8 @@ TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForNonsecureDisplay) { // -------------------------------------------------------------------- // Cleanup conditions - // Destroying the display invalidates the display state. - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + // Creating the display commits a display transaction. + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); } TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForSecureDisplay) { @@ -86,9 +86,9 @@ TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForSecureDisplay) { // -------------------------------------------------------------------- // Cleanup conditions - // Destroying the display invalidates the display state. - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + // Creating the display commits a display transaction. + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); } } // namespace -} // namespace android \ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp index e2be074fc4..7087fb6568 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp @@ -40,8 +40,8 @@ TEST_F(DestroyDisplayTest, destroyDisplayClearsCurrentStateForDisplay) { // The call should notify the interceptor that a display was created. EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1); - // Destroying the display invalidates the display state. - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + // Destroying the display commits a display transaction. + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); // -------------------------------------------------------------------- // Invocation diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp index bd89397ef6..29ff0cd90b 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp @@ -38,9 +38,8 @@ TEST_F(HotplugTest, enqueuesEventsForDisplayTransaction) { // -------------------------------------------------------------------- // Call Expectations - // We expect invalidate() to be invoked once to trigger display transaction - // processing. - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + // We expect a scheduled commit for the display transaction. + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); // -------------------------------------------------------------------- // Invocation @@ -86,9 +85,8 @@ TEST_F(HotplugTest, processesEnqueuedEventsIfCalledOnMainThread) { // -------------------------------------------------------------------- // Call Expectations - // We expect invalidate() to be invoked once to trigger display transaction - // processing. - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + // We expect a scheduled commit for the display transaction. + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); // -------------------------------------------------------------------- // Invocation diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp index bafa910270..e1b44cf549 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp @@ -46,9 +46,8 @@ TEST_F(OnInitializeDisplaysTest, onInitializeDisplaysSetsUpPrimaryDisplay) { // We expect a call to get the active display config. Case::Display::setupHwcGetActiveConfigCallExpectations(this); - // We expect invalidate() to be invoked once to trigger display transaction - // processing. - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + // We expect a scheduled commit for the display transaction. + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp index 65024202b8..e55721dd6e 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp @@ -268,7 +268,7 @@ struct DisplayPowerCase { } static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) { - EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1); + EXPECT_CALL(*test->mMessageQueue, scheduleCommit()).Times(1); } static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test, diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 7072439cea..de1caded50 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -73,8 +73,8 @@ public: return nullptr; } - std::unique_ptr createMessageQueue() override { - return std::make_unique(); + std::unique_ptr createMessageQueue(ICompositor& compositor) override { + return std::make_unique(compositor); } std::unique_ptr createVsyncConfiguration( @@ -296,6 +296,16 @@ public: * Forwarding for functions being tested */ + nsecs_t commit() { + constexpr int64_t kVsyncId = 123; + const nsecs_t now = systemTime(); + const nsecs_t expectedVsyncTime = now + 10'000'000; + mFlinger->commit(now, kVsyncId, expectedVsyncTime); + return now; + } + + void commitAndComposite() { mFlinger->composite(commit()); } + auto createDisplay(const String8& displayName, bool secure) { return mFlinger->createDisplay(displayName, secure); } @@ -343,10 +353,6 @@ public: return mFlinger->setPowerModeInternal(display, mode); } - auto onMessageReceived(int32_t what) { - return mFlinger->onMessageReceived(what, /*vsyncId=*/0, systemTime()); - } - auto renderScreenImplLocked(const RenderArea& renderArea, SurfaceFlinger::TraverseLayersFunction traverseLayers, const std::shared_ptr& buffer, @@ -761,7 +767,7 @@ public: }; private: - void scheduleRefresh(FrameHint) override {} + void scheduleComposite(FrameHint) override {} void setVsyncEnabled(bool) override {} void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override {} void kernelTimerChanged(bool) override {} diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index 1a50427b93..d8e68b8966 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -126,8 +126,7 @@ public: void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); - // called in SurfaceFlinger::signalTransaction - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); TransactionInfo transaction; setupSingle(transaction, flags, syncInputWindows, /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, @@ -157,8 +156,7 @@ public: void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); - // called in SurfaceFlinger::signalTransaction - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); // first check will see desired present time has not passed, // but afterwards it will look like the desired present time has passed @@ -187,12 +185,11 @@ public: void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); - // called in SurfaceFlinger::signalTransaction nsecs_t time = systemTime(); if (!syncInputWindows) { - EXPECT_CALL(*mMessageQueue, invalidate()).Times(2); + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(2); } else { - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); } // transaction that should go on the pending thread TransactionInfo transactionA; @@ -255,8 +252,7 @@ public: TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); - // called in SurfaceFlinger::signalTransaction - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); + EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); TransactionInfo transactionA; // transaction to go on pending queue setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h index 0e7b320787..d68433760d 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h +++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h @@ -29,17 +29,18 @@ public: MessageQueue(); ~MessageQueue() override; - MOCK_METHOD1(init, void(const sp&)); MOCK_METHOD1(setInjector, void(sp)); MOCK_METHOD0(waitMessage, void()); MOCK_METHOD1(postMessage, void(sp&&)); - MOCK_METHOD0(invalidate, void()); - MOCK_METHOD0(refresh, void()); MOCK_METHOD3(initVsync, void(scheduler::VSyncDispatch&, frametimeline::TokenManager&, std::chrono::nanoseconds)); MOCK_METHOD1(setDuration, void(std::chrono::nanoseconds workDuration)); - MOCK_METHOD0(nextExpectedInvalidate, std::optional()); + + MOCK_METHOD(void, scheduleCommit, (), (override)); + MOCK_METHOD(void, scheduleComposite, (), (override)); + + MOCK_METHOD(std::optional, getScheduledFrameTime, (), (const, override)); }; } // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h index 291559f2f9..e241dc903f 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h +++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h @@ -23,7 +23,7 @@ namespace android::mock { struct SchedulerCallback final : ISchedulerCallback { - MOCK_METHOD(void, scheduleRefresh, (FrameHint), (override)); + MOCK_METHOD(void, scheduleComposite, (FrameHint), (override)); MOCK_METHOD1(setVsyncEnabled, void(bool)); MOCK_METHOD2(changeRefreshRate, void(const scheduler::RefreshRateConfigs::RefreshRate&, @@ -33,7 +33,7 @@ struct SchedulerCallback final : ISchedulerCallback { }; struct NoOpSchedulerCallback final : ISchedulerCallback { - void scheduleRefresh(FrameHint) override {} + void scheduleComposite(FrameHint) override {} void setVsyncEnabled(bool) override {} void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&, scheduler::RefreshRateConfigEvent) override {} -- cgit v1.2.3-59-g8ed1b From 068173d9076ca25fa5cc008a116e4ec22503b9be Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Wed, 11 Aug 2021 17:22:59 -0700 Subject: SF: Add VsyncSchedule skeleton Pull the Scheduler::VsyncSchedule struct and related code into its own file, as it will be extended with more per-display state, e.g. reactor registrations, resync state machine, etc. Add for feature flags. Move Scheduler into its namespace. Bug: 185535769 Test: libsurfaceflinger_unittest Change-Id: I6e10893632c5abf40380df924791d1fcc27c3cc2 --- services/surfaceflinger/Android.bp | 3 +- services/surfaceflinger/BufferQueueLayer.cpp | 5 +- services/surfaceflinger/BufferStateLayer.cpp | 5 +- services/surfaceflinger/DisplayDevice.cpp | 4 +- services/surfaceflinger/DisplayDevice.h | 2 +- services/surfaceflinger/Layer.cpp | 4 +- services/surfaceflinger/Scheduler/LayerHistory.h | 6 +- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 8 +- services/surfaceflinger/Scheduler/Scheduler.cpp | 216 +++++++-------------- services/surfaceflinger/Scheduler/Scheduler.h | 100 ++++------ services/surfaceflinger/Scheduler/VSyncReactor.cpp | 4 +- services/surfaceflinger/Scheduler/VSyncReactor.h | 2 +- .../surfaceflinger/Scheduler/VsyncController.h | 10 +- .../surfaceflinger/Scheduler/VsyncSchedule.cpp | 113 +++++++++++ services/surfaceflinger/Scheduler/VsyncSchedule.h | 75 +++++++ .../Scheduler/include/scheduler/Features.h | 34 ++++ services/surfaceflinger/SurfaceFlinger.cpp | 43 ++-- services/surfaceflinger/SurfaceFlinger.h | 7 +- services/surfaceflinger/SurfaceFlingerFactory.h | 4 - .../tests/unittests/CompositionTest.cpp | 2 +- .../unittests/DisplayDevice_InitiateModeChange.cpp | 2 +- .../unittests/DisplayTransactionTestHelpers.h | 2 +- .../tests/unittests/FpsReporterTest.cpp | 4 + .../tests/unittests/LayerHistoryTest.cpp | 13 +- .../tests/unittests/SchedulerTest.cpp | 43 ++-- .../tests/unittests/SetFrameRateTest.cpp | 2 + .../SurfaceFlinger_NotifyPowerBoostTest.cpp | 7 +- .../tests/unittests/TestableScheduler.h | 39 ++-- .../tests/unittests/TestableSurfaceFlinger.h | 20 +- .../tests/unittests/TransactionApplicationTest.cpp | 5 +- .../tests/unittests/mock/MockSchedulerCallback.h | 17 +- .../tests/unittests/mock/MockVsyncController.h | 2 +- 32 files changed, 461 insertions(+), 342 deletions(-) create mode 100644 services/surfaceflinger/Scheduler/VsyncSchedule.cpp create mode 100644 services/surfaceflinger/Scheduler/VsyncSchedule.h create mode 100644 services/surfaceflinger/Scheduler/include/scheduler/Features.h (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 29636f84f5..c9fb7bc876 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -194,9 +194,10 @@ filegroup { "Scheduler/Timer.cpp", "Scheduler/VSyncDispatchTimerQueue.cpp", "Scheduler/VSyncPredictor.cpp", - "Scheduler/VsyncModulator.cpp", "Scheduler/VSyncReactor.cpp", "Scheduler/VsyncConfiguration.cpp", + "Scheduler/VsyncModulator.cpp", + "Scheduler/VsyncSchedule.cpp", "StartPropertySetThread.cpp", "SurfaceFlinger.cpp", "SurfaceFlingerDefaultFactory.cpp", diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index dec7cc0806..926aa1dfb2 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -372,8 +372,9 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { // Add this buffer from our internal queue tracker { // Autolock scope const nsecs_t presentTime = item.mIsAutoTimestamp ? 0 : item.mTimestamp; - mFlinger->mScheduler->recordLayerHistory(this, presentTime, - LayerHistory::LayerUpdateType::Buffer); + + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; + mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer); Mutex::Autolock lock(mQueueItemLock); // Reset the frame number tracker when we receive the first buffer after diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index b4ccb803e9..7d40fc87f9 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -476,8 +476,9 @@ bool BufferStateLayer::setBuffer(const BufferData& bufferData, nsecs_t postTime, return static_cast(0); }(); - mFlinger->mScheduler->recordLayerHistory(this, presentTime, - LayerHistory::LayerUpdateType::Buffer); + + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; + mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer); addFrameEvent(mDrawingState.acquireFence, postTime, isAutoTimestamp ? 0 : desiredPresentTime); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index fd09ae4066..76bbe2c58f 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -483,7 +483,7 @@ bool DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info) { std::scoped_lock lock(mActiveModeLock); if (mDesiredActiveModeChanged) { // If a mode change is pending, just cache the latest request in mDesiredActiveMode - const Scheduler::ModeEvent prevConfig = mDesiredActiveMode.event; + const auto prevConfig = mDesiredActiveMode.event; mDesiredActiveMode = info; mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig; return false; @@ -508,7 +508,7 @@ std::optional DisplayDevice::getDesiredActiveMode void DisplayDevice::clearDesiredActiveModeState() { std::scoped_lock lock(mActiveModeLock); - mDesiredActiveMode.event = Scheduler::ModeEvent::None; + mDesiredActiveMode.event = scheduler::DisplayModeEvent::None; mDesiredActiveModeChanged = false; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 4b9718f608..324145ef47 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -190,7 +190,7 @@ public: struct ActiveModeInfo { DisplayModePtr mode; - scheduler::RefreshRateConfigEvent event = scheduler::RefreshRateConfigEvent::None; + scheduler::DisplayModeEvent event = scheduler::DisplayModeEvent::None; bool operator!=(const ActiveModeInfo& other) const { return mode != other.mode || event != other.event; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 968a49d526..b3ea94fd94 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1293,8 +1293,8 @@ bool Layer::setFrameRateForLayerTree(FrameRate frameRate) { mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); - mFlinger->mScheduler->recordLayerHistory(this, systemTime(), - LayerHistory::LayerUpdateType::SetFrameRate); + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; + mFlinger->mScheduler->recordLayerHistory(this, systemTime(), LayerUpdateType::SetFrameRate); return true; } diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index 92236f560a..8d56951363 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -31,11 +31,9 @@ namespace android { class Layer; -class TestableScheduler; namespace scheduler { -class LayerHistoryTest; class LayerInfo; class LayerHistory { @@ -75,8 +73,8 @@ public: std::string dump() const; private: - friend LayerHistoryTest; - friend TestableScheduler; + friend class LayerHistoryTest; + friend class TestableScheduler; using LayerPair = std::pair>; using LayerInfos = std::vector; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 8a1c2062a6..492feb14df 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -37,11 +37,11 @@ namespace android::scheduler { using namespace std::chrono_literals; -enum class RefreshRateConfigEvent : unsigned { None = 0b0, Changed = 0b1 }; +enum class DisplayModeEvent : unsigned { None = 0b0, Changed = 0b1 }; -inline RefreshRateConfigEvent operator|(RefreshRateConfigEvent lhs, RefreshRateConfigEvent rhs) { - using T = std::underlying_type_t; - return static_cast(static_cast(lhs) | static_cast(rhs)); +inline DisplayModeEvent operator|(DisplayModeEvent lhs, DisplayModeEvent rhs) { + using T = std::underlying_type_t; + return static_cast(static_cast(lhs) | static_cast(rhs)); } using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 4d72798086..cbe4552b0b 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -46,11 +46,8 @@ #include "OneShotTimer.h" #include "SchedulerUtils.h" #include "SurfaceFlingerProperties.h" -#include "Timer.h" -#include "VSyncDispatchTimerQueue.h" #include "VSyncPredictor.h" #include "VSyncReactor.h" -#include "VsyncController.h" #define RETURN_IF_INVALID_HANDLE(handle, ...) \ do { \ @@ -60,68 +57,14 @@ } \ } while (false) -using namespace std::string_literals; +namespace android::scheduler { -namespace android { - -using gui::WindowInfo; - -namespace { - -std::unique_ptr createVSyncTracker() { - // TODO(b/144707443): Tune constants. - constexpr int kDefaultRate = 60; - constexpr auto initialPeriod = std::chrono::duration>(1); - constexpr nsecs_t idealPeriod = - std::chrono::duration_cast(initialPeriod).count(); - constexpr size_t vsyncTimestampHistorySize = 20; - constexpr size_t minimumSamplesForPrediction = 6; - constexpr uint32_t discardOutlierPercent = 20; - return std::make_unique(idealPeriod, vsyncTimestampHistorySize, - minimumSamplesForPrediction, - discardOutlierPercent); -} - -std::unique_ptr createVSyncDispatch(scheduler::VSyncTracker& tracker) { - // TODO(b/144707443): Tune constants. - constexpr std::chrono::nanoseconds vsyncMoveThreshold = 3ms; - constexpr std::chrono::nanoseconds timerSlack = 500us; - return std::make_unique< - scheduler::VSyncDispatchTimerQueue>(std::make_unique(), tracker, - timerSlack.count(), vsyncMoveThreshold.count()); -} - -const char* toContentDetectionString(bool useContentDetection) { - return useContentDetection ? "on" : "off"; -} - -} // namespace - -class PredictedVsyncTracer { -public: - PredictedVsyncTracer(scheduler::VSyncDispatch& dispatch) - : mRegistration(dispatch, std::bind(&PredictedVsyncTracer::callback, this), - "PredictedVsyncTracer") { - scheduleRegistration(); - } - -private: - TracedOrdinal mParity = {"VSYNC-predicted", 0}; - scheduler::VSyncCallbackRegistration mRegistration; - - void scheduleRegistration() { mRegistration.schedule({0, 0, 0}); } - - void callback() { - mParity = !mParity; - scheduleRegistration(); - } -}; - -Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, Options options) - : impl::MessageQueue(compositor), mOptions(options), mSchedulerCallback(callback) {} +Scheduler::Scheduler(ICompositor& compositor, ISchedulerCallback& callback, FeatureFlags features) + : impl::MessageQueue(compositor), mFeatures(features), mSchedulerCallback(callback) {} void Scheduler::startTimers() { using namespace sysprop; + using namespace std::string_literals; if (const int64_t millis = set_touch_timer_ms(0); millis > 0) { // Touch events are coming to SF every 100ms, so the timer needs to be higher than that @@ -154,27 +97,14 @@ void Scheduler::run() { } } -void Scheduler::createVsyncSchedule(bool supportKernelTimer) { - auto clock = std::make_unique(); - auto tracker = createVSyncTracker(); - auto dispatch = createVSyncDispatch(*tracker); - - // TODO(b/144707443): Tune constants. - constexpr size_t pendingFenceLimit = 20; - auto controller = - std::make_unique(std::move(clock), *tracker, pendingFenceLimit, - supportKernelTimer); - mVsyncSchedule = {std::move(controller), std::move(tracker), std::move(dispatch)}; - - if (base::GetBoolProperty("debug.sf.show_predicted_vsync", false)) { - mPredictedVsyncTracer = std::make_unique(*mVsyncSchedule.dispatch); - } +void Scheduler::createVsyncSchedule(FeatureFlags features) { + mVsyncSchedule.emplace(features); } std::unique_ptr Scheduler::makePrimaryDispSyncSource( const char* name, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, bool traceVsync) { - return std::make_unique(*mVsyncSchedule.dispatch, workDuration, + return std::make_unique(getVsyncDispatch(), workDuration, readyDuration, traceVsync, name); } @@ -210,7 +140,7 @@ bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const { return true; } - return mVsyncSchedule.tracker->isVSyncInPhase(expectedVsyncTimestamp, *frameRate); + return mVsyncSchedule->getTracker().isVSyncInPhase(expectedVsyncTimestamp, *frameRate); } impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const { @@ -245,7 +175,7 @@ impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction( }; } -Scheduler::ConnectionHandle Scheduler::createConnection( +ConnectionHandle Scheduler::createConnection( const char* connectionName, frametimeline::TokenManager* tokenManager, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, impl::EventThread::InterceptVSyncsCallback interceptCallback) { @@ -259,7 +189,7 @@ Scheduler::ConnectionHandle Scheduler::createConnection( return createConnection(std::move(eventThread)); } -Scheduler::ConnectionHandle Scheduler::createConnection(std::unique_ptr eventThread) { +ConnectionHandle Scheduler::createConnection(std::unique_ptr eventThread) { const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++}; ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id); @@ -346,24 +276,24 @@ void Scheduler::onFrameRateOverridesChanged(ConnectionHandle handle, PhysicalDis void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { { - std::lock_guard lock(mFeatureStateLock); + std::lock_guard lock(mPolicyLock); // Cache the last reported modes for primary display. - mFeatures.cachedModeChangedParams = {handle, mode}; + mPolicy.cachedModeChangedParams = {handle, mode}; // Invalidate content based refresh rate selection so it could be calculated // again for the new refresh rate. - mFeatures.contentRequirements.clear(); + mPolicy.contentRequirements.clear(); } onNonPrimaryDisplayModeChanged(handle, mode); } void Scheduler::dispatchCachedReportedMode() { // Check optional fields first. - if (!mFeatures.mode) { + if (!mPolicy.mode) { ALOGW("No mode ID found, not dispatching cached mode."); return; } - if (!mFeatures.cachedModeChangedParams.has_value()) { + if (!mPolicy.cachedModeChangedParams) { ALOGW("No mode changed params found, not dispatching cached mode."); return; } @@ -372,18 +302,18 @@ void Scheduler::dispatchCachedReportedMode() { // mode change is in progress. In that case we shouldn't dispatch an event // as it will be dispatched when the current mode changes. if (std::scoped_lock lock(mRefreshRateConfigsLock); - mRefreshRateConfigs->getCurrentRefreshRate().getMode() != mFeatures.mode) { + mRefreshRateConfigs->getCurrentRefreshRate().getMode() != mPolicy.mode) { return; } // If there is no change from cached mode, there is no need to dispatch an event - if (mFeatures.mode == mFeatures.cachedModeChangedParams->mode) { + if (mPolicy.mode == mPolicy.cachedModeChangedParams->mode) { return; } - mFeatures.cachedModeChangedParams->mode = mFeatures.mode; - onNonPrimaryDisplayModeChanged(mFeatures.cachedModeChangedParams->handle, - mFeatures.cachedModeChangedParams->mode); + mPolicy.cachedModeChangedParams->mode = mPolicy.mode; + onNonPrimaryDisplayModeChanged(mPolicy.cachedModeChangedParams->handle, + mPolicy.cachedModeChangedParams->mode); } void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { @@ -424,12 +354,12 @@ void Scheduler::setDuration(ConnectionHandle handle, std::chrono::nanoseconds wo } DisplayStatInfo Scheduler::getDisplayStatInfo(nsecs_t now) { - const auto vsyncTime = mVsyncSchedule.tracker->nextAnticipatedVSyncTimeFrom(now); - const auto vsyncPeriod = mVsyncSchedule.tracker->currentPeriod(); + const auto vsyncTime = mVsyncSchedule->getTracker().nextAnticipatedVSyncTimeFrom(now); + const auto vsyncPeriod = mVsyncSchedule->getTracker().currentPeriod(); return DisplayStatInfo{.vsyncTime = vsyncTime, .vsyncPeriod = vsyncPeriod}; } -Scheduler::ConnectionHandle Scheduler::enableVSyncInjection(bool enable) { +ConnectionHandle Scheduler::enableVSyncInjection(bool enable) { if (mInjectVSyncs == enable) { return {}; } @@ -470,7 +400,7 @@ bool Scheduler::injectVSync(nsecs_t when, nsecs_t expectedVSyncTime, nsecs_t dea void Scheduler::enableHardwareVsync() { std::lock_guard lock(mHWVsyncLock); if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) { - mVsyncSchedule.tracker->resetModel(); + mVsyncSchedule->getTracker().resetModel(); mSchedulerCallback.setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } @@ -523,10 +453,10 @@ void Scheduler::resync() { void Scheduler::setVsyncPeriod(nsecs_t period) { std::lock_guard lock(mHWVsyncLock); - mVsyncSchedule.controller->startPeriodTransition(period); + mVsyncSchedule->getController().startPeriodTransition(period); if (!mPrimaryHWVsyncEnabled) { - mVsyncSchedule.tracker->resetModel(); + mVsyncSchedule->getTracker().resetModel(); mSchedulerCallback.setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } @@ -539,8 +469,9 @@ void Scheduler::addResyncSample(nsecs_t timestamp, std::optional hwcVsy { // Scope for the lock std::lock_guard lock(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { - needsHwVsync = mVsyncSchedule.controller->addHwVsyncTimestamp(timestamp, hwcVsyncPeriod, - periodFlushed); + needsHwVsync = + mVsyncSchedule->getController().addHwVsyncTimestamp(timestamp, hwcVsyncPeriod, + periodFlushed); } } @@ -551,24 +482,23 @@ void Scheduler::addResyncSample(nsecs_t timestamp, std::optional hwcVsy } } -void Scheduler::addPresentFence(const std::shared_ptr& fenceTime) { - if (mVsyncSchedule.controller->addPresentFence(fenceTime)) { +void Scheduler::addPresentFence(std::shared_ptr fence) { + if (mVsyncSchedule->getController().addPresentFence(std::move(fence))) { enableHardwareVsync(); } else { disableHardwareVsync(false); } } -void Scheduler::setIgnorePresentFences(bool ignore) { - mVsyncSchedule.controller->setIgnorePresentFences(ignore); -} - void Scheduler::registerLayer(Layer* layer) { + using WindowType = gui::WindowInfo::Type; + scheduler::LayerHistory::LayerVoteType voteType; - if (!mOptions.useContentDetection || layer->getWindowType() == WindowInfo::Type::STATUS_BAR) { + if (!mFeatures.test(Feature::kContentDetection) || + layer->getWindowType() == WindowType::STATUS_BAR) { voteType = scheduler::LayerHistory::LayerVoteType::NoVote; - } else if (layer->getWindowType() == WindowInfo::Type::WALLPAPER) { + } else if (layer->getWindowType() == WindowType::WALLPAPER) { // Running Wallpaper at Min is considered as part of content detection. voteType = scheduler::LayerHistory::LayerVoteType::Min; } else { @@ -615,13 +545,13 @@ void Scheduler::chooseRefreshRateForContent() { bool frameRateChanged; bool frameRateOverridesChanged; { - std::lock_guard lock(mFeatureStateLock); - mFeatures.contentRequirements = summary; + std::lock_guard lock(mPolicyLock); + mPolicy.contentRequirements = summary; newMode = calculateRefreshRateModeId(&consideredSignals); frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); - if (mFeatures.mode == newMode) { + if (mPolicy.mode == newMode) { // We don't need to change the display mode, but we might need to send an event // about a mode change, since it was suppressed due to a previous idleConsidered if (!consideredSignals.idle) { @@ -629,15 +559,16 @@ void Scheduler::chooseRefreshRateForContent() { } frameRateChanged = false; } else { - mFeatures.mode = newMode; + mPolicy.mode = newMode; frameRateChanged = true; } } if (frameRateChanged) { - auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); + const auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); + mSchedulerCallback.changeRefreshRate(newRefreshRate, - consideredSignals.idle ? ModeEvent::None - : ModeEvent::Changed); + consideredSignals.idle ? DisplayModeEvent::None + : DisplayModeEvent::Changed); } if (frameRateOverridesChanged) { mSchedulerCallback.triggerOnFrameRateOverridesChanged(); @@ -660,8 +591,8 @@ void Scheduler::onTouchHint() { void Scheduler::setDisplayPowerState(bool normal) { { - std::lock_guard lock(mFeatureStateLock); - mFeatures.isDisplayPowerStateNormal = normal; + std::lock_guard lock(mPolicyLock); + mPolicy.isDisplayPowerStateNormal = normal; } if (mDisplayPowerTimer) { @@ -703,7 +634,7 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) { } void Scheduler::idleTimerCallback(TimerState state) { - handleTimerStateChanged(&mFeatures.idleTimer, state); + handleTimerStateChanged(&mPolicy.idleTimer, state); ATRACE_INT("ExpiredIdleTimer", static_cast(state)); } @@ -713,14 +644,14 @@ void Scheduler::touchTimerCallback(TimerState state) { // Clear layer history to get fresh FPS detection. // NOTE: Instead of checking all the layers, we should be checking the layer // that is currently on top. b/142507166 will give us this capability. - if (handleTimerStateChanged(&mFeatures.touch, touch)) { + if (handleTimerStateChanged(&mPolicy.touch, touch)) { mLayerHistory.clear(); } ATRACE_INT("TouchState", static_cast(touch)); } void Scheduler::displayPowerTimerCallback(TimerState state) { - handleTimerStateChanged(&mFeatures.displayPowerTimer, state); + handleTimerStateChanged(&mPolicy.displayPowerTimer, state); ATRACE_INT("ExpiredDisplayPowerTimer", static_cast(state)); } @@ -730,7 +661,7 @@ void Scheduler::dump(std::string& result) const { StringAppendF(&result, "+ Touch timer: %s\n", mTouchTimer ? mTouchTimer->dump().c_str() : "off"); StringAppendF(&result, "+ Content detection: %s %s\n\n", - toContentDetectionString(mOptions.useContentDetection), + mFeatures.test(Feature::kContentDetection) ? "on" : "off", mLayerHistory.dump().c_str()); { @@ -756,13 +687,8 @@ void Scheduler::dump(std::string& result) const { } } -void Scheduler::dumpVsync(std::string& s) const { - using base::StringAppendF; - - StringAppendF(&s, "VSyncReactor:\n"); - mVsyncSchedule.controller->dump(s); - StringAppendF(&s, "VSyncDispatch:\n"); - mVsyncSchedule.dispatch->dump(s); +void Scheduler::dumpVsync(std::string& out) const { + mVsyncSchedule->dump(out); } bool Scheduler::updateFrameRateOverrides( @@ -774,7 +700,7 @@ bool Scheduler::updateFrameRateOverrides( if (!consideredSignals.idle) { const auto frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(mFeatures.contentRequirements, + refreshRateConfigs->getFrameRateOverrides(mPolicy.contentRequirements, displayRefreshRate, consideredSignals); std::lock_guard lock(mFrameRateOverridesLock); if (!std::equal(mFrameRateOverridesByContent.begin(), mFrameRateOverridesByContent.end(), @@ -797,31 +723,30 @@ bool Scheduler::handleTimerStateChanged(T* currentState, T newState) { scheduler::RefreshRateConfigs::GlobalSignals consideredSignals; const auto refreshRateConfigs = holdRefreshRateConfigs(); { - std::lock_guard lock(mFeatureStateLock); + std::lock_guard lock(mPolicyLock); if (*currentState == newState) { return false; } *currentState = newState; newMode = calculateRefreshRateModeId(&consideredSignals); frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, newMode->getFps()); - if (mFeatures.mode == newMode) { + if (mPolicy.mode == newMode) { // We don't need to change the display mode, but we might need to send an event // about a mode change, since it was suppressed due to a previous idleConsidered if (!consideredSignals.idle) { dispatchCachedReportedMode(); } } else { - mFeatures.mode = newMode; + mPolicy.mode = newMode; refreshRateChanged = true; } } if (refreshRateChanged) { - const RefreshRate& newRefreshRate = - refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); + const auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); mSchedulerCallback.changeRefreshRate(newRefreshRate, - consideredSignals.idle ? ModeEvent::None - : ModeEvent::Changed); + consideredSignals.idle ? DisplayModeEvent::None + : DisplayModeEvent::Changed); } if (frameRateOverridesChanged) { mSchedulerCallback.triggerOnFrameRateOverridesChanged(); @@ -838,27 +763,26 @@ DisplayModePtr Scheduler::calculateRefreshRateModeId( // If Display Power is not in normal operation we want to be in performance mode. When coming // back to normal mode, a grace period is given with DisplayPowerTimer. if (mDisplayPowerTimer && - (!mFeatures.isDisplayPowerStateNormal || - mFeatures.displayPowerTimer == TimerState::Reset)) { + (!mPolicy.isDisplayPowerStateNormal || mPolicy.displayPowerTimer == TimerState::Reset)) { return refreshRateConfigs->getMaxRefreshRateByPolicy().getMode(); } - const bool touchActive = mTouchTimer && mFeatures.touch == TouchState::Active; - const bool idle = mFeatures.idleTimer == TimerState::Expired; + const bool touchActive = mTouchTimer && mPolicy.touch == TouchState::Active; + const bool idle = mPolicy.idleTimer == TimerState::Expired; return refreshRateConfigs - ->getBestRefreshRate(mFeatures.contentRequirements, - {.touch = touchActive, .idle = idle}, consideredSignals) + ->getBestRefreshRate(mPolicy.contentRequirements, {.touch = touchActive, .idle = idle}, + consideredSignals) .getMode(); } DisplayModePtr Scheduler::getPreferredDisplayMode() { - std::lock_guard lock(mFeatureStateLock); + std::lock_guard lock(mPolicyLock); // Make sure that the default mode ID is first updated, before returned. - if (mFeatures.mode) { - mFeatures.mode = calculateRefreshRateModeId(); + if (mPolicy.mode) { + mPolicy.mode = calculateRefreshRateModeId(); } - return mFeatures.mode; + return mPolicy.mode; } void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) { @@ -915,8 +839,8 @@ void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverrid std::chrono::steady_clock::time_point Scheduler::getPreviousVsyncFrom( nsecs_t expectedPresentTime) const { const auto presentTime = std::chrono::nanoseconds(expectedPresentTime); - const auto vsyncPeriod = std::chrono::nanoseconds(mVsyncSchedule.tracker->currentPeriod()); + const auto vsyncPeriod = std::chrono::nanoseconds(mVsyncSchedule->getTracker().currentPeriod()); return std::chrono::steady_clock::time_point(presentTime - vsyncPeriod); } -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 2a6de54e93..e127ff7371 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -31,40 +31,37 @@ #include #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" +#include + #include "EventThread.h" #include "LayerHistory.h" #include "MessageQueue.h" #include "OneShotTimer.h" #include "RefreshRateConfigs.h" #include "SchedulerUtils.h" +#include "VsyncSchedule.h" namespace android { -using namespace std::chrono_literals; -using scheduler::LayerHistory; - class FenceTime; class InjectVSyncSource; -class PredictedVsyncTracer; - -namespace scheduler { -class VsyncController; -class VSyncDispatch; -class VSyncTracker; -} // namespace scheduler namespace frametimeline { class TokenManager; } // namespace frametimeline +namespace scheduler { + struct ISchedulerCallback { // Indicates frame activity, i.e. whether commit and/or composite is taking place. enum class FrameHint { kNone, kActive }; + using RefreshRate = RefreshRateConfigs::RefreshRate; + using DisplayModeEvent = scheduler::DisplayModeEvent; + virtual void scheduleComposite(FrameHint) = 0; virtual void setVsyncEnabled(bool) = 0; - virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&, - scheduler::RefreshRateConfigEvent) = 0; + virtual void changeRefreshRate(const RefreshRate&, DisplayModeEvent) = 0; virtual void kernelTimerChanged(bool expired) = 0; virtual void triggerOnFrameRateOverridesChanged() = 0; @@ -76,18 +73,10 @@ class Scheduler : impl::MessageQueue { using Impl = impl::MessageQueue; public: - using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; - using ModeEvent = scheduler::RefreshRateConfigEvent; - - struct Options { - // Whether to use content detection at all. - bool useContentDetection; - }; - - Scheduler(ICompositor&, ISchedulerCallback&, Options); + Scheduler(ICompositor&, ISchedulerCallback&, FeatureFlags); ~Scheduler(); - void createVsyncSchedule(bool supportKernelIdleTimer); + void createVsyncSchedule(FeatureFlags); void startTimers(); void run(); @@ -107,7 +96,6 @@ public: return std::move(future); } - using ConnectionHandle = scheduler::ConnectionHandle; ConnectionHandle createConnection(const char* connectionName, frametimeline::TokenManager*, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration, @@ -119,7 +107,7 @@ public: sp getEventConnection(ConnectionHandle); void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected); - void onPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr) EXCLUDES(mFeatureStateLock); + void onPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr) EXCLUDES(mPolicyLock); void onNonPrimaryDisplayModeChanged(ConnectionHandle, DisplayModePtr); void onScreenAcquired(ConnectionHandle); void onScreenReleased(ConnectionHandle); @@ -152,8 +140,7 @@ public: // VsyncController detected that the vsync period changed, and false otherwise. void addResyncSample(nsecs_t timestamp, std::optional hwcVsyncPeriod, bool* periodFlushed); - void addPresentFence(const std::shared_ptr&); - void setIgnorePresentFences(bool ignore); + void addPresentFence(std::shared_ptr); // Layers are registered on creation, and unregistered when the weak reference expires. void registerLayer(Layer*); @@ -172,7 +159,7 @@ public: void setDisplayPowerState(bool normal); - scheduler::VSyncDispatch& getVsyncDispatch() { return *mVsyncSchedule.dispatch; } + VSyncDispatch& getVsyncDispatch() { return mVsyncSchedule->getDispatch(); } // Returns true if a given vsync timestamp is considered valid vsync // for a given uid @@ -211,7 +198,7 @@ public: std::optional getFrameRateOverride(uid_t uid) const EXCLUDES(mRefreshRateConfigsLock, mFrameRateOverridesLock); - void setRefreshRateConfigs(std::shared_ptr refreshRateConfigs) + void setRefreshRateConfigs(std::shared_ptr refreshRateConfigs) EXCLUDES(mRefreshRateConfigsLock) { // We need to stop the idle timer on the previous RefreshRateConfigs instance // and cleanup the scheduler's state before we switch to the other RefreshRateConfigs. @@ -220,8 +207,8 @@ public: if (mRefreshRateConfigs) mRefreshRateConfigs->stopIdleTimer(); } { - std::scoped_lock lock(mFeatureStateLock); - mFeatures = {}; + std::scoped_lock lock(mPolicyLock); + mPolicy = {}; } { std::scoped_lock lock(mRefreshRateConfigsLock); @@ -251,18 +238,10 @@ private: using FrameHint = ISchedulerCallback::FrameHint; - // In order to make sure that the features don't override themselves, we need a state machine - // to keep track which feature requested the config change. enum class ContentDetectionState { Off, On }; enum class TimerState { Reset, Expired }; enum class TouchState { Inactive, Active }; - struct VsyncSchedule { - std::unique_ptr controller; - std::unique_ptr tracker; - std::unique_ptr dispatch; - }; - // Create a connection on the given EventThread. ConnectionHandle createConnection(std::unique_ptr); sp createConnectionInternal( @@ -284,19 +263,17 @@ private: // selection were initialized, prioritizes them, and calculates the DisplayModeId // for the suggested refresh rate. DisplayModePtr calculateRefreshRateModeId( - scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr) - REQUIRES(mFeatureStateLock); + RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr) REQUIRES(mPolicyLock); - void dispatchCachedReportedMode() REQUIRES(mFeatureStateLock) EXCLUDES(mRefreshRateConfigsLock); - bool updateFrameRateOverrides(scheduler::RefreshRateConfigs::GlobalSignals consideredSignals, - Fps displayRefreshRate) REQUIRES(mFeatureStateLock) - EXCLUDES(mFrameRateOverridesLock); + void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mRefreshRateConfigsLock); + bool updateFrameRateOverrides(RefreshRateConfigs::GlobalSignals, Fps displayRefreshRate) + REQUIRES(mPolicyLock) EXCLUDES(mFrameRateOverridesLock); impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const EXCLUDES(mRefreshRateConfigsLock); impl::EventThread::GetVsyncPeriodFunction makeGetVsyncPeriodFunction() const; - std::shared_ptr holdRefreshRateConfigs() const + std::shared_ptr holdRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) { std::scoped_lock lock(mRefreshRateConfigsLock); return mRefreshRateConfigs; @@ -322,66 +299,63 @@ private: std::atomic mLastResyncTime = 0; - const Options mOptions; - VsyncSchedule mVsyncSchedule; + const FeatureFlags mFeatures; + std::optional mVsyncSchedule; // Used to choose refresh rate if content detection is enabled. LayerHistory mLayerHistory; // Timer used to monitor touch events. - std::optional mTouchTimer; + std::optional mTouchTimer; // Timer used to monitor display power mode. - std::optional mDisplayPowerTimer; + std::optional mDisplayPowerTimer; ISchedulerCallback& mSchedulerCallback; - // In order to make sure that the features don't override themselves, we need a state machine - // to keep track which feature requested the config change. - mutable std::mutex mFeatureStateLock; + mutable std::mutex mPolicyLock; struct { + // Policy for choosing the display mode. + LayerHistory::Summary contentRequirements; TimerState idleTimer = TimerState::Reset; TouchState touch = TouchState::Inactive; TimerState displayPowerTimer = TimerState::Expired; + bool isDisplayPowerStateNormal = true; + // Chosen display mode. DisplayModePtr mode; - LayerHistory::Summary contentRequirements; - - bool isDisplayPowerStateNormal = true; - // Used to cache the last parameters of onPrimaryDisplayModeChanged struct ModeChangedParams { ConnectionHandle handle; DisplayModePtr mode; }; + // Parameters for latest dispatch of mode change event. std::optional cachedModeChangedParams; - } mFeatures GUARDED_BY(mFeatureStateLock); + } mPolicy GUARDED_BY(mPolicyLock); mutable std::mutex mRefreshRateConfigsLock; - std::shared_ptr mRefreshRateConfigs - GUARDED_BY(mRefreshRateConfigsLock); + std::shared_ptr mRefreshRateConfigs GUARDED_BY(mRefreshRateConfigsLock); std::mutex mVsyncTimelineLock; std::optional mLastVsyncPeriodChangeTimeline GUARDED_BY(mVsyncTimelineLock); static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms; - std::unique_ptr mPredictedVsyncTracer; - // The frame rate override lists need their own mutex as they are being read // by SurfaceFlinger, Scheduler and EventThread (as a callback) to prevent deadlocks mutable std::mutex mFrameRateOverridesLock; // mappings between a UID and a preferred refresh rate that this app would // run at. - scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesByContent + RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesByContent GUARDED_BY(mFrameRateOverridesLock); - scheduler::RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesFromBackdoor + RefreshRateConfigs::UidToFrameRateOverride mFrameRateOverridesFromBackdoor GUARDED_BY(mFrameRateOverridesLock); // Keeps track of whether the screen is acquired for debug std::atomic mScreenAcquired = false; }; +} // namespace scheduler } // namespace android diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp index ee973f718a..1c9de1c452 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp @@ -47,7 +47,7 @@ VSyncReactor::VSyncReactor(std::unique_ptr clock, VSyncTracker& tracker, VSyncReactor::~VSyncReactor() = default; -bool VSyncReactor::addPresentFence(const std::shared_ptr& fence) { +bool VSyncReactor::addPresentFence(std::shared_ptr fence) { if (!fence) { return false; } @@ -80,7 +80,7 @@ bool VSyncReactor::addPresentFence(const std::shared_ptr& fe if (mPendingLimit == mUnfiredFences.size()) { mUnfiredFences.erase(mUnfiredFences.begin()); } - mUnfiredFences.push_back(fence); + mUnfiredFences.push_back(std::move(fence)); } else { timestampAccepted &= mTracker.addVsyncTimestamp(signalTime); } diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h index 449d4c3bee..a9d536be28 100644 --- a/services/surfaceflinger/Scheduler/VSyncReactor.h +++ b/services/surfaceflinger/Scheduler/VSyncReactor.h @@ -37,7 +37,7 @@ public: bool supportKernelIdleTimer); ~VSyncReactor(); - bool addPresentFence(const std::shared_ptr& fence) final; + bool addPresentFence(std::shared_ptr) final; void setIgnorePresentFences(bool ignore) final; void startPeriodTransition(nsecs_t period) final; diff --git a/services/surfaceflinger/Scheduler/VsyncController.h b/services/surfaceflinger/Scheduler/VsyncController.h index 0f0df222f4..59f65372a9 100644 --- a/services/surfaceflinger/Scheduler/VsyncController.h +++ b/services/surfaceflinger/Scheduler/VsyncController.h @@ -17,19 +17,15 @@ #pragma once #include +#include +#include #include #include #include -#include - -#include - namespace android::scheduler { -class FenceTime; - class VsyncController { public: virtual ~VsyncController(); @@ -43,7 +39,7 @@ public: * an accurate prediction, * False otherwise */ - virtual bool addPresentFence(const std::shared_ptr&) = 0; + virtual bool addPresentFence(std::shared_ptr) = 0; /* * Adds a hw sync timestamp to the model. The controller will use the timestamp diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp new file mode 100644 index 0000000000..77d1223aeb --- /dev/null +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp @@ -0,0 +1,113 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "VsyncSchedule.h" + +#include "Timer.h" +#include "VSyncDispatchTimerQueue.h" +#include "VSyncPredictor.h" +#include "VSyncReactor.h" + +#include "../TracedOrdinal.h" + +namespace android::scheduler { + +class VsyncSchedule::PredictedVsyncTracer { + // Invoked from the thread of the VsyncDispatch owned by this VsyncSchedule. + constexpr auto makeVsyncCallback() { + return [this](nsecs_t, nsecs_t, nsecs_t) { + mParity = !mParity; + schedule(); + }; + } + +public: + explicit PredictedVsyncTracer(VsyncDispatch& dispatch) + : mRegistration(dispatch, makeVsyncCallback(), __func__) { + schedule(); + } + +private: + void schedule() { mRegistration.schedule({0, 0, 0}); } + + TracedOrdinal mParity = {"VSYNC-predicted", 0}; + VSyncCallbackRegistration mRegistration; +}; + +VsyncSchedule::VsyncSchedule(FeatureFlags features) + : mTracker(createTracker()), + mDispatch(createDispatch(*mTracker)), + mController(createController(*mTracker, features)) { + if (features.test(Feature::kTracePredictedVsync)) { + mTracer = std::make_unique(*mDispatch); + } +} + +VsyncSchedule::VsyncSchedule(TrackerPtr tracker, DispatchPtr dispatch, ControllerPtr controller) + : mTracker(std::move(tracker)), + mDispatch(std::move(dispatch)), + mController(std::move(controller)) {} + +VsyncSchedule::VsyncSchedule(VsyncSchedule&&) = default; +VsyncSchedule::~VsyncSchedule() = default; + +void VsyncSchedule::dump(std::string& out) const { + out.append("VsyncController:\n"); + mController->dump(out); + + out.append("VsyncDispatch:\n"); + mDispatch->dump(out); +} + +VsyncSchedule::TrackerPtr VsyncSchedule::createTracker() { + // TODO(b/144707443): Tune constants. + constexpr nsecs_t kInitialPeriod = (60_Hz).getPeriodNsecs(); + constexpr size_t kHistorySize = 20; + constexpr size_t kMinSamplesForPrediction = 6; + constexpr uint32_t kDiscardOutlierPercent = 20; + + return std::make_unique(kInitialPeriod, kHistorySize, kMinSamplesForPrediction, + kDiscardOutlierPercent); +} + +VsyncSchedule::DispatchPtr VsyncSchedule::createDispatch(VsyncTracker& tracker) { + using namespace std::chrono_literals; + + // TODO(b/144707443): Tune constants. + constexpr std::chrono::nanoseconds kGroupDispatchWithin = 500us; + constexpr std::chrono::nanoseconds kSnapToSameVsyncWithin = 3ms; + + return std::make_unique(std::make_unique(), tracker, + kGroupDispatchWithin.count(), + kSnapToSameVsyncWithin.count()); +} + +VsyncSchedule::ControllerPtr VsyncSchedule::createController(VsyncTracker& tracker, + FeatureFlags features) { + // TODO(b/144707443): Tune constants. + constexpr size_t kMaxPendingFences = 20; + const bool hasKernelIdleTimer = features.test(Feature::kKernelIdleTimer); + + auto reactor = std::make_unique(std::make_unique(), tracker, + kMaxPendingFences, hasKernelIdleTimer); + + reactor->setIgnorePresentFences(!features.test(Feature::kPresentFences)); + return reactor; +} + +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.h b/services/surfaceflinger/Scheduler/VsyncSchedule.h new file mode 100644 index 0000000000..0d9b114875 --- /dev/null +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.h @@ -0,0 +1,75 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +namespace android::scheduler { + +// TODO(b/185535769): Rename classes, and remove aliases. +class VSyncDispatch; +class VSyncTracker; + +class VsyncController; +using VsyncDispatch = VSyncDispatch; +using VsyncTracker = VSyncTracker; + +// Schedule that synchronizes to hardware VSYNC of a physical display. +class VsyncSchedule { +public: + explicit VsyncSchedule(FeatureFlags); + VsyncSchedule(VsyncSchedule&&); + ~VsyncSchedule(); + + // TODO(b/185535769): Hide behind API. + const VsyncTracker& getTracker() const { return *mTracker; } + VsyncTracker& getTracker() { return *mTracker; } + VsyncController& getController() { return *mController; } + + // TODO(b/185535769): Remove once VsyncSchedule owns all registrations. + VsyncDispatch& getDispatch() { return *mDispatch; } + + void dump(std::string&) const; + +private: + friend class TestableScheduler; + + using TrackerPtr = std::unique_ptr; + using DispatchPtr = std::unique_ptr; + using ControllerPtr = std::unique_ptr; + + // For tests. + VsyncSchedule(TrackerPtr, DispatchPtr, ControllerPtr); + + static TrackerPtr createTracker(); + static DispatchPtr createDispatch(VsyncTracker&); + static ControllerPtr createController(VsyncTracker&, FeatureFlags); + + class PredictedVsyncTracer; + using TracerPtr = std::unique_ptr; + + // Effectively const except in move constructor. + TrackerPtr mTracker; + DispatchPtr mDispatch; + ControllerPtr mController; + TracerPtr mTracer; +}; + +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Features.h b/services/surfaceflinger/Scheduler/include/scheduler/Features.h new file mode 100644 index 0000000000..0e96678420 --- /dev/null +++ b/services/surfaceflinger/Scheduler/include/scheduler/Features.h @@ -0,0 +1,34 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +namespace android::scheduler { + +enum class Feature : std::uint8_t { + kPresentFences = 0b1, + kKernelIdleTimer = 0b10, + kContentDetection = 0b100, + kTracePredictedVsync = 0b1000, +}; + +using FeatureFlags = Flags; + +} // namespace android::scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e497d95306..3860901edb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1200,7 +1200,7 @@ void SurfaceFlinger::updateInternalStateWithChangedMode() { mRefreshRateStats->setRefreshRate(refreshRate); updatePhaseConfiguration(refreshRate); - if (upcomingModeInfo.event != Scheduler::ModeEvent::None) { + if (upcomingModeInfo.event != DisplayModeEvent::None) { mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, upcomingModeInfo.mode); } } @@ -3099,7 +3099,7 @@ void SurfaceFlinger::updateCursorAsync() { mCompositionEngine->updateCursorAsync(refreshArgs); } -void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, Scheduler::ModeEvent event) { +void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, DisplayModeEvent event) { // If this is called from the main thread mStateLock must be locked before // Currently the only way to call this function from the main thread is from // Scheduler::chooseRefreshRateForContent @@ -3147,17 +3147,32 @@ void SurfaceFlinger::initScheduler(const sp& display) { mVsyncConfiguration = getFactory().createVsyncConfiguration(currRefreshRate); mVsyncModulator = sp::make(mVsyncConfiguration->getCurrentConfigs()); - const Scheduler::Options options = { - .useContentDetection = sysprop::use_content_detection_for_refresh_rate(false)}; + using Feature = scheduler::Feature; + scheduler::FeatureFlags features; - mScheduler = std::make_unique(static_cast(*this), - static_cast(*this), options); + if (sysprop::use_content_detection_for_refresh_rate(false)) { + features |= Feature::kContentDetection; + } + if (base::GetBoolProperty("debug.sf.show_predicted_vsync"s, false)) { + features |= Feature::kTracePredictedVsync; + } + if (!base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false) && + !getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE)) { + features |= Feature::kPresentFences; + } + + mScheduler = std::make_unique(static_cast(*this), + static_cast(*this), + features); { auto configs = display->holdRefreshRateConfigs(); - mScheduler->createVsyncSchedule(configs->supportsKernelIdleTimer()); + if (configs->supportsKernelIdleTimer()) { + features |= Feature::kKernelIdleTimer; + } + + mScheduler->createVsyncSchedule(features); mScheduler->setRefreshRateConfigs(std::move(configs)); } - setVsyncEnabled(false); mScheduler->startTimers(); @@ -3190,11 +3205,6 @@ void SurfaceFlinger::initScheduler(const sp& display) { // classes from EventThread, and there should be no run-time binder cost // anyway since there are no connected apps at this point. mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, display->getActiveMode()); - static auto ignorePresentFences = - base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false); - mScheduler->setIgnorePresentFences( - ignorePresentFences || - getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE)); } void SurfaceFlinger::updatePhaseConfiguration(const Fps& refreshRate) { @@ -3818,10 +3828,11 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin clientStateFlags |= setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, isAutoTimestamp, postTime, permissions); if ((flags & eAnimation) && state.state.surface) { - if (const auto layer = fromHandle(state.state.surface).promote(); layer) { + if (const auto layer = fromHandle(state.state.surface).promote()) { + using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; mScheduler->recordLayerHistory(layer.get(), isAutoTimestamp ? 0 : desiredPresentTime, - LayerHistory::LayerUpdateType::AnimationTX); + LayerUpdateType::AnimationTX); } } } @@ -6478,7 +6489,7 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( if (display->refreshRateConfigs().isModeAllowed(preferredDisplayMode->getId())) { ALOGV("switching to Scheduler preferred display mode %d", preferredDisplayMode->getId().value()); - setDesiredActiveMode({preferredDisplayMode, Scheduler::ModeEvent::Changed}); + setDesiredActiveMode({preferredDisplayMode, DisplayModeEvent::Changed}); } else { LOG_ALWAYS_FATAL("Desired display mode not allowed: %d", preferredDisplayMode->getId().value()); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 05c058b9af..eb934b6b16 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -165,7 +165,7 @@ class SurfaceFlinger : public BnSurfaceComposer, private IBinder::DeathRecipient, private HWC2::ComposerCallback, private ICompositor, - private ISchedulerCallback { + private scheduler::ISchedulerCallback { public: struct SkipInitializationTag {}; @@ -356,7 +356,6 @@ private: friend class TransactionApplicationTest; friend class TunnelModeEnabledReporterTest; - using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using VsyncModulator = scheduler::VsyncModulator; using TransactionSchedule = scheduler::TransactionSchedule; using TraverseLayersFunction = std::function; @@ -643,7 +642,7 @@ private: // Toggles hardware VSYNC by calling into HWC. void setVsyncEnabled(bool) override; // Initiates a refresh rate change to be applied on commit. - void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override; + void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override; // Called when kernel idle timer has expired. Used to update the refresh rate overlay. void kernelTimerChanged(bool expired) override; // Called when the frame rate override list changed to trigger an event. @@ -1261,7 +1260,7 @@ private: /* * Scheduler */ - std::unique_ptr mScheduler; + std::unique_ptr mScheduler; scheduler::ConnectionHandle mAppConnectionHandle; scheduler::ConnectionHandle mSfConnectionHandle; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index e509cc9385..6153e8e354 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -42,16 +42,12 @@ class HWComposer; class IGraphicBufferConsumer; class IGraphicBufferProducer; class Layer; -class MessageQueue; -class Scheduler; class StartPropertySetThread; class SurfaceFlinger; class SurfaceInterceptor; class TimeStats; struct DisplayDeviceCreationArgs; -struct ICompositor; -struct ISchedulerCallback; struct LayerCreationArgs; namespace compositionengine { diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 8d2c078305..eb5f31e796 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -138,7 +138,7 @@ public: .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - constexpr ISchedulerCallback* kCallback = nullptr; + constexpr scheduler::ISchedulerCallback* kCallback = nullptr; constexpr bool kHasMultipleConfigs = true; mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread), std::move(sfEventThread), kCallback, diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp index d4cfbbbe0c..5a0033ea7e 100644 --- a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp @@ -29,7 +29,7 @@ using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjec class InitiateModeChangeTest : public DisplayTransactionTest { public: - using Event = scheduler::RefreshRateConfigEvent; + using Event = scheduler::DisplayModeEvent; void SetUp() override { injectFakeBufferQueueFactory(); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index de5e9dfb97..0a3437aab9 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -121,7 +121,7 @@ public: mock::VsyncController* mVsyncController = new mock::VsyncController; mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker; - mock::SchedulerCallback mSchedulerCallback; + scheduler::mock::SchedulerCallback mSchedulerCallback; mock::EventThread* mEventThread = new mock::EventThread; mock::EventThread* mSFEventThread = new mock::EventThread; diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp index cd2fc7426e..bb1f4328b5 100644 --- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp @@ -17,6 +17,8 @@ #undef LOG_TAG #define LOG_TAG "FpsReporterTest" +#include + #include #include #include @@ -36,6 +38,8 @@ namespace android { +using namespace std::chrono_literals; + using testing::_; using testing::DoAll; using testing::Mock; diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 4993a2d8bc..00687ad4b6 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -38,9 +38,9 @@ using testing::_; using testing::Return; using testing::ReturnRef; -namespace android { +namespace android::scheduler { -namespace scheduler { +using MockLayer = android::mock::MockLayer; class LayerHistoryTest : public testing::Test { protected: @@ -93,12 +93,12 @@ protected: } } - auto createLayer() { return sp(new mock::MockLayer(mFlinger.flinger())); } + auto createLayer() { return sp::make(mFlinger.flinger()); } auto createLayer(std::string name) { - return sp(new mock::MockLayer(mFlinger.flinger(), std::move(name))); + return sp::make(mFlinger.flinger(), std::move(name)); } - void recordFramesAndExpect(const sp& layer, nsecs_t& time, Fps frameRate, + void recordFramesAndExpect(const sp& layer, nsecs_t& time, Fps frameRate, Fps desiredRefreshRate, int numFrames) { LayerHistory::Summary summary; for (int i = 0; i < numFrames; i++) { @@ -768,8 +768,7 @@ INSTANTIATE_TEST_CASE_P(LeapYearTests, LayerHistoryTestParameterized, ::testing::Values(1s, 2s, 3s, 4s, 5s)); } // namespace -} // namespace scheduler -} // namespace android +} // namespace android::scheduler // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index e558f3b700..a6fd378d3d 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -28,12 +28,16 @@ #include "mock/MockLayer.h" #include "mock/MockSchedulerCallback.h" +namespace android::scheduler { + using testing::_; using testing::Return; -namespace android { namespace { +using MockEventThread = android::mock::EventThread; +using MockLayer = android::mock::MockLayer; + constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID = PhysicalDisplayId::fromPort(255u); class SchedulerTest : public testing::Test { @@ -64,21 +68,21 @@ protected: .setGroup(0) .build(); - std::shared_ptr mConfigs = - std::make_shared(DisplayModes{mode60}, mode60->getId()); + std::shared_ptr mConfigs = + std::make_shared(DisplayModes{mode60}, mode60->getId()); mock::SchedulerCallback mSchedulerCallback; TestableScheduler* mScheduler = new TestableScheduler{mConfigs, mSchedulerCallback}; - Scheduler::ConnectionHandle mConnectionHandle; - mock::EventThread* mEventThread; + ConnectionHandle mConnectionHandle; + MockEventThread* mEventThread; sp mEventThreadConnection; TestableSurfaceFlinger mFlinger; }; SchedulerTest::SchedulerTest() { - auto eventThread = std::make_unique(); + auto eventThread = std::make_unique(); mEventThread = eventThread.get(); EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0)); @@ -98,7 +102,7 @@ SchedulerTest::SchedulerTest() { } // namespace TEST_F(SchedulerTest, invalidConnectionHandle) { - Scheduler::ConnectionHandle handle; + ConnectionHandle handle; const sp connection = mScheduler->createDisplayEventConnection(handle); @@ -155,7 +159,7 @@ TEST_F(SchedulerTest, validConnectionHandle) { TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSupported) { // The layer is registered at creation time and deregistered at destruction time. - sp layer = sp::make(mFlinger.flinger()); + sp layer = sp::make(mFlinger.flinger()); // recordLayerHistory should be a noop ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); @@ -174,24 +178,22 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSup TEST_F(SchedulerTest, updateDisplayModes) { ASSERT_EQ(0u, mScheduler->layerHistorySize()); - sp layer = sp::make(mFlinger.flinger()); + sp layer = sp::make(mFlinger.flinger()); ASSERT_EQ(1u, mScheduler->layerHistorySize()); mScheduler->setRefreshRateConfigs( - std::make_shared(DisplayModes{mode60, mode120}, - mode60->getId())); + std::make_shared(DisplayModes{mode60, mode120}, mode60->getId())); ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer); ASSERT_EQ(1u, mScheduler->getNumActiveLayers()); } -TEST_F(SchedulerTest, testDispatchCachedReportedMode) { - // If the optional fields are cleared, the function should return before - // onModeChange is called. - mScheduler->clearOptionalFieldsInFeatures(); - EXPECT_NO_FATAL_FAILURE(mScheduler->dispatchCachedReportedMode()); +TEST_F(SchedulerTest, dispatchCachedReportedMode) { + mScheduler->clearCachedReportedMode(); + EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0); + EXPECT_NO_FATAL_FAILURE(mScheduler->dispatchCachedReportedMode()); } TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) { @@ -203,7 +205,7 @@ TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) { // If the handle is incorrect, the function should return before // onModeChange is called. - Scheduler::ConnectionHandle invalidHandle = {.id = 123}; + ConnectionHandle invalidHandle = {.id = 123}; EXPECT_NO_FATAL_FAILURE(mScheduler->onNonPrimaryDisplayModeChanged(invalidHandle, mode)); EXPECT_CALL(*mEventThread, onModeChanged(_)).Times(0); } @@ -224,10 +226,9 @@ MATCHER(Is120Hz, "") { TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { mScheduler->setRefreshRateConfigs( - std::make_shared(DisplayModes{mode60, mode120}, - mode60->getId())); + std::make_shared(DisplayModes{mode60, mode120}, mode60->getId())); - sp layer = sp::make(mFlinger.flinger()); + sp layer = sp::make(mFlinger.flinger()); mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer); @@ -241,4 +242,4 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { mScheduler->chooseRefreshRateForContent(); } -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index eed62a70c3..fe5f9e0717 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -48,6 +48,8 @@ using android::Hwc2::IComposerClient; using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; +using scheduler::LayerHistory; + using FrameRate = Layer::FrameRate; using FrameRateCompatibility = Layer::FrameRateCompatibility; diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp index 69e0501bd6..ec7e8a7f82 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp @@ -17,6 +17,9 @@ #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" +#include +#include + #include "DisplayTransactionTestHelpers.h" #include @@ -27,6 +30,8 @@ namespace { using android::hardware::power::Boost; TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) { + using namespace std::chrono_literals; + mFlinger.scheduler()->replaceTouchTimer(100); std::this_thread::sleep_for(10ms); // wait for callback to be triggered EXPECT_TRUE(mFlinger.scheduler()->isTouchActive()); // Starting timer activates touch @@ -47,4 +52,4 @@ TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) { } } // namespace -} // namespace android \ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 9d1fc981aa..dabd2d2cc2 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -28,22 +28,20 @@ #include "mock/MockVSyncTracker.h" #include "mock/MockVsyncController.h" -namespace android { +namespace android::scheduler { class TestableScheduler : public Scheduler, private ICompositor { public: - TestableScheduler(std::shared_ptr configs, - ISchedulerCallback& callback) + TestableScheduler(std::shared_ptr configs, ISchedulerCallback& callback) : TestableScheduler(std::make_unique(), std::make_unique(), std::move(configs), callback) {} - TestableScheduler(std::unique_ptr vsyncController, - std::unique_ptr vsyncTracker, - std::shared_ptr configs, - ISchedulerCallback& callback) - : Scheduler(*this, callback, {.useContentDetection = true}) { - mVsyncSchedule = {std::move(vsyncController), std::move(vsyncTracker), nullptr}; + TestableScheduler(std::unique_ptr controller, + std::unique_ptr tracker, + std::shared_ptr configs, ISchedulerCallback& callback) + : Scheduler(*this, callback, Feature::kContentDetection) { + mVsyncSchedule.emplace(VsyncSchedule(std::move(tracker), nullptr, std::move(controller))); setRefreshRateConfigs(std::move(configs)); ON_CALL(*this, postMessage).WillByDefault([](sp&& handler) { @@ -86,33 +84,24 @@ public: } bool isTouchActive() { - std::lock_guard lock(mFeatureStateLock); - return mFeatures.touch == Scheduler::TouchState::Active; + std::lock_guard lock(mPolicyLock); + return mPolicy.touch == Scheduler::TouchState::Active; } void dispatchCachedReportedMode() { - std::lock_guard lock(mFeatureStateLock); + std::lock_guard lock(mPolicyLock); return Scheduler::dispatchCachedReportedMode(); } - void clearOptionalFieldsInFeatures() { - std::lock_guard lock(mFeatureStateLock); - mFeatures.cachedModeChangedParams.reset(); + void clearCachedReportedMode() { + std::lock_guard lock(mPolicyLock); + mPolicy.cachedModeChangedParams.reset(); } void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, DisplayModePtr mode) { return Scheduler::onNonPrimaryDisplayModeChanged(handle, mode); } - ~TestableScheduler() { - // All these pointer and container clears help ensure that GMock does - // not report a leaked object, since the Scheduler instance may - // still be referenced by something despite our best efforts to destroy - // it after each test is done. - mVsyncSchedule.controller.reset(); - mConnections.clear(); - } - private: // ICompositor overrides: bool commit(nsecs_t, int64_t, nsecs_t) override { return false; } @@ -120,4 +109,4 @@ private: void sample() override {} }; -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 4c5789e47f..4473e01c2b 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -169,12 +169,12 @@ public: } // namespace surfaceflinger::test -class TestableSurfaceFlinger final : private ISchedulerCallback { +class TestableSurfaceFlinger final : private scheduler::ISchedulerCallback { public: using HotplugEvent = SurfaceFlinger::HotplugEvent; SurfaceFlinger* flinger() { return mFlinger.get(); } - TestableScheduler* scheduler() { return mScheduler; } + scheduler::TestableScheduler* scheduler() { return mScheduler; } // Extend this as needed for accessing SurfaceFlinger private (and public) // functions. @@ -197,7 +197,8 @@ public: std::unique_ptr vsyncTracker, std::unique_ptr appEventThread, std::unique_ptr sfEventThread, - ISchedulerCallback* callback = nullptr, bool hasMultipleModes = false) { + scheduler::ISchedulerCallback* callback = nullptr, + bool hasMultipleModes = false) { DisplayModes modes{DisplayMode::Builder(0) .setId(DisplayModeId(0)) .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) @@ -224,17 +225,18 @@ public: std::make_unique(*mFlinger->mTimeStats, currFps, /*powerMode=*/hal::PowerMode::OFF); - mScheduler = new TestableScheduler(std::move(vsyncController), std::move(vsyncTracker), - mRefreshRateConfigs, *(callback ?: this)); + mScheduler = new scheduler::TestableScheduler(std::move(vsyncController), + std::move(vsyncTracker), mRefreshRateConfigs, + *(callback ?: this)); mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread)); mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread)); resetScheduler(mScheduler); } - void resetScheduler(Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); } + void resetScheduler(scheduler::Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); } - TestableScheduler& mutableScheduler() const { return *mScheduler; } + scheduler::TestableScheduler& mutableScheduler() const { return *mScheduler; } using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction; void setCreateBufferQueueFunction(CreateBufferQueueFunction f) { @@ -759,13 +761,13 @@ public: private: void scheduleComposite(FrameHint) override {} void setVsyncEnabled(bool) override {} - void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override {} + void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override {} void kernelTimerChanged(bool) override {} void triggerOnFrameRateOverridesChanged() {} surfaceflinger::test::Factory mFactory; sp mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization); - TestableScheduler* mScheduler = nullptr; + scheduler::TestableScheduler* mScheduler = nullptr; std::shared_ptr mRefreshRateConfigs; }; diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index ec19100c2b..16d4b59250 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -26,7 +26,7 @@ #include #include #include -#include "TestableScheduler.h" + #include "TestableSurfaceFlinger.h" #include "mock/MockEventThread.h" #include "mock/MockVsyncController.h" @@ -85,11 +85,8 @@ public: std::move(eventThread), std::move(sfEventThread)); } - TestableScheduler* mScheduler; TestableSurfaceFlinger mFlinger; - std::unique_ptr mEventThread = std::make_unique(); - mock::VsyncController* mVsyncController = new mock::VsyncController(); mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker(); mock::MockFence* mFenceUnsignaled = new mock::MockFence(); diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h index e241dc903f..849e3083c4 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h +++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h @@ -20,25 +20,22 @@ #include "Scheduler/Scheduler.h" -namespace android::mock { +namespace android::scheduler::mock { struct SchedulerCallback final : ISchedulerCallback { MOCK_METHOD(void, scheduleComposite, (FrameHint), (override)); - MOCK_METHOD1(setVsyncEnabled, void(bool)); - MOCK_METHOD2(changeRefreshRate, - void(const scheduler::RefreshRateConfigs::RefreshRate&, - scheduler::RefreshRateConfigEvent)); - MOCK_METHOD1(kernelTimerChanged, void(bool)); - MOCK_METHOD0(triggerOnFrameRateOverridesChanged, void()); + MOCK_METHOD(void, setVsyncEnabled, (bool), (override)); + MOCK_METHOD(void, changeRefreshRate, (const RefreshRate&, DisplayModeEvent), (override)); + MOCK_METHOD(void, kernelTimerChanged, (bool), (override)); + MOCK_METHOD(void, triggerOnFrameRateOverridesChanged, (), (override)); }; struct NoOpSchedulerCallback final : ISchedulerCallback { void scheduleComposite(FrameHint) override {} void setVsyncEnabled(bool) override {} - void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&, - scheduler::RefreshRateConfigEvent) override {} + void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override {} void kernelTimerChanged(bool) override {} void triggerOnFrameRateOverridesChanged() {} }; -} // namespace android::mock +} // namespace android::scheduler::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h index 94d99665ce..314f681545 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h +++ b/services/surfaceflinger/tests/unittests/mock/MockVsyncController.h @@ -27,7 +27,7 @@ public: VsyncController(); ~VsyncController() override; - MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr&)); + MOCK_METHOD(bool, addPresentFence, (std::shared_ptr), (override)); MOCK_METHOD3(addHwVsyncTimestamp, bool(nsecs_t, std::optional, bool*)); MOCK_METHOD1(startPeriodTransition, void(nsecs_t)); MOCK_METHOD1(setIgnorePresentFences, void(bool)); -- cgit v1.2.3-59-g8ed1b From cdf1679ca691ba0afe3c3f94fa7ab14db67ba4ac Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 10 Dec 2021 13:16:06 -0800 Subject: Synchronize brightness change with frame update for hdr layers. When the brightness changes while hdr layers are on screen, the dimming ratio may also change based on ambient conditions, so HWC must recomposite the scene with the new brightness value. Bug: 210151839 Test: builds, boots Change-Id: I4741b28d13f4528a7b5c9045bec7a5823e802935 --- .../include/compositionengine/Output.h | 2 + .../include/compositionengine/impl/Output.h | 1 + .../impl/OutputCompositionState.h | 4 + .../include/compositionengine/mock/Output.h | 1 + .../CompositionEngine/src/Display.cpp | 13 +++ .../CompositionEngine/src/Output.cpp | 4 + .../CompositionEngine/tests/DisplayTest.cpp | 34 ++++++++ .../CompositionEngine/tests/MockHWComposer.h | 4 +- .../CompositionEngine/tests/OutputTest.cpp | 11 +++ services/surfaceflinger/DisplayDevice.cpp | 16 ++++ services/surfaceflinger/DisplayDevice.h | 6 ++ .../DisplayHardware/AidlComposerHal.cpp | 24 ++++-- .../DisplayHardware/AidlComposerHal.h | 3 +- .../surfaceflinger/DisplayHardware/ComposerHal.h | 19 ++++- services/surfaceflinger/DisplayHardware/HWC2.cpp | 9 +- services/surfaceflinger/DisplayHardware/HWC2.h | 6 +- .../surfaceflinger/DisplayHardware/HWComposer.cpp | 7 +- .../surfaceflinger/DisplayHardware/HWComposer.h | 8 +- .../DisplayHardware/HidlComposerHal.cpp | 4 +- .../DisplayHardware/HidlComposerHal.h | 3 +- services/surfaceflinger/SurfaceFlinger.cpp | 67 ++++++++++++++- services/surfaceflinger/SurfaceFlinger.h | 4 + services/surfaceflinger/tests/unittests/Android.bp | 1 + .../DisplayDevice_SetDisplayBrightnessTest.cpp | 99 ++++++++++++++++++++++ .../tests/unittests/DisplayTransactionTest.cpp | 1 + .../tests/unittests/TestableSurfaceFlinger.h | 5 ++ .../unittests/mock/DisplayHardware/MockComposer.h | 2 +- .../unittests/mock/DisplayHardware/MockHWC2.h | 3 +- .../tests/unittests/mock/MockLayer.h | 1 + 29 files changed, 334 insertions(+), 28 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 73770b7779..6cb12dda9f 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -173,6 +173,8 @@ public: // Sets the projection state to use virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, const Rect& orientedDisplaySpaceRect) = 0; + // Sets the brightness that will take effect next frame. + virtual void setNextBrightness(float brightness) = 0; // Sets the bounds to use virtual void setDisplaySize(const ui::Size&) = 0; // Gets the transform hint used in layers that belong to this output. Used to guide diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 844876a997..a7a8e97be5 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -45,6 +45,7 @@ public: void setLayerCachingTexturePoolEnabled(bool) override; void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect, const Rect& orientedDisplaySpaceRect) override; + void setNextBrightness(float brightness) override; void setDisplaySize(const ui::Size&) override; void setLayerFilter(ui::LayerFilter) override; ui::Transform::RotationFlags getTransformHint() const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index c8f177b000..cc7c2574b7 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -133,6 +133,10 @@ struct OutputCompositionState { // White point of the client target float clientTargetWhitePointNits{-1.f}; + // Display brightness that will take effect this frame. + // This is slightly distinct from nits, in that nits cannot be passed to hw composer. + std::optional displayBrightness = std::nullopt; + // Debugging void dump(std::string& result) const; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 7b0d028c11..b68b95d07b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -39,6 +39,7 @@ public: MOCK_METHOD1(setLayerCachingEnabled, void(bool)); MOCK_METHOD1(setLayerCachingTexturePoolEnabled, void(bool)); MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&)); + MOCK_METHOD1(setNextBrightness, void(float)); MOCK_METHOD1(setDisplaySize, void(const ui::Size&)); MOCK_CONST_METHOD0(getTransformHint, ui::Transform::RotationFlags()); diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 08dd22d84e..186e191447 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -226,6 +226,17 @@ void Display::chooseCompositionStrategy() { // Get any composition changes requested by the HWC device, and apply them. std::optional changes; auto& hwc = getCompositionEngine().getHwComposer(); + if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId); + physicalDisplayId && getState().displayBrightness) { + const status_t result = + hwc.setDisplayBrightness(*physicalDisplayId, *getState().displayBrightness, + Hwc2::Composer::DisplayBrightnessOptions{ + .applyImmediately = false}) + .get(); + ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)", + getName().c_str(), result, strerror(-result)); + } + if (status_t result = hwc.getDeviceCompositionChanges(*halDisplayId, anyLayersRequireClientComposition(), getState().earliestPresentTime, @@ -248,6 +259,8 @@ void Display::chooseCompositionStrategy() { auto& state = editState(); state.usesClientComposition = anyLayersRequireClientComposition(); state.usesDeviceComposition = !allLayersRequireClientComposition(); + // Clear out the display brightness now that it's been communicated to composer. + state.displayBrightness.reset(); } bool Display::getSkipColorTransform() const { diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 6833584e71..192ee047ee 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -197,6 +197,10 @@ void Output::setProjection(ui::Rotation orientation, const Rect& layerStackSpace dirtyEntireOutput(); } +void Output::setNextBrightness(float brightness) { + editState().displayBrightness = brightness; +} + void Output::setDisplaySize(const ui::Size& size) { mRenderSurface->setDisplaySize(size); diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 8558a80d0d..7dd4c2187b 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -37,6 +37,7 @@ #include "MockHWC2.h" #include "MockHWComposer.h" #include "MockPowerAdvisor.h" +#include "ftl/future.h" #include @@ -48,6 +49,7 @@ namespace { namespace hal = android::hardware::graphics::composer::hal; using testing::_; +using testing::ByMove; using testing::DoAll; using testing::Eq; using testing::InSequence; @@ -594,6 +596,38 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) { EXPECT_TRUE(state.usesDeviceComposition); } +TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithDisplayBrightness) { + // Since two calls are made to anyLayersRequireClientComposition with different return + // values, use a Sequence to control the matching so the values are returned in a known + // order. + constexpr float kDisplayBrightness = 0.5f; + Sequence s; + EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()) + .InSequence(s) + .WillOnce(Return(false)); + EXPECT_CALL(mHwComposer, + setDisplayBrightness(DEFAULT_DISPLAY_ID, kDisplayBrightness, + Hwc2::Composer::DisplayBrightnessOptions{.applyImmediately = + false})) + .WillOnce(Return(ByMove(ftl::yield(NO_ERROR)))); + + EXPECT_CALL(mHwComposer, + getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _)) + .WillOnce(Return(NO_ERROR)); + EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); + + mDisplay->setNextBrightness(kDisplayBrightness); + mDisplay->chooseCompositionStrategy(); + + auto& state = mDisplay->getState(); + EXPECT_FALSE(state.usesClientComposition); + EXPECT_TRUE(state.usesDeviceComposition); + EXPECT_FALSE(state.displayBrightness.has_value()); +} + TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { android::HWComposer::DeviceRequestedChanges changes{ {{nullptr, Composition::CLIENT}}, diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index a590e2a385..dc5c5c8fcf 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -83,7 +83,9 @@ public: MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(HalDisplayId, bool, uint8_t, uint64_t)); MOCK_METHOD4(getDisplayedContentSample, status_t(HalDisplayId, uint64_t, uint64_t, DisplayedFrameStats*)); - MOCK_METHOD2(setDisplayBrightness, std::future(PhysicalDisplayId, float)); + MOCK_METHOD3(setDisplayBrightness, + std::future(PhysicalDisplayId, float, + const Hwc2::Composer::DisplayBrightnessOptions&)); MOCK_METHOD2(getDisplayBrightnessSupport, status_t(PhysicalDisplayId, bool*)); MOCK_METHOD2(onHotplug, diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 6d96260de7..f7c75337ff 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -574,6 +574,17 @@ TEST_F(OutputTest, setRenderSurfaceResetsBounds) { EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().framebufferSpace.getBoundsAsRect()); } +/** + * Output::setDisplayBrightness() + */ + +TEST_F(OutputTest, setNextBrightness) { + constexpr float kDisplayBrightness = 0.5f; + mOutput->setNextBrightness(kDisplayBrightness); + ASSERT_TRUE(mOutput->getState().displayBrightness.has_value()); + EXPECT_EQ(kDisplayBrightness, mOutput->getState().displayBrightness); +} + /* * Output::getDirtyRegion() */ diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 76bbe2c58f..a36ea72b9f 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -311,6 +311,22 @@ void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpace orientedDisplaySpaceRect); } +void DisplayDevice::stageBrightness(float brightness) { + mStagedBrightness = brightness; +} + +void DisplayDevice::persistBrightness(bool needsComposite) { + if (needsComposite && mStagedBrightness && mBrightness != *mStagedBrightness) { + getCompositionDisplay()->setNextBrightness(*mStagedBrightness); + mBrightness = *mStagedBrightness; + } + mStagedBrightness = std::nullopt; +} + +std::optional DisplayDevice::getStagedBrightness() const { + return mStagedBrightness; +} + ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() { return sPrimaryDisplayRotationFlags; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 324145ef47..d2accaa217 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -99,6 +99,9 @@ public: void setLayerStack(ui::LayerStack); void setDisplaySize(int width, int height); void setProjection(ui::Rotation orientation, Rect viewport, Rect frame); + void stageBrightness(float brightness) REQUIRES(SF_MAIN_THREAD); + void persistBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD); + bool isBrightnessStale() const REQUIRES(SF_MAIN_THREAD); void setFlags(uint32_t flags); ui::Rotation getPhysicalOrientation() const { return mPhysicalOrientation; } @@ -106,6 +109,7 @@ public: static ui::Transform::RotationFlags getPrimaryDisplayRotationFlags(); + std::optional getStagedBrightness() const REQUIRES(SF_MAIN_THREAD); ui::Transform::RotationFlags getTransformHint() const; const ui::Transform& getTransform() const; const Rect& getLayerStackSpaceRect() const; @@ -271,6 +275,8 @@ private: hardware::graphics::composer::hal::PowerMode mPowerMode = hardware::graphics::composer::hal::PowerMode::OFF; DisplayModePtr mActiveMode; + std::optional mStagedBrightness = std::nullopt; + float mBrightness = -1.f; const DisplayModes mSupportedModes; std::atomic mLastHwVsync = 0; diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index 1091a75a82..34f5a39bc0 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -246,6 +246,7 @@ bool AidlComposer::isSupported(OptionalFeature feature) const { switch (feature) { case OptionalFeature::RefreshRateSwitching: case OptionalFeature::ExpectedPresentTime: + case OptionalFeature::DisplayBrightnessCommand: return true; } } @@ -906,13 +907,24 @@ Error AidlComposer::setLayerPerFrameMetadataBlobs( return Error::NONE; } -Error AidlComposer::setDisplayBrightness(Display display, float brightness) { - const auto status = - mAidlComposerClient->setDisplayBrightness(translate(display), brightness); - if (!status.isOk()) { - ALOGE("setDisplayBrightness failed %s", status.getDescription().c_str()); - return static_cast(status.getServiceSpecificError()); +Error AidlComposer::setDisplayBrightness(Display display, float brightness, + const DisplayBrightnessOptions& options) { + if (!options.sdrDimmingEnabled) { + const auto status = + mAidlComposerClient->setDisplayBrightness(translate(display), brightness); + if (!status.isOk()) { + ALOGE("setDisplayBrightness failed %s", status.getDescription().c_str()); + return static_cast(status.getServiceSpecificError()); + } + return Error::NONE; } + + mWriter.setDisplayBrightness(translate(display), brightness); + + if (options.applyImmediately) { + return execute(); + } + return Error::NONE; } diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h index 5c41982e8b..c72093281b 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -180,7 +180,8 @@ public: Error setLayerPerFrameMetadataBlobs( Display display, Layer layer, const std::vector& metadata) override; - Error setDisplayBrightness(Display display, float brightness) override; + Error setDisplayBrightness(Display display, float brightness, + const DisplayBrightnessOptions& options) override; // Composer HAL 2.4 Error getDisplayCapabilities( diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index f491a00c55..e492997098 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -78,6 +78,8 @@ public: enum class OptionalFeature { RefreshRateSwitching, ExpectedPresentTime, + // Whether setDisplayBrightness is able to be applied as part of a display command. + DisplayBrightnessCommand, }; virtual bool isSupported(OptionalFeature) const = 0; @@ -204,7 +206,22 @@ public: DisplayedFrameStats* outStats) = 0; virtual Error setLayerPerFrameMetadataBlobs( Display display, Layer layer, const std::vector& metadata) = 0; - virtual Error setDisplayBrightness(Display display, float brightness) = 0; + // Options for setting the display brightness + struct DisplayBrightnessOptions { + // If true, then immediately submits a brightness change request to composer. Otherwise, + // submission of the brightness change may be deferred until presenting the next frame. + // applyImmediately should only be false if OptionalFeature::DisplayBrightnessCommand is + // supported. + bool applyImmediately = true; + bool sdrDimmingEnabled = true; + + bool operator==(const DisplayBrightnessOptions& other) const { + return applyImmediately == other.applyImmediately && + sdrDimmingEnabled == other.sdrDimmingEnabled; + } + }; + virtual Error setDisplayBrightness(Display display, float brightness, + const DisplayBrightnessOptions& options) = 0; // Composer HAL 2.4 virtual Error getDisplayCapabilities( diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 548d839333..715d9fd3ce 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -37,8 +37,6 @@ #include #include -#include "ComposerHal.h" - using aidl::android::hardware::graphics::composer3::Composition; using aidl::android::hardware::graphics::composer3::DisplayCapability; @@ -532,9 +530,10 @@ Error Display::presentOrValidate(nsecs_t expectedPresentTime, uint32_t* outNumTy return error; } -std::future Display::setDisplayBrightness(float brightness) { - return ftl::defer([composer = &mComposer, id = mId, brightness] { - const auto intError = composer->setDisplayBrightness(id, brightness); +std::future Display::setDisplayBrightness( + float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) { + return ftl::defer([composer = &mComposer, id = mId, brightness, options] { + const auto intError = composer->setDisplayBrightness(id, brightness, options); return static_cast(intError); }); } diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 731d7f6d61..df4e4b8d0b 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -34,6 +34,7 @@ #include #include +#include "ComposerHal.h" #include "Hal.h" #include @@ -143,7 +144,7 @@ public: nsecs_t expectedPresentTime, uint32_t* outNumTypes, uint32_t* outNumRequests, android::sp* outPresentFence, uint32_t* state) = 0; [[clang::warn_unused_result]] virtual std::future setDisplayBrightness( - float brightness) = 0; + float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) = 0; [[clang::warn_unused_result]] virtual hal::Error setActiveConfigWithConstraints( hal::HWConfigId configId, const hal::VsyncPeriodChangeConstraints& constraints, hal::VsyncPeriodChangeTimeline* outTimeline) = 0; @@ -211,7 +212,8 @@ public: uint32_t* outNumRequests, android::sp* outPresentFence, uint32_t* state) override; - std::future setDisplayBrightness(float brightness) override; + std::future setDisplayBrightness( + float brightness, const Hwc2::Composer::DisplayBrightnessOptions& options) override; hal::Error setActiveConfigWithConstraints(hal::HWConfigId configId, const hal::VsyncPeriodChangeConstraints& constraints, hal::VsyncPeriodChangeTimeline* outTimeline) override; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 546e677e05..057db46104 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -782,12 +782,13 @@ status_t HWComposer::getDisplayedContentSample(HalDisplayId displayId, uint64_t return NO_ERROR; } -std::future HWComposer::setDisplayBrightness(PhysicalDisplayId displayId, - float brightness) { +std::future HWComposer::setDisplayBrightness( + PhysicalDisplayId displayId, float brightness, + const Hwc2::Composer::DisplayBrightnessOptions& options) { RETURN_IF_INVALID_DISPLAY(displayId, ftl::yield(BAD_INDEX)); auto& display = mDisplayData[displayId].hwcDisplay; - return ftl::chain(display->setDisplayBrightness(brightness)) + return ftl::chain(display->setDisplayBrightness(brightness, options)) .then([displayId](hal::Error error) -> status_t { if (error == hal::Error::UNSUPPORTED) { RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 69adfcd3e0..4fae06d4d8 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -192,7 +192,9 @@ public: DisplayedFrameStats* outStats) = 0; // Sets the brightness of a display. - virtual std::future setDisplayBrightness(PhysicalDisplayId, float brightness) = 0; + virtual std::future setDisplayBrightness( + PhysicalDisplayId, float brightness, + const Hwc2::Composer::DisplayBrightnessOptions&) = 0; // Events handling --------------------------------------------------------- @@ -340,7 +342,9 @@ public: uint64_t maxFrames) override; status_t getDisplayedContentSample(HalDisplayId, uint64_t maxFrames, uint64_t timestamp, DisplayedFrameStats* outStats) override; - std::future setDisplayBrightness(PhysicalDisplayId, float brightness) override; + std::future setDisplayBrightness( + PhysicalDisplayId, float brightness, + const Hwc2::Composer::DisplayBrightnessOptions&) override; // Events handling --------------------------------------------------------- diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index 7946002d33..b88475581b 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -161,6 +161,7 @@ bool HidlComposer::isSupported(OptionalFeature feature) const { case OptionalFeature::RefreshRateSwitching: return mClient_2_4 != nullptr; case OptionalFeature::ExpectedPresentTime: + case OptionalFeature::DisplayBrightnessCommand: return false; } } @@ -1013,7 +1014,8 @@ Error HidlComposer::setLayerPerFrameMetadataBlobs( return Error::NONE; } -Error HidlComposer::setDisplayBrightness(Display display, float brightness) { +Error HidlComposer::setDisplayBrightness(Display display, float brightness, + const DisplayBrightnessOptions&) { if (!mClient_2_3) { return Error::UNSUPPORTED; } diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h index 3b62fe06e3..6c8af5df59 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h @@ -289,7 +289,8 @@ public: Error setLayerPerFrameMetadataBlobs( Display display, Layer layer, const std::vector& metadata) override; - Error setDisplayBrightness(Display display, float brightness) override; + Error setDisplayBrightness(Display display, float brightness, + const DisplayBrightnessOptions& options) override; // Composer HAL 2.4 Error getDisplayCapabilities( diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 89f3bd6fbb..58f2ab6049 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1669,6 +1669,17 @@ status_t SurfaceFlinger::getDisplayBrightnessSupport(const sp& displayT return NO_ERROR; } +bool SurfaceFlinger::hasVisibleHdrLayer(const sp& display) { + bool hasHdrLayers = false; + mDrawingState.traverse([&, + compositionDisplay = display->getCompositionDisplay()](Layer* layer) { + hasHdrLayers |= (layer->isVisible() && + compositionDisplay->includesLayer(layer->getCompositionEngineLayerFE()) && + isHdrDataspace(layer->getDataSpace())); + }); + return hasHdrLayers; +} + status_t SurfaceFlinger::setDisplayBrightness(const sp& displayToken, const gui::DisplayBrightness& brightness) { if (!displayToken) { @@ -1678,13 +1689,33 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp& displayToken, const char* const whence = __func__; return ftl::chain(mScheduler->schedule([=]() MAIN_THREAD { if (const auto display = getDisplayDeviceLocked(displayToken)) { - if (enableSdrDimming) { + const bool supportsDisplayBrightnessCommand = + getHwComposer().getComposer()->isSupported( + Hwc2::Composer::OptionalFeature::DisplayBrightnessCommand); + // If we support applying display brightness as a command, then we also support + // dimming SDR layers. + // TODO(b/212634488): Once AIDL composer implementations are finalized, remove + // the enableSdrDimming check, as dimming support will be expected for AIDL + // composer. + if (enableSdrDimming && supportsDisplayBrightnessCommand) { display->getCompositionDisplay() ->setDisplayBrightness(brightness.sdrWhitePointNits, brightness.displayBrightnessNits); + MAIN_THREAD_GUARD(display->stageBrightness(brightness.displayBrightness)); + if (hasVisibleHdrLayer(display)) { + scheduleComposite(FrameHint::kNone); + } else { + scheduleCommit(FrameHint::kNone); + } + return ftl::yield(OK); + } else { + return getHwComposer().setDisplayBrightness( + display->getPhysicalId(), brightness.displayBrightness, + Hwc2::Composer::DisplayBrightnessOptions{.applyImmediately = true, + .sdrDimmingEnabled = + enableSdrDimming}); } - return getHwComposer().setDisplayBrightness(display->getPhysicalId(), - brightness.displayBrightness); + } else { ALOGE("%s: Invalid display token %p", whence, displayToken.get()); return ftl::yield(NAME_NOT_FOUND); @@ -2069,6 +2100,8 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected updateCursorAsync(); updateInputFlinger(); + MAIN_THREAD_GUARD(persistDisplayBrightness(mustComposite)); + return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER); } @@ -3101,6 +3134,34 @@ void SurfaceFlinger::updateInputFlinger() { mInputWindowCommands.clear(); } +void SurfaceFlinger::persistDisplayBrightness(bool needsComposite) { + const bool supportsDisplayBrightnessCommand = getHwComposer().getComposer()->isSupported( + Hwc2::Composer::OptionalFeature::DisplayBrightnessCommand); + if (!supportsDisplayBrightnessCommand) { + return; + } + + const auto& displays = ON_MAIN_THREAD(mDisplays); + + for (const auto& [_, display] : displays) { + if (const auto brightness = display->getStagedBrightness(); brightness) { + if (!needsComposite) { + const status_t error = + getHwComposer() + .setDisplayBrightness(display->getPhysicalId(), *brightness, + Hwc2::Composer::DisplayBrightnessOptions{ + .applyImmediately = true}) + .get(); + + ALOGE_IF(error != NO_ERROR, + "Error setting display brightness for display %s: %d (%s)", + display->getDebugName().c_str(), error, strerror(error)); + } + display->persistBrightness(needsComposite); + } + } +} + void SurfaceFlinger::buildWindowInfos(std::vector& outWindowInfos, std::vector& outDisplayInfos) { std::unordered_map& display, hal::PowerMode mode) REQUIRES(mStateLock); + // Returns true if the display has a visible HDR layer in its layer stack. + bool hasVisibleHdrLayer(const sp& display) REQUIRES(mStateLock); + // Sets the desired display mode specs. status_t setDesiredDisplayModeSpecsInternal( const sp& display, @@ -690,6 +693,7 @@ private: void updateLayerGeometry(); void updateInputFlinger(); + void persistDisplayBrightness(bool needsComposite) REQUIRES(SF_MAIN_THREAD); void buildWindowInfos(std::vector& outWindowInfos, std::vector& outDisplayInfos); void commitInputWindowCommands() REQUIRES(mStateLock); diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 55684187f8..bba880ec90 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -55,6 +55,7 @@ cc_test { "DisplayTransactionTest.cpp", "DisplayDevice_GetBestColorModeTest.cpp", "DisplayDevice_InitiateModeChange.cpp", + "DisplayDevice_SetDisplayBrightnessTest.cpp", "DisplayDevice_SetProjectionTest.cpp", "EventThreadTest.cpp", "FlagManagerTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp new file mode 100644 index 0000000000..73c60e1035 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp @@ -0,0 +1,99 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "LibSurfaceFlingerUnittests" + +#include "DisplayTransactionTestHelpers.h" + +#include +#include + +namespace android { +namespace { + +using hal::RenderIntent; + +using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector; + +class SetDisplayBrightnessTest : public DisplayTransactionTest { +public: + sp getDisplayDevice() { return injectDefaultInternalDisplay({}); } +}; + +TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessNoComposite) { + MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD); + sp displayDevice = getDisplayDevice(); + + EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); + + constexpr float kDisplayBrightness = 0.5f; + displayDevice->stageBrightness(kDisplayBrightness); + + EXPECT_EQ(0.5f, displayDevice->getStagedBrightness()); + + displayDevice->persistBrightness(false); + + EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); + EXPECT_EQ(std::nullopt, displayDevice->getCompositionDisplay()->getState().displayBrightness); +} + +TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithComposite) { + MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD); + sp displayDevice = getDisplayDevice(); + + EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); + + constexpr float kDisplayBrightness = 0.5f; + displayDevice->stageBrightness(kDisplayBrightness); + + EXPECT_EQ(0.5f, displayDevice->getStagedBrightness()); + + displayDevice->persistBrightness(true); + + EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); + EXPECT_EQ(kDisplayBrightness, + displayDevice->getCompositionDisplay()->getState().displayBrightness); +} + +TEST_F(SetDisplayBrightnessTest, persistDisplayBrightnessWithCompositeShortCircuitsOnNoOp) { + MainThreadScopedGuard fakeMainThreadGuard(SF_MAIN_THREAD); + sp displayDevice = getDisplayDevice(); + + EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); + + constexpr float kDisplayBrightness = 0.5f; + displayDevice->stageBrightness(kDisplayBrightness); + + EXPECT_EQ(0.5f, displayDevice->getStagedBrightness()); + + displayDevice->persistBrightness(true); + + EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); + EXPECT_EQ(kDisplayBrightness, + displayDevice->getCompositionDisplay()->getState().displayBrightness); + displayDevice->getCompositionDisplay()->editState().displayBrightness = std::nullopt; + + displayDevice->stageBrightness(kDisplayBrightness); + EXPECT_EQ(0.5f, displayDevice->getStagedBrightness()); + displayDevice->persistBrightness(true); + + EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness()); + EXPECT_EQ(std::nullopt, displayDevice->getCompositionDisplay()->getState().displayBrightness); +} + +} // namespace +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index b1f704a48b..c318e28ffe 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -60,6 +60,7 @@ DisplayTransactionTest::~DisplayTransactionTest() { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); + mFlinger.resetScheduler(nullptr); } void DisplayTransactionTest::injectMockScheduler() { diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 0067997398..361d629f1e 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -347,6 +347,11 @@ public: auto notifyPowerBoost(int32_t boostId) { return mFlinger->notifyPowerBoost(boostId); } + auto setDisplayBrightness(const sp& display, + const gui::DisplayBrightness& brightness) { + return mFlinger->setDisplayBrightness(display, brightness); + } + // Allow reading display state without locking, as if called on the SF main thread. auto setPowerModeInternal(const sp& display, hal::PowerMode mode) NO_THREAD_SAFETY_ANALYSIS { diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index 8c51313eb7..4932ad1229 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -120,7 +120,7 @@ public: Error(Display, uint64_t, uint64_t, DisplayedFrameStats*)); MOCK_METHOD3(setLayerPerFrameMetadataBlobs, Error(Display, Layer, const std::vector&)); - MOCK_METHOD2(setDisplayBrightness, Error(Display, float)); + MOCK_METHOD3(setDisplayBrightness, Error(Display, float, const DisplayBrightnessOptions&)); MOCK_METHOD2( getDisplayCapabilities, Error(Display, diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h index 821fc8f8f1..0527d80ddc 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h @@ -80,7 +80,8 @@ public: MOCK_METHOD(hal::Error, presentOrValidate, (nsecs_t, uint32_t *, uint32_t *, android::sp *, uint32_t *), (override)); - MOCK_METHOD(std::future, setDisplayBrightness, (float), (override)); + MOCK_METHOD(std::future, setDisplayBrightness, + (float, const Hwc2::Composer::DisplayBrightnessOptions &), (override)); MOCK_METHOD(hal::Error, setActiveConfigWithConstraints, (hal::HWConfigId, const hal::VsyncPeriodChangeConstraints &, hal::VsyncPeriodChangeTimeline *), diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h index 8b48e1c16d..0840a2f77c 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h +++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h @@ -34,6 +34,7 @@ public: MOCK_METHOD0(createClone, sp()); MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate()); MOCK_CONST_METHOD0(getOwnerUid, uid_t()); + MOCK_CONST_METHOD0(getDataSpace, ui::Dataspace()); }; } // namespace android::mock -- cgit v1.2.3-59-g8ed1b From 646f8ecfa96f04fb001d7edce54123946ab8929f Mon Sep 17 00:00:00 2001 From: Kriti Dang Date: Tue, 18 Jan 2022 14:35:02 +0100 Subject: Removing getSystemPreferredDisplayMode and adding it as part of DynamicDisplayInfo Bug: 209598222 Test: atest CtsBootDisplayModeTestCases Test: atest libcompositionengine_test Change-Id: I1ce0a5a3916b14e25212dd1d2fc4f5e82674fcd1 --- libs/gui/ISurfaceComposer.cpp | 36 ------------------ libs/gui/SurfaceComposerClient.cpp | 6 --- libs/gui/include/gui/ISurfaceComposer.h | 7 ---- libs/gui/include/gui/SurfaceComposerClient.h | 3 +- libs/gui/tests/Surface_test.cpp | 4 -- libs/ui/DynamicDisplayInfo.cpp | 5 ++- libs/ui/include/ui/DynamicDisplayInfo.h | 5 ++- .../include/compositionengine/Display.h | 3 ++ .../include/compositionengine/impl/Display.h | 2 + .../include/compositionengine/mock/Display.h | 1 + .../CompositionEngine/src/Display.cpp | 10 +++++ .../CompositionEngine/tests/DisplayTest.cpp | 43 +++++++++++++--------- .../CompositionEngine/tests/MockHWComposer.h | 2 +- services/surfaceflinger/DisplayDevice.cpp | 14 +++++-- services/surfaceflinger/DisplayDevice.h | 3 ++ services/surfaceflinger/SurfaceFlinger.cpp | 17 +-------- services/surfaceflinger/SurfaceFlinger.h | 2 - .../unittests/mock/DisplayHardware/MockComposer.h | 1 - 18 files changed, 66 insertions(+), 98 deletions(-) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index b7594df2fb..fb9ed22a33 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -495,27 +495,6 @@ public: return result; } - status_t getPreferredBootDisplayMode(const sp& display, - ui::DisplayModeId* displayModeId) override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("getPreferredBootDisplayMode failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeStrongBinder(display); - if (result != NO_ERROR) { - ALOGE("getPreferredBootDisplayMode failed to writeStrongBinder: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::GET_PREFERRED_BOOT_DISPLAY_MODE, data, - &reply); - if (result == NO_ERROR) { - reply.writeInt32(*displayModeId); - } - return result; - } - void setAutoLowLatencyMode(const sp& display, bool on) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -1659,21 +1638,6 @@ status_t BnSurfaceComposer::onTransact( } return clearBootDisplayMode(display); } - case GET_PREFERRED_BOOT_DISPLAY_MODE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp display = nullptr; - status_t result = data.readStrongBinder(&display); - if (result != NO_ERROR) { - ALOGE("getPreferredBootDisplayMode failed to readStrongBinder: %d", result); - return result; - } - ui::DisplayModeId displayModeId; - result = getPreferredBootDisplayMode(display, &displayModeId); - if (result == NO_ERROR) { - reply->writeInt32(displayModeId); - } - return result; - } case SET_AUTO_LOW_LATENCY_MODE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp display = nullptr; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 31456cda7e..1bb53740b5 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2088,12 +2088,6 @@ status_t SurfaceComposerClient::clearBootDisplayMode(const sp& display) return ComposerService::getComposerService()->clearBootDisplayMode(display); } -status_t SurfaceComposerClient::getPreferredBootDisplayMode(const sp& display, - ui::DisplayModeId* displayModeId) { - return ComposerService::getComposerService()->getPreferredBootDisplayMode(display, - displayModeId); -} - status_t SurfaceComposerClient::setOverrideFrameRate(uid_t uid, float frameRate) { return ComposerService::getComposerService()->setOverrideFrameRate(uid, frameRate); } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index fb4fb7e2da..4b5cee256a 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -234,12 +234,6 @@ public: */ virtual status_t clearBootDisplayMode(const sp& display) = 0; - /** - * Gets the display mode in which the device boots if there is no user-preferred display mode. - */ - virtual status_t getPreferredBootDisplayMode(const sp& display, - ui::DisplayModeId*) = 0; - /** * Gets whether boot time display mode operations are supported on the device. * @@ -684,7 +678,6 @@ public: GET_BOOT_DISPLAY_MODE_SUPPORT, SET_BOOT_DISPLAY_MODE, CLEAR_BOOT_DISPLAY_MODE, - GET_PREFERRED_BOOT_DISPLAY_MODE, SET_OVERRIDE_FRAME_RATE, // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 4f928781d9..e9c753332b 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -174,8 +174,7 @@ public: static status_t setBootDisplayMode(const sp& display, ui::DisplayModeId); // Clears the user-preferred display mode static status_t clearBootDisplayMode(const sp& display); - // Gets the display mode in which the device boots if there is no user-preferred display mode - static status_t getPreferredBootDisplayMode(const sp& display, ui::DisplayModeId*); + // Sets the frame rate of a particular app (uid). This is currently called // by GameManager. static status_t setOverrideFrameRate(uid_t uid, float frameRate); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 0ebd11cf32..120ed48d49 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -762,10 +762,6 @@ public: return NO_ERROR; } status_t clearBootDisplayMode(const sp& /*display*/) override { return NO_ERROR; } - status_t getPreferredBootDisplayMode(const sp& /*display*/, - ui::DisplayModeId* /*id*/) override { - return NO_ERROR; - } void setAutoLowLatencyMode(const sp& /*display*/, bool /*on*/) override {} void setGameContentType(const sp& /*display*/, bool /*on*/) override {} diff --git a/libs/ui/DynamicDisplayInfo.cpp b/libs/ui/DynamicDisplayInfo.cpp index d5c4ef0c17..78ba9965b6 100644 --- a/libs/ui/DynamicDisplayInfo.cpp +++ b/libs/ui/DynamicDisplayInfo.cpp @@ -41,7 +41,8 @@ size_t DynamicDisplayInfo::getFlattenedSize() const { FlattenableHelpers::getFlattenedSize(activeColorMode) + FlattenableHelpers::getFlattenedSize(hdrCapabilities) + FlattenableHelpers::getFlattenedSize(autoLowLatencyModeSupported) + - FlattenableHelpers::getFlattenedSize(gameContentTypeSupported); + FlattenableHelpers::getFlattenedSize(gameContentTypeSupported) + + FlattenableHelpers::getFlattenedSize(preferredBootDisplayMode); } status_t DynamicDisplayInfo::flatten(void* buffer, size_t size) const { @@ -55,6 +56,7 @@ status_t DynamicDisplayInfo::flatten(void* buffer, size_t size) const { RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, hdrCapabilities)); RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, autoLowLatencyModeSupported)); RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, gameContentTypeSupported)); + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, preferredBootDisplayMode)); return OK; } @@ -66,6 +68,7 @@ status_t DynamicDisplayInfo::unflatten(const void* buffer, size_t size) { RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &hdrCapabilities)); RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &autoLowLatencyModeSupported)); RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &gameContentTypeSupported)); + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &preferredBootDisplayMode)); return OK; } diff --git a/libs/ui/include/ui/DynamicDisplayInfo.h b/libs/ui/include/ui/DynamicDisplayInfo.h index a4c2f71a4c..ce75a65214 100644 --- a/libs/ui/include/ui/DynamicDisplayInfo.h +++ b/libs/ui/include/ui/DynamicDisplayInfo.h @@ -35,7 +35,7 @@ struct DynamicDisplayInfo : LightFlattenable { // This struct is going to be serialized over binder, so // we can't use size_t because it may have different width // in the client process. - int32_t activeDisplayModeId; + ui::DisplayModeId activeDisplayModeId; std::vector supportedColorModes; ui::ColorMode activeColorMode; @@ -49,6 +49,9 @@ struct DynamicDisplayInfo : LightFlattenable { // For more information, see the HDMI 1.4 specification. bool gameContentTypeSupported; + // The boot display mode preferred by the implementation. + ui::DisplayModeId preferredBootDisplayMode; + std::optional getActiveDisplayMode() const; bool isFixedSize() const { return false; } diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h index 01dd5343b2..a43cc636fd 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h @@ -56,6 +56,9 @@ public: // similar requests if needed. virtual void createClientCompositionCache(uint32_t cacheSize) = 0; + // Returns the boot display mode preferred by HWC. + virtual int32_t getPreferredBootModeId() const = 0; + protected: ~Display() = default; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index 3571e11ad1..9bfd78fc90 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -61,6 +61,7 @@ public: bool isSecure() const override; bool isVirtual() const override; void disconnect() override; + int32_t getPreferredBootModeId() const override; void createDisplayColorProfile( const compositionengine::DisplayColorProfileCreationArgs&) override; void createRenderSurface(const compositionengine::RenderSurfaceCreationArgs&) override; @@ -86,6 +87,7 @@ private: DisplayId mId; bool mIsDisconnected = false; Hwc2::PowerAdvisor* mPowerAdvisor = nullptr; + int32_t mPreferredBootDisplayModeId = -1; }; // This template factory function standardizes the implementation details of the diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h index 08a8b84306..f71f0e4d19 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h @@ -35,6 +35,7 @@ public: MOCK_CONST_METHOD0(getId, DisplayId()); MOCK_CONST_METHOD0(isSecure, bool()); MOCK_CONST_METHOD0(isVirtual, bool()); + MOCK_CONST_METHOD0(getPreferredBootModeId, int32_t()); MOCK_METHOD0(disconnect, void()); diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 186e191447..1ea13a7b2d 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -57,6 +57,12 @@ void Display::setConfiguration(const compositionengine::DisplayCreationArgs& arg editState().isSecure = args.isSecure; editState().displaySpace.setBounds(args.pixels); setName(args.name); + bool isBootModeSupported = getCompositionEngine().getHwComposer().getBootDisplayModeSupport(); + const auto physicalId = PhysicalDisplayId::tryCast(mId); + if (physicalId && isBootModeSupported) { + mPreferredBootDisplayModeId = static_cast( + getCompositionEngine().getHwComposer().getPreferredBootDisplayMode(*physicalId)); + } } bool Display::isValid() const { @@ -79,6 +85,10 @@ std::optional Display::getDisplayId() const { return mId; } +int32_t Display::getPreferredBootModeId() const { + return mPreferredBootDisplayModeId; +} + void Display::disconnect() { if (mIsDisconnected) { return; diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 7dd4c2187b..03c6f8dd81 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -164,6 +164,7 @@ struct DisplayTestCommon : public testing::Test { EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine)); EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false)); EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false)); + EXPECT_CALL(mHwComposer, getBootDisplayModeSupport()).WillRepeatedly(Return(false)); } DisplayCreationArgs getDisplayCreationArgsForPhysicalDisplay() { @@ -971,7 +972,8 @@ struct DisplayFunctionalTest : public testing::Test { DisplayFunctionalTest() { EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer)); - + mDisplay = createDisplay(); + mRenderSurface = createRenderSurface(); mDisplay->setRenderSurfaceForTest(std::unique_ptr(mRenderSurface)); } @@ -980,24 +982,29 @@ struct DisplayFunctionalTest : public testing::Test { NiceMock mCompositionEngine; sp mNativeWindow = new NiceMock(); sp mDisplaySurface = new NiceMock(); + std::shared_ptr mDisplay; + impl::RenderSurface* mRenderSurface; + + std::shared_ptr createDisplay() { + return impl::createDisplayTemplated(mCompositionEngine, + DisplayCreationArgsBuilder() + .setId(DEFAULT_DISPLAY_ID) + .setPixels(DEFAULT_RESOLUTION) + .setIsSecure(true) + .setPowerAdvisor(&mPowerAdvisor) + .build()); + ; + } - std::shared_ptr mDisplay = impl::createDisplayTemplated< - Display>(mCompositionEngine, - DisplayCreationArgsBuilder() - .setId(DEFAULT_DISPLAY_ID) - .setPixels(DEFAULT_RESOLUTION) - .setIsSecure(true) - .setPowerAdvisor(&mPowerAdvisor) - .build()); - - impl::RenderSurface* mRenderSurface = - new impl::RenderSurface{mCompositionEngine, *mDisplay, - RenderSurfaceCreationArgsBuilder() - .setDisplayWidth(DEFAULT_RESOLUTION.width) - .setDisplayHeight(DEFAULT_RESOLUTION.height) - .setNativeWindow(mNativeWindow) - .setDisplaySurface(mDisplaySurface) - .build()}; + impl::RenderSurface* createRenderSurface() { + return new impl::RenderSurface{mCompositionEngine, *mDisplay, + RenderSurfaceCreationArgsBuilder() + .setDisplayWidth(DEFAULT_RESOLUTION.width) + .setDisplayHeight(DEFAULT_RESOLUTION.height) + .setNativeWindow(mNativeWindow) + .setDisplaySurface(mDisplaySurface) + .build()}; + } }; TEST_F(DisplayFunctionalTest, postFramebufferCriticalCallsAreOrdered) { diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index bd3022b425..394fe03335 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -109,6 +109,7 @@ public: MOCK_METHOD2(setBootDisplayMode, status_t(PhysicalDisplayId, hal::HWConfigId)); MOCK_METHOD1(clearBootDisplayMode, status_t(PhysicalDisplayId)); MOCK_METHOD1(getPreferredBootDisplayMode, hal::HWConfigId(PhysicalDisplayId)); + MOCK_METHOD0(getBootDisplayModeSupport, bool()); MOCK_METHOD2(setAutoLowLatencyMode, status_t(PhysicalDisplayId, bool)); MOCK_METHOD2(getSupportedContentTypes, status_t(PhysicalDisplayId, std::vector*)); @@ -127,7 +128,6 @@ public: (const, override)); MOCK_METHOD(std::optional, fromPhysicalDisplayId, (PhysicalDisplayId), (const, override)); - MOCK_METHOD(bool, getBootDisplayModeSupport, (), (override)); }; } // namespace mock diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index a36ea72b9f..f542161b93 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -92,10 +92,12 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) } mCompositionDisplay->createDisplayColorProfile( - compositionengine::DisplayColorProfileCreationArgs{args.hasWideColorGamut, - std::move(args.hdrCapabilities), - args.supportedPerFrameMetadata, - args.hwcColorModes}); + compositionengine::DisplayColorProfileCreationArgsBuilder() + .setHasWideColorGamut(args.hasWideColorGamut) + .setHdrCapabilities(std::move(args.hdrCapabilities)) + .setSupportedPerFrameMetadata(args.supportedPerFrameMetadata) + .setHwcColorModes(std::move(args.hwcColorModes)) + .Build()); if (!mCompositionDisplay->isValid()) { ALOGE("Composition Display did not validate!"); @@ -454,6 +456,10 @@ HdrCapabilities DisplayDevice::getHdrCapabilities() const { capabilities.getDesiredMinLuminance()); } +ui::DisplayModeId DisplayDevice::getPreferredBootModeId() const { + return mCompositionDisplay->getPreferredBootModeId(); +} + void DisplayDevice::enableRefreshRateOverlay(bool enable, bool showSpinnner) { if (!enable) { mRefreshRateOverlay.reset(); diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index d2accaa217..ad44b16813 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -157,6 +157,9 @@ public: // respectively if hardware composer doesn't return meaningful values. HdrCapabilities getHdrCapabilities() const; + // Returns the boot display mode preferred by the implementation. + ui::DisplayModeId getPreferredBootModeId() const; + // Return true if intent is supported by the display. bool hasRenderIntent(ui::RenderIntent intent) const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ea5025fc20..b58616916e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1112,6 +1112,8 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp& displayToken, return type == hal::ContentType::GAME; }); + info->preferredBootDisplayMode = display->getPreferredBootModeId(); + return NO_ERROR; } @@ -1457,20 +1459,6 @@ status_t SurfaceFlinger::clearBootDisplayMode(const sp& displayToken) { return future.get(); } -status_t SurfaceFlinger::getPreferredBootDisplayMode(const sp& displayToken, - ui::DisplayModeId* id) { - auto future = mScheduler->schedule([=]() MAIN_THREAD mutable -> status_t { - if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { - *id = getHwComposer().getPreferredBootDisplayMode(*displayId); - return NO_ERROR; - } else { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); - return BAD_VALUE; - } - }); - return future.get(); -} - void SurfaceFlinger::setAutoLowLatencyMode(const sp& displayToken, bool on) { const char* const whence = __func__; static_cast(mScheduler->schedule([=]() MAIN_THREAD { @@ -5463,7 +5451,6 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case GET_BOOT_DISPLAY_MODE_SUPPORT: case SET_BOOT_DISPLAY_MODE: case CLEAR_BOOT_DISPLAY_MODE: - case GET_PREFERRED_BOOT_DISPLAY_MODE: case GET_AUTO_LOW_LATENCY_MODE_SUPPORT: case SET_AUTO_LOW_LATENCY_MODE: case GET_GAME_CONTENT_TYPE_SUPPORT: diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8ca9982b98..ed8d27ef1a 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -537,8 +537,6 @@ private: status_t getBootDisplayModeSupport(bool* outSupport) const override; status_t setBootDisplayMode(const sp& displayToken, ui::DisplayModeId id) override; status_t clearBootDisplayMode(const sp& displayToken) override; - status_t getPreferredBootDisplayMode(const sp& displayToken, - ui::DisplayModeId* id) override; void setAutoLowLatencyMode(const sp& displayToken, bool on) override; void setGameContentType(const sp& displayToken, bool on) override; void setPowerMode(const sp& displayToken, int mode) override; diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index 4273401bc7..8a420ef949 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -135,7 +135,6 @@ public: V2_4::Error(Display, Config, const IComposerClient::VsyncPeriodChangeConstraints&, VsyncPeriodChangeTimeline*)); MOCK_METHOD2(setAutoLowLatencyMode, V2_4::Error(Display, bool)); - MOCK_METHOD2(getBootDisplayConfigSupport, Error(Display, bool*)); MOCK_METHOD2(setBootDisplayConfig, Error(Display, Config)); MOCK_METHOD1(clearBootDisplayConfig, Error(Display)); MOCK_METHOD2(getPreferredBootDisplayConfig, Error(Display, Config*)); -- cgit v1.2.3-59-g8ed1b From 9f410f0adfb4f44fa149cbc7589b13ea88007157 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Sat, 8 Jan 2022 16:22:46 -0800 Subject: SF: Avoid allocation on hot path to IF The number of layer stacks and listeners is small, and the predominant operations are lookup and iteration respectively, so store them on the stack contiguously to avoid hashing/allocation/indirection. Preallocate the WindowInfo and DisplayInfo vectors, since reallocating the former involves copying strings and fiddling with sp<> ref counts. Bug: 185536303 Test: simpleperf Test: WindowInfosListenerTest Change-Id: I5d1d1fc3b2639a4ee5056697e1a3581c11174173 --- services/surfaceflinger/DisplayDevice.cpp | 9 ++- services/surfaceflinger/DisplayDevice.h | 11 +++- services/surfaceflinger/SurfaceFlinger.cpp | 65 +++++++++------------- .../surfaceflinger/WindowInfosListenerInvoker.cpp | 23 ++++---- .../surfaceflinger/WindowInfosListenerInvoker.h | 11 ++-- 5 files changed, 58 insertions(+), 61 deletions(-) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index f542161b93..eef00522dc 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -141,7 +141,7 @@ uint32_t DisplayDevice::getPageFlipCount() const { return mCompositionDisplay->getRenderSurface()->getPageFlipCount(); } -std::pair DisplayDevice::getInputInfo() const { +auto DisplayDevice::getInputInfo() const -> InputInfo { gui::DisplayInfo info; info.displayId = getLayerStack().id; @@ -166,10 +166,13 @@ std::pair DisplayDevice::getInputInfo() const { info.logicalWidth = getLayerStackSpaceRect().width(); info.logicalHeight = getLayerStackSpaceRect().height(); - return {info, displayTransform}; + + return {.info = info, + .transform = displayTransform, + .receivesInput = receivesInput(), + .isSecure = isSecure()}; } -// ---------------------------------------------------------------------------- void DisplayDevice::setPowerMode(hal::PowerMode mode) { mPowerMode = mode; getCompositionDisplay()->setCompositionEnabled(mPowerMode != hal::PowerMode::OFF); diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 3cae30fe92..bf6b31a76b 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -174,9 +174,14 @@ public: return mDeviceProductInfo; } - // Get the DisplayInfo that will be sent to InputFlinger, and the display transform that should - // be applied to all the input windows on the display. - std::pair getInputInfo() const; + struct InputInfo { + gui::DisplayInfo info; + ui::Transform transform; + bool receivesInput; + bool isSecure; + }; + + InputInfo getInputInfo() const; /* ------------------------------------------------------------------------ * Display power mode management. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9716d8ecea..344c2cc7d4 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -3258,60 +3259,48 @@ void SurfaceFlinger::persistDisplayBrightness(bool needsComposite) { void SurfaceFlinger::buildWindowInfos(std::vector& outWindowInfos, std::vector& outDisplayInfos) { - struct Details { - Details(bool receivesInput, bool isSecure, const ui::Transform& transform, - const DisplayInfo& info) - : receivesInput(receivesInput), - isSecure(isSecure), - transform(std::move(transform)), - info(std::move(info)) {} - bool receivesInput; - bool isSecure; - ui::Transform transform; - DisplayInfo info; - }; - std::unordered_map inputDisplayDetails; + ftl::SmallMap displayInputInfos; + for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) { - const uint32_t layerStackId = display->getLayerStack().id; - const auto& [info, transform] = display->getInputInfo(); - const auto& [it, emplaced] = - inputDisplayDetails.try_emplace(layerStackId, display->receivesInput(), - display->isSecure(), transform, info); + const auto layerStack = display->getLayerStack(); + const auto info = display->getInputInfo(); + + const auto [it, emplaced] = displayInputInfos.try_emplace(layerStack, info); if (emplaced) { continue; } - // There is more than one display for the layerStack. In this case, the first display that - // is configured to receive input takes precedence. - auto& details = it->second; - if (details.receivesInput) { + // If the layer stack is mirrored on multiple displays, the first display that is configured + // to receive input takes precedence. + auto& otherInfo = it->second; + if (otherInfo.receivesInput) { ALOGW_IF(display->receivesInput(), "Multiple displays claim to accept input for the same layer stack: %u", - layerStackId); - continue; + layerStack.id); + } else { + otherInfo = info; } - details.receivesInput = display->receivesInput(); - details.isSecure = display->isSecure(); - details.transform = std::move(transform); - details.info = std::move(info); } + static size_t sNumWindowInfos = 0; + outWindowInfos.reserve(sNumWindowInfos); + sNumWindowInfos = 0; + mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (!layer->needsInputInfo()) return; - const uint32_t layerStackId = layer->getLayerStack().id; - const auto it = inputDisplayDetails.find(layerStackId); - if (it == inputDisplayDetails.end()) { - // Do not create WindowInfos for windows on displays that cannot receive input. - return; + // Do not create WindowInfos for windows on displays that cannot receive input. + if (const auto opt = displayInputInfos.get(layer->getLayerStack())) { + const auto& info = opt->get(); + outWindowInfos.push_back(layer->fillInputInfo(info.transform, info.isSecure)); } - - const auto& details = it->second; - outWindowInfos.push_back(layer->fillInputInfo(details.transform, details.isSecure)); }); - for (const auto& [_, details] : inputDisplayDetails) { - outDisplayInfos.push_back(std::move(details.info)); + sNumWindowInfos = outWindowInfos.size(); + + outDisplayInfos.reserve(displayInputInfos.size()); + for (const auto& [_, info] : displayInputInfos) { + outDisplayInfos.push_back(info.info); } } diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index 23cd99336a..30b9d8f1cb 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -14,10 +14,11 @@ * limitations under the License. */ -#include "WindowInfosListenerInvoker.h" +#include #include -#include + #include "SurfaceFlinger.h" +#include "WindowInfosListenerInvoker.h" namespace android { @@ -41,18 +42,17 @@ WindowInfosListenerInvoker::WindowInfosListenerInvoker(SurfaceFlinger& flinger) : mFlinger(flinger), mWindowInfosReportedListener(sp::make(*this)) {} -void WindowInfosListenerInvoker::addWindowInfosListener( - const sp& windowInfosListener) { - sp asBinder = IInterface::asBinder(windowInfosListener); - +void WindowInfosListenerInvoker::addWindowInfosListener(sp listener) { + sp asBinder = IInterface::asBinder(listener); asBinder->linkToDeath(this); + std::scoped_lock lock(mListenersMutex); - mWindowInfosListeners.emplace(asBinder, windowInfosListener); + mWindowInfosListeners.try_emplace(asBinder, std::move(listener)); } void WindowInfosListenerInvoker::removeWindowInfosListener( - const sp& windowInfosListener) { - sp asBinder = IInterface::asBinder(windowInfosListener); + const sp& listener) { + sp asBinder = IInterface::asBinder(listener); std::scoped_lock lock(mListenersMutex); asBinder->unlinkToDeath(this); @@ -67,12 +67,11 @@ void WindowInfosListenerInvoker::binderDied(const wp& who) { void WindowInfosListenerInvoker::windowInfosChanged(const std::vector& windowInfos, const std::vector& displayInfos, bool shouldSync) { - std::unordered_set, SpHash> windowInfosListeners; - + ftl::SmallVector, kStaticCapacity> windowInfosListeners; { std::scoped_lock lock(mListenersMutex); for (const auto& [_, listener] : mWindowInfosListeners) { - windowInfosListeners.insert(listener); + windowInfosListeners.push_back(listener); } } diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index 2eabf481c8..d8d8d0f570 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -20,10 +20,8 @@ #include #include #include +#include #include -#include - -#include "WpHash.h" namespace android { @@ -33,7 +31,7 @@ class WindowInfosListenerInvoker : public IBinder::DeathRecipient { public: explicit WindowInfosListenerInvoker(SurfaceFlinger&); - void addWindowInfosListener(const sp& windowInfosListener); + void addWindowInfosListener(sp); void removeWindowInfosListener(const sp& windowInfosListener); void windowInfosChanged(const std::vector&, @@ -48,8 +46,11 @@ private: SurfaceFlinger& mFlinger; std::mutex mListenersMutex; - std::unordered_map, const sp, WpHash> + + static constexpr size_t kStaticCapacity = 3; + ftl::SmallMap, const sp, kStaticCapacity> mWindowInfosListeners GUARDED_BY(mListenersMutex); + sp mWindowInfosReportedListener; std::atomic mCallbacksPending{0}; }; -- cgit v1.2.3-59-g8ed1b From 30e378de095af353294506d74f8d547d5b4ad104 Mon Sep 17 00:00:00 2001 From: Kriti Dang Date: Fri, 18 Feb 2022 15:09:12 +0100 Subject: Map the hwc-id -> SF-id in getPreferredBootDisplayMode and SF-Id -> HWC id in setUserPreferredDisplayMode Bug: 219959797 Test: m Change-Id: I20e69dd50ad06b527a833ebef5e617b2ebd3d236 (cherry picked from commit f50d677e2cd96296a57a76e6ece409e08adae6ba) --- .../include/compositionengine/Display.h | 2 +- .../include/compositionengine/impl/Display.h | 4 ++-- .../include/compositionengine/mock/Display.h | 2 +- .../surfaceflinger/CompositionEngine/src/Display.cpp | 6 +++--- services/surfaceflinger/DisplayDevice.cpp | 17 ++++++++++++++++- services/surfaceflinger/DisplayDevice.h | 3 +++ services/surfaceflinger/SurfaceFlinger.cpp | 11 +++++++++-- 7 files changed, 35 insertions(+), 10 deletions(-) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h index 47aacc99f6..6a3fcb7307 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h @@ -57,7 +57,7 @@ public: virtual void createClientCompositionCache(uint32_t cacheSize) = 0; // Returns the boot display mode preferred by HWC. - virtual int32_t getPreferredBootModeId() const = 0; + virtual int32_t getPreferredBootHwcConfigId() const = 0; protected: ~Display() = default; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index c7984bd529..58d2530877 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -62,7 +62,7 @@ public: bool isSecure() const override; bool isVirtual() const override; void disconnect() override; - int32_t getPreferredBootModeId() const override; + int32_t getPreferredBootHwcConfigId() const override; void createDisplayColorProfile( const compositionengine::DisplayColorProfileCreationArgs&) override; void createRenderSurface(const compositionengine::RenderSurfaceCreationArgs&) override; @@ -88,7 +88,7 @@ private: DisplayId mId; bool mIsDisconnected = false; Hwc2::PowerAdvisor* mPowerAdvisor = nullptr; - int32_t mPreferredBootDisplayModeId = -1; + int32_t mPreferredBootHwcConfigId = -1; }; // This template factory function standardizes the implementation details of the diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h index 84afb59510..d90cc909ba 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h @@ -34,7 +34,7 @@ public: MOCK_CONST_METHOD0(getId, DisplayId()); MOCK_CONST_METHOD0(isSecure, bool()); MOCK_CONST_METHOD0(isVirtual, bool()); - MOCK_CONST_METHOD0(getPreferredBootModeId, int32_t()); + MOCK_CONST_METHOD0(getPreferredBootHwcConfigId, int32_t()); MOCK_METHOD0(disconnect, void()); diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 6390025725..6a75283f7b 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -66,7 +66,7 @@ void Display::setConfiguration(const compositionengine::DisplayCreationArgs& arg std::optional preferredBootModeId = getCompositionEngine().getHwComposer().getPreferredBootDisplayMode(*physicalId); if (preferredBootModeId.has_value()) { - mPreferredBootDisplayModeId = static_cast(preferredBootModeId.value()); + mPreferredBootHwcConfigId = static_cast(preferredBootModeId.value()); } } @@ -90,8 +90,8 @@ std::optional Display::getDisplayId() const { return mId; } -int32_t Display::getPreferredBootModeId() const { - return mPreferredBootDisplayModeId; +int32_t Display::getPreferredBootHwcConfigId() const { + return mPreferredBootHwcConfigId; } void Display::disconnect() { diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index eef00522dc..45b98bb3d3 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -235,6 +235,15 @@ DisplayModePtr DisplayDevice::getMode(DisplayModeId modeId) const { return nullptr; } +DisplayModePtr DisplayDevice::getModefromHwcId(uint32_t hwcId) const { + const auto it = std::find_if(mSupportedModes.begin(), mSupportedModes.end(), + [&](DisplayModePtr mode) { return mode->getHwcId() == hwcId; }); + if (it != mSupportedModes.end()) { + return *it; + } + return nullptr; +} + nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const { const auto physicalId = getPhysicalId(); if (!mHwComposer.isConnected(physicalId)) { @@ -460,7 +469,13 @@ HdrCapabilities DisplayDevice::getHdrCapabilities() const { } ui::DisplayModeId DisplayDevice::getPreferredBootModeId() const { - return mCompositionDisplay->getPreferredBootModeId(); + const auto preferredBootHwcModeId = mCompositionDisplay->getPreferredBootHwcConfigId(); + const auto mode = getModefromHwcId(preferredBootHwcModeId); + if (mode == nullptr) { + ALOGE("%s: invalid display mode (%d)", __FUNCTION__, preferredBootHwcModeId); + return BAD_VALUE; + } + return mode->getId().value(); } void DisplayDevice::enableRefreshRateOverlay(bool enable, bool showSpinnner) { diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index bf6b31a76b..690f2404fd 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -232,6 +232,9 @@ public: // set-top boxes after a hotplug reconnect. DisplayModePtr getMode(DisplayModeId) const; + // Returns nullptr if the given mode ID is not supported. + DisplayModePtr getModefromHwcId(uint32_t) const; + // Returns the refresh rate configs for this display. scheduler::RefreshRateConfigs& refreshRateConfigs() const { return *mRefreshRateConfigs; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 91b479b783..dc9e45011f 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1436,8 +1436,15 @@ status_t SurfaceFlinger::getBootDisplayModeSupport(bool* outSupport) const { status_t SurfaceFlinger::setBootDisplayMode(const sp& displayToken, ui::DisplayModeId id) { auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t { - if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { - return getHwComposer().setBootDisplayMode(*displayId, id); + if (const auto displayDevice = getDisplayDeviceLocked(displayToken)) { + const auto mode = displayDevice->getMode(DisplayModeId{id}); + if (mode == nullptr) { + ALOGE("%s: invalid display mode (%d)", __FUNCTION__, id); + return BAD_VALUE; + } + + return getHwComposer().setBootDisplayMode(displayDevice->getPhysicalId(), + mode->getHwcId()); } else { ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); return BAD_VALUE; -- cgit v1.2.3-59-g8ed1b From 7234fa59245e20b934a15ebbd27d4e189ad224d0 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 24 Feb 2022 14:07:11 -0800 Subject: SF: Predict HWC composition strategy Asynchronously run ValidateDisplay to determine client composition strategy. If we can predict that the composition strategy will not change from frame to frame (for example by looking at whether the geometry of the layers is changing), the hwc call is run asynchronously with the gpu composition. If the result of the call is incorrectly predicted, the gpu composition is rerun. ValidateDisplay can take multiple milliseconds to complete and by making it non-blocking in cases where we can predict the strategy chosen by the hardware, we can jump start the client composition and shave valuable milliseconds from the frame time. This feature is disabled by default. Test: perfetto traces Bug: 220031739 Change-Id: Ib4dcc0e055d5272c89cfff853211edac73aa449b --- .../surfaceflinger/CompositionEngine/Android.bp | 5 + .../include/compositionengine/DisplaySurface.h | 3 + .../include/compositionengine/Output.h | 21 +- .../include/compositionengine/RenderSurface.h | 3 + .../include/compositionengine/impl/Display.h | 9 +- .../compositionengine/impl/GpuCompositionResult.h | 38 +++ .../compositionengine/impl/HwcAsyncWorker.h | 57 ++++ .../include/compositionengine/impl/Output.h | 27 +- .../impl/OutputCompositionState.h | 4 + .../include/compositionengine/impl/RenderSurface.h | 1 + .../include/compositionengine/mock/Display.h | 1 + .../include/compositionengine/mock/Output.h | 17 +- .../include/compositionengine/mock/RenderSurface.h | 1 + .../CompositionEngine/src/Display.cpp | 24 +- .../CompositionEngine/src/DisplaySurface.cpp | 4 + .../CompositionEngine/src/HwcAsyncWorker.cpp | 73 +++++ .../CompositionEngine/src/Output.cpp | 207 ++++++++++++-- .../CompositionEngine/src/RenderSurface.cpp | 4 + .../CompositionEngine/tests/DisplayTest.cpp | 76 +++-- .../CompositionEngine/tests/OutputTest.cpp | 308 +++++++++++++++++++-- services/surfaceflinger/DisplayDevice.cpp | 1 + .../surfaceflinger/DisplayHardware/HWComposer.h | 8 + .../DisplayHardware/VirtualDisplaySurface.h | 3 + services/surfaceflinger/SurfaceFlinger.cpp | 3 + services/surfaceflinger/SurfaceFlinger.h | 5 + 25 files changed, 797 insertions(+), 106 deletions(-) create mode 100644 services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h create mode 100644 services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h create mode 100644 services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index aefc014062..9302b7bc37 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -41,6 +41,10 @@ cc_defaults { "libtonemap", "libtrace_proto", "libaidlcommonsupport", + "libprocessgroup", + "libcgrouprc", + "libjsoncpp", + "libcgrouprc_format", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", @@ -68,6 +72,7 @@ cc_library { "src/DisplayColorProfile.cpp", "src/DisplaySurface.cpp", "src/DumpHelpers.cpp", + "src/HwcAsyncWorker.cpp", "src/HwcBufferCache.cpp", "src/LayerFECompositionState.cpp", "src/Output.cpp", diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h index c553fce85d..ca86f4c604 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h @@ -72,6 +72,9 @@ public: virtual void resizeBuffers(const ui::Size&) = 0; virtual const sp& getClientTargetAcquireFence() const = 0; + + // Returns true if the render surface supports client composition prediction. + virtual bool supportsCompositionStrategyPrediction() const; }; } // namespace compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index d8644a428d..15551029b3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -35,6 +35,7 @@ #include #include +#include "DisplayHardware/HWComposer.h" namespace android { @@ -54,6 +55,7 @@ struct LayerFECompositionState; namespace impl { struct OutputCompositionState; +struct GpuCompositionResult; } // namespace impl /** @@ -262,6 +264,9 @@ public: // Latches the front-end layer state for each output layer virtual void updateLayerStateFromFE(const CompositionRefreshArgs&) const = 0; + // Enables predicting composition strategy to run client composition earlier + virtual void setPredictCompositionStrategy(bool) = 0; + protected: virtual void setDisplayColorProfile(std::unique_ptr) = 0; virtual void setRenderSurface(std::unique_ptr) = 0; @@ -278,13 +283,22 @@ protected: virtual void updateColorProfile(const CompositionRefreshArgs&) = 0; virtual void beginFrame() = 0; virtual void prepareFrame() = 0; + + using GpuCompositionResult = compositionengine::impl::GpuCompositionResult; + // Runs prepare frame in another thread while running client composition using + // the previous frame's composition strategy. + virtual GpuCompositionResult prepareFrameAsync(const CompositionRefreshArgs&) = 0; virtual void devOptRepaintFlash(const CompositionRefreshArgs&) = 0; - virtual void finishFrame(const CompositionRefreshArgs&) = 0; + virtual void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) = 0; virtual std::optional composeSurfaces( - const Region&, const compositionengine::CompositionRefreshArgs& refreshArgs) = 0; + const Region&, const compositionengine::CompositionRefreshArgs&, + std::shared_ptr, base::unique_fd&) = 0; virtual void postFramebuffer() = 0; virtual void renderCachedSets(const CompositionRefreshArgs&) = 0; - virtual void chooseCompositionStrategy() = 0; + virtual std::optional + chooseCompositionStrategy() = 0; + virtual void applyCompositionStrategy( + const std::optional& changes) = 0; virtual bool getSkipColorTransform() const = 0; virtual FrameFences presentAndGetFrameFences() = 0; virtual std::vector generateClientCompositionRequests( @@ -295,6 +309,7 @@ protected: std::vector& clientCompositionLayers) = 0; virtual void setExpensiveRenderingExpected(bool enabled) = 0; virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0; + virtual bool canPredictCompositionStrategy(const CompositionRefreshArgs&) = 0; }; } // namespace compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h index daee83bd2c..9ee779cca1 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h @@ -100,6 +100,9 @@ public: // Debugging - gets the page flip count for the RenderSurface virtual std::uint32_t getPageFlipCount() const = 0; + + // Returns true if the render surface supports client composition prediction. + virtual bool supportsCompositionStrategyPrediction() const = 0; }; } // namespace compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index c7984bd529..47f07b7cc4 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -51,11 +52,14 @@ public: void setReleasedLayers(const CompositionRefreshArgs&) override; void setColorTransform(const CompositionRefreshArgs&) override; void setColorProfile(const ColorProfile&) override; - void chooseCompositionStrategy() override; + + using DeviceRequestedChanges = android::HWComposer::DeviceRequestedChanges; + std::optional chooseCompositionStrategy() override; + void applyCompositionStrategy(const std::optional&) override; bool getSkipColorTransform() const override; compositionengine::Output::FrameFences presentAndGetFrameFences() override; void setExpensiveRenderingExpected(bool) override; - void finishFrame(const CompositionRefreshArgs&) override; + void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) override; // compositionengine::Display overrides DisplayId getId() const override; @@ -73,7 +77,6 @@ public: using DisplayRequests = android::HWComposer::DeviceRequestedChanges::DisplayRequests; using LayerRequests = android::HWComposer::DeviceRequestedChanges::LayerRequests; using ClientTargetProperty = android::HWComposer::DeviceRequestedChanges::ClientTargetProperty; - virtual bool anyLayersRequireClientComposition() const; virtual bool allLayersRequireClientComposition() const; virtual void applyChangedTypesToLayers(const ChangedTypes&); virtual void applyDisplayRequests(const DisplayRequests&); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h new file mode 100644 index 0000000000..ed1ddc172c --- /dev/null +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h @@ -0,0 +1,38 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace android::compositionengine::impl { + +struct GpuCompositionResult { + // True if composition strategy was predicted successfully. + bool succeeded = false; + + // Composition ready fence. + base::unique_fd fence{}; + + // Buffer to be used for gpu composition. If gpu composition was not successful, + // then we want to reuse the buffer instead of dequeuing another buffer. + std::shared_ptr buffer = nullptr; + + bool bufferAvailable() const { return buffer != nullptr; }; +}; + +} // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h new file mode 100644 index 0000000000..11c0054089 --- /dev/null +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h @@ -0,0 +1,57 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include "DisplayHardware/HWComposer.h" + +namespace android::compositionengine::impl { + +// HWC Validate call may take multiple milliseconds to complete and can account for +// a signification amount of time in the display hotpath. This helper class allows +// us to run the hwc validate function on a real time thread if we can predict what +// the composition strategy will be and if composition includes client composition. +// While the hwc validate runs, client composition is kicked off with the prediction. +// When the worker returns with a value, the composition continues if the prediction +// was successful otherwise the client composition is re-executed. +// +// Note: This does not alter the sequence between HWC and surfaceflinger. +class HwcAsyncWorker final { +public: + HwcAsyncWorker(); + ~HwcAsyncWorker(); + // Runs the provided function which calls hwc validate and returns the requested + // device changes as a future. + std::future> send( + std::function()>); + +private: + std::mutex mMutex; + std::condition_variable mCv GUARDED_BY(mMutex); + bool mDone GUARDED_BY(mMutex) = false; + bool mTaskRequested GUARDED_BY(mMutex) = false; + std::packaged_task()> mTask + GUARDED_BY(mMutex); + std::thread mThread; + void run(); +}; + +} // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index a7a8e97be5..0be5d018f6 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -17,9 +17,13 @@ #pragma once #include +#include #include #include +#include +#include #include +#include #include #include #include @@ -92,25 +96,38 @@ public: void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override; void beginFrame() override; void prepareFrame() override; + GpuCompositionResult prepareFrameAsync(const CompositionRefreshArgs&) override; void devOptRepaintFlash(const CompositionRefreshArgs&) override; - void finishFrame(const CompositionRefreshArgs&) override; - std::optional composeSurfaces( - const Region&, const compositionengine::CompositionRefreshArgs& refreshArgs) override; + void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) override; + std::optional composeSurfaces(const Region&, + const compositionengine::CompositionRefreshArgs&, + std::shared_ptr, + base::unique_fd&) override; void postFramebuffer() override; void renderCachedSets(const CompositionRefreshArgs&) override; void cacheClientCompositionRequests(uint32_t) override; + bool canPredictCompositionStrategy(const CompositionRefreshArgs&) override; + void setPredictCompositionStrategy(bool) override; // Testing const ReleasedLayers& getReleasedLayersForTest() const; void setDisplayColorProfileForTest(std::unique_ptr); void setRenderSurfaceForTest(std::unique_ptr); bool plannerEnabled() const { return mPlanner != nullptr; } + virtual bool anyLayersRequireClientComposition() const; + virtual void updateProtectedContentState(); + virtual bool dequeueRenderBuffer(base::unique_fd*, + std::shared_ptr*); + virtual std::future> + chooseCompositionStrategyAsync(); protected: std::unique_ptr createOutputLayer(const sp&) const; std::optional findCurrentOutputLayerForLayer( const sp&) const; - void chooseCompositionStrategy() override; + using DeviceRequestedChanges = android::HWComposer::DeviceRequestedChanges; + std::optional chooseCompositionStrategy() override; + void applyCompositionStrategy(const std::optional&) override{}; bool getSkipColorTransform() const override; compositionengine::Output::FrameFences presentAndGetFrameFences() override; std::vector generateClientCompositionRequests( @@ -131,6 +148,7 @@ protected: private: void dirtyEntireOutput(); compositionengine::OutputLayer* findLayerRequestingBackgroundComposition() const; + void finishPrepareFrame(); ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const; compositionengine::Output::ColorProfile pickColorProfile( const compositionengine::CompositionRefreshArgs&) const; @@ -144,6 +162,7 @@ private: OutputLayer* mLayerRequestingBackgroundBlur = nullptr; std::unique_ptr mClientCompositionRequestCache; std::unique_ptr mPlanner; + std::unique_ptr mHwComposerAsyncWorker; }; // This template factory function standardizes the implementation details of the diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 66dd825e5b..92f22b6a16 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -37,6 +37,8 @@ #include #include +#include "DisplayHardware/HWComposer.h" + namespace android { namespace compositionengine::impl { @@ -114,6 +116,8 @@ struct OutputCompositionState { // Current target dataspace ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN}; + std::optional previousDeviceRequestedChanges{}; + // The earliest time to send the present command to the HAL std::chrono::steady_clock::time_point earliestPresentTime; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h index a8a538003e..e4cb113645 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h @@ -63,6 +63,7 @@ public: void queueBuffer(base::unique_fd readyFence) override; void onPresentDisplayCompleted() override; void flip() override; + bool supportsCompositionStrategyPrediction() const override; // Debugging void dump(std::string& result) const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h index 84afb59510..164984340d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h @@ -41,6 +41,7 @@ public: MOCK_METHOD1(createDisplayColorProfile, void(const DisplayColorProfileCreationArgs&)); MOCK_METHOD1(createRenderSurface, void(const RenderSurfaceCreationArgs&)); MOCK_METHOD1(createClientCompositionCache, void(uint32_t)); + MOCK_METHOD1(setPredictCompositionStrategy, void(bool)); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index b68b95d07b..27303a82be 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -99,16 +100,22 @@ public: MOCK_METHOD0(beginFrame, void()); MOCK_METHOD0(prepareFrame, void()); - MOCK_METHOD0(chooseCompositionStrategy, void()); + MOCK_METHOD1(prepareFrameAsync, GpuCompositionResult(const CompositionRefreshArgs&)); + MOCK_METHOD0(chooseCompositionStrategy, + std::optional()); + MOCK_METHOD1(applyCompositionStrategy, + void(const std::optional&)); MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&)); - MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&)); + MOCK_METHOD2(finishFrame, + void(const compositionengine::CompositionRefreshArgs&, GpuCompositionResult&&)); - MOCK_METHOD2(composeSurfaces, + MOCK_METHOD4(composeSurfaces, std::optional( const Region&, - const compositionengine::CompositionRefreshArgs& refreshArgs)); + const compositionengine::CompositionRefreshArgs& refreshArgs, + std::shared_ptr, base::unique_fd&)); MOCK_CONST_METHOD0(getSkipColorTransform, bool()); MOCK_METHOD0(postFramebuffer, void()); @@ -121,6 +128,8 @@ public: void(const Region&, std::vector&)); MOCK_METHOD1(setExpensiveRenderingExpected, void(bool)); MOCK_METHOD1(cacheClientCompositionRequests, void(uint32_t)); + MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&)); + MOCK_METHOD1(setPredictCompositionStrategy, void(bool)); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h index fe858c2817..e12aebb50c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h @@ -45,6 +45,7 @@ public: MOCK_METHOD0(flip, void()); MOCK_CONST_METHOD1(dump, void(std::string& result)); MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t()); + MOCK_CONST_METHOD0(supportsCompositionStrategyPrediction, bool()); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 6390025725..ecf5ecf0da 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -221,12 +221,12 @@ void Display::setReleasedLayers(const compositionengine::CompositionRefreshArgs& setReleasedLayers(std::move(releasedLayers)); } -void Display::chooseCompositionStrategy() { +std::optional Display::chooseCompositionStrategy() { ATRACE_CALL(); ALOGV(__FUNCTION__); if (mIsDisconnected) { - return; + return {}; } // Default to the base settings -- client composition only. @@ -235,7 +235,7 @@ void Display::chooseCompositionStrategy() { // If we don't have a HWC display, then we are done. const auto halDisplayId = HalDisplayId::tryCast(mId); if (!halDisplayId) { - return; + return {}; } // Get any composition changes requested by the HWC device, and apply them. @@ -260,8 +260,13 @@ void Display::chooseCompositionStrategy() { result != NO_ERROR) { ALOGE("chooseCompositionStrategy failed for %s: %d (%s)", getName().c_str(), result, strerror(-result)); - return; + return {}; } + + return changes; +} + +void Display::applyCompositionStrategy(const std::optional& changes) { if (changes) { applyChangedTypesToLayers(changes->changedTypes); applyDisplayRequests(changes->displayRequests); @@ -287,12 +292,6 @@ bool Display::getSkipColorTransform() const { return hwc.hasCapability(Capability::SKIP_CLIENT_COLOR_TRANSFORM); } -bool Display::anyLayersRequireClientComposition() const { - const auto layers = getOutputLayersOrderedByZ(); - return std::any_of(layers.begin(), layers.end(), - [](const auto& layer) { return layer->requiresClientComposition(); }); -} - bool Display::allLayersRequireClientComposition() const { const auto layers = getOutputLayersOrderedByZ(); return std::all_of(layers.begin(), layers.end(), @@ -390,7 +389,8 @@ void Display::setExpensiveRenderingExpected(bool enabled) { } } -void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) { +void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs, + GpuCompositionResult&& result) { // We only need to actually compose the display if: // 1) It is being handled by hardware composer, which may need this to // keep its virtual display state machine in sync, or @@ -400,7 +400,7 @@ void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refre return; } - impl::Output::finishFrame(refreshArgs); + impl::Output::finishFrame(refreshArgs, std::move(result)); } } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp index db6d4f2fed..28900af162 100644 --- a/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp @@ -20,4 +20,8 @@ namespace android::compositionengine { DisplaySurface::~DisplaySurface() = default; +bool DisplaySurface::supportsCompositionStrategyPrediction() const { + return true; +} + } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp b/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp new file mode 100644 index 0000000000..497424a327 --- /dev/null +++ b/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp @@ -0,0 +1,73 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace android::compositionengine::impl { + +HwcAsyncWorker::HwcAsyncWorker() { + mThread = std::thread(&HwcAsyncWorker::run, this); + pthread_setname_np(mThread.native_handle(), "HwcAsyncWorker"); +} + +HwcAsyncWorker::~HwcAsyncWorker() { + { + std::scoped_lock lock(mMutex); + mDone = true; + mCv.notify_all(); + } + if (mThread.joinable()) { + mThread.join(); + } +} +std::future> HwcAsyncWorker::send( + std::function()> task) { + std::unique_lock lock(mMutex); + android::base::ScopedLockAssertion assumeLock(mMutex); + mTask = std::packaged_task()>( + [task = std::move(task)]() { return task(); }); + mTaskRequested = true; + mCv.notify_one(); + return mTask.get_future(); +} + +void HwcAsyncWorker::run() { + set_sched_policy(0, SP_FOREGROUND); + struct sched_param param = {0}; + param.sched_priority = 2; + sched_setscheduler(gettid(), SCHED_FIFO, ¶m); + + std::unique_lock lock(mMutex); + android::base::ScopedLockAssertion assumeLock(mMutex); + while (!mDone) { + mCv.wait(lock); + if (mTaskRequested && mTask.valid()) { + mTask(); + mTaskRequested = false; + } + } +} + +} // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index ff332ebe2c..8d560d732c 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -434,9 +435,17 @@ void Output::present(const compositionengine::CompositionRefreshArgs& refreshArg writeCompositionState(refreshArgs); setColorTransform(refreshArgs); beginFrame(); - prepareFrame(); + + GpuCompositionResult result; + const bool predictCompositionStrategy = canPredictCompositionStrategy(refreshArgs); + if (predictCompositionStrategy) { + result = prepareFrameAsync(refreshArgs); + } else { + prepareFrame(); + } + devOptRepaintFlash(refreshArgs); - finishFrame(refreshArgs); + finishFrame(refreshArgs, std::move(result)); postFramebuffer(); renderCachedSets(refreshArgs); } @@ -951,19 +960,62 @@ void Output::prepareFrame() { ATRACE_CALL(); ALOGV(__FUNCTION__); - const auto& outputState = getState(); + auto& outputState = editState(); if (!outputState.isEnabled) { return; } - chooseCompositionStrategy(); + auto changes = chooseCompositionStrategy(); + outputState.previousDeviceRequestedChanges = changes; + if (changes) { + applyCompositionStrategy(changes); + } + finishPrepareFrame(); +} - if (mPlanner) { - mPlanner->reportFinalPlan(getOutputLayersOrderedByZ()); +std::future> +Output::chooseCompositionStrategyAsync() { + return mHwComposerAsyncWorker->send([&]() { return chooseCompositionStrategy(); }); +} + +GpuCompositionResult Output::prepareFrameAsync(const CompositionRefreshArgs& refreshArgs) { + ATRACE_CALL(); + ALOGV(__FUNCTION__); + auto& state = editState(); + const auto& previousChanges = state.previousDeviceRequestedChanges; + auto hwcResult = chooseCompositionStrategyAsync(); + applyCompositionStrategy(previousChanges); + finishPrepareFrame(); + + base::unique_fd bufferFence; + std::shared_ptr buffer; + updateProtectedContentState(); + const bool dequeueSucceeded = dequeueRenderBuffer(&bufferFence, &buffer); + GpuCompositionResult compositionResult; + if (dequeueSucceeded) { + std::optional optFd = + composeSurfaces(Region::INVALID_REGION, refreshArgs, buffer, bufferFence); + if (optFd) { + compositionResult.fence = std::move(*optFd); + } } - mRenderSurface->prepareFrame(outputState.usesClientComposition, - outputState.usesDeviceComposition); + auto changes = hwcResult.valid() ? hwcResult.get() : std::nullopt; + const bool predictionSucceeded = dequeueSucceeded && changes == previousChanges; + compositionResult.succeeded = predictionSucceeded; + if (!predictionSucceeded) { + ATRACE_NAME("CompositionStrategyPredictionMiss"); + if (changes) { + applyCompositionStrategy(changes); + } + finishPrepareFrame(); + // Track the dequeued buffer to reuse so we don't need to dequeue another one. + compositionResult.buffer = buffer; + } else { + ATRACE_NAME("CompositionStrategyPredictionHit"); + } + state.previousDeviceRequestedChanges = std::move(changes); + return compositionResult; } void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& refreshArgs) { @@ -973,7 +1025,11 @@ void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& if (getState().isEnabled) { if (const auto dirtyRegion = getDirtyRegion(); !dirtyRegion.isEmpty()) { - static_cast(composeSurfaces(dirtyRegion, refreshArgs)); + base::unique_fd bufferFence; + std::shared_ptr buffer; + updateProtectedContentState(); + dequeueRenderBuffer(&bufferFence, &buffer); + static_cast(composeSurfaces(dirtyRegion, refreshArgs, buffer, bufferFence)); mRenderSurface->queueBuffer(base::unique_fd()); } } @@ -985,7 +1041,7 @@ void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& prepareFrame(); } -void Output::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) { +void Output::finishFrame(const CompositionRefreshArgs& refreshArgs, GpuCompositionResult&& result) { ATRACE_CALL(); ALOGV(__FUNCTION__); @@ -993,9 +1049,25 @@ void Output::finishFrame(const compositionengine::CompositionRefreshArgs& refres return; } - // Repaint the framebuffer (if needed), getting the optional fence for when - // the composition completes. - auto optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs); + std::optional optReadyFence; + std::shared_ptr buffer; + base::unique_fd bufferFence; + if (result.succeeded) { + optReadyFence = std::move(result.fence); + } else { + if (result.bufferAvailable()) { + buffer = std::move(result.buffer); + bufferFence = std::move(result.fence); + } else { + updateProtectedContentState(); + if (!dequeueRenderBuffer(&bufferFence, &buffer)) { + return; + } + } + // Repaint the framebuffer (if needed), getting the optional fence for when + // the composition completes. + optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs, buffer, bufferFence); + } if (!optReadyFence) { return; } @@ -1004,16 +1076,8 @@ void Output::finishFrame(const compositionengine::CompositionRefreshArgs& refres mRenderSurface->queueBuffer(std::move(*optReadyFence)); } -std::optional Output::composeSurfaces( - const Region& debugRegion, const compositionengine::CompositionRefreshArgs& refreshArgs) { - ATRACE_CALL(); - ALOGV(__FUNCTION__); - +void Output::updateProtectedContentState() { const auto& outputState = getState(); - OutputCompositionState& outputCompositionState = editState(); - const TracedOrdinal hasClientComposition = {"hasClientComposition", - outputState.usesClientComposition}; - auto& renderEngine = getCompositionEngine().getRenderEngine(); const bool supportsProtectedContent = renderEngine.supportsProtectedContent(); @@ -1035,29 +1099,48 @@ std::optional Output::composeSurfaces( } else if (!outputState.isSecure && renderEngine.isProtected()) { renderEngine.useProtectedContext(false); } +} - base::unique_fd fd; - - std::shared_ptr tex; +bool Output::dequeueRenderBuffer(base::unique_fd* bufferFence, + std::shared_ptr* tex) { + const auto& outputState = getState(); // If we aren't doing client composition on this output, but do have a // flipClientTarget request for this frame on this output, we still need to // dequeue a buffer. - if (hasClientComposition || outputState.flipClientTarget) { - tex = mRenderSurface->dequeueBuffer(&fd); - if (tex == nullptr) { + if (outputState.usesClientComposition || outputState.flipClientTarget) { + *tex = mRenderSurface->dequeueBuffer(bufferFence); + if (*tex == nullptr) { ALOGW("Dequeuing buffer for display [%s] failed, bailing out of " "client composition for this frame", mName.c_str()); - return {}; + return false; } } + return true; +} +std::optional Output::composeSurfaces( + const Region& debugRegion, const compositionengine::CompositionRefreshArgs& refreshArgs, + std::shared_ptr tex, base::unique_fd& fd) { + ATRACE_CALL(); + ALOGV(__FUNCTION__); + + const auto& outputState = getState(); + const TracedOrdinal hasClientComposition = {"hasClientComposition", + outputState.usesClientComposition}; if (!hasClientComposition) { setExpensiveRenderingExpected(false); return base::unique_fd(); } + if (tex == nullptr) { + ALOGW("Buffer not valid for display [%s], bailing out of " + "client composition for this frame", + mName.c_str()); + return {}; + } + ALOGV("hasClientComposition"); renderengine::DisplaySettings clientCompositionDisplay; @@ -1085,6 +1168,8 @@ std::optional Output::composeSurfaces( outputState.usesDeviceComposition || getSkipColorTransform(); // Generate the client composition requests for the layers on this output. + auto& renderEngine = getCompositionEngine().getRenderEngine(); + const bool supportsProtectedContent = renderEngine.supportsProtectedContent(); std::vector clientCompositionLayersFE; std::vector clientCompositionLayers = generateClientCompositionRequests(supportsProtectedContent, @@ -1092,16 +1177,19 @@ std::optional Output::composeSurfaces( clientCompositionLayersFE); appendRegionFlashRequests(debugRegion, clientCompositionLayers); + OutputCompositionState& outputCompositionState = editState(); // Check if the client composition requests were rendered into the provided graphic buffer. If // so, we can reuse the buffer and avoid client composition. if (mClientCompositionRequestCache) { if (mClientCompositionRequestCache->exists(tex->getBuffer()->getId(), clientCompositionDisplay, clientCompositionLayers)) { + ATRACE_NAME("ClientCompositionCacheHit"); outputCompositionState.reusedClientComposition = true; setExpensiveRenderingExpected(false); return base::unique_fd(); } + ATRACE_NAME("ClientCompositionCacheMiss"); mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay, clientCompositionLayers); } @@ -1349,12 +1437,13 @@ void Output::dirtyEntireOutput() { outputState.dirtyRegion.set(outputState.displaySpace.getBoundsAsRect()); } -void Output::chooseCompositionStrategy() { +std::optional Output::chooseCompositionStrategy() { // The base output implementation can only do client composition auto& outputState = editState(); outputState.usesClientComposition = true; outputState.usesDeviceComposition = false; outputState.reusedClientComposition = false; + return {}; } bool Output::getSkipColorTransform() const { @@ -1369,5 +1458,63 @@ compositionengine::Output::FrameFences Output::presentAndGetFrameFences() { return result; } +void Output::setPredictCompositionStrategy(bool predict) { + if (predict) { + mHwComposerAsyncWorker = std::make_unique(); + } else { + mHwComposerAsyncWorker.reset(nullptr); + } +} + +bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) { + if (!getState().isEnabled || !mHwComposerAsyncWorker) { + ALOGV("canPredictCompositionStrategy disabled"); + return false; + } + + if (!getState().previousDeviceRequestedChanges) { + ALOGV("canPredictCompositionStrategy previous changes not available"); + return false; + } + + if (!mRenderSurface->supportsCompositionStrategyPrediction()) { + ALOGV("canPredictCompositionStrategy surface does not support"); + return false; + } + + if (refreshArgs.devOptFlashDirtyRegionsDelay) { + ALOGV("canPredictCompositionStrategy devOptFlashDirtyRegionsDelay"); + return false; + } + + // If no layer uses clientComposition, then don't predict composition strategy + // because we have less work to do in parallel. + if (!anyLayersRequireClientComposition()) { + ALOGV("canPredictCompositionStrategy no layer uses clientComposition"); + return false; + } + + if (!refreshArgs.updatingOutputGeometryThisFrame) { + return true; + } + + ALOGV("canPredictCompositionStrategy updatingOutputGeometryThisFrame"); + return false; +} + +bool Output::anyLayersRequireClientComposition() const { + const auto layers = getOutputLayersOrderedByZ(); + return std::any_of(layers.begin(), layers.end(), + [](const auto& layer) { return layer->requiresClientComposition(); }); +} + +void Output::finishPrepareFrame() { + const auto& state = getState(); + if (mPlanner) { + mPlanner->reportFinalPlan(getOutputLayersOrderedByZ()); + } + mRenderSurface->prepareFrame(state.usesClientComposition, state.usesDeviceComposition); +} + } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index 12c2c8eb38..5a3af7bfea 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -289,5 +289,9 @@ std::shared_ptr& RenderSurface::mutableTextureFor return mTexture; } +bool RenderSurface::supportsCompositionStrategyPrediction() const { + return mDisplaySurface->supportsCompositionStrategyPrediction(); +} + } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index cd0323555c..36b04d909f 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -30,7 +30,9 @@ #include #include #include +#include #include + #include #include @@ -198,6 +200,22 @@ struct PartialMockDisplayTestCommon : public DisplayTestCommon { std::shared_ptr mDisplay = createPartialMockDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay()); + + android::HWComposer::DeviceRequestedChanges mDeviceRequestedChanges{ + {{nullptr, Composition::CLIENT}}, + hal::DisplayRequest::FLIP_CLIENT_TARGET, + {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}}, + {hal::PixelFormat::RGBA_8888, hal::Dataspace::UNKNOWN}, + -1.f, + }; + + void chooseCompositionStrategy(Display* display) { + std::optional changes = + display->chooseCompositionStrategy(); + if (changes) { + display->applyCompositionStrategy(changes); + } + } }; struct FullDisplayImplTestCommon : public DisplayTestCommon { @@ -214,6 +232,11 @@ struct DisplayWithLayersTestCommon : public FullDisplayImplTestCommon { std::unique_ptr(mLayer2.outputLayer)); mDisplay->injectOutputLayerForTest( std::unique_ptr(mLayer3.outputLayer)); + mResultWithBuffer.buffer = std::make_shared< + renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 1ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); } Layer mLayer1; @@ -222,6 +245,8 @@ struct DisplayWithLayersTestCommon : public FullDisplayImplTestCommon { StrictMock hwc2LayerUnknown; std::shared_ptr mDisplay = createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay()); + impl::GpuCompositionResult mResultWithBuffer; + impl::GpuCompositionResult mResultWithoutBuffer; }; /* @@ -554,7 +579,7 @@ TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfGpuDisplay) { createPartialMockDisplay(mCompositionEngine, args); EXPECT_TRUE(GpuVirtualDisplayId::tryCast(gpuDisplay->getId())); - gpuDisplay->chooseCompositionStrategy(); + chooseCompositionStrategy(gpuDisplay.get()); auto& state = gpuDisplay->getState(); EXPECT_TRUE(state.usesClientComposition); @@ -567,11 +592,12 @@ TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutOnHwcError) { getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), false, _, _, _, _)) .WillOnce(Return(INVALID_OPERATION)); - mDisplay->chooseCompositionStrategy(); + chooseCompositionStrategy(mDisplay.get()); auto& state = mDisplay->getState(); EXPECT_TRUE(state.usesClientComposition); EXPECT_FALSE(state.usesDeviceComposition); + EXPECT_FALSE(state.previousDeviceRequestedChanges.has_value()); } TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) { @@ -588,10 +614,16 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) { EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _)) - .WillOnce(Return(NO_ERROR)); + .WillOnce(testing::DoAll(testing::SetArgPointee<5>(mDeviceRequestedChanges), + Return(NO_ERROR))); + EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes)) + .Times(1); + EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1); + EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests)) + .Times(1); EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); - mDisplay->chooseCompositionStrategy(); + chooseCompositionStrategy(mDisplay.get()); auto& state = mDisplay->getState(); EXPECT_FALSE(state.usesClientComposition); @@ -618,11 +650,17 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithDisplayBrightnes EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _)) - .WillOnce(Return(NO_ERROR)); + .WillOnce(testing::DoAll(testing::SetArgPointee<5>(mDeviceRequestedChanges), + Return(NO_ERROR))); + EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes)) + .Times(1); + EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1); + EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests)) + .Times(1); EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); mDisplay->setNextBrightness(kDisplayBrightness); - mDisplay->chooseCompositionStrategy(); + chooseCompositionStrategy(mDisplay.get()); auto& state = mDisplay->getState(); EXPECT_FALSE(state.usesClientComposition); @@ -631,14 +669,6 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithDisplayBrightnes } TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { - android::HWComposer::DeviceRequestedChanges changes{ - {{nullptr, Composition::CLIENT}}, - hal::DisplayRequest::FLIP_CLIENT_TARGET, - {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}}, - {hal::PixelFormat::RGBA_8888, hal::Dataspace::UNKNOWN}, - -1.f, - }; - // Since two calls are made to anyLayersRequireClientComposition with different return // values, use a Sequence to control the matching so the values are returned in a known // order. @@ -652,13 +682,15 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _)) - .WillOnce(DoAll(SetArgPointee<5>(changes), Return(NO_ERROR))); - EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1); - EXPECT_CALL(*mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1); - EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1); + .WillOnce(DoAll(SetArgPointee<5>(mDeviceRequestedChanges), Return(NO_ERROR))); + EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes)) + .Times(1); + EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1); + EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests)) + .Times(1); EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); - mDisplay->chooseCompositionStrategy(); + chooseCompositionStrategy(mDisplay.get()); auto& state = mDisplay->getState(); EXPECT_FALSE(state.usesClientComposition); @@ -922,7 +954,7 @@ TEST_F(DisplayFinishFrameTest, doesNotSkipCompositionIfNotDirtyOnHwcDisplay) { mDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1)); mDisplay->editState().dirtyRegion = Region::INVALID_REGION; - mDisplay->finishFrame({}); + mDisplay->finishFrame({}, std::move(mResultWithBuffer)); } TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) { @@ -940,7 +972,7 @@ TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) { gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1)); gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION; - gpuDisplay->finishFrame({}); + gpuDisplay->finishFrame({}, std::move(mResultWithoutBuffer)); } TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) { @@ -957,7 +989,7 @@ TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) { gpuDisplay->editState().usesClientComposition = false; gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1)); gpuDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1)); - gpuDisplay->finishFrame({}); + gpuDisplay->finishFrame({}, std::move(mResultWithBuffer)); } /* diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index c2521b2fc2..4e875c8a25 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -989,7 +990,7 @@ struct OutputPrepareFrameTest : public testing::Test { struct OutputPartialMock : public OutputPartialMockBase { // Sets up the helper functions called by the function under test to use // mock implementations. - MOCK_METHOD0(chooseCompositionStrategy, void()); + MOCK_METHOD0(chooseCompositionStrategy, std::optional()); }; OutputPrepareFrameTest() { @@ -1037,6 +1038,133 @@ TEST_F(OutputTest, prepareFrameSetsClientCompositionOnlyByDefault) { EXPECT_FALSE(mOutput->getState().usesDeviceComposition); } +struct OutputPrepareFrameAsyncTest : public testing::Test { + struct OutputPartialMock : public OutputPartialMockBase { + // Sets up the helper functions called by the function under test to use + // mock implementations. + MOCK_METHOD0(chooseCompositionStrategy, std::optional()); + MOCK_METHOD0(updateProtectedContentState, void()); + MOCK_METHOD2(dequeueRenderBuffer, + bool(base::unique_fd*, std::shared_ptr*)); + MOCK_METHOD0(chooseCompositionStrategyAsync, + std::future>()); + MOCK_METHOD4(composeSurfaces, + std::optional( + const Region&, const compositionengine::CompositionRefreshArgs&, + std::shared_ptr, base::unique_fd&)); + }; + + OutputPrepareFrameAsyncTest() { + mOutput.setDisplayColorProfileForTest( + std::unique_ptr(mDisplayColorProfile)); + mOutput.setRenderSurfaceForTest(std::unique_ptr(mRenderSurface)); + } + + StrictMock mCompositionEngine; + mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock(); + mock::RenderSurface* mRenderSurface = new StrictMock(); + StrictMock mOutput; + CompositionRefreshArgs mRefreshArgs; +}; + +TEST_F(OutputPrepareFrameAsyncTest, delegatesToChooseCompositionStrategyAndRenderSurface) { + mOutput.editState().isEnabled = true; + mOutput.editState().usesClientComposition = false; + mOutput.editState().usesDeviceComposition = true; + mOutput.editState().previousDeviceRequestedChanges = + std::make_optional({}); + std::promise> p; + p.set_value(mOutput.editState().previousDeviceRequestedChanges); + + EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); + EXPECT_CALL(mOutput, updateProtectedContentState()); + EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true)); + EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)); + EXPECT_CALL(mOutput, chooseCompositionStrategyAsync()).WillOnce([&] { return p.get_future(); }); + EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _)); + + impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs); + EXPECT_TRUE(result.succeeded); + EXPECT_FALSE(result.bufferAvailable()); +} + +TEST_F(OutputPrepareFrameAsyncTest, skipCompositionOnDequeueFailure) { + mOutput.editState().isEnabled = true; + mOutput.editState().usesClientComposition = false; + mOutput.editState().usesDeviceComposition = true; + mOutput.editState().previousDeviceRequestedChanges = + std::make_optional({}); + std::promise> p; + p.set_value(mOutput.editState().previousDeviceRequestedChanges); + + EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); + EXPECT_CALL(mOutput, updateProtectedContentState()); + EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(false)); + EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2); + EXPECT_CALL(mOutput, chooseCompositionStrategyAsync()).WillOnce([&] { return p.get_future(); }); + + impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs); + EXPECT_FALSE(result.succeeded); + EXPECT_FALSE(result.bufferAvailable()); +} + +// Tests that in the event of hwc error when choosing composition strategy, we would fall back +// client composition +TEST_F(OutputPrepareFrameAsyncTest, chooseCompositionStrategyFailureCallsPrepareFrame) { + mOutput.editState().isEnabled = true; + mOutput.editState().usesClientComposition = false; + mOutput.editState().usesDeviceComposition = true; + mOutput.editState().previousDeviceRequestedChanges = + std::make_optional({}); + std::promise> p; + p.set_value({}); + std::shared_ptr tex = + std::make_shared(1, 1, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + 2); + + EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); + EXPECT_CALL(mOutput, updateProtectedContentState()); + EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(tex), Return(true))); + EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2); + EXPECT_CALL(mOutput, chooseCompositionStrategyAsync()).WillOnce([&] { return p.get_future(); }); + EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _)); + + impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs); + EXPECT_FALSE(result.succeeded); + EXPECT_TRUE(result.bufferAvailable()); +} + +TEST_F(OutputPrepareFrameAsyncTest, predictionMiss) { + mOutput.editState().isEnabled = true; + mOutput.editState().usesClientComposition = false; + mOutput.editState().usesDeviceComposition = true; + mOutput.editState().previousDeviceRequestedChanges = + std::make_optional({}); + auto newDeviceRequestedChanges = + std::make_optional({}); + newDeviceRequestedChanges->clientTargetBrightness = 5.f; + std::promise> p; + p.set_value(newDeviceRequestedChanges); + std::shared_ptr tex = + std::make_shared(1, 1, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + 2); + + EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); + EXPECT_CALL(mOutput, updateProtectedContentState()); + EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(tex), Return(true))); + EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2); + EXPECT_CALL(mOutput, chooseCompositionStrategyAsync()).WillOnce([&] { return p.get_future(); }); + EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _)); + + impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs); + EXPECT_FALSE(result.succeeded); + EXPECT_TRUE(result.bufferAvailable()); +} + /* * Output::prepare() */ @@ -1795,10 +1923,14 @@ struct OutputPresentTest : public testing::Test { MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&)); MOCK_METHOD0(beginFrame, void()); MOCK_METHOD0(prepareFrame, void()); + MOCK_METHOD1(prepareFrameAsync, GpuCompositionResult(const CompositionRefreshArgs&)); MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&)); - MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&)); + MOCK_METHOD2(finishFrame, + void(const compositionengine::CompositionRefreshArgs&, + GpuCompositionResult&&)); MOCK_METHOD0(postFramebuffer, void()); MOCK_METHOD1(renderCachedSets, void(const compositionengine::CompositionRefreshArgs&)); + MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&)); }; StrictMock mOutput; @@ -1814,9 +1946,30 @@ TEST_F(OutputPresentTest, justInvokesChildFunctionsInSequence) { EXPECT_CALL(mOutput, writeCompositionState(Ref(args))); EXPECT_CALL(mOutput, setColorTransform(Ref(args))); EXPECT_CALL(mOutput, beginFrame()); + EXPECT_CALL(mOutput, canPredictCompositionStrategy(Ref(args))).WillOnce(Return(false)); EXPECT_CALL(mOutput, prepareFrame()); EXPECT_CALL(mOutput, devOptRepaintFlash(Ref(args))); - EXPECT_CALL(mOutput, finishFrame(Ref(args))); + EXPECT_CALL(mOutput, finishFrame(Ref(args), _)); + EXPECT_CALL(mOutput, postFramebuffer()); + EXPECT_CALL(mOutput, renderCachedSets(Ref(args))); + + mOutput.present(args); +} + +TEST_F(OutputPresentTest, predictingCompositionStrategyInvokesPrepareFrameAsync) { + CompositionRefreshArgs args; + + InSequence seq; + EXPECT_CALL(mOutput, updateColorProfile(Ref(args))); + EXPECT_CALL(mOutput, updateCompositionState(Ref(args))); + EXPECT_CALL(mOutput, planComposition()); + EXPECT_CALL(mOutput, writeCompositionState(Ref(args))); + EXPECT_CALL(mOutput, setColorTransform(Ref(args))); + EXPECT_CALL(mOutput, beginFrame()); + EXPECT_CALL(mOutput, canPredictCompositionStrategy(Ref(args))).WillOnce(Return(true)); + EXPECT_CALL(mOutput, prepareFrameAsync(Ref(args))); + EXPECT_CALL(mOutput, devOptRepaintFlash(Ref(args))); + EXPECT_CALL(mOutput, finishFrame(Ref(args), _)); EXPECT_CALL(mOutput, postFramebuffer()); EXPECT_CALL(mOutput, renderCachedSets(Ref(args))); @@ -2714,11 +2867,15 @@ struct OutputDevOptRepaintFlashTest : public testing::Test { // Sets up the helper functions called by the function under test to use // mock implementations. MOCK_METHOD(Region, getDirtyRegion, (), (const)); - MOCK_METHOD2(composeSurfaces, + MOCK_METHOD4(composeSurfaces, std::optional( - const Region&, const compositionengine::CompositionRefreshArgs&)); + const Region&, const compositionengine::CompositionRefreshArgs&, + std::shared_ptr, base::unique_fd&)); MOCK_METHOD0(postFramebuffer, void()); MOCK_METHOD0(prepareFrame, void()); + MOCK_METHOD0(updateProtectedContentState, void()); + MOCK_METHOD2(dequeueRenderBuffer, + bool(base::unique_fd*, std::shared_ptr*)); }; OutputDevOptRepaintFlashTest() { @@ -2775,7 +2932,9 @@ TEST_F(OutputDevOptRepaintFlashTest, alsoComposesSurfacesAndQueuesABufferIfDirty InSequence seq; EXPECT_CALL(mOutput, getDirtyRegion()).WillOnce(Return(kNotEmptyRegion)); - EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs))); + EXPECT_CALL(mOutput, updateProtectedContentState()); + EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)); + EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs), _, _)); EXPECT_CALL(*mRenderSurface, queueBuffer(_)); EXPECT_CALL(mOutput, postFramebuffer()); EXPECT_CALL(mOutput, prepareFrame()); @@ -2791,10 +2950,14 @@ struct OutputFinishFrameTest : public testing::Test { struct OutputPartialMock : public OutputPartialMockBase { // Sets up the helper functions called by the function under test to use // mock implementations. - MOCK_METHOD2(composeSurfaces, + MOCK_METHOD4(composeSurfaces, std::optional( - const Region&, const compositionengine::CompositionRefreshArgs&)); + const Region&, const compositionengine::CompositionRefreshArgs&, + std::shared_ptr, base::unique_fd&)); MOCK_METHOD0(postFramebuffer, void()); + MOCK_METHOD0(updateProtectedContentState, void()); + MOCK_METHOD2(dequeueRenderBuffer, + bool(base::unique_fd*, std::shared_ptr*)); }; OutputFinishFrameTest() { @@ -2812,27 +2975,63 @@ struct OutputFinishFrameTest : public testing::Test { TEST_F(OutputFinishFrameTest, ifNotEnabledDoesNothing) { mOutput.mState.isEnabled = false; - mOutput.finishFrame(mRefreshArgs); + impl::GpuCompositionResult result; + mOutput.finishFrame(mRefreshArgs, std::move(result)); } TEST_F(OutputFinishFrameTest, takesEarlyOutifComposeSurfacesReturnsNoFence) { mOutput.mState.isEnabled = true; + EXPECT_CALL(mOutput, updateProtectedContentState()); + EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true)); + EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _, _)); - InSequence seq; - EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _)); - - mOutput.finishFrame(mRefreshArgs); + impl::GpuCompositionResult result; + mOutput.finishFrame(mRefreshArgs, std::move(result)); } TEST_F(OutputFinishFrameTest, queuesBufferIfComposeSurfacesReturnsAFence) { mOutput.mState.isEnabled = true; InSequence seq; - EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _)) + EXPECT_CALL(mOutput, updateProtectedContentState()); + EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true)); + EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _, _)) .WillOnce(Return(ByMove(base::unique_fd()))); EXPECT_CALL(*mRenderSurface, queueBuffer(_)); - mOutput.finishFrame(mRefreshArgs); + impl::GpuCompositionResult result; + mOutput.finishFrame(mRefreshArgs, std::move(result)); +} + +TEST_F(OutputFinishFrameTest, predictionSucceeded) { + mOutput.mState.isEnabled = true; + + InSequence seq; + EXPECT_CALL(*mRenderSurface, queueBuffer(_)); + + impl::GpuCompositionResult result; + result.succeeded = true; + mOutput.finishFrame(mRefreshArgs, std::move(result)); +} + +TEST_F(OutputFinishFrameTest, predictionFailedAndBufferIsReused) { + mOutput.mState.isEnabled = true; + + InSequence seq; + + impl::GpuCompositionResult result; + result.succeeded = false; + result.buffer = + std::make_shared(1, 1, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + 2); + + EXPECT_CALL(mOutput, + composeSurfaces(RegionEq(Region::INVALID_REGION), _, result.buffer, + Eq(ByRef(result.fence)))) + .WillOnce(Return(ByMove(base::unique_fd()))); + EXPECT_CALL(*mRenderSurface, queueBuffer(_)); + mOutput.finishFrame(mRefreshArgs, std::move(result)); } /* @@ -3079,8 +3278,15 @@ struct OutputComposeSurfacesTest : public testing::Test { struct ExecuteState : public CallOrderStateMachineHelper { auto execute() { - getInstance()->mReadyFence = - getInstance()->mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fence; + std::shared_ptr externalTexture; + const bool success = + getInstance()->mOutput.dequeueRenderBuffer(&fence, &externalTexture); + if (success) { + getInstance()->mReadyFence = + getInstance()->mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, + externalTexture, fence); + } return nextState(); } }; @@ -3641,7 +3847,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifDisplayIsNotSecure) EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true)); EXPECT_CALL(mRenderEngine, useProtectedContext(false)); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifRenderEngineDoesNotSupportIt) { @@ -3649,7 +3859,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifRenderEngineDoesNotS mLayer2.mLayerFEState.hasProtectedContent = true; EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false)); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNoProtectedContentLayers) { @@ -3661,7 +3875,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNoProtectedContentLa EXPECT_CALL(mRenderEngine, useProtectedContext(false)); EXPECT_CALL(*mRenderSurface, setProtected(false)); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) { @@ -3683,7 +3901,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) { .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEverywhere) { @@ -3693,7 +3915,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEveryw EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true)); EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true)); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifFailsToEnableInRenderEngine) { @@ -3704,7 +3930,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifFailsToEnableInRende EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false)); EXPECT_CALL(mRenderEngine, useProtectedContext(true)); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderEngine) { @@ -3715,7 +3945,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRend EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false)); EXPECT_CALL(*mRenderSurface, setProtected(true)); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderSurface) { @@ -3726,7 +3960,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRend EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true)); EXPECT_CALL(mRenderEngine, useProtectedContext(true)); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } struct OutputComposeSurfacesTest_SetsExpensiveRendering : public OutputComposeSurfacesTest { @@ -3755,7 +3993,11 @@ TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering, IfExepensiveOutputDatas .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } struct OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur @@ -3790,7 +4032,12 @@ TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur, IfBlursAreExpen mOutput.writeCompositionState(mRefreshArgs); EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)); - mOutput.composeSurfaces(kDebugRegion, mRefreshArgs); + + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, mRefreshArgs, tex, fd); } TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur, IfBlursAreNotExpensive) { @@ -3800,7 +4047,12 @@ TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur, IfBlursAreNotEx mOutput.writeCompositionState(mRefreshArgs); EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)).Times(0); - mOutput.composeSurfaces(kDebugRegion, mRefreshArgs); + + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, mRefreshArgs, tex, fd); } /* diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index eef00522dc..87119ee09d 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -91,6 +91,7 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) static_cast(SurfaceFlinger::maxFrameBufferAcquiredBuffers)); } + mCompositionDisplay->setPredictCompositionStrategy(mFlinger->mPredictCompositionStrategy); mCompositionDisplay->createDisplayColorProfile( compositionengine::DisplayColorProfileCreationArgsBuilder() .setHasWideColorGamut(args.hasWideColorGamut) diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 5b2e265eb6..a8d439b7e0 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -269,6 +269,14 @@ public: support) = 0; }; +static inline bool operator==(const android::HWComposer::DeviceRequestedChanges& lhs, + const android::HWComposer::DeviceRequestedChanges& rhs) { + return lhs.changedTypes == rhs.changedTypes && lhs.displayRequests == rhs.displayRequests && + lhs.layerRequests == rhs.layerRequests && + lhs.clientTargetProperty == rhs.clientTargetProperty && + lhs.clientTargetBrightness == rhs.clientTargetBrightness; +} + namespace impl { class HWComposer final : public android::HWComposer { diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 307da41667..e21095aa88 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -89,6 +89,9 @@ public: virtual void dumpAsString(String8& result) const; virtual void resizeBuffers(const ui::Size&) override; virtual const sp& getClientTargetAcquireFence() const override; + // Virtual display surface needs to prepare the frame based on composition type. Skip + // any client composition prediction. + virtual bool supportsCompositionStrategyPrediction() const override { return false; }; private: enum Source : size_t { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5ccbccf85e..c8f0dfb9d0 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -480,6 +480,9 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("debug.sf.disable_client_composition_cache", value, "0"); mDisableClientCompositionCache = atoi(value); + property_get("debug.sf.predict_hwc_composition_strategy", value, "0"); + mPredictCompositionStrategy = atoi(value); + // We should be reading 'persist.sys.sf.color_saturation' here // but since /data may be encrypted, we need to wait until after vold // comes online to attempt to read the property. The property is diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a7ff2459aa..58298387c1 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -344,6 +344,11 @@ public: void disableExpensiveRendering(); FloatRect getMaxDisplayBounds(); + // If set, composition engine tries to predict the composition strategy provided by HWC + // based on the previous frame. If the strategy can be predicted, gpu composition will + // run parallel to the hwc validateDisplay call and re-run if the predition is incorrect. + bool mPredictCompositionStrategy = false; + protected: // We're reference counted, never destroy SurfaceFlinger directly virtual ~SurfaceFlinger(); -- cgit v1.2.3-59-g8ed1b From 6fe2befa82f1f54c07891f33706e1b1d6672f927 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 9 Mar 2022 13:49:41 -0800 Subject: Revert "SF: Predict HWC composition strategy" This reverts commit 7234fa59245e20b934a15ebbd27d4e189ad224d0. Change-Id: I908f9c279bb91ce2ee654a05eb8ac8d0057caa47 Bug: 223543469 --- .../surfaceflinger/CompositionEngine/Android.bp | 5 - .../include/compositionengine/DisplaySurface.h | 3 - .../include/compositionengine/Output.h | 21 +- .../include/compositionengine/RenderSurface.h | 3 - .../include/compositionengine/impl/Display.h | 9 +- .../compositionengine/impl/GpuCompositionResult.h | 38 --- .../compositionengine/impl/HwcAsyncWorker.h | 57 ---- .../include/compositionengine/impl/Output.h | 27 +- .../impl/OutputCompositionState.h | 4 - .../include/compositionengine/impl/RenderSurface.h | 1 - .../include/compositionengine/mock/Display.h | 1 - .../include/compositionengine/mock/Output.h | 17 +- .../include/compositionengine/mock/RenderSurface.h | 1 - .../CompositionEngine/src/Display.cpp | 24 +- .../CompositionEngine/src/DisplaySurface.cpp | 4 - .../CompositionEngine/src/HwcAsyncWorker.cpp | 73 ----- .../CompositionEngine/src/Output.cpp | 207 ++------------ .../CompositionEngine/src/RenderSurface.cpp | 4 - .../CompositionEngine/tests/DisplayTest.cpp | 76 ++--- .../CompositionEngine/tests/OutputTest.cpp | 308 ++------------------- services/surfaceflinger/DisplayDevice.cpp | 1 - .../surfaceflinger/DisplayHardware/HWComposer.h | 8 - .../DisplayHardware/VirtualDisplaySurface.h | 3 - services/surfaceflinger/SurfaceFlinger.cpp | 3 - services/surfaceflinger/SurfaceFlinger.h | 5 - 25 files changed, 106 insertions(+), 797 deletions(-) delete mode 100644 services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h delete mode 100644 services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h delete mode 100644 services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 9302b7bc37..aefc014062 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -41,10 +41,6 @@ cc_defaults { "libtonemap", "libtrace_proto", "libaidlcommonsupport", - "libprocessgroup", - "libcgrouprc", - "libjsoncpp", - "libcgrouprc_format", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", @@ -72,7 +68,6 @@ cc_library { "src/DisplayColorProfile.cpp", "src/DisplaySurface.cpp", "src/DumpHelpers.cpp", - "src/HwcAsyncWorker.cpp", "src/HwcBufferCache.cpp", "src/LayerFECompositionState.cpp", "src/Output.cpp", diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h index ca86f4c604..c553fce85d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h @@ -72,9 +72,6 @@ public: virtual void resizeBuffers(const ui::Size&) = 0; virtual const sp& getClientTargetAcquireFence() const = 0; - - // Returns true if the render surface supports client composition prediction. - virtual bool supportsCompositionStrategyPrediction() const; }; } // namespace compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 15551029b3..d8644a428d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -35,7 +35,6 @@ #include #include -#include "DisplayHardware/HWComposer.h" namespace android { @@ -55,7 +54,6 @@ struct LayerFECompositionState; namespace impl { struct OutputCompositionState; -struct GpuCompositionResult; } // namespace impl /** @@ -264,9 +262,6 @@ public: // Latches the front-end layer state for each output layer virtual void updateLayerStateFromFE(const CompositionRefreshArgs&) const = 0; - // Enables predicting composition strategy to run client composition earlier - virtual void setPredictCompositionStrategy(bool) = 0; - protected: virtual void setDisplayColorProfile(std::unique_ptr) = 0; virtual void setRenderSurface(std::unique_ptr) = 0; @@ -283,22 +278,13 @@ protected: virtual void updateColorProfile(const CompositionRefreshArgs&) = 0; virtual void beginFrame() = 0; virtual void prepareFrame() = 0; - - using GpuCompositionResult = compositionengine::impl::GpuCompositionResult; - // Runs prepare frame in another thread while running client composition using - // the previous frame's composition strategy. - virtual GpuCompositionResult prepareFrameAsync(const CompositionRefreshArgs&) = 0; virtual void devOptRepaintFlash(const CompositionRefreshArgs&) = 0; - virtual void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) = 0; + virtual void finishFrame(const CompositionRefreshArgs&) = 0; virtual std::optional composeSurfaces( - const Region&, const compositionengine::CompositionRefreshArgs&, - std::shared_ptr, base::unique_fd&) = 0; + const Region&, const compositionengine::CompositionRefreshArgs& refreshArgs) = 0; virtual void postFramebuffer() = 0; virtual void renderCachedSets(const CompositionRefreshArgs&) = 0; - virtual std::optional - chooseCompositionStrategy() = 0; - virtual void applyCompositionStrategy( - const std::optional& changes) = 0; + virtual void chooseCompositionStrategy() = 0; virtual bool getSkipColorTransform() const = 0; virtual FrameFences presentAndGetFrameFences() = 0; virtual std::vector generateClientCompositionRequests( @@ -309,7 +295,6 @@ protected: std::vector& clientCompositionLayers) = 0; virtual void setExpensiveRenderingExpected(bool enabled) = 0; virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0; - virtual bool canPredictCompositionStrategy(const CompositionRefreshArgs&) = 0; }; } // namespace compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h index 9ee779cca1..daee83bd2c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h @@ -100,9 +100,6 @@ public: // Debugging - gets the page flip count for the RenderSurface virtual std::uint32_t getPageFlipCount() const = 0; - - // Returns true if the render surface supports client composition prediction. - virtual bool supportsCompositionStrategyPrediction() const = 0; }; } // namespace compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index 3b8b06fc2f..58d2530877 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -52,14 +51,11 @@ public: void setReleasedLayers(const CompositionRefreshArgs&) override; void setColorTransform(const CompositionRefreshArgs&) override; void setColorProfile(const ColorProfile&) override; - - using DeviceRequestedChanges = android::HWComposer::DeviceRequestedChanges; - std::optional chooseCompositionStrategy() override; - void applyCompositionStrategy(const std::optional&) override; + void chooseCompositionStrategy() override; bool getSkipColorTransform() const override; compositionengine::Output::FrameFences presentAndGetFrameFences() override; void setExpensiveRenderingExpected(bool) override; - void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) override; + void finishFrame(const CompositionRefreshArgs&) override; // compositionengine::Display overrides DisplayId getId() const override; @@ -77,6 +73,7 @@ public: using DisplayRequests = android::HWComposer::DeviceRequestedChanges::DisplayRequests; using LayerRequests = android::HWComposer::DeviceRequestedChanges::LayerRequests; using ClientTargetProperty = android::HWComposer::DeviceRequestedChanges::ClientTargetProperty; + virtual bool anyLayersRequireClientComposition() const; virtual bool allLayersRequireClientComposition() const; virtual void applyChangedTypesToLayers(const ChangedTypes&); virtual void applyDisplayRequests(const DisplayRequests&); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h deleted file mode 100644 index ed1ddc172c..0000000000 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -namespace android::compositionengine::impl { - -struct GpuCompositionResult { - // True if composition strategy was predicted successfully. - bool succeeded = false; - - // Composition ready fence. - base::unique_fd fence{}; - - // Buffer to be used for gpu composition. If gpu composition was not successful, - // then we want to reuse the buffer instead of dequeuing another buffer. - std::shared_ptr buffer = nullptr; - - bool bufferAvailable() const { return buffer != nullptr; }; -}; - -} // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h deleted file mode 100644 index 11c0054089..0000000000 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include - -#include "DisplayHardware/HWComposer.h" - -namespace android::compositionengine::impl { - -// HWC Validate call may take multiple milliseconds to complete and can account for -// a signification amount of time in the display hotpath. This helper class allows -// us to run the hwc validate function on a real time thread if we can predict what -// the composition strategy will be and if composition includes client composition. -// While the hwc validate runs, client composition is kicked off with the prediction. -// When the worker returns with a value, the composition continues if the prediction -// was successful otherwise the client composition is re-executed. -// -// Note: This does not alter the sequence between HWC and surfaceflinger. -class HwcAsyncWorker final { -public: - HwcAsyncWorker(); - ~HwcAsyncWorker(); - // Runs the provided function which calls hwc validate and returns the requested - // device changes as a future. - std::future> send( - std::function()>); - -private: - std::mutex mMutex; - std::condition_variable mCv GUARDED_BY(mMutex); - bool mDone GUARDED_BY(mMutex) = false; - bool mTaskRequested GUARDED_BY(mMutex) = false; - std::packaged_task()> mTask - GUARDED_BY(mMutex); - std::thread mThread; - void run(); -}; - -} // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 0be5d018f6..a7a8e97be5 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -17,13 +17,9 @@ #pragma once #include -#include #include #include -#include -#include #include -#include #include #include #include @@ -96,38 +92,25 @@ public: void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override; void beginFrame() override; void prepareFrame() override; - GpuCompositionResult prepareFrameAsync(const CompositionRefreshArgs&) override; void devOptRepaintFlash(const CompositionRefreshArgs&) override; - void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) override; - std::optional composeSurfaces(const Region&, - const compositionengine::CompositionRefreshArgs&, - std::shared_ptr, - base::unique_fd&) override; + void finishFrame(const CompositionRefreshArgs&) override; + std::optional composeSurfaces( + const Region&, const compositionengine::CompositionRefreshArgs& refreshArgs) override; void postFramebuffer() override; void renderCachedSets(const CompositionRefreshArgs&) override; void cacheClientCompositionRequests(uint32_t) override; - bool canPredictCompositionStrategy(const CompositionRefreshArgs&) override; - void setPredictCompositionStrategy(bool) override; // Testing const ReleasedLayers& getReleasedLayersForTest() const; void setDisplayColorProfileForTest(std::unique_ptr); void setRenderSurfaceForTest(std::unique_ptr); bool plannerEnabled() const { return mPlanner != nullptr; } - virtual bool anyLayersRequireClientComposition() const; - virtual void updateProtectedContentState(); - virtual bool dequeueRenderBuffer(base::unique_fd*, - std::shared_ptr*); - virtual std::future> - chooseCompositionStrategyAsync(); protected: std::unique_ptr createOutputLayer(const sp&) const; std::optional findCurrentOutputLayerForLayer( const sp&) const; - using DeviceRequestedChanges = android::HWComposer::DeviceRequestedChanges; - std::optional chooseCompositionStrategy() override; - void applyCompositionStrategy(const std::optional&) override{}; + void chooseCompositionStrategy() override; bool getSkipColorTransform() const override; compositionengine::Output::FrameFences presentAndGetFrameFences() override; std::vector generateClientCompositionRequests( @@ -148,7 +131,6 @@ protected: private: void dirtyEntireOutput(); compositionengine::OutputLayer* findLayerRequestingBackgroundComposition() const; - void finishPrepareFrame(); ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const; compositionengine::Output::ColorProfile pickColorProfile( const compositionengine::CompositionRefreshArgs&) const; @@ -162,7 +144,6 @@ private: OutputLayer* mLayerRequestingBackgroundBlur = nullptr; std::unique_ptr mClientCompositionRequestCache; std::unique_ptr mPlanner; - std::unique_ptr mHwComposerAsyncWorker; }; // This template factory function standardizes the implementation details of the diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 92f22b6a16..66dd825e5b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -37,8 +37,6 @@ #include #include -#include "DisplayHardware/HWComposer.h" - namespace android { namespace compositionengine::impl { @@ -116,8 +114,6 @@ struct OutputCompositionState { // Current target dataspace ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN}; - std::optional previousDeviceRequestedChanges{}; - // The earliest time to send the present command to the HAL std::chrono::steady_clock::time_point earliestPresentTime; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h index e4cb113645..a8a538003e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h @@ -63,7 +63,6 @@ public: void queueBuffer(base::unique_fd readyFence) override; void onPresentDisplayCompleted() override; void flip() override; - bool supportsCompositionStrategyPrediction() const override; // Debugging void dump(std::string& result) const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h index 72e6f3bdbb..d90cc909ba 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h @@ -41,7 +41,6 @@ public: MOCK_METHOD1(createDisplayColorProfile, void(const DisplayColorProfileCreationArgs&)); MOCK_METHOD1(createRenderSurface, void(const RenderSurfaceCreationArgs&)); MOCK_METHOD1(createClientCompositionCache, void(uint32_t)); - MOCK_METHOD1(setPredictCompositionStrategy, void(bool)); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index 27303a82be..b68b95d07b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -100,22 +99,16 @@ public: MOCK_METHOD0(beginFrame, void()); MOCK_METHOD0(prepareFrame, void()); - MOCK_METHOD1(prepareFrameAsync, GpuCompositionResult(const CompositionRefreshArgs&)); - MOCK_METHOD0(chooseCompositionStrategy, - std::optional()); - MOCK_METHOD1(applyCompositionStrategy, - void(const std::optional&)); + MOCK_METHOD0(chooseCompositionStrategy, void()); MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&)); - MOCK_METHOD2(finishFrame, - void(const compositionengine::CompositionRefreshArgs&, GpuCompositionResult&&)); + MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&)); - MOCK_METHOD4(composeSurfaces, + MOCK_METHOD2(composeSurfaces, std::optional( const Region&, - const compositionengine::CompositionRefreshArgs& refreshArgs, - std::shared_ptr, base::unique_fd&)); + const compositionengine::CompositionRefreshArgs& refreshArgs)); MOCK_CONST_METHOD0(getSkipColorTransform, bool()); MOCK_METHOD0(postFramebuffer, void()); @@ -128,8 +121,6 @@ public: void(const Region&, std::vector&)); MOCK_METHOD1(setExpensiveRenderingExpected, void(bool)); MOCK_METHOD1(cacheClientCompositionRequests, void(uint32_t)); - MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&)); - MOCK_METHOD1(setPredictCompositionStrategy, void(bool)); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h index e12aebb50c..fe858c2817 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h @@ -45,7 +45,6 @@ public: MOCK_METHOD0(flip, void()); MOCK_CONST_METHOD1(dump, void(std::string& result)); MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t()); - MOCK_CONST_METHOD0(supportsCompositionStrategyPrediction, bool()); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 09648c356d..6a75283f7b 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -221,12 +221,12 @@ void Display::setReleasedLayers(const compositionengine::CompositionRefreshArgs& setReleasedLayers(std::move(releasedLayers)); } -std::optional Display::chooseCompositionStrategy() { +void Display::chooseCompositionStrategy() { ATRACE_CALL(); ALOGV(__FUNCTION__); if (mIsDisconnected) { - return {}; + return; } // Default to the base settings -- client composition only. @@ -235,7 +235,7 @@ std::optional Display::chooseCompos // If we don't have a HWC display, then we are done. const auto halDisplayId = HalDisplayId::tryCast(mId); if (!halDisplayId) { - return {}; + return; } // Get any composition changes requested by the HWC device, and apply them. @@ -260,13 +260,8 @@ std::optional Display::chooseCompos result != NO_ERROR) { ALOGE("chooseCompositionStrategy failed for %s: %d (%s)", getName().c_str(), result, strerror(-result)); - return {}; + return; } - - return changes; -} - -void Display::applyCompositionStrategy(const std::optional& changes) { if (changes) { applyChangedTypesToLayers(changes->changedTypes); applyDisplayRequests(changes->displayRequests); @@ -292,6 +287,12 @@ bool Display::getSkipColorTransform() const { return hwc.hasCapability(Capability::SKIP_CLIENT_COLOR_TRANSFORM); } +bool Display::anyLayersRequireClientComposition() const { + const auto layers = getOutputLayersOrderedByZ(); + return std::any_of(layers.begin(), layers.end(), + [](const auto& layer) { return layer->requiresClientComposition(); }); +} + bool Display::allLayersRequireClientComposition() const { const auto layers = getOutputLayersOrderedByZ(); return std::all_of(layers.begin(), layers.end(), @@ -389,8 +390,7 @@ void Display::setExpensiveRenderingExpected(bool enabled) { } } -void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs, - GpuCompositionResult&& result) { +void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) { // We only need to actually compose the display if: // 1) It is being handled by hardware composer, which may need this to // keep its virtual display state machine in sync, or @@ -400,7 +400,7 @@ void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refre return; } - impl::Output::finishFrame(refreshArgs, std::move(result)); + impl::Output::finishFrame(refreshArgs); } } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp index 28900af162..db6d4f2fed 100644 --- a/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp @@ -20,8 +20,4 @@ namespace android::compositionengine { DisplaySurface::~DisplaySurface() = default; -bool DisplaySurface::supportsCompositionStrategyPrediction() const { - return true; -} - } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp b/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp deleted file mode 100644 index 497424a327..0000000000 --- a/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace android::compositionengine::impl { - -HwcAsyncWorker::HwcAsyncWorker() { - mThread = std::thread(&HwcAsyncWorker::run, this); - pthread_setname_np(mThread.native_handle(), "HwcAsyncWorker"); -} - -HwcAsyncWorker::~HwcAsyncWorker() { - { - std::scoped_lock lock(mMutex); - mDone = true; - mCv.notify_all(); - } - if (mThread.joinable()) { - mThread.join(); - } -} -std::future> HwcAsyncWorker::send( - std::function()> task) { - std::unique_lock lock(mMutex); - android::base::ScopedLockAssertion assumeLock(mMutex); - mTask = std::packaged_task()>( - [task = std::move(task)]() { return task(); }); - mTaskRequested = true; - mCv.notify_one(); - return mTask.get_future(); -} - -void HwcAsyncWorker::run() { - set_sched_policy(0, SP_FOREGROUND); - struct sched_param param = {0}; - param.sched_priority = 2; - sched_setscheduler(gettid(), SCHED_FIFO, ¶m); - - std::unique_lock lock(mMutex); - android::base::ScopedLockAssertion assumeLock(mMutex); - while (!mDone) { - mCv.wait(lock); - if (mTaskRequested && mTask.valid()) { - mTask(); - mTaskRequested = false; - } - } -} - -} // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index cd10bc10b5..aef55d49fe 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -435,17 +434,9 @@ void Output::present(const compositionengine::CompositionRefreshArgs& refreshArg writeCompositionState(refreshArgs); setColorTransform(refreshArgs); beginFrame(); - - GpuCompositionResult result; - const bool predictCompositionStrategy = canPredictCompositionStrategy(refreshArgs); - if (predictCompositionStrategy) { - result = prepareFrameAsync(refreshArgs); - } else { - prepareFrame(); - } - + prepareFrame(); devOptRepaintFlash(refreshArgs); - finishFrame(refreshArgs, std::move(result)); + finishFrame(refreshArgs); postFramebuffer(); renderCachedSets(refreshArgs); } @@ -960,62 +951,19 @@ void Output::prepareFrame() { ATRACE_CALL(); ALOGV(__FUNCTION__); - auto& outputState = editState(); + const auto& outputState = getState(); if (!outputState.isEnabled) { return; } - auto changes = chooseCompositionStrategy(); - outputState.previousDeviceRequestedChanges = changes; - if (changes) { - applyCompositionStrategy(changes); - } - finishPrepareFrame(); -} + chooseCompositionStrategy(); -std::future> -Output::chooseCompositionStrategyAsync() { - return mHwComposerAsyncWorker->send([&]() { return chooseCompositionStrategy(); }); -} - -GpuCompositionResult Output::prepareFrameAsync(const CompositionRefreshArgs& refreshArgs) { - ATRACE_CALL(); - ALOGV(__FUNCTION__); - auto& state = editState(); - const auto& previousChanges = state.previousDeviceRequestedChanges; - auto hwcResult = chooseCompositionStrategyAsync(); - applyCompositionStrategy(previousChanges); - finishPrepareFrame(); - - base::unique_fd bufferFence; - std::shared_ptr buffer; - updateProtectedContentState(); - const bool dequeueSucceeded = dequeueRenderBuffer(&bufferFence, &buffer); - GpuCompositionResult compositionResult; - if (dequeueSucceeded) { - std::optional optFd = - composeSurfaces(Region::INVALID_REGION, refreshArgs, buffer, bufferFence); - if (optFd) { - compositionResult.fence = std::move(*optFd); - } + if (mPlanner) { + mPlanner->reportFinalPlan(getOutputLayersOrderedByZ()); } - auto changes = hwcResult.valid() ? hwcResult.get() : std::nullopt; - const bool predictionSucceeded = dequeueSucceeded && changes == previousChanges; - compositionResult.succeeded = predictionSucceeded; - if (!predictionSucceeded) { - ATRACE_NAME("CompositionStrategyPredictionMiss"); - if (changes) { - applyCompositionStrategy(changes); - } - finishPrepareFrame(); - // Track the dequeued buffer to reuse so we don't need to dequeue another one. - compositionResult.buffer = buffer; - } else { - ATRACE_NAME("CompositionStrategyPredictionHit"); - } - state.previousDeviceRequestedChanges = std::move(changes); - return compositionResult; + mRenderSurface->prepareFrame(outputState.usesClientComposition, + outputState.usesDeviceComposition); } void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& refreshArgs) { @@ -1025,11 +973,7 @@ void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& if (getState().isEnabled) { if (const auto dirtyRegion = getDirtyRegion(); !dirtyRegion.isEmpty()) { - base::unique_fd bufferFence; - std::shared_ptr buffer; - updateProtectedContentState(); - dequeueRenderBuffer(&bufferFence, &buffer); - static_cast(composeSurfaces(dirtyRegion, refreshArgs, buffer, bufferFence)); + static_cast(composeSurfaces(dirtyRegion, refreshArgs)); mRenderSurface->queueBuffer(base::unique_fd()); } } @@ -1041,7 +985,7 @@ void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& prepareFrame(); } -void Output::finishFrame(const CompositionRefreshArgs& refreshArgs, GpuCompositionResult&& result) { +void Output::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) { ATRACE_CALL(); ALOGV(__FUNCTION__); @@ -1049,25 +993,9 @@ void Output::finishFrame(const CompositionRefreshArgs& refreshArgs, GpuCompositi return; } - std::optional optReadyFence; - std::shared_ptr buffer; - base::unique_fd bufferFence; - if (result.succeeded) { - optReadyFence = std::move(result.fence); - } else { - if (result.bufferAvailable()) { - buffer = std::move(result.buffer); - bufferFence = std::move(result.fence); - } else { - updateProtectedContentState(); - if (!dequeueRenderBuffer(&bufferFence, &buffer)) { - return; - } - } - // Repaint the framebuffer (if needed), getting the optional fence for when - // the composition completes. - optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs, buffer, bufferFence); - } + // Repaint the framebuffer (if needed), getting the optional fence for when + // the composition completes. + auto optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs); if (!optReadyFence) { return; } @@ -1076,8 +1004,16 @@ void Output::finishFrame(const CompositionRefreshArgs& refreshArgs, GpuCompositi mRenderSurface->queueBuffer(std::move(*optReadyFence)); } -void Output::updateProtectedContentState() { +std::optional Output::composeSurfaces( + const Region& debugRegion, const compositionengine::CompositionRefreshArgs& refreshArgs) { + ATRACE_CALL(); + ALOGV(__FUNCTION__); + const auto& outputState = getState(); + OutputCompositionState& outputCompositionState = editState(); + const TracedOrdinal hasClientComposition = {"hasClientComposition", + outputState.usesClientComposition}; + auto& renderEngine = getCompositionEngine().getRenderEngine(); const bool supportsProtectedContent = renderEngine.supportsProtectedContent(); @@ -1099,48 +1035,29 @@ void Output::updateProtectedContentState() { } else if (!outputState.isSecure && renderEngine.isProtected()) { renderEngine.useProtectedContext(false); } -} -bool Output::dequeueRenderBuffer(base::unique_fd* bufferFence, - std::shared_ptr* tex) { - const auto& outputState = getState(); + base::unique_fd fd; + + std::shared_ptr tex; // If we aren't doing client composition on this output, but do have a // flipClientTarget request for this frame on this output, we still need to // dequeue a buffer. - if (outputState.usesClientComposition || outputState.flipClientTarget) { - *tex = mRenderSurface->dequeueBuffer(bufferFence); - if (*tex == nullptr) { + if (hasClientComposition || outputState.flipClientTarget) { + tex = mRenderSurface->dequeueBuffer(&fd); + if (tex == nullptr) { ALOGW("Dequeuing buffer for display [%s] failed, bailing out of " "client composition for this frame", mName.c_str()); - return false; + return {}; } } - return true; -} -std::optional Output::composeSurfaces( - const Region& debugRegion, const compositionengine::CompositionRefreshArgs& refreshArgs, - std::shared_ptr tex, base::unique_fd& fd) { - ATRACE_CALL(); - ALOGV(__FUNCTION__); - - const auto& outputState = getState(); - const TracedOrdinal hasClientComposition = {"hasClientComposition", - outputState.usesClientComposition}; if (!hasClientComposition) { setExpensiveRenderingExpected(false); return base::unique_fd(); } - if (tex == nullptr) { - ALOGW("Buffer not valid for display [%s], bailing out of " - "client composition for this frame", - mName.c_str()); - return {}; - } - ALOGV("hasClientComposition"); renderengine::DisplaySettings clientCompositionDisplay; @@ -1168,8 +1085,6 @@ std::optional Output::composeSurfaces( outputState.usesDeviceComposition || getSkipColorTransform(); // Generate the client composition requests for the layers on this output. - auto& renderEngine = getCompositionEngine().getRenderEngine(); - const bool supportsProtectedContent = renderEngine.supportsProtectedContent(); std::vector clientCompositionLayersFE; std::vector clientCompositionLayers = generateClientCompositionRequests(supportsProtectedContent, @@ -1177,19 +1092,16 @@ std::optional Output::composeSurfaces( clientCompositionLayersFE); appendRegionFlashRequests(debugRegion, clientCompositionLayers); - OutputCompositionState& outputCompositionState = editState(); // Check if the client composition requests were rendered into the provided graphic buffer. If // so, we can reuse the buffer and avoid client composition. if (mClientCompositionRequestCache) { if (mClientCompositionRequestCache->exists(tex->getBuffer()->getId(), clientCompositionDisplay, clientCompositionLayers)) { - ATRACE_NAME("ClientCompositionCacheHit"); outputCompositionState.reusedClientComposition = true; setExpensiveRenderingExpected(false); return base::unique_fd(); } - ATRACE_NAME("ClientCompositionCacheMiss"); mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay, clientCompositionLayers); } @@ -1441,13 +1353,12 @@ void Output::dirtyEntireOutput() { outputState.dirtyRegion.set(outputState.displaySpace.getBoundsAsRect()); } -std::optional Output::chooseCompositionStrategy() { +void Output::chooseCompositionStrategy() { // The base output implementation can only do client composition auto& outputState = editState(); outputState.usesClientComposition = true; outputState.usesDeviceComposition = false; outputState.reusedClientComposition = false; - return {}; } bool Output::getSkipColorTransform() const { @@ -1462,63 +1373,5 @@ compositionengine::Output::FrameFences Output::presentAndGetFrameFences() { return result; } -void Output::setPredictCompositionStrategy(bool predict) { - if (predict) { - mHwComposerAsyncWorker = std::make_unique(); - } else { - mHwComposerAsyncWorker.reset(nullptr); - } -} - -bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) { - if (!getState().isEnabled || !mHwComposerAsyncWorker) { - ALOGV("canPredictCompositionStrategy disabled"); - return false; - } - - if (!getState().previousDeviceRequestedChanges) { - ALOGV("canPredictCompositionStrategy previous changes not available"); - return false; - } - - if (!mRenderSurface->supportsCompositionStrategyPrediction()) { - ALOGV("canPredictCompositionStrategy surface does not support"); - return false; - } - - if (refreshArgs.devOptFlashDirtyRegionsDelay) { - ALOGV("canPredictCompositionStrategy devOptFlashDirtyRegionsDelay"); - return false; - } - - // If no layer uses clientComposition, then don't predict composition strategy - // because we have less work to do in parallel. - if (!anyLayersRequireClientComposition()) { - ALOGV("canPredictCompositionStrategy no layer uses clientComposition"); - return false; - } - - if (!refreshArgs.updatingOutputGeometryThisFrame) { - return true; - } - - ALOGV("canPredictCompositionStrategy updatingOutputGeometryThisFrame"); - return false; -} - -bool Output::anyLayersRequireClientComposition() const { - const auto layers = getOutputLayersOrderedByZ(); - return std::any_of(layers.begin(), layers.end(), - [](const auto& layer) { return layer->requiresClientComposition(); }); -} - -void Output::finishPrepareFrame() { - const auto& state = getState(); - if (mPlanner) { - mPlanner->reportFinalPlan(getOutputLayersOrderedByZ()); - } - mRenderSurface->prepareFrame(state.usesClientComposition, state.usesDeviceComposition); -} - } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index 5a3af7bfea..12c2c8eb38 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -289,9 +289,5 @@ std::shared_ptr& RenderSurface::mutableTextureFor return mTexture; } -bool RenderSurface::supportsCompositionStrategyPrediction() const { - return mDisplaySurface->supportsCompositionStrategyPrediction(); -} - } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 36b04d909f..cd0323555c 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -30,9 +30,7 @@ #include #include #include -#include #include - #include #include @@ -200,22 +198,6 @@ struct PartialMockDisplayTestCommon : public DisplayTestCommon { std::shared_ptr mDisplay = createPartialMockDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay()); - - android::HWComposer::DeviceRequestedChanges mDeviceRequestedChanges{ - {{nullptr, Composition::CLIENT}}, - hal::DisplayRequest::FLIP_CLIENT_TARGET, - {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}}, - {hal::PixelFormat::RGBA_8888, hal::Dataspace::UNKNOWN}, - -1.f, - }; - - void chooseCompositionStrategy(Display* display) { - std::optional changes = - display->chooseCompositionStrategy(); - if (changes) { - display->applyCompositionStrategy(changes); - } - } }; struct FullDisplayImplTestCommon : public DisplayTestCommon { @@ -232,11 +214,6 @@ struct DisplayWithLayersTestCommon : public FullDisplayImplTestCommon { std::unique_ptr(mLayer2.outputLayer)); mDisplay->injectOutputLayerForTest( std::unique_ptr(mLayer3.outputLayer)); - mResultWithBuffer.buffer = std::make_shared< - renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, - 1ULL /* bufferId */, - HAL_PIXEL_FORMAT_RGBA_8888, - 0ULL /*usage*/); } Layer mLayer1; @@ -245,8 +222,6 @@ struct DisplayWithLayersTestCommon : public FullDisplayImplTestCommon { StrictMock hwc2LayerUnknown; std::shared_ptr mDisplay = createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay()); - impl::GpuCompositionResult mResultWithBuffer; - impl::GpuCompositionResult mResultWithoutBuffer; }; /* @@ -579,7 +554,7 @@ TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfGpuDisplay) { createPartialMockDisplay(mCompositionEngine, args); EXPECT_TRUE(GpuVirtualDisplayId::tryCast(gpuDisplay->getId())); - chooseCompositionStrategy(gpuDisplay.get()); + gpuDisplay->chooseCompositionStrategy(); auto& state = gpuDisplay->getState(); EXPECT_TRUE(state.usesClientComposition); @@ -592,12 +567,11 @@ TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutOnHwcError) { getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), false, _, _, _, _)) .WillOnce(Return(INVALID_OPERATION)); - chooseCompositionStrategy(mDisplay.get()); + mDisplay->chooseCompositionStrategy(); auto& state = mDisplay->getState(); EXPECT_TRUE(state.usesClientComposition); EXPECT_FALSE(state.usesDeviceComposition); - EXPECT_FALSE(state.previousDeviceRequestedChanges.has_value()); } TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) { @@ -614,16 +588,10 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) { EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _)) - .WillOnce(testing::DoAll(testing::SetArgPointee<5>(mDeviceRequestedChanges), - Return(NO_ERROR))); - EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes)) - .Times(1); - EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1); - EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests)) - .Times(1); + .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); - chooseCompositionStrategy(mDisplay.get()); + mDisplay->chooseCompositionStrategy(); auto& state = mDisplay->getState(); EXPECT_FALSE(state.usesClientComposition); @@ -650,17 +618,11 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithDisplayBrightnes EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _)) - .WillOnce(testing::DoAll(testing::SetArgPointee<5>(mDeviceRequestedChanges), - Return(NO_ERROR))); - EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes)) - .Times(1); - EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1); - EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests)) - .Times(1); + .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); mDisplay->setNextBrightness(kDisplayBrightness); - chooseCompositionStrategy(mDisplay.get()); + mDisplay->chooseCompositionStrategy(); auto& state = mDisplay->getState(); EXPECT_FALSE(state.usesClientComposition); @@ -669,6 +631,14 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithDisplayBrightnes } TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { + android::HWComposer::DeviceRequestedChanges changes{ + {{nullptr, Composition::CLIENT}}, + hal::DisplayRequest::FLIP_CLIENT_TARGET, + {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}}, + {hal::PixelFormat::RGBA_8888, hal::Dataspace::UNKNOWN}, + -1.f, + }; + // Since two calls are made to anyLayersRequireClientComposition with different return // values, use a Sequence to control the matching so the values are returned in a known // order. @@ -682,15 +652,13 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _)) - .WillOnce(DoAll(SetArgPointee<5>(mDeviceRequestedChanges), Return(NO_ERROR))); - EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes)) - .Times(1); - EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1); - EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests)) - .Times(1); + .WillOnce(DoAll(SetArgPointee<5>(changes), Return(NO_ERROR))); + EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1); + EXPECT_CALL(*mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1); + EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1); EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); - chooseCompositionStrategy(mDisplay.get()); + mDisplay->chooseCompositionStrategy(); auto& state = mDisplay->getState(); EXPECT_FALSE(state.usesClientComposition); @@ -954,7 +922,7 @@ TEST_F(DisplayFinishFrameTest, doesNotSkipCompositionIfNotDirtyOnHwcDisplay) { mDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1)); mDisplay->editState().dirtyRegion = Region::INVALID_REGION; - mDisplay->finishFrame({}, std::move(mResultWithBuffer)); + mDisplay->finishFrame({}); } TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) { @@ -972,7 +940,7 @@ TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) { gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1)); gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION; - gpuDisplay->finishFrame({}, std::move(mResultWithoutBuffer)); + gpuDisplay->finishFrame({}); } TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) { @@ -989,7 +957,7 @@ TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) { gpuDisplay->editState().usesClientComposition = false; gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1)); gpuDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1)); - gpuDisplay->finishFrame({}, std::move(mResultWithBuffer)); + gpuDisplay->finishFrame({}); } /* diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 4e875c8a25..c2521b2fc2 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -990,7 +989,7 @@ struct OutputPrepareFrameTest : public testing::Test { struct OutputPartialMock : public OutputPartialMockBase { // Sets up the helper functions called by the function under test to use // mock implementations. - MOCK_METHOD0(chooseCompositionStrategy, std::optional()); + MOCK_METHOD0(chooseCompositionStrategy, void()); }; OutputPrepareFrameTest() { @@ -1038,133 +1037,6 @@ TEST_F(OutputTest, prepareFrameSetsClientCompositionOnlyByDefault) { EXPECT_FALSE(mOutput->getState().usesDeviceComposition); } -struct OutputPrepareFrameAsyncTest : public testing::Test { - struct OutputPartialMock : public OutputPartialMockBase { - // Sets up the helper functions called by the function under test to use - // mock implementations. - MOCK_METHOD0(chooseCompositionStrategy, std::optional()); - MOCK_METHOD0(updateProtectedContentState, void()); - MOCK_METHOD2(dequeueRenderBuffer, - bool(base::unique_fd*, std::shared_ptr*)); - MOCK_METHOD0(chooseCompositionStrategyAsync, - std::future>()); - MOCK_METHOD4(composeSurfaces, - std::optional( - const Region&, const compositionengine::CompositionRefreshArgs&, - std::shared_ptr, base::unique_fd&)); - }; - - OutputPrepareFrameAsyncTest() { - mOutput.setDisplayColorProfileForTest( - std::unique_ptr(mDisplayColorProfile)); - mOutput.setRenderSurfaceForTest(std::unique_ptr(mRenderSurface)); - } - - StrictMock mCompositionEngine; - mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock(); - mock::RenderSurface* mRenderSurface = new StrictMock(); - StrictMock mOutput; - CompositionRefreshArgs mRefreshArgs; -}; - -TEST_F(OutputPrepareFrameAsyncTest, delegatesToChooseCompositionStrategyAndRenderSurface) { - mOutput.editState().isEnabled = true; - mOutput.editState().usesClientComposition = false; - mOutput.editState().usesDeviceComposition = true; - mOutput.editState().previousDeviceRequestedChanges = - std::make_optional({}); - std::promise> p; - p.set_value(mOutput.editState().previousDeviceRequestedChanges); - - EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); - EXPECT_CALL(mOutput, updateProtectedContentState()); - EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true)); - EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)); - EXPECT_CALL(mOutput, chooseCompositionStrategyAsync()).WillOnce([&] { return p.get_future(); }); - EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _)); - - impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs); - EXPECT_TRUE(result.succeeded); - EXPECT_FALSE(result.bufferAvailable()); -} - -TEST_F(OutputPrepareFrameAsyncTest, skipCompositionOnDequeueFailure) { - mOutput.editState().isEnabled = true; - mOutput.editState().usesClientComposition = false; - mOutput.editState().usesDeviceComposition = true; - mOutput.editState().previousDeviceRequestedChanges = - std::make_optional({}); - std::promise> p; - p.set_value(mOutput.editState().previousDeviceRequestedChanges); - - EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); - EXPECT_CALL(mOutput, updateProtectedContentState()); - EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(false)); - EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2); - EXPECT_CALL(mOutput, chooseCompositionStrategyAsync()).WillOnce([&] { return p.get_future(); }); - - impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs); - EXPECT_FALSE(result.succeeded); - EXPECT_FALSE(result.bufferAvailable()); -} - -// Tests that in the event of hwc error when choosing composition strategy, we would fall back -// client composition -TEST_F(OutputPrepareFrameAsyncTest, chooseCompositionStrategyFailureCallsPrepareFrame) { - mOutput.editState().isEnabled = true; - mOutput.editState().usesClientComposition = false; - mOutput.editState().usesDeviceComposition = true; - mOutput.editState().previousDeviceRequestedChanges = - std::make_optional({}); - std::promise> p; - p.set_value({}); - std::shared_ptr tex = - std::make_shared(1, 1, - HAL_PIXEL_FORMAT_RGBA_8888, 1, - 2); - - EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); - EXPECT_CALL(mOutput, updateProtectedContentState()); - EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(tex), Return(true))); - EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2); - EXPECT_CALL(mOutput, chooseCompositionStrategyAsync()).WillOnce([&] { return p.get_future(); }); - EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _)); - - impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs); - EXPECT_FALSE(result.succeeded); - EXPECT_TRUE(result.bufferAvailable()); -} - -TEST_F(OutputPrepareFrameAsyncTest, predictionMiss) { - mOutput.editState().isEnabled = true; - mOutput.editState().usesClientComposition = false; - mOutput.editState().usesDeviceComposition = true; - mOutput.editState().previousDeviceRequestedChanges = - std::make_optional({}); - auto newDeviceRequestedChanges = - std::make_optional({}); - newDeviceRequestedChanges->clientTargetBrightness = 5.f; - std::promise> p; - p.set_value(newDeviceRequestedChanges); - std::shared_ptr tex = - std::make_shared(1, 1, - HAL_PIXEL_FORMAT_RGBA_8888, 1, - 2); - - EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); - EXPECT_CALL(mOutput, updateProtectedContentState()); - EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(tex), Return(true))); - EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2); - EXPECT_CALL(mOutput, chooseCompositionStrategyAsync()).WillOnce([&] { return p.get_future(); }); - EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _)); - - impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs); - EXPECT_FALSE(result.succeeded); - EXPECT_TRUE(result.bufferAvailable()); -} - /* * Output::prepare() */ @@ -1923,14 +1795,10 @@ struct OutputPresentTest : public testing::Test { MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&)); MOCK_METHOD0(beginFrame, void()); MOCK_METHOD0(prepareFrame, void()); - MOCK_METHOD1(prepareFrameAsync, GpuCompositionResult(const CompositionRefreshArgs&)); MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&)); - MOCK_METHOD2(finishFrame, - void(const compositionengine::CompositionRefreshArgs&, - GpuCompositionResult&&)); + MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&)); MOCK_METHOD0(postFramebuffer, void()); MOCK_METHOD1(renderCachedSets, void(const compositionengine::CompositionRefreshArgs&)); - MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&)); }; StrictMock mOutput; @@ -1946,30 +1814,9 @@ TEST_F(OutputPresentTest, justInvokesChildFunctionsInSequence) { EXPECT_CALL(mOutput, writeCompositionState(Ref(args))); EXPECT_CALL(mOutput, setColorTransform(Ref(args))); EXPECT_CALL(mOutput, beginFrame()); - EXPECT_CALL(mOutput, canPredictCompositionStrategy(Ref(args))).WillOnce(Return(false)); EXPECT_CALL(mOutput, prepareFrame()); EXPECT_CALL(mOutput, devOptRepaintFlash(Ref(args))); - EXPECT_CALL(mOutput, finishFrame(Ref(args), _)); - EXPECT_CALL(mOutput, postFramebuffer()); - EXPECT_CALL(mOutput, renderCachedSets(Ref(args))); - - mOutput.present(args); -} - -TEST_F(OutputPresentTest, predictingCompositionStrategyInvokesPrepareFrameAsync) { - CompositionRefreshArgs args; - - InSequence seq; - EXPECT_CALL(mOutput, updateColorProfile(Ref(args))); - EXPECT_CALL(mOutput, updateCompositionState(Ref(args))); - EXPECT_CALL(mOutput, planComposition()); - EXPECT_CALL(mOutput, writeCompositionState(Ref(args))); - EXPECT_CALL(mOutput, setColorTransform(Ref(args))); - EXPECT_CALL(mOutput, beginFrame()); - EXPECT_CALL(mOutput, canPredictCompositionStrategy(Ref(args))).WillOnce(Return(true)); - EXPECT_CALL(mOutput, prepareFrameAsync(Ref(args))); - EXPECT_CALL(mOutput, devOptRepaintFlash(Ref(args))); - EXPECT_CALL(mOutput, finishFrame(Ref(args), _)); + EXPECT_CALL(mOutput, finishFrame(Ref(args))); EXPECT_CALL(mOutput, postFramebuffer()); EXPECT_CALL(mOutput, renderCachedSets(Ref(args))); @@ -2867,15 +2714,11 @@ struct OutputDevOptRepaintFlashTest : public testing::Test { // Sets up the helper functions called by the function under test to use // mock implementations. MOCK_METHOD(Region, getDirtyRegion, (), (const)); - MOCK_METHOD4(composeSurfaces, + MOCK_METHOD2(composeSurfaces, std::optional( - const Region&, const compositionengine::CompositionRefreshArgs&, - std::shared_ptr, base::unique_fd&)); + const Region&, const compositionengine::CompositionRefreshArgs&)); MOCK_METHOD0(postFramebuffer, void()); MOCK_METHOD0(prepareFrame, void()); - MOCK_METHOD0(updateProtectedContentState, void()); - MOCK_METHOD2(dequeueRenderBuffer, - bool(base::unique_fd*, std::shared_ptr*)); }; OutputDevOptRepaintFlashTest() { @@ -2932,9 +2775,7 @@ TEST_F(OutputDevOptRepaintFlashTest, alsoComposesSurfacesAndQueuesABufferIfDirty InSequence seq; EXPECT_CALL(mOutput, getDirtyRegion()).WillOnce(Return(kNotEmptyRegion)); - EXPECT_CALL(mOutput, updateProtectedContentState()); - EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)); - EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs), _, _)); + EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs))); EXPECT_CALL(*mRenderSurface, queueBuffer(_)); EXPECT_CALL(mOutput, postFramebuffer()); EXPECT_CALL(mOutput, prepareFrame()); @@ -2950,14 +2791,10 @@ struct OutputFinishFrameTest : public testing::Test { struct OutputPartialMock : public OutputPartialMockBase { // Sets up the helper functions called by the function under test to use // mock implementations. - MOCK_METHOD4(composeSurfaces, + MOCK_METHOD2(composeSurfaces, std::optional( - const Region&, const compositionengine::CompositionRefreshArgs&, - std::shared_ptr, base::unique_fd&)); + const Region&, const compositionengine::CompositionRefreshArgs&)); MOCK_METHOD0(postFramebuffer, void()); - MOCK_METHOD0(updateProtectedContentState, void()); - MOCK_METHOD2(dequeueRenderBuffer, - bool(base::unique_fd*, std::shared_ptr*)); }; OutputFinishFrameTest() { @@ -2975,63 +2812,27 @@ struct OutputFinishFrameTest : public testing::Test { TEST_F(OutputFinishFrameTest, ifNotEnabledDoesNothing) { mOutput.mState.isEnabled = false; - impl::GpuCompositionResult result; - mOutput.finishFrame(mRefreshArgs, std::move(result)); + mOutput.finishFrame(mRefreshArgs); } TEST_F(OutputFinishFrameTest, takesEarlyOutifComposeSurfacesReturnsNoFence) { mOutput.mState.isEnabled = true; - EXPECT_CALL(mOutput, updateProtectedContentState()); - EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true)); - EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _, _)); - - impl::GpuCompositionResult result; - mOutput.finishFrame(mRefreshArgs, std::move(result)); -} - -TEST_F(OutputFinishFrameTest, queuesBufferIfComposeSurfacesReturnsAFence) { - mOutput.mState.isEnabled = true; - - InSequence seq; - EXPECT_CALL(mOutput, updateProtectedContentState()); - EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true)); - EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _, _)) - .WillOnce(Return(ByMove(base::unique_fd()))); - EXPECT_CALL(*mRenderSurface, queueBuffer(_)); - - impl::GpuCompositionResult result; - mOutput.finishFrame(mRefreshArgs, std::move(result)); -} - -TEST_F(OutputFinishFrameTest, predictionSucceeded) { - mOutput.mState.isEnabled = true; InSequence seq; - EXPECT_CALL(*mRenderSurface, queueBuffer(_)); + EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _)); - impl::GpuCompositionResult result; - result.succeeded = true; - mOutput.finishFrame(mRefreshArgs, std::move(result)); + mOutput.finishFrame(mRefreshArgs); } -TEST_F(OutputFinishFrameTest, predictionFailedAndBufferIsReused) { +TEST_F(OutputFinishFrameTest, queuesBufferIfComposeSurfacesReturnsAFence) { mOutput.mState.isEnabled = true; InSequence seq; - - impl::GpuCompositionResult result; - result.succeeded = false; - result.buffer = - std::make_shared(1, 1, - HAL_PIXEL_FORMAT_RGBA_8888, 1, - 2); - - EXPECT_CALL(mOutput, - composeSurfaces(RegionEq(Region::INVALID_REGION), _, result.buffer, - Eq(ByRef(result.fence)))) + EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _)) .WillOnce(Return(ByMove(base::unique_fd()))); EXPECT_CALL(*mRenderSurface, queueBuffer(_)); - mOutput.finishFrame(mRefreshArgs, std::move(result)); + + mOutput.finishFrame(mRefreshArgs); } /* @@ -3278,15 +3079,8 @@ struct OutputComposeSurfacesTest : public testing::Test { struct ExecuteState : public CallOrderStateMachineHelper { auto execute() { - base::unique_fd fence; - std::shared_ptr externalTexture; - const bool success = - getInstance()->mOutput.dequeueRenderBuffer(&fence, &externalTexture); - if (success) { - getInstance()->mReadyFence = - getInstance()->mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, - externalTexture, fence); - } + getInstance()->mReadyFence = + getInstance()->mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); return nextState(); } }; @@ -3847,11 +3641,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifDisplayIsNotSecure) EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true)); EXPECT_CALL(mRenderEngine, useProtectedContext(false)); - base::unique_fd fd; - std::shared_ptr tex; - mOutput.updateProtectedContentState(); - mOutput.dequeueRenderBuffer(&fd, &tex); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifRenderEngineDoesNotSupportIt) { @@ -3859,11 +3649,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifRenderEngineDoesNotS mLayer2.mLayerFEState.hasProtectedContent = true; EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false)); - base::unique_fd fd; - std::shared_ptr tex; - mOutput.updateProtectedContentState(); - mOutput.dequeueRenderBuffer(&fd, &tex); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNoProtectedContentLayers) { @@ -3875,11 +3661,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNoProtectedContentLa EXPECT_CALL(mRenderEngine, useProtectedContext(false)); EXPECT_CALL(*mRenderSurface, setProtected(false)); - base::unique_fd fd; - std::shared_ptr tex; - mOutput.updateProtectedContentState(); - mOutput.dequeueRenderBuffer(&fd, &tex); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) { @@ -3901,11 +3683,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) { .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))); - base::unique_fd fd; - std::shared_ptr tex; - mOutput.updateProtectedContentState(); - mOutput.dequeueRenderBuffer(&fd, &tex); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEverywhere) { @@ -3915,11 +3693,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEveryw EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true)); EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true)); - base::unique_fd fd; - std::shared_ptr tex; - mOutput.updateProtectedContentState(); - mOutput.dequeueRenderBuffer(&fd, &tex); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifFailsToEnableInRenderEngine) { @@ -3930,11 +3704,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifFailsToEnableInRende EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false)); EXPECT_CALL(mRenderEngine, useProtectedContext(true)); - base::unique_fd fd; - std::shared_ptr tex; - mOutput.updateProtectedContentState(); - mOutput.dequeueRenderBuffer(&fd, &tex); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderEngine) { @@ -3945,11 +3715,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRend EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false)); EXPECT_CALL(*mRenderSurface, setProtected(true)); - base::unique_fd fd; - std::shared_ptr tex; - mOutput.updateProtectedContentState(); - mOutput.dequeueRenderBuffer(&fd, &tex); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderSurface) { @@ -3960,11 +3726,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRend EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true)); EXPECT_CALL(mRenderEngine, useProtectedContext(true)); - base::unique_fd fd; - std::shared_ptr tex; - mOutput.updateProtectedContentState(); - mOutput.dequeueRenderBuffer(&fd, &tex); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } struct OutputComposeSurfacesTest_SetsExpensiveRendering : public OutputComposeSurfacesTest { @@ -3993,11 +3755,7 @@ TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering, IfExepensiveOutputDatas .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))); - base::unique_fd fd; - std::shared_ptr tex; - mOutput.updateProtectedContentState(); - mOutput.dequeueRenderBuffer(&fd, &tex); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); } struct OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur @@ -4032,12 +3790,7 @@ TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur, IfBlursAreExpen mOutput.writeCompositionState(mRefreshArgs); EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)); - - base::unique_fd fd; - std::shared_ptr tex; - mOutput.updateProtectedContentState(); - mOutput.dequeueRenderBuffer(&fd, &tex); - mOutput.composeSurfaces(kDebugRegion, mRefreshArgs, tex, fd); + mOutput.composeSurfaces(kDebugRegion, mRefreshArgs); } TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur, IfBlursAreNotExpensive) { @@ -4047,12 +3800,7 @@ TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur, IfBlursAreNotEx mOutput.writeCompositionState(mRefreshArgs); EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)).Times(0); - - base::unique_fd fd; - std::shared_ptr tex; - mOutput.updateProtectedContentState(); - mOutput.dequeueRenderBuffer(&fd, &tex); - mOutput.composeSurfaces(kDebugRegion, mRefreshArgs, tex, fd); + mOutput.composeSurfaces(kDebugRegion, mRefreshArgs); } /* diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 610d86f29a..45b98bb3d3 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -91,7 +91,6 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) static_cast(SurfaceFlinger::maxFrameBufferAcquiredBuffers)); } - mCompositionDisplay->setPredictCompositionStrategy(mFlinger->mPredictCompositionStrategy); mCompositionDisplay->createDisplayColorProfile( compositionengine::DisplayColorProfileCreationArgsBuilder() .setHasWideColorGamut(args.hasWideColorGamut) diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index a8d439b7e0..5b2e265eb6 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -269,14 +269,6 @@ public: support) = 0; }; -static inline bool operator==(const android::HWComposer::DeviceRequestedChanges& lhs, - const android::HWComposer::DeviceRequestedChanges& rhs) { - return lhs.changedTypes == rhs.changedTypes && lhs.displayRequests == rhs.displayRequests && - lhs.layerRequests == rhs.layerRequests && - lhs.clientTargetProperty == rhs.clientTargetProperty && - lhs.clientTargetBrightness == rhs.clientTargetBrightness; -} - namespace impl { class HWComposer final : public android::HWComposer { diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index e21095aa88..307da41667 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -89,9 +89,6 @@ public: virtual void dumpAsString(String8& result) const; virtual void resizeBuffers(const ui::Size&) override; virtual const sp& getClientTargetAcquireFence() const override; - // Virtual display surface needs to prepare the frame based on composition type. Skip - // any client composition prediction. - virtual bool supportsCompositionStrategyPrediction() const override { return false; }; private: enum Source : size_t { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index efaa975ff2..089875c91b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -480,9 +480,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("debug.sf.disable_client_composition_cache", value, "0"); mDisableClientCompositionCache = atoi(value); - property_get("debug.sf.predict_hwc_composition_strategy", value, "0"); - mPredictCompositionStrategy = atoi(value); - // We should be reading 'persist.sys.sf.color_saturation' here // but since /data may be encrypted, we need to wait until after vold // comes online to attempt to read the property. The property is diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 86c83338ff..f5a695b07c 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -344,11 +344,6 @@ public: void disableExpensiveRendering(); FloatRect getMaxDisplayBounds(); - // If set, composition engine tries to predict the composition strategy provided by HWC - // based on the previous frame. If the strategy can be predicted, gpu composition will - // run parallel to the hwc validateDisplay call and re-run if the predition is incorrect. - bool mPredictCompositionStrategy = false; - protected: // We're reference counted, never destroy SurfaceFlinger directly virtual ~SurfaceFlinger(); -- cgit v1.2.3-59-g8ed1b From 6c7b36e812413a8fb0ada8e287a648dcedfbb107 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Thu, 3 Mar 2022 08:27:58 -0800 Subject: SF: Clean up plumbing for boot display mode Avoid CE round trip, and validate API against virtual displays. Bug: 182939859 Test: Boot Change-Id: Ic4e14dcc06218097c65f9374f2962a345d347820 --- .../include/compositionengine/Display.h | 3 -- .../include/compositionengine/impl/Display.h | 2 - .../CompositionEngine/src/Display.cpp | 14 ----- .../CompositionEngine/tests/MockHWComposer.h | 4 +- services/surfaceflinger/DisplayDevice.cpp | 26 ++++----- services/surfaceflinger/DisplayDevice.h | 6 +-- .../surfaceflinger/DisplayHardware/HWComposer.cpp | 7 +-- .../surfaceflinger/DisplayHardware/HWComposer.h | 13 ++++- services/surfaceflinger/SurfaceFlinger.cpp | 62 +++++++++++++--------- 9 files changed, 65 insertions(+), 72 deletions(-) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h index 6a3fcb7307..16cb41b024 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h @@ -56,9 +56,6 @@ public: // similar requests if needed. virtual void createClientCompositionCache(uint32_t cacheSize) = 0; - // Returns the boot display mode preferred by HWC. - virtual int32_t getPreferredBootHwcConfigId() const = 0; - protected: ~Display() = default; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index 58d2530877..e12d1b4fdf 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -62,7 +62,6 @@ public: bool isSecure() const override; bool isVirtual() const override; void disconnect() override; - int32_t getPreferredBootHwcConfigId() const override; void createDisplayColorProfile( const compositionengine::DisplayColorProfileCreationArgs&) override; void createRenderSurface(const compositionengine::RenderSurfaceCreationArgs&) override; @@ -88,7 +87,6 @@ private: DisplayId mId; bool mIsDisconnected = false; Hwc2::PowerAdvisor* mPowerAdvisor = nullptr; - int32_t mPreferredBootHwcConfigId = -1; }; // This template factory function standardizes the implementation details of the diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 6a75283f7b..2165e1d77b 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -58,16 +58,6 @@ void Display::setConfiguration(const compositionengine::DisplayCreationArgs& arg editState().isSecure = args.isSecure; editState().displaySpace.setBounds(args.pixels); setName(args.name); - bool isBootModeSupported = getCompositionEngine().getHwComposer().getBootDisplayModeSupport(); - const auto physicalId = PhysicalDisplayId::tryCast(mId); - if (!physicalId || !isBootModeSupported) { - return; - } - std::optional preferredBootModeId = - getCompositionEngine().getHwComposer().getPreferredBootDisplayMode(*physicalId); - if (preferredBootModeId.has_value()) { - mPreferredBootHwcConfigId = static_cast(preferredBootModeId.value()); - } } bool Display::isValid() const { @@ -90,10 +80,6 @@ std::optional Display::getDisplayId() const { return mId; } -int32_t Display::getPreferredBootHwcConfigId() const { - return mPreferredBootHwcConfigId; -} - void Display::disconnect() { if (mIsDisconnected) { return; diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index 1f1dd1afb2..a8cad53cb0 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -112,8 +112,8 @@ public: MOCK_METHOD1(getPreferredBootDisplayMode, std::optional(PhysicalDisplayId)); MOCK_METHOD0(getBootDisplayModeSupport, bool()); MOCK_METHOD2(setAutoLowLatencyMode, status_t(PhysicalDisplayId, bool)); - MOCK_METHOD2(getSupportedContentTypes, - status_t(PhysicalDisplayId, std::vector*)); + MOCK_METHOD(status_t, getSupportedContentTypes, + (PhysicalDisplayId, std::vector*), (const, override)); MOCK_METHOD2(setContentType, status_t(PhysicalDisplayId, hal::ContentType)); MOCK_CONST_METHOD0(getSupportedLayerGenericMetadata, const std::unordered_map&()); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 45b98bb3d3..99335e59c0 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -227,21 +227,23 @@ const DisplayModes& DisplayDevice::getSupportedModes() const { } DisplayModePtr DisplayDevice::getMode(DisplayModeId modeId) const { - const auto it = std::find_if(mSupportedModes.begin(), mSupportedModes.end(), - [&](DisplayModePtr mode) { return mode->getId() == modeId; }); + const auto it = + std::find_if(mSupportedModes.begin(), mSupportedModes.end(), + [&](const DisplayModePtr& mode) { return mode->getId() == modeId; }); if (it != mSupportedModes.end()) { return *it; } return nullptr; } -DisplayModePtr DisplayDevice::getModefromHwcId(uint32_t hwcId) const { - const auto it = std::find_if(mSupportedModes.begin(), mSupportedModes.end(), - [&](DisplayModePtr mode) { return mode->getHwcId() == hwcId; }); +std::optional DisplayDevice::translateModeId(hal::HWConfigId hwcId) const { + const auto it = + std::find_if(mSupportedModes.begin(), mSupportedModes.end(), + [&](const DisplayModePtr& mode) { return mode->getHwcId() == hwcId; }); if (it != mSupportedModes.end()) { - return *it; + return (*it)->getId(); } - return nullptr; + return {}; } nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const { @@ -468,16 +470,6 @@ HdrCapabilities DisplayDevice::getHdrCapabilities() const { capabilities.getDesiredMinLuminance()); } -ui::DisplayModeId DisplayDevice::getPreferredBootModeId() const { - const auto preferredBootHwcModeId = mCompositionDisplay->getPreferredBootHwcConfigId(); - const auto mode = getModefromHwcId(preferredBootHwcModeId); - if (mode == nullptr) { - ALOGE("%s: invalid display mode (%d)", __FUNCTION__, preferredBootHwcModeId); - return BAD_VALUE; - } - return mode->getId().value(); -} - void DisplayDevice::enableRefreshRateOverlay(bool enable, bool showSpinnner) { if (!enable) { mRefreshRateOverlay.reset(); diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 690f2404fd..2c4a300a0b 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -157,9 +157,6 @@ public: // respectively if hardware composer doesn't return meaningful values. HdrCapabilities getHdrCapabilities() const; - // Returns the boot display mode preferred by the implementation. - ui::DisplayModeId getPreferredBootModeId() const; - // Return true if intent is supported by the display. bool hasRenderIntent(ui::RenderIntent intent) const; @@ -232,8 +229,7 @@ public: // set-top boxes after a hotplug reconnect. DisplayModePtr getMode(DisplayModeId) const; - // Returns nullptr if the given mode ID is not supported. - DisplayModePtr getModefromHwcId(uint32_t) const; + std::optional translateModeId(hal::HWConfigId) const; // Returns the refresh rate configs for this display. scheduler::RefreshRateConfigs& refreshRateConfigs() const { return *mRefreshRateConfigs; } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 02b3772baa..7b9ffed13e 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -814,10 +814,11 @@ status_t HWComposer::setAutoLowLatencyMode(PhysicalDisplayId displayId, bool on) } status_t HWComposer::getSupportedContentTypes( - PhysicalDisplayId displayId, std::vector* outSupportedContentTypes) { + PhysicalDisplayId displayId, + std::vector* outSupportedContentTypes) const { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); - const auto error = - mDisplayData[displayId].hwcDisplay->getSupportedContentTypes(outSupportedContentTypes); + const auto error = mDisplayData.at(displayId).hwcDisplay->getSupportedContentTypes( + outSupportedContentTypes); RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index f9637f0772..3dd910bc1a 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -234,8 +234,16 @@ public: hal::VsyncPeriodChangeTimeline* outTimeline) = 0; virtual status_t setAutoLowLatencyMode(PhysicalDisplayId, bool on) = 0; virtual status_t getSupportedContentTypes( - PhysicalDisplayId, std::vector* outSupportedContentTypes) = 0; + PhysicalDisplayId, std::vector* outSupportedContentTypes) const = 0; + + bool supportsContentType(PhysicalDisplayId displayId, hal::ContentType type) const { + std::vector types; + return getSupportedContentTypes(displayId, &types) == NO_ERROR && + std::find(types.begin(), types.end(), type) != types.end(); + } + virtual status_t setContentType(PhysicalDisplayId, hal::ContentType) = 0; + virtual const std::unordered_map& getSupportedLayerGenericMetadata() const = 0; @@ -390,7 +398,8 @@ public: const hal::VsyncPeriodChangeConstraints&, hal::VsyncPeriodChangeTimeline* outTimeline) override; status_t setAutoLowLatencyMode(PhysicalDisplayId, bool) override; - status_t getSupportedContentTypes(PhysicalDisplayId, std::vector*) override; + status_t getSupportedContentTypes(PhysicalDisplayId, + std::vector*) const override; status_t setContentType(PhysicalDisplayId, hal::ContentType) override; const std::unordered_map& getSupportedLayerGenericMetadata() const override; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 425b78bd68..94b16b4821 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -578,13 +578,13 @@ void SurfaceFlinger::destroyDisplay(const sp& displayToken) { const ssize_t index = mCurrentState.displays.indexOfKey(displayToken); if (index < 0) { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + ALOGE("%s: Invalid display token %p", __func__, displayToken.get()); return; } const DisplayDeviceState& state = mCurrentState.displays.valueAt(index); if (state.physical) { - ALOGE("%s: Invalid operation on physical display", __FUNCTION__); + ALOGE("%s: Invalid operation on physical display", __func__); return; } mInterceptor->saveDisplayDeletion(state.sequenceId); @@ -1039,7 +1039,7 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp& displayToken, return INVALID_OPERATION; } - info->activeDisplayModeId = static_cast(display->getActiveMode()->getId().value()); + info->activeDisplayModeId = display->getActiveMode()->getId().value(); const auto& supportedModes = display->getSupportedModes(); info->supportedDisplayModes.clear(); @@ -1104,13 +1104,17 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp& displayToken, info->autoLowLatencyModeSupported = getHwComposer().hasDisplayCapability(*displayId, DisplayCapability::AUTO_LOW_LATENCY_MODE); - std::vector types; - getHwComposer().getSupportedContentTypes(*displayId, &types); - info->gameContentTypeSupported = std::any_of(types.begin(), types.end(), [](auto type) { - return type == hal::ContentType::GAME; - }); - - info->preferredBootDisplayMode = display->getPreferredBootModeId(); + info->gameContentTypeSupported = + getHwComposer().supportsContentType(*displayId, hal::ContentType::GAME); + + info->preferredBootDisplayMode = static_cast(-1); + if (getHwComposer().getBootDisplayModeSupport()) { + if (const auto hwcId = getHwComposer().getPreferredBootDisplayMode(*displayId)) { + if (const auto modeId = display->translateModeId(*hwcId)) { + info->preferredBootDisplayMode = modeId->value(); + } + } + } return NO_ERROR; } @@ -1432,31 +1436,41 @@ status_t SurfaceFlinger::getBootDisplayModeSupport(bool* outSupport) const { return future.get(); } -status_t SurfaceFlinger::setBootDisplayMode(const sp& displayToken, ui::DisplayModeId id) { +status_t SurfaceFlinger::setBootDisplayMode(const sp& displayToken, + ui::DisplayModeId modeId) { + const char* const whence = __func__; auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t { - if (const auto displayDevice = getDisplayDeviceLocked(displayToken)) { - const auto mode = displayDevice->getMode(DisplayModeId{id}); - if (mode == nullptr) { - ALOGE("%s: invalid display mode (%d)", __FUNCTION__, id); - return BAD_VALUE; - } + const auto display = getDisplayDeviceLocked(displayToken); + if (!display) { + ALOGE("%s: Invalid display token %p", whence, displayToken.get()); + return NAME_NOT_FOUND; + } - return getHwComposer().setBootDisplayMode(displayDevice->getPhysicalId(), - mode->getHwcId()); - } else { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + if (display->isVirtual()) { + ALOGE("%s: Invalid operation on virtual display", whence); + return INVALID_OPERATION; + } + + const auto displayId = display->getPhysicalId(); + const auto mode = display->getMode(DisplayModeId{modeId}); + if (!mode) { + ALOGE("%s: Invalid mode %d for display %s", whence, modeId, + to_string(displayId).c_str()); return BAD_VALUE; } + + return getHwComposer().setBootDisplayMode(displayId, mode->getHwcId()); }); return future.get(); } status_t SurfaceFlinger::clearBootDisplayMode(const sp& displayToken) { + const char* const whence = __func__; auto future = mScheduler->schedule([=]() MAIN_THREAD -> status_t { if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) { return getHwComposer().clearBootDisplayMode(*displayId); } else { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + ALOGE("%s: Invalid display token %p", whence, displayToken.get()); return BAD_VALUE; } }); @@ -1504,7 +1518,7 @@ status_t SurfaceFlinger::overrideHdrTypes(const sp& displayToken, auto display = getDisplayDeviceLocked(displayToken); if (!display) { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); + ALOGE("%s: Invalid display token %p", __func__, displayToken.get()); return NAME_NOT_FOUND; } @@ -4805,7 +4819,7 @@ void SurfaceFlinger::initializeDisplays() { void SurfaceFlinger::setPowerModeInternal(const sp& display, hal::PowerMode mode) { if (display->isVirtual()) { - ALOGE("%s: Invalid operation on virtual display", __FUNCTION__); + ALOGE("%s: Invalid operation on virtual display", __func__); return; } -- cgit v1.2.3-59-g8ed1b From b0054a2646e2031b9e55230f6e511e00171601f7 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Thu, 3 Mar 2022 09:03:06 -0800 Subject: SF: Unify data types for display modes Remove the RefreshRateConfigs::RefreshRate wrapper around DisplayMode. Store DisplayModes as a SmallMap, so that RefreshRateConfigs uses the same data structure for lookup by ID. Use iterators into that map for all bookkeeping in RefreshRateConfigs. Bug: 182939859 Bug: 185535769 Test: libsurfaceflinger_unittest Change-Id: I7708fa997089802c45d906b17b7a073f5c82105e --- services/surfaceflinger/BufferLayer.cpp | 2 +- services/surfaceflinger/DisplayDevice.cpp | 23 +- .../surfaceflinger/DisplayHardware/DisplayMode.h | 95 ++-- .../Scheduler/RefreshRateConfigs.cpp | 580 ++++++++++---------- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 146 ++--- .../surfaceflinger/Scheduler/RefreshRateStats.h | 17 +- services/surfaceflinger/Scheduler/Scheduler.cpp | 55 +- services/surfaceflinger/Scheduler/Scheduler.h | 8 +- .../Scheduler/VSyncDispatchTimerQueue.h | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 148 +++--- services/surfaceflinger/SurfaceFlinger.h | 9 +- .../fuzzer/surfaceflinger_fuzzers_utils.h | 51 +- .../fuzzer/surfaceflinger_scheduler_fuzzer.cpp | 72 +-- .../fuzzer/surfaceflinger_scheduler_fuzzer.h | 29 +- .../unittests/DisplayDevice_InitiateModeChange.cpp | 74 +-- .../unittests/DisplayTransactionTestHelpers.h | 20 +- .../tests/unittests/LayerHistoryTest.cpp | 25 +- .../tests/unittests/RefreshRateConfigsTest.cpp | 589 ++++++++++----------- .../tests/unittests/RefreshRateStatsTest.cpp | 65 +-- .../tests/unittests/SchedulerTest.cpp | 31 +- .../SurfaceFlinger_DisplayModeSwitching.cpp | 137 ++--- ...ceFlinger_SetupNewDisplayDeviceInternalTest.cpp | 11 +- .../tests/unittests/TestableSurfaceFlinger.h | 110 ++-- .../mock/DisplayHardware/MockDisplayMode.h | 36 ++ .../tests/unittests/mock/MockSchedulerCallback.h | 4 +- 25 files changed, 1061 insertions(+), 1277 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 0b23a5a5bb..635b0884d9 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -404,7 +404,7 @@ void BufferLayer::onPostComposition(const DisplayDevice* display, } if (display) { - const Fps refreshRate = display->refreshRateConfigs().getCurrentRefreshRate().getFps(); + const Fps refreshRate = display->refreshRateConfigs().getActiveMode()->getFps(); const std::optional renderRate = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 99335e59c0..f5a4b3d6ca 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -196,7 +196,7 @@ void DisplayDevice::setActiveMode(DisplayModeId id) { ATRACE_INT(mActiveModeFPSTrace.c_str(), mode->getFps().getIntValue()); mActiveMode = mode; if (mRefreshRateConfigs) { - mRefreshRateConfigs->setCurrentModeId(mActiveMode->getId()); + mRefreshRateConfigs->setActiveModeId(mActiveMode->getId()); } if (mRefreshRateOverlay) { mRefreshRateOverlay->changeRefreshRate(mActiveMode->getFps()); @@ -227,21 +227,16 @@ const DisplayModes& DisplayDevice::getSupportedModes() const { } DisplayModePtr DisplayDevice::getMode(DisplayModeId modeId) const { - const auto it = - std::find_if(mSupportedModes.begin(), mSupportedModes.end(), - [&](const DisplayModePtr& mode) { return mode->getId() == modeId; }); - if (it != mSupportedModes.end()) { - return *it; - } - return nullptr; + const DisplayModePtr nullMode; + return mSupportedModes.get(modeId).value_or(std::cref(nullMode)); } std::optional DisplayDevice::translateModeId(hal::HWConfigId hwcId) const { const auto it = std::find_if(mSupportedModes.begin(), mSupportedModes.end(), - [&](const DisplayModePtr& mode) { return mode->getHwcId() == hwcId; }); + [hwcId](const auto& pair) { return pair.second->getHwcId() == hwcId; }); if (it != mSupportedModes.end()) { - return (*it)->getId(); + return it->second->getId(); } return {}; } @@ -366,12 +361,12 @@ void DisplayDevice::dump(std::string& result) const { activeMode ? to_string(*activeMode).c_str() : "none"); result.append(" supportedModes=\n"); - - for (const auto& mode : mSupportedModes) { - result.append(" "); + for (const auto& [id, mode] : mSupportedModes) { + result.append(" "); result.append(to_string(*mode)); - result.append("\n"); + result.push_back('\n'); } + StringAppendF(&result, " deviceProductInfo="); if (mDeviceProductInfo) { mDeviceProductInfo->dump(result); diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h index 0ab9605fca..61a9a08a5c 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayMode.h +++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h @@ -18,10 +18,10 @@ #include #include -#include #include #include +#include #include #include #include @@ -38,8 +38,17 @@ namespace hal = android::hardware::graphics::composer::hal; class DisplayMode; using DisplayModePtr = std::shared_ptr; -using DisplayModes = std::vector; -using DisplayModeId = StrongTyping; + +// Prevent confusion with fps_approx_ops on the underlying Fps. +bool operator<(const DisplayModePtr&, const DisplayModePtr&) = delete; +bool operator>(const DisplayModePtr&, const DisplayModePtr&) = delete; +bool operator<=(const DisplayModePtr&, const DisplayModePtr&) = delete; +bool operator>=(const DisplayModePtr&, const DisplayModePtr&) = delete; + +using DisplayModeId = StrongTyping; + +using DisplayModes = ftl::SmallMap; +using DisplayModeIterator = DisplayModes::const_iterator; class DisplayMode { public: @@ -61,35 +70,30 @@ public: return *this; } - Builder& setWidth(int32_t width) { - mDisplayMode->mWidth = width; - return *this; - } - - Builder& setHeight(int32_t height) { - mDisplayMode->mHeight = height; + Builder& setResolution(ui::Size resolution) { + mDisplayMode->mResolution = resolution; return *this; } - Builder& setVsyncPeriod(int32_t vsyncPeriod) { + Builder& setVsyncPeriod(nsecs_t vsyncPeriod) { mDisplayMode->mFps = Fps::fromPeriodNsecs(vsyncPeriod); return *this; } Builder& setDpiX(int32_t dpiX) { if (dpiX == -1) { - mDisplayMode->mDpiX = getDefaultDensity(); + mDisplayMode->mDpi.x = getDefaultDensity(); } else { - mDisplayMode->mDpiX = dpiX / 1000.0f; + mDisplayMode->mDpi.x = dpiX / 1000.f; } return *this; } Builder& setDpiY(int32_t dpiY) { if (dpiY == -1) { - mDisplayMode->mDpiY = getDefaultDensity(); + mDisplayMode->mDpi.y = getDefaultDensity(); } else { - mDisplayMode->mDpiY = dpiY / 1000.0f; + mDisplayMode->mDpi.y = dpiY / 1000.f; } return *this; } @@ -107,59 +111,76 @@ public: // information to begin with. This is also used for virtual displays and // older HWC implementations, so be careful about orientation. - auto longDimension = std::max(mDisplayMode->mWidth, mDisplayMode->mHeight); - if (longDimension >= 1080) { + if (std::max(mDisplayMode->getWidth(), mDisplayMode->getHeight()) >= 1080) { return ACONFIGURATION_DENSITY_XHIGH; } else { return ACONFIGURATION_DENSITY_TV; } } + std::shared_ptr mDisplayMode; }; DisplayModeId getId() const { return mId; } + hal::HWConfigId getHwcId() const { return mHwcId; } PhysicalDisplayId getPhysicalDisplayId() const { return mPhysicalDisplayId; } - int32_t getWidth() const { return mWidth; } - int32_t getHeight() const { return mHeight; } - ui::Size getSize() const { return {mWidth, mHeight}; } + ui::Size getResolution() const { return mResolution; } + int32_t getWidth() const { return mResolution.getWidth(); } + int32_t getHeight() const { return mResolution.getHeight(); } + Fps getFps() const { return mFps; } nsecs_t getVsyncPeriod() const { return mFps.getPeriodNsecs(); } - float getDpiX() const { return mDpiX; } - float getDpiY() const { return mDpiY; } + + struct Dpi { + float x = -1; + float y = -1; + + bool operator==(Dpi other) const { return x == other.x && y == other.y; } + }; + + Dpi getDpi() const { return mDpi; } // Switches between modes in the same group are seamless, i.e. // without visual interruptions such as a black screen. int32_t getGroup() const { return mGroup; } - bool equalsExceptDisplayModeId(const DisplayModePtr& other) const { - return mHwcId == other->mHwcId && mWidth == other->mWidth && mHeight == other->mHeight && - getVsyncPeriod() == other->getVsyncPeriod() && mDpiX == other->mDpiX && - mDpiY == other->mDpiY && mGroup == other->mGroup; - } - private: explicit DisplayMode(hal::HWConfigId id) : mHwcId(id) {} - hal::HWConfigId mHwcId; + const hal::HWConfigId mHwcId; DisplayModeId mId; + PhysicalDisplayId mPhysicalDisplayId; - int32_t mWidth = -1; - int32_t mHeight = -1; + ui::Size mResolution; Fps mFps; - float mDpiX = -1; - float mDpiY = -1; + Dpi mDpi; int32_t mGroup = -1; }; +inline bool equalsExceptDisplayModeId(const DisplayMode& lhs, const DisplayMode& rhs) { + return lhs.getHwcId() == rhs.getHwcId() && lhs.getResolution() == rhs.getResolution() && + lhs.getVsyncPeriod() == rhs.getVsyncPeriod() && lhs.getDpi() == rhs.getDpi() && + lhs.getGroup() == rhs.getGroup(); +} + inline std::string to_string(const DisplayMode& mode) { - return base::StringPrintf("{id=%d, hwcId=%d, width=%d, height=%d, refreshRate=%s, " - "dpiX=%.2f, dpiY=%.2f, group=%d}", + return base::StringPrintf("{id=%d, hwcId=%d, resolution=%dx%d, refreshRate=%s, " + "dpi=%.2fx%.2f, group=%d}", mode.getId().value(), mode.getHwcId(), mode.getWidth(), - mode.getHeight(), to_string(mode.getFps()).c_str(), mode.getDpiX(), - mode.getDpiY(), mode.getGroup()); + mode.getHeight(), to_string(mode.getFps()).c_str(), mode.getDpi().x, + mode.getDpi().y, mode.getGroup()); +} + +template +inline DisplayModes makeModes(const DisplayModePtrs&... modePtrs) { + DisplayModes modes; + // Note: The omission of std::move(modePtrs) is intentional, because order of evaluation for + // arguments is unspecified. + (modes.try_emplace(modePtrs->getId(), modePtrs), ...); + return modes; } } // namespace android diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 65c8613c1b..3226f22027 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -38,10 +38,33 @@ namespace android::scheduler { namespace { +struct RefreshRateScore { + DisplayModeIterator modeIt; + float score; +}; + +template +const DisplayModePtr& getMaxScoreRefreshRate(Iterator begin, Iterator end) { + const auto it = + std::max_element(begin, end, [](RefreshRateScore max, RefreshRateScore current) { + const auto& [modeIt, score] = current; + + std::string name = to_string(modeIt->second->getFps()); + ALOGV("%s scores %.2f", name.c_str(), score); + + ATRACE_INT(name.c_str(), static_cast(std::round(score * 100))); + + constexpr float kEpsilon = 0.0001f; + return score > max.score * (1 + kEpsilon); + }); + + return it->modeIt->second; +} + constexpr RefreshRateConfigs::GlobalSignals kNoSignals; std::string formatLayerInfo(const RefreshRateConfigs::LayerRequirement& layer, float weight) { - return base::StringPrintf("%s (type=%s, weight=%.2f seamlessness=%s) %s", layer.name.c_str(), + return base::StringPrintf("%s (type=%s, weight=%.2f, seamlessness=%s) %s", layer.name.c_str(), ftl::enum_string(layer.vote).c_str(), weight, ftl::enum_string(layer.seamlessness).c_str(), to_string(layer.desiredRefreshRate).c_str()); @@ -52,8 +75,8 @@ std::vector constructKnownFrameRates(const DisplayModes& modes) { knownFrameRates.reserve(knownFrameRates.size() + modes.size()); // Add all supported refresh rates. - for (const auto& mode : modes) { - knownFrameRates.push_back(Fps::fromPeriodNsecs(mode->getVsyncPeriod())); + for (const auto& [id, mode] : modes) { + knownFrameRates.push_back(mode->getFps()); } // Sort and remove duplicates. @@ -64,17 +87,51 @@ std::vector constructKnownFrameRates(const DisplayModes& modes) { return knownFrameRates; } -} // namespace +// The Filter is a `bool(const DisplayMode&)` predicate. +template +std::vector sortByRefreshRate(const DisplayModes& modes, Filter&& filter) { + std::vector sortedModes; + sortedModes.reserve(modes.size()); + + for (auto it = modes.begin(); it != modes.end(); ++it) { + const auto& [id, mode] = *it; -using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType; -using RefreshRate = RefreshRateConfigs::RefreshRate; + if (filter(*mode)) { + ALOGV("%s: including mode %d", __func__, id.value()); + sortedModes.push_back(it); + } + } + + std::sort(sortedModes.begin(), sortedModes.end(), [](auto it1, auto it2) { + const auto& mode1 = it1->second; + const auto& mode2 = it2->second; + + if (mode1->getVsyncPeriod() == mode2->getVsyncPeriod()) { + return mode1->getGroup() > mode2->getGroup(); + } + + return mode1->getVsyncPeriod() > mode2->getVsyncPeriod(); + }); -std::string RefreshRate::toString() const { - return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}", - getModeId().value(), mode->getHwcId(), getFps().getValue(), - mode->getWidth(), mode->getHeight(), getModeGroup()); + return sortedModes; +} + +bool canModesSupportFrameRateOverride(const std::vector& sortedModes) { + for (const auto it1 : sortedModes) { + const auto& mode1 = it1->second; + for (const auto it2 : sortedModes) { + const auto& mode2 = it2->second; + + if (RefreshRateConfigs::getFrameRateDivisor(mode1->getFps(), mode2->getFps()) >= 2) { + return true; + } + } + } + return false; } +} // namespace + std::string RefreshRateConfigs::Policy::toString() const { return base::StringPrintf("default mode ID: %d, allowGroupSwitching = %d" ", primary range: %s, app request range: %s", @@ -94,15 +151,14 @@ std::pair RefreshRateConfigs::getDisplayFrames(nsecs_t layerPe return {quotient, remainder}; } -bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer, - const RefreshRate& refreshRate) const { +bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer, Fps refreshRate) const { using namespace fps_approx_ops; switch (layer.vote) { case LayerVoteType::ExplicitExactOrMultiple: case LayerVoteType::Heuristic: if (mConfig.frameRateMultipleThreshold != 0 && - refreshRate.getFps() >= Fps::fromValue(mConfig.frameRateMultipleThreshold) && + refreshRate >= Fps::fromValue(mConfig.frameRateMultipleThreshold) && layer.desiredRefreshRate < Fps::fromValue(mConfig.frameRateMultipleThreshold / 2)) { // Don't vote high refresh rates past the threshold for layers with a low desired // refresh rate. For example, desired 24 fps with 120 Hz threshold means no vote for @@ -120,11 +176,11 @@ bool RefreshRateConfigs::isVoteAllowed(const LayerRequirement& layer, return true; } -float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked( - const LayerRequirement& layer, const RefreshRate& refreshRate) const { +float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(const LayerRequirement& layer, + Fps refreshRate) const { constexpr float kScoreForFractionalPairs = .8f; - const auto displayPeriod = refreshRate.getVsyncPeriod(); + const auto displayPeriod = refreshRate.getPeriodNsecs(); const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs(); if (layer.vote == LayerVoteType::ExplicitDefault) { // Find the actual rate the layer will render, assuming @@ -147,7 +203,7 @@ float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked( if (layer.vote == LayerVoteType::ExplicitExactOrMultiple || layer.vote == LayerVoteType::Heuristic) { - if (isFractionalPairOrMultiple(refreshRate.getFps(), layer.desiredRefreshRate)) { + if (isFractionalPairOrMultiple(refreshRate, layer.desiredRefreshRate)) { return kScoreForFractionalPairs; } @@ -182,8 +238,7 @@ float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked( return 0; } -float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, - const RefreshRate& refreshRate, +float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate, bool isSeamlessSwitch) const { if (!isVoteAllowed(layer, refreshRate)) { return 0; @@ -195,14 +250,14 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye // If the layer wants Max, give higher score to the higher refresh rate if (layer.vote == LayerVoteType::Max) { - const auto ratio = refreshRate.getFps().getValue() / - mAppRequestRefreshRates.back()->getFps().getValue(); + const auto& maxRefreshRate = mAppRequestRefreshRates.back()->second; + const auto ratio = refreshRate.getValue() / maxRefreshRate->getFps().getValue(); // use ratio^2 to get a lower score the more we get further from peak return ratio * ratio; } if (layer.vote == LayerVoteType::ExplicitExact) { - const int divisor = getFrameRateDivisor(refreshRate.getFps(), layer.desiredRefreshRate); + const int divisor = getFrameRateDivisor(refreshRate, layer.desiredRefreshRate); if (mSupportsFrameRateOverrideByContent) { // Since we support frame rate override, allow refresh rates which are // multiples of the layer's request, as those apps would be throttled @@ -215,7 +270,7 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye // If the layer frame rate is a divisor of the refresh rate it should score // the highest score. - if (getFrameRateDivisor(refreshRate.getFps(), layer.desiredRefreshRate) > 0) { + if (getFrameRateDivisor(refreshRate, layer.desiredRefreshRate) > 0) { return 1.0f * seamlessness; } @@ -227,14 +282,9 @@ float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& laye kNonExactMatchingPenalty; } -struct RefreshRateScore { - const RefreshRate* refreshRate; - float score; -}; - auto RefreshRateConfigs::getBestRefreshRate(const std::vector& layers, GlobalSignals signals) const - -> std::pair { + -> std::pair { std::lock_guard lock(mLock); if (mGetBestRefreshRateCache && @@ -249,7 +299,7 @@ auto RefreshRateConfigs::getBestRefreshRate(const std::vector& auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector& layers, GlobalSignals signals) const - -> std::pair { + -> std::pair { ATRACE_CALL(); ALOGV("%s: %zu layers", __func__, layers.size()); @@ -298,21 +348,22 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vector 0 || explicitExact > 0; const Policy* policy = getCurrentPolicyLocked(); - const auto& defaultMode = mRefreshRates.at(policy->defaultMode); + const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get(); // If the default mode group is different from the group of current mode, // this means a layer requesting a seamed mode switch just disappeared and // we should switch back to the default group. // However if a seamed layer is still present we anchor around the group // of the current mode, in order to prevent unnecessary seamed mode switches // (e.g. when pausing a video playback). - const auto anchorGroup = seamedFocusedLayers > 0 ? mCurrentRefreshRate->getModeGroup() - : defaultMode->getModeGroup(); + const auto anchorGroup = + seamedFocusedLayers > 0 ? mActiveModeIt->second->getGroup() : defaultMode->getGroup(); // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've // selected a refresh rate to see if we should apply touch boost. if (signals.touch && !hasExplicitVoteLayers) { - ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str()); - return {getMaxRefreshRateByPolicyLocked(anchorGroup), GlobalSignals{.touch = true}}; + const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup); + ALOGV("TouchBoost - choose %s", to_string(max->getFps()).c_str()); + return {max, GlobalSignals{.touch = true}}; } // If the primary range consists of a single refresh rate then we can only @@ -322,28 +373,30 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vectorprimaryRange.min, policy->primaryRange.max); if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { - ALOGV("Idle - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str()); - return {getMinRefreshRateByPolicyLocked(), GlobalSignals{.idle = true}}; + const DisplayModePtr& min = getMinRefreshRateByPolicyLocked(); + ALOGV("Idle - choose %s", to_string(min->getFps()).c_str()); + return {min, GlobalSignals{.idle = true}}; } if (layers.empty() || noVoteLayers == layers.size()) { - const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); - ALOGV("no layers with votes - choose %s", refreshRate.getName().c_str()); - return {refreshRate, kNoSignals}; + const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup); + ALOGV("no layers with votes - choose %s", to_string(max->getFps()).c_str()); + return {max, kNoSignals}; } // Only if all layers want Min we should return Min if (noVoteLayers + minVoteLayers == layers.size()) { - ALOGV("all layers Min - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str()); - return {getMinRefreshRateByPolicyLocked(), kNoSignals}; + const DisplayModePtr& min = getMinRefreshRateByPolicyLocked(); + ALOGV("all layers Min - choose %s", to_string(min->getFps()).c_str()); + return {min, kNoSignals}; } // Find the best refresh rate based on score std::vector scores; scores.reserve(mAppRequestRefreshRates.size()); - for (const auto refreshRate : mAppRequestRefreshRates) { - scores.emplace_back(RefreshRateScore{refreshRate, 0.0f}); + for (const DisplayModeIterator modeIt : mAppRequestRefreshRates) { + scores.emplace_back(RefreshRateScore{modeIt, 0.0f}); } for (const auto& layer : layers) { @@ -354,17 +407,16 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vectorgetModeGroup() == mCurrentRefreshRate->getModeGroup(); + for (auto& [modeIt, score] : scores) { + const auto& [id, mode] = *modeIt; + const bool isSeamlessSwitch = mode->getGroup() == mActiveModeIt->second->getGroup(); if (layer.seamlessness == Seamlessness::OnlySeamless && !isSeamlessSwitch) { ALOGV("%s ignores %s to avoid non-seamless switch. Current mode = %s", - formatLayerInfo(layer, weight).c_str(), - scores[i].refreshRate->toString().c_str(), - mCurrentRefreshRate->toString().c_str()); + formatLayerInfo(layer, weight).c_str(), to_string(*mode).c_str(), + to_string(*mActiveModeIt->second).c_str()); continue; } @@ -372,9 +424,8 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vectortoString().c_str(), - mCurrentRefreshRate->toString().c_str()); + formatLayerInfo(layer, weight).c_str(), to_string(*mode).c_str(), + to_string(*mActiveModeIt->second).c_str()); continue; } @@ -383,17 +434,14 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vectorgetModeGroup() == anchorGroup; + const bool isInPolicyForDefault = mode->getGroup() == anchorGroup; if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault) { ALOGV("%s ignores %s. Current mode = %s", formatLayerInfo(layer, weight).c_str(), - scores[i].refreshRate->toString().c_str(), - mCurrentRefreshRate->toString().c_str()); + to_string(*mode).c_str(), to_string(*mActiveModeIt->second).c_str()); continue; } - const bool inPrimaryRange = - policy->primaryRange.includes(scores[i].refreshRate->getFps()); - + const bool inPrimaryRange = policy->primaryRange.includes(mode->getFps()); if ((primaryRangeIsSingleRate || !inPrimaryRange) && !(layer.focused && (layer.vote == LayerVoteType::ExplicitDefault || @@ -404,30 +452,31 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vectorgetFps(), isSeamlessSwitch); ALOGV("%s gives %s score of %.4f", formatLayerInfo(layer, weight).c_str(), - scores[i].refreshRate->getName().c_str(), layerScore); - scores[i].score += weight * layerScore; + to_string(mode->getFps()).c_str(), layerScore); + + score += weight * layerScore; } } // Now that we scored all the refresh rates we need to pick the one that got the highest score. // In case of a tie we will pick the higher refresh rate if any of the layers wanted Max, // or the lower otherwise. - const RefreshRate* bestRefreshRate = maxVoteLayers > 0 - ? getBestRefreshRate(scores.rbegin(), scores.rend()) - : getBestRefreshRate(scores.begin(), scores.end()); + const DisplayModePtr& bestRefreshRate = maxVoteLayers > 0 + ? getMaxScoreRefreshRate(scores.rbegin(), scores.rend()) + : getMaxScoreRefreshRate(scores.begin(), scores.end()); if (primaryRangeIsSingleRate) { // If we never scored any layers, then choose the rate from the primary // range instead of picking a random score from the app range. if (std::all_of(scores.begin(), scores.end(), [](RefreshRateScore score) { return score.score == 0; })) { - const auto& refreshRate = getMaxRefreshRateByPolicyLocked(anchorGroup); - ALOGV("layers not scored - choose %s", refreshRate.getName().c_str()); - return {refreshRate, kNoSignals}; + const DisplayModePtr& max = getMaxRefreshRateByPolicyLocked(anchorGroup); + ALOGV("layers not scored - choose %s", to_string(max->getFps()).c_str()); + return {max, kNoSignals}; } else { - return {*bestRefreshRate, kNoSignals}; + return {bestRefreshRate, kNoSignals}; } } @@ -435,7 +484,7 @@ auto RefreshRateConfigs::getBestRefreshRateLocked(const std::vectorgetFps() < touchRefreshRate.getFps()) { - ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str()); + bestRefreshRate->getFps() < touchRefreshRate->getFps()) { + ALOGV("TouchBoost - choose %s", to_string(touchRefreshRate->getFps()).c_str()); return {touchRefreshRate, GlobalSignals{.touch = true}}; } - return {*bestRefreshRate, kNoSignals}; + return {bestRefreshRate, kNoSignals}; } std::unordered_map> @@ -489,26 +538,28 @@ groupLayersByUid(const std::vector& layers return layersByUid; } -std::vector initializeScoresForAllRefreshRates( - const AllRefreshRatesMapType& refreshRates) { - std::vector scores; - scores.reserve(refreshRates.size()); - for (const auto& [ignored, refreshRate] : refreshRates) { - scores.emplace_back(RefreshRateScore{refreshRate.get(), 0.0f}); - } - std::sort(scores.begin(), scores.end(), - [](const auto& a, const auto& b) { return *a.refreshRate < *b.refreshRate; }); - return scores; -} - RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverrides( - const std::vector& layers, Fps displayFrameRate, + const std::vector& layers, Fps displayRefreshRate, GlobalSignals globalSignals) const { ATRACE_CALL(); - ALOGV("getFrameRateOverrides %zu layers", layers.size()); + ALOGV("%s: %zu layers", __func__, layers.size()); + std::lock_guard lock(mLock); - std::vector scores = initializeScoresForAllRefreshRates(mRefreshRates); + + std::vector scores; + scores.reserve(mDisplayModes.size()); + + for (auto it = mDisplayModes.begin(); it != mDisplayModes.end(); ++it) { + scores.emplace_back(RefreshRateScore{it, 0.0f}); + } + + std::sort(scores.begin(), scores.end(), [](const auto& lhs, const auto& rhs) { + const auto& mode1 = lhs.modeIt->second; + const auto& mode2 = rhs.modeIt->second; + return isStrictlyLess(mode1->getFps(), mode2->getFps()); + }); + std::unordered_map> layersByUid = groupLayersByUid(layers); UidToFrameRateOverride frameRateOverrides; @@ -524,8 +575,8 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr continue; } - for (auto& score : scores) { - score.score = 0; + for (auto& [_, score] : scores) { + score = 0; } for (const auto& layer : layersWithSameUid) { @@ -536,137 +587,114 @@ RefreshRateConfigs::UidToFrameRateOverride RefreshRateConfigs::getFrameRateOverr LOG_ALWAYS_FATAL_IF(layer->vote != LayerVoteType::ExplicitDefault && layer->vote != LayerVoteType::ExplicitExactOrMultiple && layer->vote != LayerVoteType::ExplicitExact); - for (RefreshRateScore& score : scores) { - const auto layerScore = calculateLayerScoreLocked(*layer, *score.refreshRate, - /*isSeamlessSwitch*/ true); - score.score += layer->weight * layerScore; + for (auto& [modeIt, score] : scores) { + constexpr bool isSeamlessSwitch = true; + const auto layerScore = calculateLayerScoreLocked(*layer, modeIt->second->getFps(), + isSeamlessSwitch); + score += layer->weight * layerScore; } } // We just care about the refresh rates which are a divisor of the // display refresh rate - auto iter = - std::remove_if(scores.begin(), scores.end(), [&](const RefreshRateScore& score) { - return getFrameRateDivisor(displayFrameRate, score.refreshRate->getFps()) == 0; - }); - scores.erase(iter, scores.end()); + const auto it = std::remove_if(scores.begin(), scores.end(), [&](RefreshRateScore score) { + const auto& [id, mode] = *score.modeIt; + return getFrameRateDivisor(displayRefreshRate, mode->getFps()) == 0; + }); + scores.erase(it, scores.end()); // If we never scored any layers, we don't have a preferred frame rate if (std::all_of(scores.begin(), scores.end(), - [](const RefreshRateScore& score) { return score.score == 0; })) { + [](RefreshRateScore score) { return score.score == 0; })) { continue; } // Now that we scored all the refresh rates we need to pick the one that got the highest // score. - const RefreshRate* bestRefreshRate = getBestRefreshRate(scores.begin(), scores.end()); + const DisplayModePtr& bestRefreshRate = + getMaxScoreRefreshRate(scores.begin(), scores.end()); + frameRateOverrides.emplace(uid, bestRefreshRate->getFps()); } return frameRateOverrides; } -template -const RefreshRate* RefreshRateConfigs::getBestRefreshRate(Iter begin, Iter end) const { - constexpr auto kEpsilon = 0.0001f; - const RefreshRate* bestRefreshRate = begin->refreshRate; - float max = begin->score; - for (auto i = begin; i != end; ++i) { - const auto [refreshRate, score] = *i; - ALOGV("%s scores %.2f", refreshRate->getName().c_str(), score); - - ATRACE_INT(refreshRate->getName().c_str(), static_cast(std::round(score * 100))); - - if (score > max * (1 + kEpsilon)) { - max = score; - bestRefreshRate = refreshRate; - } - } - - return bestRefreshRate; -} - std::optional RefreshRateConfigs::onKernelTimerChanged( - std::optional desiredActiveConfigId, bool timerExpired) const { + std::optional desiredActiveModeId, bool timerExpired) const { std::lock_guard lock(mLock); - const auto& current = desiredActiveConfigId ? *mRefreshRates.at(*desiredActiveConfigId) - : *mCurrentRefreshRate; - const auto& min = *mMinSupportedRefreshRate; + const DisplayModePtr& current = desiredActiveModeId + ? mDisplayModes.get(*desiredActiveModeId)->get() + : mActiveModeIt->second; - if (current != min) { - const auto& refreshRate = timerExpired ? min : current; - return refreshRate.getFps(); + const DisplayModePtr& min = mMinRefreshRateModeIt->second; + if (current == min) { + return {}; } - return {}; + const auto& mode = timerExpired ? min : current; + return mode->getFps(); } -const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const { - for (auto refreshRate : mPrimaryRefreshRates) { - if (mCurrentRefreshRate->getModeGroup() == refreshRate->getModeGroup()) { - return *refreshRate; +const DisplayModePtr& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const { + for (const DisplayModeIterator modeIt : mPrimaryRefreshRates) { + const auto& mode = modeIt->second; + if (mActiveModeIt->second->getGroup() == mode->getGroup()) { + return mode; } } + ALOGE("Can't find min refresh rate by policy with the same mode group" " as the current mode %s", - mCurrentRefreshRate->toString().c_str()); - // Defaulting to the lowest refresh rate - return *mPrimaryRefreshRates.front(); + to_string(*mActiveModeIt->second).c_str()); + + // Default to the lowest refresh rate. + return mPrimaryRefreshRates.front()->second; } -RefreshRate RefreshRateConfigs::getMaxRefreshRateByPolicy() const { +DisplayModePtr RefreshRateConfigs::getMaxRefreshRateByPolicy() const { std::lock_guard lock(mLock); return getMaxRefreshRateByPolicyLocked(); } -const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const { - for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); it++) { - const auto& refreshRate = (**it); - if (anchorGroup == refreshRate.getModeGroup()) { - return refreshRate; +const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const { + for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); ++it) { + const auto& mode = (*it)->second; + if (anchorGroup == mode->getGroup()) { + return mode; } } + ALOGE("Can't find max refresh rate by policy with the same mode group" " as the current mode %s", - mCurrentRefreshRate->toString().c_str()); - // Defaulting to the highest refresh rate - return *mPrimaryRefreshRates.back(); -} + to_string(*mActiveModeIt->second).c_str()); -RefreshRate RefreshRateConfigs::getCurrentRefreshRate() const { - std::lock_guard lock(mLock); - return *mCurrentRefreshRate; + // Default to the highest refresh rate. + return mPrimaryRefreshRates.back()->second; } -RefreshRate RefreshRateConfigs::getCurrentRefreshRateByPolicy() const { +DisplayModePtr RefreshRateConfigs::getActiveMode() const { std::lock_guard lock(mLock); - return getCurrentRefreshRateByPolicyLocked(); + return mActiveModeIt->second; } -const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicyLocked() const { - if (std::find(mAppRequestRefreshRates.begin(), mAppRequestRefreshRates.end(), - mCurrentRefreshRate) != mAppRequestRefreshRates.end()) { - return *mCurrentRefreshRate; - } - return *mRefreshRates.at(getCurrentPolicyLocked()->defaultMode); -} - -void RefreshRateConfigs::setCurrentModeId(DisplayModeId modeId) { +void RefreshRateConfigs::setActiveModeId(DisplayModeId modeId) { std::lock_guard lock(mLock); // Invalidate the cached invocation to getBestRefreshRate. This forces // the refresh rate to be recomputed on the next call to getBestRefreshRate. mGetBestRefreshRateCache.reset(); - mCurrentRefreshRate = mRefreshRates.at(modeId).get(); + mActiveModeIt = mDisplayModes.find(modeId); + LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end()); } -RefreshRateConfigs::RefreshRateConfigs(const DisplayModes& modes, DisplayModeId currentModeId, +RefreshRateConfigs::RefreshRateConfigs(DisplayModes modes, DisplayModeId activeModeId, Config config) : mKnownFrameRates(constructKnownFrameRates(modes)), mConfig(config) { initializeIdleTimer(); - updateDisplayModes(modes, currentModeId); + updateDisplayModes(std::move(modes), activeModeId); } void RefreshRateConfigs::initializeIdleTimer() { @@ -688,64 +716,43 @@ void RefreshRateConfigs::initializeIdleTimer() { } } -void RefreshRateConfigs::updateDisplayModes(const DisplayModes& modes, - DisplayModeId currentModeId) { +void RefreshRateConfigs::updateDisplayModes(DisplayModes modes, DisplayModeId activeModeId) { std::lock_guard lock(mLock); - // The current mode should be supported - LOG_ALWAYS_FATAL_IF(std::none_of(modes.begin(), modes.end(), [&](DisplayModePtr mode) { - return mode->getId() == currentModeId; - })); - // Invalidate the cached invocation to getBestRefreshRate. This forces // the refresh rate to be recomputed on the next call to getBestRefreshRate. mGetBestRefreshRateCache.reset(); - mRefreshRates.clear(); - for (const auto& mode : modes) { - const auto modeId = mode->getId(); - mRefreshRates.emplace(modeId, - std::make_unique(mode, RefreshRate::ConstructorTag(0))); - if (modeId == currentModeId) { - mCurrentRefreshRate = mRefreshRates.at(modeId).get(); - } - } + mDisplayModes = std::move(modes); + mActiveModeIt = mDisplayModes.find(activeModeId); + LOG_ALWAYS_FATAL_IF(mActiveModeIt == mDisplayModes.end()); + + const auto sortedModes = + sortByRefreshRate(mDisplayModes, [](const DisplayMode&) { return true; }); + mMinRefreshRateModeIt = sortedModes.front(); + mMaxRefreshRateModeIt = sortedModes.back(); - std::vector sortedModes; - getSortedRefreshRateListLocked([](const RefreshRate&) { return true; }, &sortedModes); // Reset the policy because the old one may no longer be valid. mDisplayManagerPolicy = {}; - mDisplayManagerPolicy.defaultMode = currentModeId; - mMinSupportedRefreshRate = sortedModes.front(); - mMaxSupportedRefreshRate = sortedModes.back(); - - mSupportsFrameRateOverrideByContent = false; - if (mConfig.enableFrameRateOverride) { - for (const auto& mode1 : sortedModes) { - for (const auto& mode2 : sortedModes) { - if (getFrameRateDivisor(mode1->getFps(), mode2->getFps()) >= 2) { - mSupportsFrameRateOverrideByContent = true; - break; - } - } - } - } + mDisplayManagerPolicy.defaultMode = activeModeId; + + mSupportsFrameRateOverrideByContent = + mConfig.enableFrameRateOverride && canModesSupportFrameRateOverride(sortedModes); constructAvailableRefreshRates(); } bool RefreshRateConfigs::isPolicyValidLocked(const Policy& policy) const { // defaultMode must be a valid mode, and within the given refresh rate range. - auto iter = mRefreshRates.find(policy.defaultMode); - if (iter == mRefreshRates.end()) { + if (const auto mode = mDisplayModes.get(policy.defaultMode)) { + if (!policy.primaryRange.includes(mode->get()->getFps())) { + ALOGE("Default mode is not in the primary range."); + return false; + } + } else { ALOGE("Default mode is not found."); return false; } - const RefreshRate& refreshRate = *iter->second; - if (!policy.primaryRange.includes(refreshRate.getFps())) { - ALOGE("Default mode is not in the primary range."); - return false; - } using namespace fps_approx_ops; return policy.appRequestRange.min <= policy.primaryRange.min && @@ -799,77 +806,46 @@ RefreshRateConfigs::Policy RefreshRateConfigs::getDisplayManagerPolicy() const { bool RefreshRateConfigs::isModeAllowed(DisplayModeId modeId) const { std::lock_guard lock(mLock); - for (const RefreshRate* refreshRate : mAppRequestRefreshRates) { - if (refreshRate->getModeId() == modeId) { - return true; - } - } - return false; -} - -void RefreshRateConfigs::getSortedRefreshRateListLocked( - const std::function& shouldAddRefreshRate, - std::vector* outRefreshRates) { - outRefreshRates->clear(); - outRefreshRates->reserve(mRefreshRates.size()); - for (const auto& [type, refreshRate] : mRefreshRates) { - if (shouldAddRefreshRate(*refreshRate)) { - ALOGV("getSortedRefreshRateListLocked: mode %d added to list policy", - refreshRate->getModeId().value()); - outRefreshRates->push_back(refreshRate.get()); - } - } - - std::sort(outRefreshRates->begin(), outRefreshRates->end(), - [](const auto refreshRate1, const auto refreshRate2) { - if (refreshRate1->mode->getVsyncPeriod() != - refreshRate2->mode->getVsyncPeriod()) { - return refreshRate1->mode->getVsyncPeriod() > - refreshRate2->mode->getVsyncPeriod(); - } else { - return refreshRate1->mode->getGroup() > refreshRate2->mode->getGroup(); - } - }); + return std::any_of(mAppRequestRefreshRates.begin(), mAppRequestRefreshRates.end(), + [modeId](DisplayModeIterator modeIt) { + return modeIt->second->getId() == modeId; + }); } void RefreshRateConfigs::constructAvailableRefreshRates() { - // Filter modes based on current policy and sort based on vsync period + // Filter modes based on current policy and sort on refresh rate. const Policy* policy = getCurrentPolicyLocked(); - const auto& defaultMode = mRefreshRates.at(policy->defaultMode)->mode; - ALOGV("constructAvailableRefreshRates: %s ", policy->toString().c_str()); - - auto filterRefreshRates = - [&](FpsRange range, const char* rangeName, - std::vector* outRefreshRates) REQUIRES(mLock) { - getSortedRefreshRateListLocked( - [&](const RefreshRate& refreshRate) REQUIRES(mLock) { - const auto& mode = refreshRate.mode; - - return mode->getHeight() == defaultMode->getHeight() && - mode->getWidth() == defaultMode->getWidth() && - mode->getDpiX() == defaultMode->getDpiX() && - mode->getDpiY() == defaultMode->getDpiY() && - (policy->allowGroupSwitching || - mode->getGroup() == defaultMode->getGroup()) && - range.includes(mode->getFps()); - }, - outRefreshRates); - - LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(), "No matching modes for %s range %s", - rangeName, to_string(range).c_str()); - - auto stringifyRefreshRates = [&]() -> std::string { - std::string str; - for (auto refreshRate : *outRefreshRates) { - base::StringAppendF(&str, "%s ", refreshRate->getName().c_str()); - } - return str; - }; - ALOGV("%s refresh rates: %s", rangeName, stringifyRefreshRates().c_str()); - }; + ALOGV("%s: %s ", __func__, policy->toString().c_str()); + + const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get(); + + const auto filterRefreshRates = [&](FpsRange range, const char* rangeName) REQUIRES(mLock) { + const auto filter = [&](const DisplayMode& mode) { + return mode.getResolution() == defaultMode->getResolution() && + mode.getDpi() == defaultMode->getDpi() && + (policy->allowGroupSwitching || mode.getGroup() == defaultMode->getGroup()) && + range.includes(mode.getFps()); + }; + + const auto modes = sortByRefreshRate(mDisplayModes, filter); + LOG_ALWAYS_FATAL_IF(modes.empty(), "No matching modes for %s range %s", rangeName, + to_string(range).c_str()); + + const auto stringifyModes = [&] { + std::string str; + for (const auto modeIt : modes) { + str += to_string(modeIt->second->getFps()); + str.push_back(' '); + } + return str; + }; + ALOGV("%s refresh rates: %s", rangeName, stringifyModes().c_str()); + + return modes; + }; - filterRefreshRates(policy->primaryRange, "primary", &mPrimaryRefreshRates); - filterRefreshRates(policy->appRequestRange, "app request", &mAppRequestRefreshRates); + mPrimaryRefreshRates = filterRefreshRates(policy->primaryRange, "primary"); + mAppRequestRefreshRates = filterRefreshRates(policy->appRequestRange, "app request"); } Fps RefreshRateConfigs::findClosestKnownFrameRate(Fps frameRate) const { @@ -893,36 +869,39 @@ Fps RefreshRateConfigs::findClosestKnownFrameRate(Fps frameRate) const { RefreshRateConfigs::KernelIdleTimerAction RefreshRateConfigs::getIdleTimerAction() const { std::lock_guard lock(mLock); - const auto& deviceMin = *mMinSupportedRefreshRate; - const auto& minByPolicy = getMinRefreshRateByPolicyLocked(); - const auto& maxByPolicy = getMaxRefreshRateByPolicyLocked(); - const auto& currentPolicy = getCurrentPolicyLocked(); + + const Fps deviceMinFps = mMinRefreshRateModeIt->second->getFps(); + const DisplayModePtr& minByPolicy = getMinRefreshRateByPolicyLocked(); // Kernel idle timer will set the refresh rate to the device min. If DisplayManager says that // the min allowed refresh rate is higher than the device min, we do not want to enable the // timer. - if (deviceMin < minByPolicy) { - return RefreshRateConfigs::KernelIdleTimerAction::TurnOff; + if (isStrictlyLess(deviceMinFps, minByPolicy->getFps())) { + return KernelIdleTimerAction::TurnOff; } + + const DisplayModePtr& maxByPolicy = getMaxRefreshRateByPolicyLocked(); if (minByPolicy == maxByPolicy) { - // when min primary range in display manager policy is below device min turn on the timer. - if (isApproxLess(currentPolicy->primaryRange.min, deviceMin.getFps())) { - return RefreshRateConfigs::KernelIdleTimerAction::TurnOn; + // Turn on the timer when the min of the primary range is below the device min. + if (const Policy* currentPolicy = getCurrentPolicyLocked(); + isApproxLess(currentPolicy->primaryRange.min, deviceMinFps)) { + return KernelIdleTimerAction::TurnOn; } - return RefreshRateConfigs::KernelIdleTimerAction::TurnOff; + return KernelIdleTimerAction::TurnOff; } + // Turn on the timer in all other cases. - return RefreshRateConfigs::KernelIdleTimerAction::TurnOn; + return KernelIdleTimerAction::TurnOn; } -int RefreshRateConfigs::getFrameRateDivisor(Fps displayFrameRate, Fps layerFrameRate) { +int RefreshRateConfigs::getFrameRateDivisor(Fps displayRefreshRate, Fps layerFrameRate) { // This calculation needs to be in sync with the java code // in DisplayManagerService.getDisplayInfoForFrameRateOverride // The threshold must be smaller than 0.001 in order to differentiate // between the fractional pairs (e.g. 59.94 and 60). constexpr float kThreshold = 0.0009f; - const auto numPeriods = displayFrameRate.getValue() / layerFrameRate.getValue(); + const auto numPeriods = displayRefreshRate.getValue() / layerFrameRate.getValue(); const auto numPeriodsRounded = std::round(numPeriods); if (std::abs(numPeriods - numPeriodsRounded) > kThreshold) { return 0; @@ -952,29 +931,32 @@ void RefreshRateConfigs::dump(std::string& result) const { currentPolicy.toString().c_str()); } - auto mode = mCurrentRefreshRate->mode; - base::StringAppendF(&result, "Current mode: %s\n", mCurrentRefreshRate->toString().c_str()); + base::StringAppendF(&result, "Active mode: %s\n", to_string(*mActiveModeIt->second).c_str()); - result.append("Refresh rates:\n"); - for (const auto& [id, refreshRate] : mRefreshRates) { - mode = refreshRate->mode; - base::StringAppendF(&result, "\t%s\n", refreshRate->toString().c_str()); + result.append("Display modes:\n"); + for (const auto& [id, mode] : mDisplayModes) { + result.push_back('\t'); + result.append(to_string(*mode)); + result.push_back('\n'); } base::StringAppendF(&result, "Supports Frame Rate Override By Content: %s\n", mSupportsFrameRateOverrideByContent ? "yes" : "no"); - base::StringAppendF(&result, "Idle timer: "); - if (mConfig.kernelIdleTimerController.has_value()) { - if (mConfig.kernelIdleTimerController == KernelIdleTimerController::Sysprop) { - base::StringAppendF(&result, "(kernel(sysprop))"); - } else { - base::StringAppendF(&result, "(kernel(hwc))"); - } + + result.append("Idle timer: "); + if (const auto controller = mConfig.kernelIdleTimerController) { + base::StringAppendF(&result, "(kernel via %s) ", ftl::enum_string(*controller).c_str()); + } else { + result.append("(platform) "); + } + + if (mIdleTimer) { + result.append(mIdleTimer->dump()); } else { - base::StringAppendF(&result, "(platform)"); + result.append("off"); } - base::StringAppendF(&result, " %s\n", mIdleTimer ? mIdleTimer->dump().c_str() : "off"); - result.append("\n"); + + result.append("\n\n"); } std::chrono::milliseconds RefreshRateConfigs::getIdleTimerTimeout() { diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 30d3edd05e..05a8692f51 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -56,50 +56,6 @@ public: static constexpr nsecs_t MARGIN_FOR_PERIOD_CALCULATION = std::chrono::nanoseconds(800us).count(); - class RefreshRate { - private: - // Effectively making the constructor private while allowing - // std::make_unique to create the object - struct ConstructorTag { - explicit ConstructorTag(int) {} - }; - - public: - RefreshRate(DisplayModePtr mode, ConstructorTag) : mode(mode) {} - - DisplayModeId getModeId() const { return mode->getId(); } - nsecs_t getVsyncPeriod() const { return mode->getVsyncPeriod(); } - int32_t getModeGroup() const { return mode->getGroup(); } - std::string getName() const { return to_string(getFps()); } - Fps getFps() const { return mode->getFps(); } - DisplayModePtr getMode() const { return mode; } - - // Checks whether the fps of this RefreshRate struct is within a given min and max refresh - // rate passed in. Margin of error is applied to the boundaries for approximation. - bool inPolicy(Fps minRefreshRate, Fps maxRefreshRate) const; - - bool operator==(const RefreshRate& other) const { return mode == other.mode; } - bool operator!=(const RefreshRate& other) const { return !operator==(other); } - - bool operator<(const RefreshRate& other) const { - return isStrictlyLess(getFps(), other.getFps()); - } - - std::string toString() const; - friend std::ostream& operator<<(std::ostream& os, const RefreshRate& refreshRate) { - return os << refreshRate.toString(); - } - - private: - friend RefreshRateConfigs; - friend class RefreshRateConfigsTest; - - DisplayModePtr mode; - }; - - using AllRefreshRatesMapType = - std::unordered_map>; - struct Policy { private: static constexpr int kAllowGroupSwitchingDefault = false; @@ -236,12 +192,12 @@ public: // Returns the refresh rate that best fits the given layers, and whether the refresh rate was // chosen based on touch boost and/or idle timer. - std::pair getBestRefreshRate(const std::vector&, - GlobalSignals) const EXCLUDES(mLock); + std::pair getBestRefreshRate( + const std::vector&, GlobalSignals) const EXCLUDES(mLock); FpsRange getSupportedRefreshRateRange() const EXCLUDES(mLock) { std::lock_guard lock(mLock); - return {mMinSupportedRefreshRate->getFps(), mMaxSupportedRefreshRate->getFps()}; + return {mMinRefreshRateModeIt->second->getFps(), mMaxRefreshRateModeIt->second->getFps()}; } std::optional onKernelTimerChanged(std::optional desiredActiveModeId, @@ -249,30 +205,15 @@ public: // Returns the highest refresh rate according to the current policy. May change at runtime. Only // uses the primary range, not the app request range. - RefreshRate getMaxRefreshRateByPolicy() const EXCLUDES(mLock); - - // Returns the current refresh rate - RefreshRate getCurrentRefreshRate() const EXCLUDES(mLock); - - // Returns the current refresh rate, if allowed. Otherwise the default that is allowed by - // the policy. - RefreshRate getCurrentRefreshRateByPolicy() const; - - // Returns the refresh rate that corresponds to a DisplayModeId. This may change at - // runtime. - // TODO(b/159590486) An invalid mode id may be given here if the dipslay modes have changed. - RefreshRate getRefreshRateFromModeId(DisplayModeId modeId) const EXCLUDES(mLock) { - std::lock_guard lock(mLock); - return *mRefreshRates.at(modeId); - }; + DisplayModePtr getMaxRefreshRateByPolicy() const EXCLUDES(mLock); - // Stores the current modeId the device operates at - void setCurrentModeId(DisplayModeId) EXCLUDES(mLock); + void setActiveModeId(DisplayModeId) EXCLUDES(mLock); + DisplayModePtr getActiveMode() const EXCLUDES(mLock); // Returns a known frame rate that is the closest to frameRate Fps findClosestKnownFrameRate(Fps frameRate) const; - enum class KernelIdleTimerController { Sysprop, HwcApi }; + enum class KernelIdleTimerController { Sysprop, HwcApi, ftl_last = HwcApi }; // Configuration flags. struct Config { @@ -291,7 +232,7 @@ public: std::optional kernelIdleTimerController; }; - RefreshRateConfigs(const DisplayModes&, DisplayModeId, + RefreshRateConfigs(DisplayModes, DisplayModeId activeModeId, Config config = {.enableFrameRateOverride = false, .frameRateMultipleThreshold = 0, .idleTimerTimeout = 0ms, @@ -305,7 +246,7 @@ public: // differ in resolution. bool canSwitch() const EXCLUDES(mLock) { std::lock_guard lock(mLock); - return mRefreshRates.size() > 1; + return mDisplayModes.size() > 1; } // Class to enumerate options around toggling the kernel timer on and off. @@ -323,7 +264,7 @@ public: // Return the display refresh rate divisor to match the layer // frame rate, or 0 if the display refresh rate is not a multiple of the // layer refresh rate. - static int getFrameRateDivisor(Fps displayFrameRate, Fps layerFrameRate); + static int getFrameRateDivisor(Fps displayRefreshRate, Fps layerFrameRate); // Returns if the provided frame rates have a ratio t*1000/1001 or t*1001/1000 // for an integer t. @@ -391,54 +332,39 @@ private: void constructAvailableRefreshRates() REQUIRES(mLock); - void getSortedRefreshRateListLocked( - const std::function& shouldAddRefreshRate, - std::vector* outRefreshRates) REQUIRES(mLock); - - std::pair getBestRefreshRateLocked( + std::pair getBestRefreshRateLocked( const std::vector&, GlobalSignals) const REQUIRES(mLock); - // Returns the refresh rate with the highest score in the collection specified from begin - // to end. If there are more than one with the same highest refresh rate, the first one is - // returned. - template - const RefreshRate* getBestRefreshRate(Iter begin, Iter end) const; - // Returns number of display frames and remainder when dividing the layer refresh period by // display refresh period. std::pair getDisplayFrames(nsecs_t layerPeriod, nsecs_t displayPeriod) const; // Returns the lowest refresh rate according to the current policy. May change at runtime. Only // uses the primary range, not the app request range. - const RefreshRate& getMinRefreshRateByPolicyLocked() const REQUIRES(mLock); + const DisplayModePtr& getMinRefreshRateByPolicyLocked() const REQUIRES(mLock); // Returns the highest refresh rate according to the current policy. May change at runtime. Only // uses the primary range, not the app request range. - const RefreshRate& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock) { - return getMaxRefreshRateByPolicyLocked(mCurrentRefreshRate->getModeGroup()); + const DisplayModePtr& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock); + const DisplayModePtr& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock) { + return getMaxRefreshRateByPolicyLocked(mActiveModeIt->second->getGroup()); } - const RefreshRate& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock); - - // Returns the current refresh rate, if allowed. Otherwise the default that is allowed by - // the policy. - const RefreshRate& getCurrentRefreshRateByPolicyLocked() const REQUIRES(mLock); - const Policy* getCurrentPolicyLocked() const REQUIRES(mLock); bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock); // Returns whether the layer is allowed to vote for the given refresh rate. - bool isVoteAllowed(const LayerRequirement&, const RefreshRate&) const; + bool isVoteAllowed(const LayerRequirement&, Fps) const; // calculates a score for a layer. Used to determine the display refresh rate // and the frame rate override for certains applications. - float calculateLayerScoreLocked(const LayerRequirement&, const RefreshRate&, + float calculateLayerScoreLocked(const LayerRequirement&, Fps refreshRate, bool isSeamlessSwitch) const REQUIRES(mLock); - float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&, - const RefreshRate&) const REQUIRES(mLock); + float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&, Fps refreshRate) const + REQUIRES(mLock); - void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock); + void updateDisplayModes(DisplayModes, DisplayModeId activeModeId) EXCLUDES(mLock); void initializeIdleTimer(); @@ -449,32 +375,22 @@ private: : mIdleTimerCallbacks->platform; } - // The list of refresh rates, indexed by display modes ID. This may change after this - // object is initialized. - AllRefreshRatesMapType mRefreshRates GUARDED_BY(mLock); - - // The list of refresh rates in the primary range of the current policy, ordered by vsyncPeriod - // (the first element is the lowest refresh rate). - std::vector mPrimaryRefreshRates GUARDED_BY(mLock); + // The display modes of the active display. The DisplayModeIterators below are pointers into + // this container, so must be invalidated whenever the DisplayModes change. The Policy below + // is also dependent, so must be reset as well. + DisplayModes mDisplayModes GUARDED_BY(mLock); - // The list of refresh rates in the app request range of the current policy, ordered by - // vsyncPeriod (the first element is the lowest refresh rate). - std::vector mAppRequestRefreshRates GUARDED_BY(mLock); + DisplayModeIterator mActiveModeIt GUARDED_BY(mLock); + DisplayModeIterator mMinRefreshRateModeIt GUARDED_BY(mLock); + DisplayModeIterator mMaxRefreshRateModeIt GUARDED_BY(mLock); - // The current display mode. This will change at runtime. This is set by SurfaceFlinger on - // the main thread, and read by the Scheduler (and other objects) on other threads. - const RefreshRate* mCurrentRefreshRate GUARDED_BY(mLock); + // Display modes that satisfy the Policy's ranges, filtered and sorted by refresh rate. + std::vector mPrimaryRefreshRates GUARDED_BY(mLock); + std::vector mAppRequestRefreshRates GUARDED_BY(mLock); - // The policy values will change at runtime. They're set by SurfaceFlinger on the main thread, - // and read by the Scheduler (and other objects) on other threads. Policy mDisplayManagerPolicy GUARDED_BY(mLock); std::optional mOverridePolicy GUARDED_BY(mLock); - // The min and max refresh rates supported by the device. - // This may change at runtime. - const RefreshRate* mMinSupportedRefreshRate GUARDED_BY(mLock); - const RefreshRate* mMaxSupportedRefreshRate GUARDED_BY(mLock); - mutable std::mutex mLock; // A sorted list of known frame rates that a Heuristic layer will choose @@ -486,7 +402,7 @@ private: struct GetBestRefreshRateCache { std::pair, GlobalSignals> arguments; - std::pair result; + std::pair result; }; mutable std::optional mGetBestRefreshRateCache GUARDED_BY(mLock); diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h index f1ad75597a..ed65bc607d 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateStats.h +++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h @@ -17,7 +17,9 @@ #pragma once #include -#include +#include +#include +#include #include #include @@ -25,6 +27,7 @@ #include +#include "DisplayHardware/Hal.h" #include "TimeStats/TimeStats.h" namespace android::scheduler { @@ -41,16 +44,16 @@ class RefreshRateStats { static constexpr int64_t MS_PER_HOUR = 60 * MS_PER_MIN; static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR; + using PowerMode = android::hardware::graphics::composer::hal::PowerMode; + public: // TODO(b/185535769): Inject clock to avoid sleeping in tests. - RefreshRateStats(TimeStats& timeStats, Fps currentRefreshRate, - android::hardware::graphics::composer::hal::PowerMode currentPowerMode) + RefreshRateStats(TimeStats& timeStats, Fps currentRefreshRate, PowerMode currentPowerMode) : mTimeStats(timeStats), mCurrentRefreshRate(currentRefreshRate), mCurrentPowerMode(currentPowerMode) {} - // Sets power mode. - void setPowerMode(android::hardware::graphics::composer::hal::PowerMode mode) { + void setPowerMode(PowerMode mode) { if (mCurrentPowerMode == mode) { return; } @@ -115,7 +118,7 @@ private: uint32_t fps = 0; - if (mCurrentPowerMode == android::hardware::graphics::composer::hal::PowerMode::ON) { + if (mCurrentPowerMode == PowerMode::ON) { // Normal power mode is counted under different config modes. const auto total = std::as_const(mFpsTotalTimes) .get(mCurrentRefreshRate) @@ -144,7 +147,7 @@ private: TimeStats& mTimeStats; Fps mCurrentRefreshRate; - android::hardware::graphics::composer::hal::PowerMode mCurrentPowerMode; + PowerMode mCurrentPowerMode; ftl::SmallMap mFpsTotalTimes; std::chrono::milliseconds mScreenOffTime = std::chrono::milliseconds::zero(); diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 1fa455aad0..74d77394af 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -166,18 +166,15 @@ impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const { return [this](uid_t uid) { - const auto refreshRateConfigs = holdRefreshRateConfigs(); - nsecs_t basePeriod = refreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); + const Fps refreshRate = holdRefreshRateConfigs()->getActiveMode()->getFps(); + const nsecs_t basePeriod = refreshRate.getPeriodNsecs(); + const auto frameRate = getFrameRateOverride(uid); if (!frameRate.has_value()) { return basePeriod; } - const auto divisor = - scheduler::RefreshRateConfigs::getFrameRateDivisor(refreshRateConfigs - ->getCurrentRefreshRate() - .getFps(), - *frameRate); + const auto divisor = RefreshRateConfigs::getFrameRateDivisor(refreshRate, *frameRate); if (divisor <= 1) { return basePeriod; } @@ -307,7 +304,7 @@ void Scheduler::dispatchCachedReportedMode() { // mode change is in progress. In that case we shouldn't dispatch an event // as it will be dispatched when the current mode changes. if (std::scoped_lock lock(mRefreshRateConfigsLock); - mRefreshRateConfigs->getCurrentRefreshRate().getMode() != mPolicy.mode) { + mRefreshRateConfigs->getActiveMode() != mPolicy.mode) { return; } @@ -422,7 +419,7 @@ void Scheduler::disableHardwareVsync(bool makeUnavailable) { } } -void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) { +void Scheduler::resyncToHardwareVsync(bool makeAvailable, Fps refreshRate) { { std::lock_guard lock(mHWVsyncLock); if (makeAvailable) { @@ -434,11 +431,7 @@ void Scheduler::resyncToHardwareVsync(bool makeAvailable, nsecs_t period) { } } - if (period <= 0) { - return; - } - - setVsyncPeriod(period); + setVsyncPeriod(refreshRate.getPeriodNsecs()); } void Scheduler::resync() { @@ -448,15 +441,17 @@ void Scheduler::resync() { const nsecs_t last = mLastResyncTime.exchange(now); if (now - last > kIgnoreDelay) { - const auto vsyncPeriod = [&] { + const auto refreshRate = [&] { std::scoped_lock lock(mRefreshRateConfigsLock); - return mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); + return mRefreshRateConfigs->getActiveMode()->getFps(); }(); - resyncToHardwareVsync(false, vsyncPeriod); + resyncToHardwareVsync(false, refreshRate); } } void Scheduler::setVsyncPeriod(nsecs_t period) { + if (period <= 0) return; + std::lock_guard lock(mHWVsyncLock); mVsyncSchedule->getController().startPeriodTransition(period); @@ -578,21 +573,20 @@ void Scheduler::kernelIdleTimerCallback(TimerState state) { // TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate // magic number - const auto refreshRate = [&] { + const Fps refreshRate = [&] { std::scoped_lock lock(mRefreshRateConfigsLock); - return mRefreshRateConfigs->getCurrentRefreshRate(); + return mRefreshRateConfigs->getActiveMode()->getFps(); }(); constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER = 65_Hz; using namespace fps_approx_ops; - if (state == TimerState::Reset && refreshRate.getFps() > FPS_THRESHOLD_FOR_KERNEL_TIMER) { + if (state == TimerState::Reset && refreshRate > FPS_THRESHOLD_FOR_KERNEL_TIMER) { // If we're not in performance mode then the kernel timer shouldn't do // anything, as the refresh rate during DPU power collapse will be the // same. - resyncToHardwareVsync(true /* makeAvailable */, refreshRate.getVsyncPeriod()); - } else if (state == TimerState::Expired && - refreshRate.getFps() <= FPS_THRESHOLD_FOR_KERNEL_TIMER) { + resyncToHardwareVsync(true /* makeAvailable */, refreshRate); + } else if (state == TimerState::Expired && refreshRate <= FPS_THRESHOLD_FOR_KERNEL_TIMER) { // Disable HW VSYNC if the timer expired, as we don't need it enabled if // we're not pushing frames, and if we're in PERFORMANCE mode then we'll // need to update the VsyncController model anyway. @@ -693,11 +687,9 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals } } if (refreshRateChanged) { - const auto newRefreshRate = refreshRateConfigs->getRefreshRateFromModeId(newMode->getId()); - - mSchedulerCallback.changeRefreshRate(newRefreshRate, - consideredSignals.idle ? DisplayModeEvent::None - : DisplayModeEvent::Changed); + mSchedulerCallback.requestDisplayMode(std::move(newMode), + consideredSignals.idle ? DisplayModeEvent::None + : DisplayModeEvent::Changed); } if (frameRateOverridesChanged) { mSchedulerCallback.triggerOnFrameRateOverridesChanged(); @@ -715,16 +707,13 @@ auto Scheduler::chooseDisplayMode() -> std::pair if (mDisplayPowerTimer && (!mPolicy.isDisplayPowerStateNormal || mPolicy.displayPowerTimer == TimerState::Reset)) { constexpr GlobalSignals kNoSignals; - return {configs->getMaxRefreshRateByPolicy().getMode(), kNoSignals}; + return {configs->getMaxRefreshRateByPolicy(), kNoSignals}; } const GlobalSignals signals{.touch = mTouchTimer && mPolicy.touch == TouchState::Active, .idle = mPolicy.idleTimer == TimerState::Expired}; - const auto [refreshRate, consideredSignals] = - configs->getBestRefreshRate(mPolicy.contentRequirements, signals); - - return {refreshRate.getMode(), consideredSignals}; + return configs->getBestRefreshRate(mPolicy.contentRequirements, signals); } DisplayModePtr Scheduler::getPreferredDisplayMode() { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index f6c81c0ba2..a8113d423a 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -86,12 +86,11 @@ struct ISchedulerCallback { // Indicates frame activity, i.e. whether commit and/or composite is taking place. enum class FrameHint { kNone, kActive }; - using RefreshRate = RefreshRateConfigs::RefreshRate; using DisplayModeEvent = scheduler::DisplayModeEvent; virtual void scheduleComposite(FrameHint) = 0; virtual void setVsyncEnabled(bool) = 0; - virtual void changeRefreshRate(const RefreshRate&, DisplayModeEvent) = 0; + virtual void requestDisplayMode(DisplayModePtr, DisplayModeEvent) = 0; virtual void kernelTimerChanged(bool expired) = 0; virtual void triggerOnFrameRateOverridesChanged() = 0; @@ -166,8 +165,7 @@ public: // If makeAvailable is true, then hardware vsync will be turned on. // Otherwise, if hardware vsync is not already enabled then this method will // no-op. - // The period is the vsync period from the current display configuration. - void resyncToHardwareVsync(bool makeAvailable, nsecs_t period); + void resyncToHardwareVsync(bool makeAvailable, Fps refreshRate); void resync() EXCLUDES(mRefreshRateConfigsLock); void forceNextResync() { mLastResyncTime = 0; } @@ -236,7 +234,7 @@ public: nsecs_t getVsyncPeriodFromRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) { std::scoped_lock lock(mRefreshRateConfigsLock); - return mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod(); + return mRefreshRateConfigs->getActiveMode()->getFps().getPeriodNsecs(); } // Returns the framerate of the layer with the given sequence ID diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h index 3186d6d399..4923031098 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h @@ -29,6 +29,7 @@ namespace android::scheduler { +class TimeKeeper; class VSyncTracker; // VSyncDispatchTimerQueueEntry is a helper class representing internal state for each entry in diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 94b16b4821..0ee3121489 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1044,15 +1044,13 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp& displayToken, const auto& supportedModes = display->getSupportedModes(); info->supportedDisplayModes.clear(); info->supportedDisplayModes.reserve(supportedModes.size()); - for (const auto& mode : supportedModes) { - ui::DisplayMode outMode; - outMode.id = static_cast(mode->getId().value()); - auto width = mode->getWidth(); - auto height = mode->getHeight(); + for (const auto& [id, mode] : supportedModes) { + ui::DisplayMode outMode; + outMode.id = static_cast(id.value()); - auto xDpi = mode->getDpiX(); - auto yDpi = mode->getDpiY(); + auto [width, height] = mode->getResolution(); + auto [xDpi, yDpi] = mode->getDpi(); if (display->isPrimary() && (internalDisplayOrientation == ui::ROTATION_90 || @@ -1146,7 +1144,7 @@ void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) { // Start receiving vsync samples now, so that we can detect a period // switch. - mScheduler->resyncToHardwareVsync(true, info.mode->getVsyncPeriod()); + mScheduler->resyncToHardwareVsync(true, info.mode->getFps()); // As we called to set period, we will call to onRefreshRateChangeCompleted once // VsyncController model is locked. modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated); @@ -1212,7 +1210,7 @@ void SurfaceFlinger::updateInternalStateWithChangedMode() { return; } - if (display->getActiveMode()->getSize() != upcomingModeInfo.mode->getSize()) { + if (display->getActiveMode()->getResolution() != upcomingModeInfo.mode->getResolution()) { auto& state = mCurrentState.displays.editValueFor(display->getDisplayToken()); // We need to generate new sequenceId in order to recreate the display (and this // way the framebuffer). @@ -1248,7 +1246,7 @@ void SurfaceFlinger::clearDesiredActiveModeState(const sp& displa void SurfaceFlinger::desiredActiveModeChangeDone(const sp& display) { const auto refreshRate = display->getDesiredActiveMode()->mode->getFps(); clearDesiredActiveModeState(display); - mScheduler->resyncToHardwareVsync(true, refreshRate.getPeriodNsecs()); + mScheduler->resyncToHardwareVsync(true, refreshRate); updatePhaseConfiguration(refreshRate); } @@ -2680,11 +2678,11 @@ void SurfaceFlinger::commitTransactions() { mDebugInTransaction = 0; } -void SurfaceFlinger::loadDisplayModes(PhysicalDisplayId displayId, DisplayModes& outModes, - DisplayModePtr& outActiveMode) const { +std::pair SurfaceFlinger::loadDisplayModes( + PhysicalDisplayId displayId) const { std::vector hwcModes; std::optional activeModeHwcId; - bool activeModeIsSupported; + int attempt = 0; constexpr int kMaxAttempts = 3; do { @@ -2692,63 +2690,60 @@ void SurfaceFlinger::loadDisplayModes(PhysicalDisplayId displayId, DisplayModes& activeModeHwcId = getHwComposer().getActiveMode(displayId); LOG_ALWAYS_FATAL_IF(!activeModeHwcId, "HWC returned no active mode"); - activeModeIsSupported = - std::any_of(hwcModes.begin(), hwcModes.end(), - [activeModeHwcId](const HWComposer::HWCDisplayMode& mode) { - return mode.hwcId == *activeModeHwcId; - }); - } while (!activeModeIsSupported && ++attempt < kMaxAttempts); - LOG_ALWAYS_FATAL_IF(!activeModeIsSupported, + const auto isActiveMode = [activeModeHwcId](const HWComposer::HWCDisplayMode& mode) { + return mode.hwcId == *activeModeHwcId; + }; + + if (std::any_of(hwcModes.begin(), hwcModes.end(), isActiveMode)) { + break; + } + } while (++attempt < kMaxAttempts); + + LOG_ALWAYS_FATAL_IF(attempt == kMaxAttempts, "After %d attempts HWC still returns an active mode which is not" - " supported. Active mode ID = %" PRIu64 " . Supported modes = %s", + " supported. Active mode ID = %" PRIu64 ". Supported modes = %s", kMaxAttempts, *activeModeHwcId, base::Join(hwcModes, ", ").c_str()); DisplayModes oldModes; - if (const auto token = getPhysicalDisplayTokenLocked(displayId)) { oldModes = getDisplayDeviceLocked(token)->getSupportedModes(); } - int largestUsedModeId = -1; // Use int instead of DisplayModeId for signedness - for (const auto& mode : oldModes) { - const auto id = static_cast(mode->getId().value()); - if (id > largestUsedModeId) { - largestUsedModeId = id; - } - } + ui::DisplayModeId nextModeId = 1 + + std::accumulate(oldModes.begin(), oldModes.end(), static_cast(-1), + [](ui::DisplayModeId max, const auto& pair) { + return std::max(max, pair.first.value()); + }); DisplayModes newModes; - int32_t nextModeId = largestUsedModeId + 1; for (const auto& hwcMode : hwcModes) { - newModes.push_back(DisplayMode::Builder(hwcMode.hwcId) - .setId(DisplayModeId{nextModeId++}) - .setPhysicalDisplayId(displayId) - .setWidth(hwcMode.width) - .setHeight(hwcMode.height) - .setVsyncPeriod(hwcMode.vsyncPeriod) - .setDpiX(hwcMode.dpiX) - .setDpiY(hwcMode.dpiY) - .setGroup(hwcMode.configGroup) - .build()); - } - - const bool modesAreSame = + const DisplayModeId id{nextModeId++}; + newModes.try_emplace(id, + DisplayMode::Builder(hwcMode.hwcId) + .setId(id) + .setPhysicalDisplayId(displayId) + .setResolution({hwcMode.width, hwcMode.height}) + .setVsyncPeriod(hwcMode.vsyncPeriod) + .setDpiX(hwcMode.dpiX) + .setDpiY(hwcMode.dpiY) + .setGroup(hwcMode.configGroup) + .build()); + } + + const bool sameModes = std::equal(newModes.begin(), newModes.end(), oldModes.begin(), oldModes.end(), - [](DisplayModePtr left, DisplayModePtr right) { - return left->equalsExceptDisplayModeId(right); + [](const auto& lhs, const auto& rhs) { + return equalsExceptDisplayModeId(*lhs.second, *rhs.second); }); - if (modesAreSame) { - // The supported modes have not changed, keep the old IDs. - outModes = oldModes; - } else { - outModes = newModes; - } + // Keep IDs if modes have not changed. + const auto& modes = sameModes ? oldModes : newModes; + const DisplayModePtr activeMode = + std::find_if(modes.begin(), modes.end(), [activeModeHwcId](const auto& pair) { + return pair.second->getHwcId() == activeModeHwcId; + })->second; - outActiveMode = *std::find_if(outModes.begin(), outModes.end(), - [activeModeHwcId](const DisplayModePtr& mode) { - return mode->getHwcId() == *activeModeHwcId; - }); + return {modes, activeMode}; } void SurfaceFlinger::processDisplayHotplugEventsLocked() { @@ -2764,9 +2759,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { const auto it = mPhysicalDisplayTokens.find(displayId); if (event.connection == hal::Connection::CONNECTED) { - DisplayModes supportedModes; - DisplayModePtr activeMode; - loadDisplayModes(displayId, supportedModes, activeMode); + auto [supportedModes, activeMode] = loadDisplayModes(displayId); if (it == mPhysicalDisplayTokens.end()) { ALOGV("Creating display %s", to_string(displayId).c_str()); @@ -2777,7 +2770,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { .hwcDisplayId = event.hwcDisplayId, .deviceProductInfo = std::move(info->deviceProductInfo), .supportedModes = std::move(supportedModes), - .activeMode = activeMode}; + .activeMode = std::move(activeMode)}; state.isSecure = true; // All physical displays are currently considered secure. state.displayName = std::move(info->name); @@ -2792,7 +2785,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { auto& state = mCurrentState.displays.editValueFor(token); state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId state.physical->supportedModes = std::move(supportedModes); - state.physical->activeMode = activeMode; + state.physical->activeMode = std::move(activeMode); if (getHwComposer().updatesDeviceProductInfoOnHotplugReconnect()) { state.physical->deviceProductInfo = std::move(info->deviceProductInfo); } @@ -2925,7 +2918,7 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, ui::Size resolution(0, 0); ui::PixelFormat pixelFormat = static_cast(PIXEL_FORMAT_UNKNOWN); if (state.physical) { - resolution = state.physical->activeMode->getSize(); + resolution = state.physical->activeMode->getResolution(); pixelFormat = static_cast(PIXEL_FORMAT_RGBA_8888); } else if (state.surface != nullptr) { int status = state.surface->query(NATIVE_WINDOW_WIDTH, &resolution.width); @@ -2979,7 +2972,7 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, LOG_FATAL_IF(!displayId); displaySurface = sp::make(getHwComposer(), *displayId, bqConsumer, - state.physical->activeMode->getSize(), + state.physical->activeMode->getResolution(), ui::Size(maxGraphicsWidth, maxGraphicsHeight)); producer = bqProducer; } @@ -3092,7 +3085,7 @@ void SurfaceFlinger::processDisplayChanged(const wp& displayToken, } void SurfaceFlinger::updateInternalDisplayVsyncLocked(const sp& activeDisplay) { mVsyncConfiguration->reset(); - const Fps refreshRate = activeDisplay->refreshRateConfigs().getCurrentRefreshRate().getFps(); + const Fps refreshRate = activeDisplay->refreshRateConfigs().getActiveMode()->getFps(); updatePhaseConfiguration(refreshRate); mRefreshRateStats->setRefreshRate(refreshRate); } @@ -3354,7 +3347,7 @@ void SurfaceFlinger::updateCursorAsync() { mCompositionEngine->updateCursorAsync(refreshArgs); } -void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, DisplayModeEvent event) { +void SurfaceFlinger::requestDisplayMode(DisplayModePtr mode, DisplayModeEvent event) { // If this is called from the main thread mStateLock must be locked before // Currently the only way to call this function from the main thread is from // Scheduler::chooseRefreshRateForContent @@ -3367,14 +3360,12 @@ void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, DisplayMo } ATRACE_CALL(); - // Don't do any updating if the current fps is the same as the new one. - if (!display->refreshRateConfigs().isModeAllowed(refreshRate.getModeId())) { - ALOGV("Skipping mode %d as it is not part of allowed modes", - refreshRate.getModeId().value()); + if (!display->refreshRateConfigs().isModeAllowed(mode->getId())) { + ALOGV("Skipping disallowed mode %d", mode->getId().value()); return; } - setDesiredActiveMode({refreshRate.getMode(), event}); + setDesiredActiveMode({std::move(mode), event}); } void SurfaceFlinger::triggerOnFrameRateOverridesChanged() { @@ -4802,8 +4793,7 @@ void SurfaceFlinger::onInitializeDisplays() { {}, mPid, getuid(), transactionId); setPowerModeInternal(display, hal::PowerMode::ON); - const nsecs_t vsyncPeriod = - display->refreshRateConfigs().getCurrentRefreshRate().getVsyncPeriod(); + const nsecs_t vsyncPeriod = display->refreshRateConfigs().getActiveMode()->getVsyncPeriod(); mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod); mActiveDisplayTransformHint = display->getTransformHint(); // Use phase of 0 since phase is not known. @@ -4842,7 +4832,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: if (mInterceptor->isEnabled()) { mInterceptor->savePowerModeUpdate(display->getSequenceId(), static_cast(mode)); } - const auto vsyncPeriod = display->refreshRateConfigs().getCurrentRefreshRate().getVsyncPeriod(); + const auto refreshRate = display->refreshRateConfigs().getActiveMode()->getFps(); if (currentMode == hal::PowerMode::OFF) { // Turn on the display if (display->isInternal() && (!activeDisplay || !activeDisplay->isPoweredOn())) { @@ -4860,7 +4850,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: if (isDisplayActiveLocked(display) && mode != hal::PowerMode::DOZE_SUSPEND) { setHWCVsyncEnabled(displayId, mHWCVsyncPendingState); mScheduler->onScreenAcquired(mAppConnectionHandle); - mScheduler->resyncToHardwareVsync(true, vsyncPeriod); + mScheduler->resyncToHardwareVsync(true, refreshRate); } mVisibleRegionsDirty = true; @@ -4890,7 +4880,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp& display, hal: getHwComposer().setPowerMode(displayId, mode); if (isDisplayActiveLocked(display) && currentMode == hal::PowerMode::DOZE_SUSPEND) { mScheduler->onScreenAcquired(mAppConnectionHandle); - mScheduler->resyncToHardwareVsync(true, vsyncPeriod); + mScheduler->resyncToHardwareVsync(true, refreshRate); } } else if (mode == hal::PowerMode::DOZE_SUSPEND) { // Leave display going to doze @@ -5376,8 +5366,10 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co std::string fps, xDpi, yDpi; if (const auto activeMode = display->getActiveMode()) { fps = to_string(activeMode->getFps()); - xDpi = base::StringPrintf("%.2f", activeMode->getDpiX()); - yDpi = base::StringPrintf("%.2f", activeMode->getDpiY()); + + const auto dpi = activeMode->getDpi(); + xDpi = base::StringPrintf("%.2f", dpi.x); + yDpi = base::StringPrintf("%.2f", dpi.y); } else { fps = "unknown"; xDpi = "unknown"; @@ -6137,7 +6129,7 @@ void SurfaceFlinger::kernelTimerChanged(bool expired) { if (!updateOverlay) return; // Update the overlay on the main thread to avoid race conditions with - // mRefreshRateConfigs->getCurrentRefreshRate() + // mRefreshRateConfigs->getActiveMode() static_cast(mScheduler->schedule([=] { const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); if (!display) { @@ -7181,7 +7173,7 @@ uint32_t SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t ui refreshRate = *frameRateOverride; } else if (!getHwComposer().isHeadless()) { if (const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked())) { - refreshRate = display->refreshRateConfigs().getCurrentRefreshRate().getFps(); + refreshRate = display->refreshRateConfigs().getActiveMode()->getFps(); } } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index fa6580342b..01732be337 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -679,8 +679,8 @@ private: // Toggles hardware VSYNC by calling into HWC. void setVsyncEnabled(bool) override; - // Initiates a refresh rate change to be applied on commit. - void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override; + // Sets the desired display mode if allowed by policy. + void requestDisplayMode(DisplayModePtr, DisplayModeEvent) override; // Called when kernel idle timer has expired. Used to update the refresh rate overlay. void kernelTimerChanged(bool expired) override; // Called when the frame rate override list changed to trigger an event. @@ -975,8 +975,9 @@ private: /* * Display management */ - void loadDisplayModes(PhysicalDisplayId displayId, DisplayModes& outModes, - DisplayModePtr& outActiveMode) const REQUIRES(mStateLock); + std::pair loadDisplayModes(PhysicalDisplayId) const + REQUIRES(mStateLock); + sp setupNewDisplayDeviceInternal( const wp& displayToken, std::shared_ptr compositionDisplay, diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index b796dfeb1f..93abc9f3eb 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -55,6 +55,7 @@ #include "renderengine/mock/RenderEngine.h" #include "scheduler/TimeKeeper.h" #include "tests/unittests/mock/DisplayHardware/MockComposer.h" +#include "tests/unittests/mock/DisplayHardware/MockDisplayMode.h" #include "tests/unittests/mock/DisplayHardware/MockHWC2.h" #include "tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h" #include "tests/unittests/mock/MockEventThread.h" @@ -207,7 +208,9 @@ struct FakePhaseOffsets : scheduler::VsyncConfiguration { void setRefreshRateFps(Fps) override {} void dump(std::string &) const override {} }; + namespace scheduler { + class TestableScheduler : public Scheduler, private ICompositor { public: TestableScheduler(const std::shared_ptr &refreshRateConfigs, @@ -216,9 +219,6 @@ public: std::make_unique(), refreshRateConfigs, callback) {} - void scheduleFrame(){}; - void postMessage(sp &&){}; - TestableScheduler(std::unique_ptr controller, std::unique_ptr tracker, std::shared_ptr configs, ISchedulerCallback &callback) @@ -273,8 +273,13 @@ private: bool commit(nsecs_t, int64_t, nsecs_t) override { return false; } void composite(nsecs_t, int64_t) override {} void sample() override {} + + // MessageQueue overrides: + void scheduleFrame() override {} + void postMessage(sp&&) override {} }; -}; // namespace scheduler + +} // namespace scheduler namespace surfaceflinger::test { @@ -405,8 +410,6 @@ public: return mFlinger->onInitializeDisplays(); } - void scheduleComposite(FrameHint){}; - void setGlobalShadowSettings(FuzzedDataProvider *fdp) { const half4 ambientColor{fdp->ConsumeFloatingPoint(), fdp->ConsumeFloatingPoint(), @@ -678,31 +681,22 @@ public: std::unique_ptr sfEventThread, scheduler::ISchedulerCallback *callback = nullptr, bool hasMultipleModes = false) { - DisplayModes modes{DisplayMode::Builder(0) - .setId(DisplayModeId(0)) - .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) - .setVsyncPeriod(16'666'667) - .setGroup(0) - .build()}; + constexpr DisplayModeId kModeId60{0}; + DisplayModes modes = makeModes(mock::createDisplayMode(kModeId60, 60_Hz)); if (hasMultipleModes) { - modes.emplace_back(DisplayMode::Builder(1) - .setId(DisplayModeId(1)) - .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) - .setVsyncPeriod(11'111'111) - .setGroup(0) - .build()); + constexpr DisplayModeId kModeId90{1}; + modes.try_emplace(kModeId90, mock::createDisplayMode(kModeId90, 90_Hz)); } - const auto currMode = DisplayModeId(0); - mRefreshRateConfigs = std::make_shared(modes, currMode); - const auto currFps = mRefreshRateConfigs->getCurrentRefreshRate().getFps(); - mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(currFps); + mRefreshRateConfigs = std::make_shared(modes, kModeId60); + const auto fps = mRefreshRateConfigs->getActiveMode()->getFps(); + mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps); mFlinger->mVsyncModulator = sp::make( mFlinger->mVsyncConfiguration->getCurrentConfigs()); mFlinger->mRefreshRateStats = - std::make_unique(*mFlinger->mTimeStats, currFps, - /*powerMode=*/hal::PowerMode::OFF); + std::make_unique(*mFlinger->mTimeStats, fps, + hal::PowerMode::OFF); mScheduler = new scheduler::TestableScheduler(std::move(vsyncController), std::move(vsyncTracker), mRefreshRateConfigs, @@ -765,8 +759,6 @@ public: return mFlinger->setPowerModeInternal(display, mode); } - auto onMessageReceived(int32_t /*what*/) { return 0; } - auto &getTransactionQueue() { return mFlinger->mTransactionQueue; } auto &getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; } @@ -818,15 +810,16 @@ public: } private: - void scheduleRefresh(FrameHint) {} + void scheduleComposite(FrameHint) override {} void setVsyncEnabled(bool) override {} - void changeRefreshRate(const RefreshRate &, DisplayModeEvent) override {} + void requestDisplayMode(DisplayModePtr, DisplayModeEvent) override {} void kernelTimerChanged(bool) override {} - void triggerOnFrameRateOverridesChanged() {} + void triggerOnFrameRateOverridesChanged() override {} surfaceflinger::test::Factory mFactory; sp mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization); scheduler::TestableScheduler *mScheduler = nullptr; std::shared_ptr mRefreshRateConfigs; }; + } // namespace android diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp index d5041553dc..da60a6981b 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp @@ -15,22 +15,31 @@ * */ -#include "surfaceflinger_scheduler_fuzzer.h" +#include #include #include + #include "Scheduler/DispSyncSource.h" #include "Scheduler/OneShotTimer.h" #include "Scheduler/VSyncDispatchTimerQueue.h" #include "Scheduler/VSyncPredictor.h" #include "Scheduler/VSyncReactor.h" + #include "surfaceflinger_fuzzers_utils.h" +#include "surfaceflinger_scheduler_fuzzer.h" namespace android::fuzz { using hardware::graphics::composer::hal::PowerMode; -static constexpr PowerMode kPowerModes[] = {PowerMode::ON, PowerMode::DOZE, PowerMode::OFF, - PowerMode::DOZE_SUSPEND, PowerMode::ON_SUSPEND}; +constexpr nsecs_t kVsyncPeriods[] = {(30_Hz).getPeriodNsecs(), (60_Hz).getPeriodNsecs(), + (72_Hz).getPeriodNsecs(), (90_Hz).getPeriodNsecs(), + (120_Hz).getPeriodNsecs()}; + +constexpr auto kLayerVoteTypes = ftl::enum_range(); + +constexpr PowerMode kPowerModes[] = {PowerMode::ON, PowerMode::DOZE, PowerMode::OFF, + PowerMode::DOZE_SUSPEND, PowerMode::ON_SUSPEND}; constexpr uint16_t kRandomStringLength = 256; constexpr std::chrono::duration kSyncPeriod(16ms); @@ -319,39 +328,42 @@ void SchedulerFuzzer::fuzzRefreshRateConfigs() { using RefreshRateConfigs = scheduler::RefreshRateConfigs; using LayerRequirement = RefreshRateConfigs::LayerRequirement; using RefreshRateStats = scheduler::RefreshRateStats; - uint16_t minRefreshRate = mFdp.ConsumeIntegralInRange(1, UINT16_MAX >> 1); - uint16_t maxRefreshRate = mFdp.ConsumeIntegralInRange(minRefreshRate + 1, UINT16_MAX); - DisplayModeId hwcConfigIndexType = DisplayModeId(mFdp.ConsumeIntegralInRange(0, 10)); + const uint16_t minRefreshRate = mFdp.ConsumeIntegralInRange(1, UINT16_MAX >> 1); + const uint16_t maxRefreshRate = + mFdp.ConsumeIntegralInRange(minRefreshRate + 1, UINT16_MAX); + + const DisplayModeId modeId{mFdp.ConsumeIntegralInRange(0, 10)}; DisplayModes displayModes; for (uint16_t fps = minRefreshRate; fps < maxRefreshRate; ++fps) { - constexpr int32_t kGroup = 0; - const auto refreshRate = Fps::fromValue(static_cast(fps)); - displayModes.push_back(scheduler::createDisplayMode(hwcConfigIndexType, kGroup, - refreshRate.getPeriodNsecs())); + displayModes.try_emplace(modeId, + mock::createDisplayMode(modeId, + Fps::fromValue(static_cast(fps)))); } - auto refreshRateConfigs = - std::make_unique(displayModes, hwcConfigIndexType); + + RefreshRateConfigs refreshRateConfigs(displayModes, modeId); + const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false}; - auto layers = std::vector{ - LayerRequirement{.weight = mFdp.ConsumeFloatingPoint()}}; - refreshRateConfigs->getBestRefreshRate(layers, globalSignals); + std::vector layers = {{.weight = mFdp.ConsumeFloatingPoint()}}; + + refreshRateConfigs.getBestRefreshRate(layers, globalSignals); + layers[0].name = mFdp.ConsumeRandomLengthString(kRandomStringLength); layers[0].ownerUid = mFdp.ConsumeIntegral(); layers[0].desiredRefreshRate = Fps::fromValue(mFdp.ConsumeFloatingPoint()); - layers[0].vote = mFdp.PickValueInArray(kLayerVoteTypes); + layers[0].vote = mFdp.PickValueInArray(kLayerVoteTypes.values); auto frameRateOverrides = - refreshRateConfigs->getFrameRateOverrides(layers, - Fps::fromValue( - mFdp.ConsumeFloatingPoint()), - globalSignals); + refreshRateConfigs.getFrameRateOverrides(layers, + Fps::fromValue( + mFdp.ConsumeFloatingPoint()), + globalSignals); - refreshRateConfigs->setDisplayManagerPolicy( - {hwcConfigIndexType, + refreshRateConfigs.setDisplayManagerPolicy( + {modeId, {Fps::fromValue(mFdp.ConsumeFloatingPoint()), Fps::fromValue(mFdp.ConsumeFloatingPoint())}}); - refreshRateConfigs->setCurrentModeId(hwcConfigIndexType); + refreshRateConfigs.setActiveModeId(modeId); RefreshRateConfigs::isFractionalPairOrMultiple(Fps::fromValue( mFdp.ConsumeFloatingPoint()), @@ -361,13 +373,13 @@ void SchedulerFuzzer::fuzzRefreshRateConfigs() { Fps::fromValue(mFdp.ConsumeFloatingPoint())); android::mock::TimeStats timeStats; - std::unique_ptr refreshRateStats = - std::make_unique(timeStats, - Fps::fromValue(mFdp.ConsumeFloatingPoint()), - PowerMode::OFF); - refreshRateStats->setRefreshRate( - refreshRateConfigs->getRefreshRateFromModeId(hwcConfigIndexType).getFps()); - refreshRateStats->setPowerMode(mFdp.PickValueInArray(kPowerModes)); + RefreshRateStats refreshRateStats(timeStats, Fps::fromValue(mFdp.ConsumeFloatingPoint()), + PowerMode::OFF); + + const auto fpsOpt = displayModes.get(modeId, [](const auto& mode) { return mode->getFps(); }); + refreshRateStats.setRefreshRate(*fpsOpt); + + refreshRateStats.setPowerMode(mFdp.PickValueInArray(kPowerModes)); } void SchedulerFuzzer::process() { diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h index 84b391246e..1a49ead275 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h @@ -22,6 +22,8 @@ #pragma once +#include + #include "Clock.h" #include "Layer.h" #include "Scheduler/EventThread.h" @@ -29,24 +31,9 @@ #include "Scheduler/Scheduler.h" #include "Scheduler/VSyncTracker.h" #include "Scheduler/VsyncModulator.h" -#include "scheduler/TimeKeeper.h" namespace android::fuzz { -constexpr int64_t kVsyncPeriods[] = {static_cast(1e9f / 30), - static_cast(1e9f / 60), - static_cast(1e9f / 72), - static_cast(1e9f / 90), - static_cast(1e9f / 120)}; - -android::scheduler::RefreshRateConfigs::LayerVoteType kLayerVoteTypes[] = - {android::scheduler::RefreshRateConfigs::LayerVoteType::NoVote, - android::scheduler::RefreshRateConfigs::LayerVoteType::Min, - android::scheduler::RefreshRateConfigs::LayerVoteType::Max, - android::scheduler::RefreshRateConfigs::LayerVoteType::Heuristic, - android::scheduler::RefreshRateConfigs::LayerVoteType::ExplicitDefault, - android::scheduler::RefreshRateConfigs::LayerVoteType::ExplicitExactOrMultiple}; - class FuzzImplClock : public android::scheduler::Clock { public: nsecs_t now() const { return 1; } @@ -168,18 +155,6 @@ public: namespace android::scheduler { -DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod, - ui::Size resolution = ui::Size()) { - return DisplayMode::Builder(hal::HWConfigId(modeId.value())) - .setId(modeId) - .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) - .setVsyncPeriod(int32_t(vsyncPeriod)) - .setGroup(group) - .setHeight(resolution.height) - .setWidth(resolution.width) - .build(); -} - class ControllableClock : public TimeKeeper { public: nsecs_t now() const { return 1; }; diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp index 40a9b1aad0..93af225b3e 100644 --- a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp @@ -44,68 +44,42 @@ public: mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED); mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this) - .setDisplayModes({kDisplayMode60, kDisplayMode90, kDisplayMode120}, - kDisplayModeId60) + .setDisplayModes(makeModes(kMode60, kMode90, kMode120), kModeId60) .inject(); } protected: sp mDisplay; - const DisplayModeId kDisplayModeId60 = DisplayModeId(0); - const DisplayModePtr kDisplayMode60 = - DisplayMode::Builder(hal::HWConfigId(kDisplayModeId60.value())) - .setId(kDisplayModeId60) - .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) - .setVsyncPeriod(int32_t(16'666'667)) - .setGroup(0) - .setHeight(1000) - .setWidth(1000) - .build(); - - const DisplayModeId kDisplayModeId90 = DisplayModeId(1); - const DisplayModePtr kDisplayMode90 = - DisplayMode::Builder(hal::HWConfigId(kDisplayModeId90.value())) - .setId(kDisplayModeId90) - .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) - .setVsyncPeriod(int32_t(11'111'111)) - .setGroup(0) - .setHeight(1000) - .setWidth(1000) - .build(); - - const DisplayModeId kDisplayModeId120 = DisplayModeId(2); - const DisplayModePtr kDisplayMode120 = - DisplayMode::Builder(hal::HWConfigId(kDisplayModeId120.value())) - .setId(kDisplayModeId120) - .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) - .setVsyncPeriod(int32_t(8'333'333)) - .setGroup(0) - .setHeight(1000) - .setWidth(1000) - .build(); + static constexpr DisplayModeId kModeId60{0}; + static constexpr DisplayModeId kModeId90{1}; + static constexpr DisplayModeId kModeId120{2}; + + static inline const DisplayModePtr kMode60 = createDisplayMode(kModeId60, 60_Hz); + static inline const DisplayModePtr kMode90 = createDisplayMode(kModeId90, 90_Hz); + static inline const DisplayModePtr kMode120 = createDisplayMode(kModeId120, 120_Hz); }; TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setCurrentMode) { - EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode60, Event::None})); + EXPECT_FALSE(mDisplay->setDesiredActiveMode({kMode60, Event::None})); EXPECT_EQ(std::nullopt, mDisplay->getDesiredActiveMode()); } TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setNewMode) { - EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None})); + EXPECT_TRUE(mDisplay->setDesiredActiveMode({kMode90, Event::None})); ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); - EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode); + EXPECT_EQ(kMode90, mDisplay->getDesiredActiveMode()->mode); EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); // Setting another mode should be cached but return false - EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode120, Event::None})); + EXPECT_FALSE(mDisplay->setDesiredActiveMode({kMode120, Event::None})); ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); - EXPECT_EQ(kDisplayMode120, mDisplay->getDesiredActiveMode()->mode); + EXPECT_EQ(kMode120, mDisplay->getDesiredActiveMode()->mode); EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); } TEST_F(InitiateModeChangeTest, clearDesiredActiveModeState) { - EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None})); + EXPECT_TRUE(mDisplay->setDesiredActiveMode({kMode90, Event::None})); ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); mDisplay->clearDesiredActiveModeState(); @@ -113,9 +87,9 @@ TEST_F(InitiateModeChangeTest, clearDesiredActiveModeState) { } TEST_F(InitiateModeChangeTest, initiateModeChange) NO_THREAD_SAFETY_ANALYSIS { - EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None})); + EXPECT_TRUE(mDisplay->setDesiredActiveMode({kMode90, Event::None})); ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); - EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode); + EXPECT_EQ(kMode90, mDisplay->getDesiredActiveMode()->mode); EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); hal::VsyncPeriodChangeConstraints constraints{ @@ -126,7 +100,7 @@ TEST_F(InitiateModeChangeTest, initiateModeChange) NO_THREAD_SAFETY_ANALYSIS { EXPECT_EQ(OK, mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints, &timeline)); - EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode); + EXPECT_EQ(kMode90, mDisplay->getUpcomingActiveMode().mode); EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event); mDisplay->clearDesiredActiveModeState(); @@ -135,9 +109,9 @@ TEST_F(InitiateModeChangeTest, initiateModeChange) NO_THREAD_SAFETY_ANALYSIS { TEST_F(InitiateModeChangeTest, getUpcomingActiveMode_desiredActiveModeChanged) NO_THREAD_SAFETY_ANALYSIS { - EXPECT_TRUE(mDisplay->setDesiredActiveMode({kDisplayMode90, Event::None})); + EXPECT_TRUE(mDisplay->setDesiredActiveMode({kMode90, Event::None})); ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); - EXPECT_EQ(kDisplayMode90, mDisplay->getDesiredActiveMode()->mode); + EXPECT_EQ(kMode90, mDisplay->getDesiredActiveMode()->mode); EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); hal::VsyncPeriodChangeConstraints constraints{ @@ -148,21 +122,21 @@ NO_THREAD_SAFETY_ANALYSIS { EXPECT_EQ(OK, mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints, &timeline)); - EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode); + EXPECT_EQ(kMode90, mDisplay->getUpcomingActiveMode().mode); EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event); - EXPECT_FALSE(mDisplay->setDesiredActiveMode({kDisplayMode120, Event::None})); + EXPECT_FALSE(mDisplay->setDesiredActiveMode({kMode120, Event::None})); ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); - EXPECT_EQ(kDisplayMode120, mDisplay->getDesiredActiveMode()->mode); + EXPECT_EQ(kMode120, mDisplay->getDesiredActiveMode()->mode); EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); - EXPECT_EQ(kDisplayMode90, mDisplay->getUpcomingActiveMode().mode); + EXPECT_EQ(kMode90, mDisplay->getUpcomingActiveMode().mode); EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event); EXPECT_EQ(OK, mDisplay->initiateModeChange(*mDisplay->getDesiredActiveMode(), constraints, &timeline)); - EXPECT_EQ(kDisplayMode120, mDisplay->getUpcomingActiveMode().mode); + EXPECT_EQ(kMode120, mDisplay->getUpcomingActiveMode().mode); EXPECT_EQ(Event::None, mDisplay->getUpcomingActiveMode().event); mDisplay->clearDesiredActiveModeState(); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index 54b8bcb2a4..565c2445e0 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -45,6 +45,7 @@ #include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" +#include "mock/DisplayHardware/MockDisplayMode.h" #include "mock/DisplayHardware/MockPowerAdvisor.h" #include "mock/MockEventThread.h" #include "mock/MockNativeWindowSurface.h" @@ -235,9 +236,9 @@ struct DisplayVariant { using CONNECTION_TYPE = DisplayConnectionTypeGetter; using HWC_DISPLAY_ID_OPT = HwcDisplayIdGetter; - // The display width and height static constexpr int WIDTH = width; static constexpr int HEIGHT = height; + static constexpr ui::Size RESOLUTION{WIDTH, HEIGHT}; static constexpr int GRALLOC_USAGE = grallocUsage; @@ -262,7 +263,7 @@ struct DisplayVariant { static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) { auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder(); ceDisplayArgs.setId(DISPLAY_ID::get()) - .setPixels({WIDTH, HEIGHT}) + .setPixels(RESOLUTION) .setPowerAdvisor(&test->mPowerAdvisor); auto compositionDisplay = @@ -357,8 +358,7 @@ struct HwcDisplayVariant { TestableSurfaceFlinger::FakeHwcDisplayInjector(displayId, HWC_DISPLAY_TYPE, static_cast(DisplayVariant::PRIMARY)) .setHwcDisplayId(HWC_DISPLAY_ID) - .setWidth(DisplayVariant::WIDTH) - .setHeight(DisplayVariant::HEIGHT) + .setResolution(DisplayVariant::RESOLUTION) .setActiveConfig(HWC_ACTIVE_CONFIG_ID) .setPowerMode(INIT_POWER_MODE) .inject(&test->mFlinger, test->mComposer); @@ -381,7 +381,7 @@ struct HwcDisplayVariant { auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() .setId(DisplayVariant::DISPLAY_ID::get()) - .setPixels({DisplayVariant::WIDTH, DisplayVariant::HEIGHT}) + .setPixels(DisplayVariant::RESOLUTION) .setIsSecure(static_cast(DisplayVariant::SECURE)) .setPowerAdvisor(&test->mPowerAdvisor) .setName(std::string("Injected display for ") + @@ -541,7 +541,7 @@ struct NonHwcVirtualDisplayVariant auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() .setId(Base::DISPLAY_ID::get()) - .setPixels({Base::WIDTH, Base::HEIGHT}) + .setPixels(Base::RESOLUTION) .setIsSecure(static_cast(Base::SECURE)) .setPowerAdvisor(&test->mPowerAdvisor) .setName(std::string("Injected display for ") + @@ -593,7 +593,7 @@ struct HwcVirtualDisplayVariant const auto displayId = Base::DISPLAY_ID::get(); auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() .setId(displayId) - .setPixels({Base::WIDTH, Base::HEIGHT}) + .setPixels(Base::RESOLUTION) .setIsSecure(static_cast(Base::SECURE)) .setPowerAdvisor(&test->mPowerAdvisor) .setName(std::string("Injected display for ") + @@ -736,6 +736,12 @@ using HwcVirtualDisplayCase = HdrNotSupportedVariant, NoPerFrameMetadataSupportVariant>; +inline DisplayModePtr createDisplayMode(DisplayModeId modeId, Fps refreshRate, int32_t group = 0, + ui::Size resolution = ui::Size(1920, 1080)) { + return mock::createDisplayMode(modeId, refreshRate, group, resolution, + PrimaryDisplayVariant::DISPLAY_ID::get()); +} + } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index e108beaca9..17511cd615 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -31,6 +31,7 @@ #include "Scheduler/LayerInfo.h" #include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" +#include "mock/DisplayHardware/MockDisplayMode.h" #include "mock/MockLayer.h" #include "mock/MockSchedulerCallback.h" @@ -42,6 +43,8 @@ namespace android::scheduler { using MockLayer = android::mock::MockLayer; +using android::mock::createDisplayMode; + class LayerHistoryTest : public testing::Test { protected: static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfo::HISTORY_SIZE; @@ -122,22 +125,12 @@ protected: ASSERT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate); } - std::shared_ptr mConfigs = std::make_shared< - RefreshRateConfigs>(DisplayModes{DisplayMode::Builder(0) - .setId(DisplayModeId(0)) - .setPhysicalDisplayId( - PhysicalDisplayId::fromPort(0)) - .setVsyncPeriod(int32_t(LO_FPS_PERIOD)) - .setGroup(0) - .build(), - DisplayMode::Builder(1) - .setId(DisplayModeId(1)) - .setPhysicalDisplayId( - PhysicalDisplayId::fromPort(0)) - .setVsyncPeriod(int32_t(HI_FPS_PERIOD)) - .setGroup(0) - .build()}, - DisplayModeId(0)); + std::shared_ptr mConfigs = + std::make_shared(makeModes(createDisplayMode(DisplayModeId(0), + LO_FPS), + createDisplayMode(DisplayModeId(1), + HI_FPS)), + DisplayModeId(0)); mock::SchedulerCallback mSchedulerCallback; diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 97f3747d07..fcde532b85 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -25,46 +25,33 @@ #include "DisplayHardware/HWC2.h" #include "FpsOps.h" #include "Scheduler/RefreshRateConfigs.h" +#include "mock/DisplayHardware/MockDisplayMode.h" using namespace std::chrono_literals; namespace android::scheduler { -namespace { - -DisplayModePtr createDisplayMode(DisplayModeId modeId, Fps refreshRate, int32_t group = 0, - ui::Size resolution = ui::Size()) { - return DisplayMode::Builder(hal::HWConfigId(modeId.value())) - .setId(modeId) - .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) - .setVsyncPeriod(static_cast(refreshRate.getPeriodNsecs())) - .setGroup(group) - .setHeight(resolution.height) - .setWidth(resolution.width) - .build(); -} - -} // namespace namespace hal = android::hardware::graphics::composer::hal; -using RefreshRate = RefreshRateConfigs::RefreshRate; using LayerVoteType = RefreshRateConfigs::LayerVoteType; using LayerRequirement = RefreshRateConfigs::LayerRequirement; +using mock::createDisplayMode; + struct TestableRefreshRateConfigs : RefreshRateConfigs { using RefreshRateConfigs::RefreshRateConfigs; - RefreshRate getMinSupportedRefreshRate() const { + DisplayModePtr getMinSupportedRefreshRate() const { std::lock_guard lock(mLock); - return *mMinSupportedRefreshRate; + return mMinRefreshRateModeIt->second; } - RefreshRate getMaxSupportedRefreshRate() const { + DisplayModePtr getMaxSupportedRefreshRate() const { std::lock_guard lock(mLock); - return *mMaxSupportedRefreshRate; + return mMaxRefreshRateModeIt->second; } - RefreshRate getMinRefreshRateByPolicy() const { + DisplayModePtr getMinRefreshRateByPolicy() const { std::lock_guard lock(mLock); return getMinRefreshRateByPolicyLocked(); } @@ -79,8 +66,8 @@ struct TestableRefreshRateConfigs : RefreshRateConfigs { return RefreshRateConfigs::getBestRefreshRate(layers, signals); } - RefreshRate getBestRefreshRate(const std::vector& layers = {}, - GlobalSignals signals = {}) const { + DisplayModePtr getBestRefreshRate(const std::vector& layers = {}, + GlobalSignals signals = {}) const { return getBestRefreshRateAndSignals(layers, signals).first; } }; @@ -90,10 +77,6 @@ protected: RefreshRateConfigsTest(); ~RefreshRateConfigsTest(); - static RefreshRate asRefreshRate(DisplayModePtr displayMode) { - return {displayMode, RefreshRate::ConstructorTag(0)}; - } - static constexpr DisplayModeId kModeId60{0}; static constexpr DisplayModeId kModeId90{1}; static constexpr DisplayModeId kModeId72{2}; @@ -126,30 +109,30 @@ protected: static inline const DisplayModePtr kMode24Frac = createDisplayMode(kModeId24Frac, 23.976_Hz); // Test configurations. - static inline const DisplayModes kModes_60 = {kMode60}; - static inline const DisplayModes kModes_60_90 = {kMode60, kMode90}; - static inline const DisplayModes kModes_60_90_G1 = {kMode60, kMode90_G1}; - static inline const DisplayModes kModes_60_90_4K = {kMode60, kMode90_4K}; - static inline const DisplayModes kModes_60_72_90 = {kMode60, kMode90, kMode72}; - static inline const DisplayModes kModes_60_90_72_120 = {kMode60, kMode90, kMode72, kMode120}; - static inline const DisplayModes kModes_30_60_72_90_120 = {kMode60, kMode90, kMode72, kMode120, - kMode30}; - - static inline const DisplayModes kModes_30_60 = {kMode60, kMode90_G1, kMode72_G1, kMode120_G1, - kMode30}; - static inline const DisplayModes kModes_30_60_72_90 = {kMode60, kMode90, kMode72, kMode120_G1, - kMode30}; - static inline const DisplayModes kModes_30_60_90 = {kMode60, kMode90, kMode72_G1, kMode120_G1, - kMode30}; - static inline const DisplayModes kModes_25_30_50_60 = {kMode60, kMode90, kMode72_G1, - kMode120_G1, kMode30_G1, kMode25_G1, - kMode50}; - static inline const DisplayModes kModes_60_120 = {kMode60, kMode120}; + static inline const DisplayModes kModes_60 = makeModes(kMode60); + static inline const DisplayModes kModes_60_90 = makeModes(kMode60, kMode90); + static inline const DisplayModes kModes_60_90_G1 = makeModes(kMode60, kMode90_G1); + static inline const DisplayModes kModes_60_90_4K = makeModes(kMode60, kMode90_4K); + static inline const DisplayModes kModes_60_72_90 = makeModes(kMode60, kMode90, kMode72); + static inline const DisplayModes kModes_60_90_72_120 = + makeModes(kMode60, kMode90, kMode72, kMode120); + static inline const DisplayModes kModes_30_60_72_90_120 = + makeModes(kMode60, kMode90, kMode72, kMode120, kMode30); + + static inline const DisplayModes kModes_30_60 = + makeModes(kMode60, kMode90_G1, kMode72_G1, kMode120_G1, kMode30); + static inline const DisplayModes kModes_30_60_72_90 = + makeModes(kMode60, kMode90, kMode72, kMode120_G1, kMode30); + static inline const DisplayModes kModes_30_60_90 = + makeModes(kMode60, kMode90, kMode72_G1, kMode120_G1, kMode30); + static inline const DisplayModes kModes_25_30_50_60 = + makeModes(kMode60, kMode90, kMode72_G1, kMode120_G1, kMode30_G1, kMode25_G1, kMode50); + static inline const DisplayModes kModes_60_120 = makeModes(kMode60, kMode120); // This is a typical TV configuration. - static inline const DisplayModes kModes_24_25_30_50_60_Frac = {kMode24, kMode24Frac, kMode25, - kMode30, kMode30Frac, kMode50, - kMode60, kMode60Frac}; + static inline const DisplayModes kModes_24_25_30_50_60_Frac = + makeModes(kMode24, kMode24Frac, kMode25, kMode30, kMode30Frac, kMode50, kMode60, + kMode60Frac); }; RefreshRateConfigsTest::RefreshRateConfigsTest() { @@ -183,8 +166,8 @@ TEST_F(RefreshRateConfigsTest, twoModes_storesFullRefreshRateMap) { const auto minRate = configs.getMinSupportedRefreshRate(); const auto performanceRate = configs.getMaxSupportedRefreshRate(); - EXPECT_EQ(asRefreshRate(kMode60), minRate); - EXPECT_EQ(asRefreshRate(kMode90), performanceRate); + EXPECT_EQ(kMode60, minRate); + EXPECT_EQ(kMode90, performanceRate); const auto minRateByPolicy = configs.getMinRefreshRateByPolicy(); const auto performanceRateByPolicy = configs.getMaxRefreshRateByPolicy(); @@ -201,19 +184,19 @@ TEST_F(RefreshRateConfigsTest, twoModes_storesFullRefreshRateMap_differentGroups const auto minRate60 = configs.getMinRefreshRateByPolicy(); const auto performanceRate60 = configs.getMaxRefreshRateByPolicy(); - EXPECT_EQ(asRefreshRate(kMode60), minRate); - EXPECT_EQ(asRefreshRate(kMode60), minRate60); - EXPECT_EQ(asRefreshRate(kMode60), performanceRate60); + EXPECT_EQ(kMode60, minRate); + EXPECT_EQ(kMode60, minRate60); + EXPECT_EQ(kMode60, performanceRate60); EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}), 0); - configs.setCurrentModeId(kModeId90); + configs.setActiveModeId(kModeId90); const auto minRate90 = configs.getMinRefreshRateByPolicy(); const auto performanceRate90 = configs.getMaxRefreshRateByPolicy(); - EXPECT_EQ(asRefreshRate(kMode90_G1), performanceRate); - EXPECT_EQ(asRefreshRate(kMode90_G1), minRate90); - EXPECT_EQ(asRefreshRate(kMode90_G1), performanceRate90); + EXPECT_EQ(kMode90_G1, performanceRate); + EXPECT_EQ(kMode90_G1, minRate90); + EXPECT_EQ(kMode90_G1, performanceRate90); } TEST_F(RefreshRateConfigsTest, twoModes_storesFullRefreshRateMap_differentResolutions) { @@ -224,19 +207,19 @@ TEST_F(RefreshRateConfigsTest, twoModes_storesFullRefreshRateMap_differentResolu const auto minRate60 = configs.getMinRefreshRateByPolicy(); const auto performanceRate60 = configs.getMaxRefreshRateByPolicy(); - EXPECT_EQ(asRefreshRate(kMode60), minRate); - EXPECT_EQ(asRefreshRate(kMode60), minRate60); - EXPECT_EQ(asRefreshRate(kMode60), performanceRate60); + EXPECT_EQ(kMode60, minRate); + EXPECT_EQ(kMode60, minRate60); + EXPECT_EQ(kMode60, performanceRate60); EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {60_Hz, 90_Hz}}), 0); - configs.setCurrentModeId(kModeId90); + configs.setActiveModeId(kModeId90); const auto minRate90 = configs.getMinRefreshRateByPolicy(); const auto performanceRate90 = configs.getMaxRefreshRateByPolicy(); - EXPECT_EQ(asRefreshRate(kMode90_4K), performanceRate); - EXPECT_EQ(asRefreshRate(kMode90_4K), minRate90); - EXPECT_EQ(asRefreshRate(kMode90_4K), performanceRate90); + EXPECT_EQ(kMode90_4K, performanceRate); + EXPECT_EQ(kMode90_4K, minRate90); + EXPECT_EQ(kMode90_4K, performanceRate90); } TEST_F(RefreshRateConfigsTest, twoModes_policyChange) { @@ -245,35 +228,35 @@ TEST_F(RefreshRateConfigsTest, twoModes_policyChange) { const auto minRate = configs.getMinRefreshRateByPolicy(); const auto performanceRate = configs.getMaxRefreshRateByPolicy(); - EXPECT_EQ(asRefreshRate(kMode60), minRate); - EXPECT_EQ(asRefreshRate(kMode90), performanceRate); + EXPECT_EQ(kMode60, minRate); + EXPECT_EQ(kMode90, performanceRate); EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}), 0); const auto minRate60 = configs.getMinRefreshRateByPolicy(); const auto performanceRate60 = configs.getMaxRefreshRateByPolicy(); - EXPECT_EQ(asRefreshRate(kMode60), minRate60); - EXPECT_EQ(asRefreshRate(kMode60), performanceRate60); + EXPECT_EQ(kMode60, minRate60); + EXPECT_EQ(kMode60, performanceRate60); } -TEST_F(RefreshRateConfigsTest, twoModes_getCurrentRefreshRate) { +TEST_F(RefreshRateConfigsTest, twoModes_getActiveMode) { TestableRefreshRateConfigs configs(kModes_60_90, kModeId60); { - const auto current = configs.getCurrentRefreshRate(); - EXPECT_EQ(current.getModeId(), kModeId60); + const auto mode = configs.getActiveMode(); + EXPECT_EQ(mode->getId(), kModeId60); } - configs.setCurrentModeId(kModeId90); + configs.setActiveModeId(kModeId90); { - const auto current = configs.getCurrentRefreshRate(); - EXPECT_EQ(current.getModeId(), kModeId90); + const auto mode = configs.getActiveMode(); + EXPECT_EQ(mode->getId(), kModeId90); } EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}), 0); { - const auto current = configs.getCurrentRefreshRate(); - EXPECT_EQ(current.getModeId(), kModeId90); + const auto mode = configs.getActiveMode(); + EXPECT_EQ(mode->getId(), kModeId90); } } @@ -283,10 +266,10 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_noLayers) { // If there are no layers we select the default frame rate, which is the max of the primary // range. - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate()); + EXPECT_EQ(kMode90, configs.getBestRefreshRate()); EXPECT_EQ(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}), NO_ERROR); - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate()); + EXPECT_EQ(kMode60, configs.getBestRefreshRate()); } { // We select max even when this will cause a non-seamless switch. @@ -294,7 +277,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_noLayers) { constexpr bool kAllowGroupSwitching = true; EXPECT_EQ(configs.setDisplayManagerPolicy({kModeId90, kAllowGroupSwitching, {0_Hz, 90_Hz}}), NO_ERROR); - EXPECT_EQ(asRefreshRate(kMode90_G1), configs.getBestRefreshRate()); + EXPECT_EQ(kMode90_G1, configs.getBestRefreshRate()); } } @@ -306,104 +289,104 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_90) { lr.vote = LayerVoteType::Min; lr.name = "Min"; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.vote = LayerVoteType::Max; lr.name = "Max"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; lr.name = "90Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 45_Hz; lr.name = "45Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 30_Hz; lr.name = "30Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 24_Hz; lr.name = "24Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.name = ""; EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}}), 0); lr.vote = LayerVoteType::Min; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.vote = LayerVoteType::Max; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}), 0); lr.vote = LayerVoteType::Min; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.vote = LayerVoteType::Max; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {0_Hz, 120_Hz}}), 0); lr.vote = LayerVoteType::Min; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.vote = LayerVoteType::Max; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_multipleThreshold_60_90) { @@ -414,32 +397,32 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_multipleThreshold_60_90) { lr.vote = LayerVoteType::Min; lr.name = "Min"; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.vote = LayerVoteType::Max; lr.name = "Max"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; lr.name = "90Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 45_Hz; lr.name = "45Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 30_Hz; lr.name = "30Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 24_Hz; lr.name = "24Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_72_90) { @@ -449,26 +432,26 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_72_90) { auto& lr = layers[0]; lr.vote = LayerVoteType::Min; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.vote = LayerVoteType::Max; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90_120) { @@ -482,19 +465,19 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90_120) { lr1.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 48_Hz; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 48_Hz; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) { @@ -510,7 +493,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) { lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -518,7 +501,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) { lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -526,7 +509,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) { lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "60Hz ExplicitDefault"; - EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -534,7 +517,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) { lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -542,7 +525,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) { lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; @@ -550,7 +533,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) { lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; @@ -558,7 +541,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) { lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -566,7 +549,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) { lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; @@ -574,7 +557,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) { lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.name = "90Hz ExplicitExactOrMultiple"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_multipleThreshold) { @@ -591,7 +574,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_mu lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -599,7 +582,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_mu lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -607,7 +590,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_mu lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "60Hz ExplicitDefault"; - EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -615,7 +598,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_mu lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -623,7 +606,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_mu lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; @@ -631,7 +614,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_mu lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; @@ -639,7 +622,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_mu lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -647,7 +630,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_mu lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; @@ -655,7 +638,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes_mu lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.name = "90Hz ExplicitExactOrMultiple"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) { @@ -665,26 +648,26 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) { auto& lr = layers[0]; lr.vote = LayerVoteType::Min; - EXPECT_EQ(asRefreshRate(kMode30), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers)); lr.vote = LayerVoteType::Max; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(asRefreshRate(kMode30), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90) { @@ -695,42 +678,42 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90) { lr.vote = LayerVoteType::Min; lr.name = "Min"; - EXPECT_EQ(asRefreshRate(kMode30), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers)); lr.vote = LayerVoteType::Max; lr.name = "Max"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; lr.name = "90Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers, {.touch = true})); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true})); lr.desiredRefreshRate = 45_Hz; lr.name = "45Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers, {.touch = true})); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true})); lr.desiredRefreshRate = 30_Hz; lr.name = "30Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode30), configs.getBestRefreshRate(layers)); - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers, {.touch = true})); + EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true})); lr.desiredRefreshRate = 24_Hz; lr.name = "24Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers)); - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers, {.touch = true})); + EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true})); lr.desiredRefreshRate = 24_Hz; lr.vote = LayerVoteType::ExplicitExactOrMultiple; lr.name = "24Hz ExplicitExactOrMultiple"; - EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers)); - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers, {.touch = true})); + EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_PriorityTest) { @@ -742,39 +725,39 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_PriorityTest) { lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::Max; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 24_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 24_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr1.vote = LayerVoteType::Max; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60_Hz; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr1.vote = LayerVoteType::Max; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 60_Hz; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr1.vote = LayerVoteType::Heuristic; lr1.desiredRefreshRate = 15_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 45_Hz; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr1.vote = LayerVoteType::Heuristic; lr1.desiredRefreshRate = 30_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 45_Hz; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_24FpsVideo) { @@ -786,9 +769,9 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_24FpsVideo) { lr.vote = LayerVoteType::ExplicitExactOrMultiple; for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) { lr.desiredRefreshRate = Fps::fromValue(fps); - const auto refreshRate = configs.getBestRefreshRate(layers); - EXPECT_EQ(asRefreshRate(kMode60), refreshRate) - << lr.desiredRefreshRate << " chooses " << refreshRate.getName(); + const auto mode = configs.getBestRefreshRate(layers); + EXPECT_EQ(kMode60, mode) << lr.desiredRefreshRate << " chooses " + << to_string(mode->getFps()); } } @@ -802,9 +785,9 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_24FpsVideo_multipleThreshold_6 lr.vote = LayerVoteType::ExplicitExactOrMultiple; for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) { lr.desiredRefreshRate = Fps::fromValue(fps); - const auto refreshRate = configs.getBestRefreshRate(layers); - EXPECT_EQ(asRefreshRate(kMode60), refreshRate) - << lr.desiredRefreshRate << " chooses " << refreshRate.getName(); + const auto mode = configs.getBestRefreshRate(layers); + EXPECT_EQ(kMode60, mode) << lr.desiredRefreshRate << " chooses " + << to_string(mode->getFps()); } } @@ -819,19 +802,19 @@ TEST_F(RefreshRateConfigsTest, twoModes_getBestRefreshRate_Explicit) { lr1.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 90_Hz; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr1.vote = LayerVoteType::ExplicitDefault; lr1.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 60_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr1.vote = LayerVoteType::Heuristic; lr1.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 60_Hz; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_75HzContent) { @@ -843,9 +826,9 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_75HzContent) { lr.vote = LayerVoteType::ExplicitExactOrMultiple; for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) { lr.desiredRefreshRate = Fps::fromValue(fps); - const auto refreshRate = configs.getBestRefreshRate(layers, {}); - EXPECT_EQ(asRefreshRate(kMode90), refreshRate) - << lr.desiredRefreshRate << " chooses " << refreshRate.getName(); + const auto mode = configs.getBestRefreshRate(layers, {}); + EXPECT_EQ(kMode90, mode) << lr.desiredRefreshRate << " chooses " + << to_string(mode->getFps()); } } @@ -862,7 +845,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_Multiples) { lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 90_Hz; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60_Hz; @@ -870,14 +853,14 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_Multiples) { lr2.vote = LayerVoteType::ExplicitDefault; lr2.desiredRefreshRate = 90_Hz; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 30_Hz; @@ -885,14 +868,14 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_Multiples) { lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 90_Hz; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 30_Hz; lr1.name = "30Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); } TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) { @@ -907,28 +890,28 @@ TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) { lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::NoVote; lr2.name = "NoVote"; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::NoVote; lr2.name = "NoVote"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers, {.touch = true})); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true})); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers, {.touch = true})); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.touch = true})); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); // The other layer starts to provide buffers lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -937,7 +920,7 @@ TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) { lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 90_Hz; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); } TEST_F(RefreshRateConfigsTest, touchConsidered) { @@ -1023,8 +1006,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitDefault) { ss << "ExplicitDefault " << desired; lr.name = ss.str(); - const auto refreshRate = configs.getBestRefreshRate(layers); - EXPECT_EQ(refreshRate.getFps(), expected); + EXPECT_EQ(expected, configs.getBestRefreshRate(layers)->getFps()); } } @@ -1035,36 +1017,36 @@ TEST_F(RefreshRateConfigsTest, // Test that 23.976 will choose 24 if 23.976 is not supported { - TestableRefreshRateConfigs configs({kMode24, kMode25, kMode30, kMode30Frac, kMode60, - kMode60Frac}, + TestableRefreshRateConfigs configs(makeModes(kMode24, kMode25, kMode30, kMode30Frac, + kMode60, kMode60Frac), kModeId60); lr.vote = LayerVoteType::ExplicitExactOrMultiple; lr.desiredRefreshRate = 23.976_Hz; lr.name = "ExplicitExactOrMultiple 23.976 Hz"; - EXPECT_EQ(kModeId24, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId24, configs.getBestRefreshRate(layers)->getId()); } // Test that 24 will choose 23.976 if 24 is not supported { - TestableRefreshRateConfigs configs({kMode24Frac, kMode25, kMode30, kMode30Frac, kMode60, - kMode60Frac}, + TestableRefreshRateConfigs configs(makeModes(kMode24Frac, kMode25, kMode30, kMode30Frac, + kMode60, kMode60Frac), kModeId60); lr.desiredRefreshRate = 24_Hz; lr.name = "ExplicitExactOrMultiple 24 Hz"; - EXPECT_EQ(kModeId24Frac, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId24Frac, configs.getBestRefreshRate(layers)->getId()); } // Test that 29.97 will prefer 59.94 over 60 and 30 { - TestableRefreshRateConfigs configs({kMode24, kMode24Frac, kMode25, kMode30, kMode60, - kMode60Frac}, + TestableRefreshRateConfigs configs(makeModes(kMode24, kMode24Frac, kMode25, kMode30, + kMode60, kMode60Frac), kModeId60); lr.desiredRefreshRate = 29.97_Hz; lr.name = "ExplicitExactOrMultiple 29.97 Hz"; - EXPECT_EQ(kModeId60Frac, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId60Frac, configs.getBestRefreshRate(layers)->getId()); } } @@ -1083,32 +1065,31 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact_WithFractionalRe ss << "ExplicitExact " << desired; lr.name = ss.str(); - auto selectedRefreshRate = configs.getBestRefreshRate(layers); - EXPECT_EQ(selectedRefreshRate.getFps(), lr.desiredRefreshRate); + EXPECT_EQ(lr.desiredRefreshRate, configs.getBestRefreshRate(layers)->getFps()); } } // Test that 23.976 will choose 24 if 23.976 is not supported { - TestableRefreshRateConfigs configs({kMode24, kMode25, kMode30, kMode30Frac, kMode60, - kMode60Frac}, + TestableRefreshRateConfigs configs(makeModes(kMode24, kMode25, kMode30, kMode30Frac, + kMode60, kMode60Frac), kModeId60); lr.vote = LayerVoteType::ExplicitExact; lr.desiredRefreshRate = 23.976_Hz; lr.name = "ExplicitExact 23.976 Hz"; - EXPECT_EQ(kModeId24, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId24, configs.getBestRefreshRate(layers)->getId()); } // Test that 24 will choose 23.976 if 24 is not supported { - TestableRefreshRateConfigs configs({kMode24Frac, kMode25, kMode30, kMode30Frac, kMode60, - kMode60Frac}, + TestableRefreshRateConfigs configs(makeModes(kMode24Frac, kMode25, kMode30, kMode30Frac, + kMode60, kMode60Frac), kModeId60); lr.desiredRefreshRate = 24_Hz; lr.name = "ExplicitExact 24 Hz"; - EXPECT_EQ(kModeId24Frac, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId24Frac, configs.getBestRefreshRate(layers)->getId()); } } @@ -1126,10 +1107,9 @@ TEST_F(RefreshRateConfigsTest, lr.name = "60Hz ExplicitDefault"; lr.focused = true; - const auto [refreshRate, signals] = - configs.getBestRefreshRate(layers, {.touch = true, .idle = true}); + const auto [mode, signals] = configs.getBestRefreshRate(layers, {.touch = true, .idle = true}); - EXPECT_EQ(refreshRate, asRefreshRate(kMode60)); + EXPECT_EQ(mode, kMode60); EXPECT_FALSE(signals.touch); } @@ -1146,7 +1126,7 @@ TEST_F(RefreshRateConfigsTest, lr.desiredRefreshRate = 90_Hz; lr.name = "90Hz ExplicitDefault"; lr.focused = true; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers, {.idle = true})); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers, {.idle = true})); } TEST_F(RefreshRateConfigsTest, @@ -1155,8 +1135,8 @@ TEST_F(RefreshRateConfigsTest, EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0); - const auto [refreshRate, signals] = configs.getBestRefreshRateAndSignals({}, {}); - EXPECT_EQ(refreshRate, asRefreshRate(kMode90)); + const auto [mode, signals] = configs.getBestRefreshRateAndSignals({}, {}); + EXPECT_EQ(mode, kMode90); EXPECT_FALSE(signals.touch); std::vector layers = {{.weight = 1.f}}; @@ -1166,46 +1146,46 @@ TEST_F(RefreshRateConfigsTest, lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz ExplicitExactOrMultiple"; lr.focused = false; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.focused = true; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.vote = LayerVoteType::ExplicitDefault; lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz ExplicitDefault"; lr.focused = false; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.focused = true; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); lr.vote = LayerVoteType::Heuristic; lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Heuristic"; lr.focused = false; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.focused = true; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.vote = LayerVoteType::Max; lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Max"; lr.focused = false; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.focused = true; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.vote = LayerVoteType::Min; lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Min"; lr.focused = false; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); lr.focused = true; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); } TEST_F(RefreshRateConfigsTest, groupSwitchingNotAllowed) { @@ -1221,7 +1201,7 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingNotAllowed) { layer.name = "90Hz ExplicitDefault"; layer.focused = true; - EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers)->getId()); } TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayer) { @@ -1239,7 +1219,7 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayer) { layer.seamlessness = Seamlessness::SeamedAndSeamless; layer.name = "90Hz ExplicitDefault"; layer.focused = true; - EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers)->getId()); } TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamless) { @@ -1258,7 +1238,7 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamless) { layer.seamlessness = Seamlessness::OnlySeamless; layer.name = "90Hz ExplicitDefault"; layer.focused = true; - EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers)->getId()); } TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamlessDefaultFps) { @@ -1269,7 +1249,7 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamlessDefaultFps) policy.allowGroupSwitching = true; EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0); - configs.setCurrentModeId(kModeId90); + configs.setActiveModeId(kModeId90); // Verify that we won't do a seamless switch if we request the same mode as the default std::vector layers = {{.weight = 1.f}}; @@ -1279,7 +1259,7 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerOnlySeamlessDefaultFps) layer.seamlessness = Seamlessness::OnlySeamless; layer.name = "60Hz ExplicitDefault"; layer.focused = true; - EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers)->getId()); } TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerDefaultSeamlessness) { @@ -1290,7 +1270,7 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerDefaultSeamlessness) { policy.allowGroupSwitching = true; EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0); - configs.setCurrentModeId(kModeId90); + configs.setActiveModeId(kModeId90); // Verify that if the current config is in another group and there are no layers with // seamlessness=SeamedAndSeamless we'll go back to the default group. @@ -1303,7 +1283,7 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithOneLayerDefaultSeamlessness) { layer.name = "60Hz ExplicitDefault"; layer.focused = true; - EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers)->getId()); } TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed) { @@ -1314,7 +1294,7 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed) policy.allowGroupSwitching = true; EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0); - configs.setCurrentModeId(kModeId90); + configs.setActiveModeId(kModeId90); // If there's a layer with seamlessness=SeamedAndSeamless, another layer with // seamlessness=OnlySeamless can't change the mode group. @@ -1332,7 +1312,7 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed) layers[1].name = "90Hz ExplicitDefault"; layers[1].focused = false; - EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers)->getId()); } TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultFocusedAndSeamed) { @@ -1343,7 +1323,7 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultFocusedAndSeame policy.allowGroupSwitching = true; EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0); - configs.setCurrentModeId(kModeId90); + configs.setActiveModeId(kModeId90); // If there's a focused layer with seamlessness=SeamedAndSeamless, another layer with // seamlessness=Default can't change the mode group back to the group of the default @@ -1365,7 +1345,7 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultFocusedAndSeame layers[1].vote = LayerVoteType::ExplicitDefault; layers[1].name = "90Hz ExplicitDefault"; - EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers)->getId()); } TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultNotFocusedAndSeamed) { @@ -1376,7 +1356,7 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultNotFocusedAndSe policy.allowGroupSwitching = true; EXPECT_GE(configs.setDisplayManagerPolicy(policy), 0); - configs.setCurrentModeId(kModeId90); + configs.setActiveModeId(kModeId90); // Layer with seamlessness=Default can change the mode group if there's a not // focused layer with seamlessness=SeamedAndSeamless. This happens for example, @@ -1395,7 +1375,7 @@ TEST_F(RefreshRateConfigsTest, groupSwitchingWithTwoLayersDefaultNotFocusedAndSe layers[1].vote = LayerVoteType::ExplicitDefault; layers[1].name = "90Hz ExplicitDefault"; - EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers)->getId()); } TEST_F(RefreshRateConfigsTest, nonSeamlessVotePrefersSeamlessSwitches) { @@ -1415,10 +1395,10 @@ TEST_F(RefreshRateConfigsTest, nonSeamlessVotePrefersSeamlessSwitches) { layer.name = "60Hz ExplicitExactOrMultiple"; layer.focused = true; - EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId60, configs.getBestRefreshRate(layers)->getId()); - configs.setCurrentModeId(kModeId120); - EXPECT_EQ(kModeId120, configs.getBestRefreshRate(layers).getModeId()); + configs.setActiveModeId(kModeId120); + EXPECT_EQ(kModeId120, configs.getBestRefreshRate(layers)->getId()); } TEST_F(RefreshRateConfigsTest, nonSeamlessExactAndSeamlessMultipleLayers) { @@ -1443,14 +1423,14 @@ TEST_F(RefreshRateConfigsTest, nonSeamlessExactAndSeamlessMultipleLayers) { .weight = 1.f, .focused = true}}; - EXPECT_EQ(kModeId50, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId50, configs.getBestRefreshRate(layers)->getId()); auto& seamedLayer = layers[0]; seamedLayer.desiredRefreshRate = 30_Hz; seamedLayer.name = "30Hz ExplicitDefault"; - configs.setCurrentModeId(kModeId30); + configs.setActiveModeId(kModeId30); - EXPECT_EQ(kModeId25, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId25, configs.getBestRefreshRate(layers)->getId()); } TEST_F(RefreshRateConfigsTest, minLayersDontTrigerSeamedSwitch) { @@ -1465,7 +1445,7 @@ TEST_F(RefreshRateConfigsTest, minLayersDontTrigerSeamedSwitch) { std::vector layers = { {.name = "Min", .vote = LayerVoteType::Min, .weight = 1.f, .focused = true}}; - EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers).getModeId()); + EXPECT_EQ(kModeId90, configs.getBestRefreshRate(layers)->getId()); } TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) { @@ -1485,12 +1465,12 @@ TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) { layers[0].vote = voteType; layers[0].desiredRefreshRate = fps; layers[0].focused = args.focused; - return configs.getBestRefreshRate(layers, {.touch = args.touch}).getModeId(); + return configs.getBestRefreshRate(layers, {.touch = args.touch})->getId(); }; EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {30_Hz, 60_Hz}, {30_Hz, 90_Hz}}), 0); - EXPECT_EQ(kModeId60, configs.getBestRefreshRate().getModeId()); + EXPECT_EQ(kModeId60, configs.getBestRefreshRate()->getId()); EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::NoVote, 90_Hz)); EXPECT_EQ(kModeId30, getFrameRate(LayerVoteType::Min, 90_Hz)); EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Max, 90_Hz)); @@ -1537,7 +1517,7 @@ TEST_F(RefreshRateConfigsTest, idle) { // Refresh rate will be chosen by either touch state or idle state. EXPECT_EQ(!touchActive, signals.idle); - return refreshRate.getModeId(); + return refreshRate->getId(); }; EXPECT_GE(configs.setDisplayManagerPolicy({kModeId60, {60_Hz, 90_Hz}, {60_Hz, 90_Hz}}), 0); @@ -1555,10 +1535,10 @@ TEST_F(RefreshRateConfigsTest, idle) { } // With no layers, idle should still be lower priority than touch boost. - EXPECT_EQ(kModeId90, configs.getBestRefreshRate({}, {.touch = true, .idle = true}).getModeId()); + EXPECT_EQ(kModeId90, configs.getBestRefreshRate({}, {.touch = true, .idle = true})->getId()); // Idle should be higher precedence than other layer frame rate considerations. - configs.setCurrentModeId(kModeId90); + configs.setActiveModeId(kModeId90); { constexpr bool kTouchActive = false; @@ -1572,7 +1552,7 @@ TEST_F(RefreshRateConfigsTest, idle) { } // Idle should be applied rather than the current config when there are no layers. - EXPECT_EQ(kModeId60, configs.getBestRefreshRate({}, {.idle = true}).getModeId()); + EXPECT_EQ(kModeId60, configs.getBestRefreshRate({}, {.idle = true})->getId()); } TEST_F(RefreshRateConfigsTest, findClosestKnownFrameRate) { @@ -1598,13 +1578,12 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_KnownFrameRate) { struct Expectation { Fps fps; - const RefreshRate& refreshRate; + DisplayModePtr mode; }; const std::initializer_list knownFrameRatesExpectations = { - {24_Hz, asRefreshRate(kMode60)}, {30_Hz, asRefreshRate(kMode60)}, - {45_Hz, asRefreshRate(kMode90)}, {60_Hz, asRefreshRate(kMode60)}, - {72_Hz, asRefreshRate(kMode90)}, {90_Hz, asRefreshRate(kMode90)}, + {24_Hz, kMode60}, {30_Hz, kMode60}, {45_Hz, kMode90}, + {60_Hz, kMode60}, {72_Hz, kMode90}, {90_Hz, kMode90}, }; // Make sure the test tests all the known frame rate @@ -1620,9 +1599,9 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_KnownFrameRate) { auto& layer = layers[0]; layer.vote = LayerVoteType::Heuristic; - for (const auto& [fps, refreshRate] : knownFrameRatesExpectations) { + for (const auto& [fps, mode] : knownFrameRatesExpectations) { layer.desiredRefreshRate = fps; - EXPECT_EQ(refreshRate, configs.getBestRefreshRate(layers)); + EXPECT_EQ(mode, configs.getBestRefreshRate(layers)); } } @@ -1641,21 +1620,21 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExact) { explicitExactLayer.name = "ExplicitExact"; explicitExactLayer.desiredRefreshRate = 30_Hz; - EXPECT_EQ(asRefreshRate(kMode30), configs.getBestRefreshRate(layers)); - EXPECT_EQ(asRefreshRate(kMode30), configs.getBestRefreshRate(layers, {.touch = true})); + EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode30, configs.getBestRefreshRate(layers, {.touch = true})); explicitExactOrMultipleLayer.desiredRefreshRate = 120_Hz; explicitExactLayer.desiredRefreshRate = 60_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); explicitExactLayer.desiredRefreshRate = 72_Hz; - EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); explicitExactLayer.desiredRefreshRate = 90_Hz; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); explicitExactLayer.desiredRefreshRate = 120_Hz; - EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactEnableFrameRateOverride) { @@ -1674,21 +1653,21 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactEnableFrameRateOv explicitExactLayer.name = "ExplicitExact"; explicitExactLayer.desiredRefreshRate = 30_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); - EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers, {.touch = true})); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers, {.touch = true})); explicitExactOrMultipleLayer.desiredRefreshRate = 120_Hz; explicitExactLayer.desiredRefreshRate = 60_Hz; - EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); explicitExactLayer.desiredRefreshRate = 72_Hz; - EXPECT_EQ(asRefreshRate(kMode72), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode72, configs.getBestRefreshRate(layers)); explicitExactLayer.desiredRefreshRate = 90_Hz; - EXPECT_EQ(asRefreshRate(kMode90), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode90, configs.getBestRefreshRate(layers)); explicitExactLayer.desiredRefreshRate = 120_Hz; - EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers)); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ReadsCache) { @@ -1697,7 +1676,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ReadsCache) { using GlobalSignals = RefreshRateConfigs::GlobalSignals; const auto args = std::make_pair(std::vector{}, GlobalSignals{.touch = true, .idle = true}); - const auto result = std::make_pair(asRefreshRate(kMode90), GlobalSignals{.touch = true}); + const auto result = std::make_pair(kMode90, GlobalSignals{.touch = true}); configs.mutableGetBestRefreshRateCache() = {args, result}; @@ -1736,13 +1715,13 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitExactTouchBoost) { explicitExactLayer.name = "ExplicitExact"; explicitExactLayer.desiredRefreshRate = 30_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); - EXPECT_EQ(asRefreshRate(kMode120), configs.getBestRefreshRate(layers, {.touch = true})); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode120, configs.getBestRefreshRate(layers, {.touch = true})); explicitExactOrMultipleLayer.vote = LayerVoteType::NoVote; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers, {.touch = true})); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers, {.touch = true})); } TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAndDefault) { @@ -1761,7 +1740,7 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_FractionalRefreshRates_ExactAn explicitDefaultLayer.name = "ExplicitDefault"; explicitDefaultLayer.desiredRefreshRate = 59.94_Hz; - EXPECT_EQ(asRefreshRate(kMode60), configs.getBestRefreshRate(layers)); + EXPECT_EQ(kMode60, configs.getBestRefreshRate(layers)); } // b/190578904 @@ -1771,17 +1750,20 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_withCloseRefreshRates) { DisplayModes displayModes; for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) { - displayModes.push_back( - createDisplayMode(DisplayModeId(fps), Fps::fromValue(static_cast(fps)))); + const DisplayModeId modeId(fps); + displayModes.try_emplace(modeId, + createDisplayMode(modeId, + Fps::fromValue(static_cast(fps)))); } - const TestableRefreshRateConfigs configs(displayModes, displayModes[0]->getId()); + const TestableRefreshRateConfigs configs(std::move(displayModes), + DisplayModeId(kMinRefreshRate)); std::vector layers = {{.weight = 1.f}}; const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) { layers[0].desiredRefreshRate = fps; layers[0].vote = vote; - EXPECT_EQ(fps.getIntValue(), configs.getBestRefreshRate(layers).getFps().getIntValue()) + EXPECT_EQ(fps.getIntValue(), configs.getBestRefreshRate(layers)->getFps().getIntValue()) << "Failed for " << ftl::enum_string(vote); }; @@ -1796,15 +1778,14 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_withCloseRefreshRates) { // b/190578904 TEST_F(RefreshRateConfigsTest, getBestRefreshRate_conflictingVotes) { - const DisplayModes displayModes = { - createDisplayMode(DisplayModeId(0), 43_Hz), - createDisplayMode(DisplayModeId(1), 53_Hz), - createDisplayMode(DisplayModeId(2), 55_Hz), - createDisplayMode(DisplayModeId(3), 60_Hz), - }; + constexpr DisplayModeId kActiveModeId{0}; + DisplayModes displayModes = makeModes(createDisplayMode(kActiveModeId, 43_Hz), + createDisplayMode(DisplayModeId(1), 53_Hz), + createDisplayMode(DisplayModeId(2), 55_Hz), + createDisplayMode(DisplayModeId(3), 60_Hz)); const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false}; - const TestableRefreshRateConfigs configs(displayModes, displayModes[0]->getId()); + const TestableRefreshRateConfigs configs(std::move(displayModes), kActiveModeId); const std::vector layers = { { @@ -1821,13 +1802,13 @@ TEST_F(RefreshRateConfigsTest, getBestRefreshRate_conflictingVotes) { }, }; - EXPECT_EQ(53_Hz, configs.getBestRefreshRate(layers, globalSignals).getFps()); + EXPECT_EQ(53_Hz, configs.getBestRefreshRate(layers, globalSignals)->getFps()); } -TEST_F(RefreshRateConfigsTest, testComparisonOperator) { - EXPECT_TRUE(asRefreshRate(kMode60) < asRefreshRate(kMode90)); - EXPECT_FALSE(asRefreshRate(kMode60) < asRefreshRate(kMode60)); - EXPECT_FALSE(asRefreshRate(kMode90) < asRefreshRate(kMode90)); +TEST_F(RefreshRateConfigsTest, modeComparison) { + EXPECT_LT(kMode60->getFps(), kMode90->getFps()); + EXPECT_GE(kMode60->getFps(), kMode60->getFps()); + EXPECT_GE(kMode90->getFps(), kMode90->getFps()); } TEST_F(RefreshRateConfigsTest, testKernelIdleTimerAction) { @@ -1877,27 +1858,27 @@ TEST_F(RefreshRateConfigsTest, getFrameRateDivisor) { RefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId30); const auto frameRate = 30_Hz; - Fps displayRefreshRate = configs.getCurrentRefreshRate().getFps(); + Fps displayRefreshRate = configs.getActiveMode()->getFps(); EXPECT_EQ(1, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate)); - configs.setCurrentModeId(kModeId60); - displayRefreshRate = configs.getCurrentRefreshRate().getFps(); + configs.setActiveModeId(kModeId60); + displayRefreshRate = configs.getActiveMode()->getFps(); EXPECT_EQ(2, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate)); - configs.setCurrentModeId(kModeId72); - displayRefreshRate = configs.getCurrentRefreshRate().getFps(); + configs.setActiveModeId(kModeId72); + displayRefreshRate = configs.getActiveMode()->getFps(); EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate)); - configs.setCurrentModeId(kModeId90); - displayRefreshRate = configs.getCurrentRefreshRate().getFps(); + configs.setActiveModeId(kModeId90); + displayRefreshRate = configs.getActiveMode()->getFps(); EXPECT_EQ(3, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate)); - configs.setCurrentModeId(kModeId120); - displayRefreshRate = configs.getCurrentRefreshRate().getFps(); + configs.setActiveModeId(kModeId120); + displayRefreshRate = configs.getActiveMode()->getFps(); EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate)); - configs.setCurrentModeId(kModeId90); - displayRefreshRate = configs.getCurrentRefreshRate().getFps(); + configs.setActiveModeId(kModeId90); + displayRefreshRate = configs.getActiveMode()->getFps(); EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, 22.5_Hz)); EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(24_Hz, 25_Hz)); diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index df4a9c46d1..e2e3d7b12b 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -21,8 +21,6 @@ #include #include -#include "DisplayHardware/DisplayMode.h" -#include "Scheduler/RefreshRateConfigs.h" #include "Scheduler/RefreshRateStats.h" #include "mock/MockTimeStats.h" @@ -35,29 +33,15 @@ namespace android::scheduler { class RefreshRateStatsTest : public testing::Test { protected: - static inline const auto CONFIG_ID_0 = DisplayModeId(0); - static inline const auto CONFIG_ID_1 = DisplayModeId(1); - static inline const auto CONFIG_GROUP_0 = 0; - static constexpr int64_t VSYNC_90 = 11111111; - static constexpr int64_t VSYNC_60 = 16666667; - RefreshRateStatsTest(); ~RefreshRateStatsTest(); - void init(const DisplayModes& configs) { - mRefreshRateConfigs = - std::make_unique(configs, /*currentConfig=*/CONFIG_ID_0); - - const auto currFps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps(); - mRefreshRateStats = std::make_unique(mTimeStats, currFps, - /*currentPowerMode=*/PowerMode::OFF); + void resetStats(Fps fps) { + mRefreshRateStats = std::make_unique(mTimeStats, fps, PowerMode::OFF); } mock::TimeStats mTimeStats; - std::unique_ptr mRefreshRateConfigs; std::unique_ptr mRefreshRateStats; - - DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod); }; RefreshRateStatsTest::RefreshRateStatsTest() { @@ -72,20 +56,10 @@ RefreshRateStatsTest::~RefreshRateStatsTest() { ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } -DisplayModePtr RefreshRateStatsTest::createDisplayMode(DisplayModeId modeId, int32_t group, - int64_t vsyncPeriod) { - return DisplayMode::Builder(static_cast(modeId.value())) - .setId(modeId) - .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) - .setVsyncPeriod(static_cast(vsyncPeriod)) - .setGroup(group) - .build(); -} - namespace { -TEST_F(RefreshRateStatsTest, oneConfigTest) { - init({createDisplayMode(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90)}); +TEST_F(RefreshRateStatsTest, oneMode) { + resetStats(90_Hz); EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); @@ -102,8 +76,7 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { EXPECT_LT(screenOff, times.get("ScreenOff")->get()); EXPECT_FALSE(times.contains("90.00 Hz")); - const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps(); - mRefreshRateStats->setRefreshRate(config0Fps); + mRefreshRateStats->setRefreshRate(90_Hz); mRefreshRateStats->setPowerMode(PowerMode::ON); screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); @@ -121,20 +94,18 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { EXPECT_LT(screenOff, times.get("ScreenOff")->get()); EXPECT_EQ(ninety, times.get("90.00 Hz")->get()); - mRefreshRateStats->setRefreshRate(config0Fps); + mRefreshRateStats->setRefreshRate(90_Hz); screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); - // Because the power mode is not PowerMode::ON, switching the config - // does not update refresh rates that come from the config. + // Stats are not updated while the screen is off. EXPECT_LT(screenOff, times.get("ScreenOff")->get()); EXPECT_EQ(ninety, times.get("90.00 Hz")->get()); } -TEST_F(RefreshRateStatsTest, twoConfigsTest) { - init({createDisplayMode(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90), - createDisplayMode(CONFIG_ID_1, CONFIG_GROUP_0, VSYNC_60)}); +TEST_F(RefreshRateStatsTest, twoModes) { + resetStats(90_Hz); EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1)); @@ -153,9 +124,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { EXPECT_FALSE(times.contains("60.00 Hz")); EXPECT_FALSE(times.contains("90.00 Hz")); - const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps(); - const auto config1Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_1).getFps(); - mRefreshRateStats->setRefreshRate(config0Fps); + mRefreshRateStats->setRefreshRate(90_Hz); mRefreshRateStats->setPowerMode(PowerMode::ON); screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); @@ -165,8 +134,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { ASSERT_TRUE(times.contains("90.00 Hz")); EXPECT_LT(0ms, times.get("90.00 Hz")->get()); - // When power mode is normal, time for configs updates. - mRefreshRateStats->setRefreshRate(config1Fps); + mRefreshRateStats->setRefreshRate(60_Hz); auto ninety = mRefreshRateStats->getTotalTimes().get("90.00 Hz")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); @@ -176,7 +144,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { ASSERT_TRUE(times.contains("60.00 Hz")); EXPECT_LT(0ms, times.get("60.00 Hz")->get()); - mRefreshRateStats->setRefreshRate(config0Fps); + mRefreshRateStats->setRefreshRate(90_Hz); auto sixty = mRefreshRateStats->getTotalTimes().get("60.00 Hz")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); @@ -185,7 +153,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { EXPECT_LT(ninety, times.get("90.00 Hz")->get()); EXPECT_EQ(sixty, times.get("60.00 Hz")->get()); - mRefreshRateStats->setRefreshRate(config1Fps); + mRefreshRateStats->setRefreshRate(60_Hz); ninety = mRefreshRateStats->getTotalTimes().get("90.00 Hz")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); @@ -194,10 +162,9 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { EXPECT_EQ(ninety, times.get("90.00 Hz")->get()); EXPECT_LT(sixty, times.get("60.00 Hz")->get()); - // Because the power mode is not PowerMode::ON, switching the config - // does not update refresh rates that come from the config. + // Stats are not updated while the screen is off. mRefreshRateStats->setPowerMode(PowerMode::DOZE); - mRefreshRateStats->setRefreshRate(config0Fps); + mRefreshRateStats->setRefreshRate(90_Hz); sixty = mRefreshRateStats->getTotalTimes().get("60.00 Hz")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); @@ -206,7 +173,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { EXPECT_EQ(ninety, times.get("90.00 Hz")->get()); EXPECT_EQ(sixty, times.get("60.00 Hz")->get()); - mRefreshRateStats->setRefreshRate(config1Fps); + mRefreshRateStats->setRefreshRate(60_Hz); screenOff = mRefreshRateStats->getTotalTimes().get("ScreenOff")->get(); std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index a992a91226..aab27957c3 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -24,12 +24,15 @@ #include "Scheduler/RefreshRateConfigs.h" #include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" +#include "mock/DisplayHardware/MockDisplayMode.h" #include "mock/MockEventThread.h" #include "mock/MockLayer.h" #include "mock/MockSchedulerCallback.h" namespace android::scheduler { +using android::mock::createDisplayMode; + using testing::_; using testing::Return; @@ -55,21 +58,11 @@ protected: SchedulerTest(); - const DisplayModePtr mode60 = DisplayMode::Builder(0) - .setId(DisplayModeId(0)) - .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) - .setVsyncPeriod((60_Hz).getPeriodNsecs()) - .setGroup(0) - .build(); - const DisplayModePtr mode120 = DisplayMode::Builder(1) - .setId(DisplayModeId(1)) - .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) - .setVsyncPeriod((120_Hz).getPeriodNsecs()) - .setGroup(0) - .build(); + static inline const DisplayModePtr kMode60 = createDisplayMode(DisplayModeId(0), 60_Hz); + static inline const DisplayModePtr kMode120 = createDisplayMode(DisplayModeId(1), 120_Hz); std::shared_ptr mConfigs = - std::make_shared(DisplayModes{mode60}, mode60->getId()); + std::make_shared(makeModes(kMode60), kMode60->getId()); mock::SchedulerCallback mSchedulerCallback; TestableScheduler* mScheduler = new TestableScheduler{mConfigs, mSchedulerCallback}; @@ -172,7 +165,7 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSup constexpr uint32_t kDisplayArea = 999'999; mScheduler->onActiveDisplayAreaChanged(kDisplayArea); - EXPECT_CALL(mSchedulerCallback, changeRefreshRate(_, _)).Times(0); + EXPECT_CALL(mSchedulerCallback, requestDisplayMode(_, _)).Times(0); mScheduler->chooseRefreshRateForContent(); } @@ -182,7 +175,7 @@ TEST_F(SchedulerTest, updateDisplayModes) { ASSERT_EQ(1u, mScheduler->layerHistorySize()); mScheduler->setRefreshRateConfigs( - std::make_shared(DisplayModes{mode60, mode120}, mode60->getId())); + std::make_shared(makeModes(kMode60, kMode120), kMode60->getId())); ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); mScheduler->recordLayerHistory(layer.get(), 0, LayerHistory::LayerUpdateType::Buffer); @@ -221,12 +214,12 @@ TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) { } MATCHER(Is120Hz, "") { - return isApproxEqual(arg.getFps(), 120_Hz); + return isApproxEqual(arg->getFps(), 120_Hz); } TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { mScheduler->setRefreshRateConfigs( - std::make_shared(DisplayModes{mode60, mode120}, mode60->getId())); + std::make_shared(makeModes(kMode60, kMode120), kMode60->getId())); const sp layer = sp::make(mFlinger.flinger()); EXPECT_CALL(*layer, isVisible()).WillOnce(Return(true)); @@ -239,11 +232,11 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { constexpr uint32_t kDisplayArea = 999'999; mScheduler->onActiveDisplayAreaChanged(kDisplayArea); - EXPECT_CALL(mSchedulerCallback, changeRefreshRate(Is120Hz(), _)).Times(1); + EXPECT_CALL(mSchedulerCallback, requestDisplayMode(Is120Hz(), _)).Times(1); mScheduler->chooseRefreshRateForContent(); // No-op if layer requirements have not changed. - EXPECT_CALL(mSchedulerCallback, changeRefreshRate(_, _)).Times(0); + EXPECT_CALL(mSchedulerCallback, requestDisplayMode(_, _)).Times(0); mScheduler->chooseRefreshRateForContent(); } diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp index 3205952f5a..32d57b5b34 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -43,13 +43,11 @@ public: mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED); { - DisplayModes modes = {kDisplayMode60, kDisplayMode90, kDisplayMode120, - kDisplayMode90DifferentResolution}; - const DisplayModeId activeModeId = kDisplayModeId60; - auto configs = std::make_shared(modes, activeModeId); + DisplayModes modes = makeModes(kMode60, kMode90, kMode120, kMode90_4K); + auto configs = std::make_shared(modes, kModeId60); mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this) - .setDisplayModes(modes, activeModeId, std::move(configs)) + .setDisplayModes(std::move(modes), kModeId60, std::move(configs)) .inject(); } @@ -68,49 +66,18 @@ protected: sp mDisplay; mock::EventThread* mAppEventThread; - const DisplayModeId kDisplayModeId60 = DisplayModeId(0); - const DisplayModePtr kDisplayMode60 = - DisplayMode::Builder(hal::HWConfigId(kDisplayModeId60.value())) - .setId(kDisplayModeId60) - .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) - .setVsyncPeriod((60_Hz).getPeriodNsecs()) - .setGroup(0) - .setHeight(1000) - .setWidth(1000) - .build(); - - const DisplayModeId kDisplayModeId90 = DisplayModeId(1); - const DisplayModePtr kDisplayMode90 = - DisplayMode::Builder(hal::HWConfigId(kDisplayModeId90.value())) - .setId(kDisplayModeId90) - .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) - .setVsyncPeriod((90_Hz).getPeriodNsecs()) - .setGroup(1) - .setHeight(1000) - .setWidth(1000) - .build(); - - const DisplayModeId kDisplayModeId120 = DisplayModeId(2); - const DisplayModePtr kDisplayMode120 = - DisplayMode::Builder(hal::HWConfigId(kDisplayModeId120.value())) - .setId(kDisplayModeId120) - .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) - .setVsyncPeriod((120_Hz).getPeriodNsecs()) - .setGroup(2) - .setHeight(1000) - .setWidth(1000) - .build(); - - const DisplayModeId kDisplayModeId90DifferentResolution = DisplayModeId(3); - const DisplayModePtr kDisplayMode90DifferentResolution = - DisplayMode::Builder(hal::HWConfigId(kDisplayModeId90DifferentResolution.value())) - .setId(kDisplayModeId90DifferentResolution) - .setPhysicalDisplayId(PrimaryDisplayVariant::DISPLAY_ID::get()) - .setVsyncPeriod((90_Hz).getPeriodNsecs()) - .setGroup(3) - .setHeight(2000) - .setWidth(2000) - .build(); + static constexpr DisplayModeId kModeId60{0}; + static constexpr DisplayModeId kModeId90{1}; + static constexpr DisplayModeId kModeId120{2}; + static constexpr DisplayModeId kModeId90_4K{3}; + + static inline const DisplayModePtr kMode60 = createDisplayMode(kModeId60, 60_Hz, 0); + static inline const DisplayModePtr kMode90 = createDisplayMode(kModeId90, 90_Hz, 1); + static inline const DisplayModePtr kMode120 = createDisplayMode(kModeId120, 120_Hz, 2); + + static constexpr ui::Size kResolution4K{3840, 2160}; + static inline const DisplayModePtr kMode90_4K = + createDisplayMode(kModeId90_4K, 90_Hz, 3, kResolution4K); }; void DisplayModeSwitchingTest::setupScheduler( @@ -145,39 +112,39 @@ void DisplayModeSwitchingTest::setupScheduler( TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithRefreshRequired) { ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60); mFlinger.onActiveDisplayChanged(mDisplay); - mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), - kDisplayModeId90.value(), false, 0.f, 120.f, 0.f, 120.f); + mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), kModeId90.value(), + false, 0.f, 120.f, 0.f, 120.f); ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kDisplayModeId90); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60); + ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId90); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60); // Verify that next commit will call setActiveConfigWithConstraints in HWC const VsyncPeriodChangeTimeline timeline{.refreshRequired = true}; EXPECT_CALL(*mComposer, setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID, - hal::HWConfigId(kDisplayModeId90.value()), _, _)) + hal::HWConfigId(kModeId90.value()), _, _)) .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE))); mFlinger.commit(); Mock::VerifyAndClearExpectations(mComposer); ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60); // Verify that the next commit will complete the mode change and send // a onModeChanged event to the framework. - EXPECT_CALL(*mAppEventThread, onModeChanged(kDisplayMode90)); + EXPECT_CALL(*mAppEventThread, onModeChanged(kMode90)); mFlinger.commit(); Mock::VerifyAndClearExpectations(mAppEventThread); ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId90); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId90); } TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithoutRefreshRequired) { @@ -185,27 +152,27 @@ TEST_F(DisplayModeSwitchingTest, changeRefreshRate_OnActiveDisplay_WithoutRefres mFlinger.onActiveDisplayChanged(mDisplay); - mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), - kDisplayModeId90.value(), true, 0.f, 120.f, 0.f, 120.f); + mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), kModeId90.value(), + true, 0.f, 120.f, 0.f, 120.f); ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kDisplayModeId90); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60); + ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId90); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60); // Verify that next commit will call setActiveConfigWithConstraints in HWC // and complete the mode change. const VsyncPeriodChangeTimeline timeline{.refreshRequired = false}; EXPECT_CALL(*mComposer, setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID, - hal::HWConfigId(kDisplayModeId90.value()), _, _)) + hal::HWConfigId(kModeId90.value()), _, _)) .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE))); - EXPECT_CALL(*mAppEventThread, onModeChanged(kDisplayMode90)); + EXPECT_CALL(*mAppEventThread, onModeChanged(kMode90)); mFlinger.commit(); ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId90); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId90); } TEST_F(DisplayModeSwitchingTest, twoConsecutiveSetDesiredDisplayModeSpecs) { @@ -213,72 +180,72 @@ TEST_F(DisplayModeSwitchingTest, twoConsecutiveSetDesiredDisplayModeSpecs) { // is still being processed the later call will be respected. ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60); mFlinger.onActiveDisplayChanged(mDisplay); - mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), - kDisplayModeId90.value(), false, 0.f, 120.f, 0.f, 120.f); + mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), kModeId90.value(), + false, 0.f, 120.f, 0.f, 120.f); const VsyncPeriodChangeTimeline timeline{.refreshRequired = true}; EXPECT_CALL(*mComposer, setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID, - hal::HWConfigId(kDisplayModeId90.value()), _, _)) + hal::HWConfigId(kModeId90.value()), _, _)) .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE))); mFlinger.commit(); - mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), - kDisplayModeId120.value(), false, 0.f, 180.f, 0.f, 180.f); + mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), kModeId120.value(), + false, 0.f, 180.f, 0.f, 180.f); ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kDisplayModeId120); + ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId120); EXPECT_CALL(*mComposer, setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID, - hal::HWConfigId(kDisplayModeId120.value()), _, _)) + hal::HWConfigId(kModeId120.value()), _, _)) .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE))); mFlinger.commit(); ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kDisplayModeId120); + ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId120); mFlinger.commit(); ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId120); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId120); } TEST_F(DisplayModeSwitchingTest, changeResolution_OnActiveDisplay_WithoutRefreshRequired) { ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60); mFlinger.onActiveDisplayChanged(mDisplay); - mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), - kDisplayModeId90DifferentResolution.value(), false, 0.f, - 120.f, 0.f, 120.f); + mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(), kModeId90_4K.value(), + false, 0.f, 120.f, 0.f, 120.f); ASSERT_TRUE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kDisplayModeId90DifferentResolution); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId60); + ASSERT_EQ(mDisplay->getDesiredActiveMode()->mode->getId(), kModeId90_4K); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId60); // Verify that next commit will call setActiveConfigWithConstraints in HWC // and complete the mode change. const VsyncPeriodChangeTimeline timeline{.refreshRequired = false}; EXPECT_CALL(*mComposer, setActiveConfigWithConstraints(PrimaryDisplayVariant::HWC_DISPLAY_ID, - hal::HWConfigId( - kDisplayModeId90DifferentResolution.value()), - _, _)) + hal::HWConfigId(kModeId90_4K.value()), _, _)) .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE))); EXPECT_CALL(*mAppEventThread, onHotplugReceived(mDisplay->getPhysicalId(), true)); // Misc expecations. We don't need to enforce these method calls, but since the helper methods // already set expectations we should add new ones here, otherwise the test will fail. - EXPECT_CALL(*mConsumer, setDefaultBufferSize(2000, 2000)).WillOnce(Return(NO_ERROR)); + EXPECT_CALL(*mConsumer, + setDefaultBufferSize(static_cast(kResolution4K.getWidth()), + static_cast(kResolution4K.getHeight()))) + .WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mConsumer, consumerConnect(_, false)).WillOnce(Return(NO_ERROR)); EXPECT_CALL(*mComposer, setClientTargetSlotCount(_)).WillOnce(Return(hal::Error::NONE)); @@ -296,7 +263,7 @@ TEST_F(DisplayModeSwitchingTest, changeResolution_OnActiveDisplay_WithoutRefresh mDisplay = mFlinger.getDisplay(displayToken); ASSERT_FALSE(mDisplay->getDesiredActiveMode().has_value()); - ASSERT_EQ(mDisplay->getActiveMode()->getId(), kDisplayModeId90DifferentResolution); + ASSERT_EQ(mDisplay->getActiveMode()->getId(), kModeId90_4K); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp index 38dceb9570..a0e078bf5e 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp @@ -240,19 +240,17 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { ASSERT_TRUE(hwcDisplayId); mFlinger.getHwComposer().allocatePhysicalDisplay(*hwcDisplayId, *displayId); DisplayModePtr activeMode = DisplayMode::Builder(Case::Display::HWC_ACTIVE_CONFIG_ID) - .setWidth(Case::Display::WIDTH) - .setHeight(Case::Display::HEIGHT) + .setResolution(Case::Display::RESOLUTION) .setVsyncPeriod(DEFAULT_VSYNC_PERIOD) .setDpiX(DEFAULT_DPI) .setDpiY(DEFAULT_DPI) .setGroup(0) .build(); - DisplayModes modes{activeMode}; state.physical = {.id = *displayId, .type = *connectionType, .hwcDisplayId = *hwcDisplayId, - .supportedModes = modes, - .activeMode = activeMode}; + .supportedModes = makeModes(activeMode), + .activeMode = std::move(activeMode)}; } state.isSecure = static_cast(Case::Display::SECURE); @@ -270,8 +268,7 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { EXPECT_EQ(static_cast(Case::Display::VIRTUAL), device->isVirtual()); EXPECT_EQ(static_cast(Case::Display::SECURE), device->isSecure()); EXPECT_EQ(static_cast(Case::Display::PRIMARY), device->isPrimary()); - EXPECT_EQ(Case::Display::WIDTH, device->getWidth()); - EXPECT_EQ(Case::Display::HEIGHT, device->getHeight()); + EXPECT_EQ(Case::Display::RESOLUTION, device->getSize()); EXPECT_EQ(Case::WideColorSupport::WIDE_COLOR_SUPPORTED, device->hasWideColorGamut()); EXPECT_EQ(Case::HdrSupport::HDR10_PLUS_SUPPORTED, device->hasHDR10PlusSupport()); EXPECT_EQ(Case::HdrSupport::HDR10_SUPPORTED, device->hasHDR10Support()); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index fe0564e0d3..aff4d83398 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -45,6 +45,7 @@ #include "SurfaceInterceptor.h" #include "TestableScheduler.h" #include "mock/DisplayHardware/MockComposer.h" +#include "mock/DisplayHardware/MockDisplayMode.h" #include "mock/MockFrameTimeline.h" #include "mock/MockFrameTracer.h" #include "mock/MockSchedulerCallback.h" @@ -227,31 +228,24 @@ public: if (std::holds_alternative(modesVariant)) { configs = std::move(std::get(modesVariant)); } else { - DisplayModes modes = {DisplayMode::Builder(0) - .setId(DisplayModeId(0)) - .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) - .setVsyncPeriod(16'666'667) - .setGroup(0) - .build()}; + constexpr DisplayModeId kModeId60{0}; + DisplayModes modes = makeModes(mock::createDisplayMode(kModeId60, 60_Hz)); if (std::holds_alternative(modesVariant)) { - modes.emplace_back(DisplayMode::Builder(1) - .setId(DisplayModeId(1)) - .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) - .setVsyncPeriod(11'111'111) - .setGroup(0) - .build()); + constexpr DisplayModeId kModeId90{1}; + modes.try_emplace(kModeId90, mock::createDisplayMode(kModeId90, 90_Hz)); } - configs = std::make_shared(modes, DisplayModeId(0)); + configs = std::make_shared(modes, kModeId60); } - const auto currFps = configs->getCurrentRefreshRate().getFps(); - mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(currFps); + const auto fps = configs->getActiveMode()->getFps(); + mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps); mFlinger->mVsyncModulator = sp::make( mFlinger->mVsyncConfiguration->getCurrentConfigs()); + mFlinger->mRefreshRateStats = - std::make_unique(*mFlinger->mTimeStats, currFps, + std::make_unique(*mFlinger->mTimeStats, fps, hal::PowerMode::OFF); using Callback = scheduler::ISchedulerCallback; @@ -572,8 +566,7 @@ public: class FakeHwcDisplayInjector { public: static constexpr hal::HWDisplayId DEFAULT_HWC_DISPLAY_ID = 1000; - static constexpr int32_t DEFAULT_WIDTH = 1920; - static constexpr int32_t DEFAULT_HEIGHT = 1280; + static constexpr ui::Size DEFAULT_RESOLUTION{1920, 1280}; static constexpr int32_t DEFAULT_VSYNC_PERIOD = 16'666'667; static constexpr int32_t DEFAULT_CONFIG_GROUP = 7; static constexpr int32_t DEFAULT_DPI = 320; @@ -589,17 +582,12 @@ public: return *this; } - auto& setWidth(int32_t width) { - mWidth = width; - return *this; - } - - auto& setHeight(int32_t height) { - mHeight = height; + auto& setResolution(ui::Size resolution) { + mResolution = resolution; return *this; } - auto& setVsyncPeriod(int32_t vsyncPeriod) { + auto& setVsyncPeriod(nsecs_t vsyncPeriod) { mVsyncPeriod = vsyncPeriod; return *this; } @@ -660,18 +648,20 @@ public: EXPECT_CALL(*composer, getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::WIDTH, _)) - .WillRepeatedly(DoAll(SetArgPointee<3>(mWidth), Return(hal::Error::NONE))); + .WillRepeatedly(DoAll(SetArgPointee<3>(mResolution.getWidth()), + Return(hal::Error::NONE))); EXPECT_CALL(*composer, getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::HEIGHT, _)) - .WillRepeatedly(DoAll(SetArgPointee<3>(mHeight), Return(hal::Error::NONE))); + .WillRepeatedly(DoAll(SetArgPointee<3>(mResolution.getHeight()), + Return(hal::Error::NONE))); EXPECT_CALL(*composer, getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::VSYNC_PERIOD, _)) - .WillRepeatedly( - DoAll(SetArgPointee<3>(mVsyncPeriod), Return(hal::Error::NONE))); + .WillRepeatedly(DoAll(SetArgPointee<3>(static_cast(mVsyncPeriod)), + Return(hal::Error::NONE))); EXPECT_CALL(*composer, getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::DPI_X, _)) @@ -708,9 +698,8 @@ public: const bool mIsPrimary; hal::HWDisplayId mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID; - int32_t mWidth = DEFAULT_WIDTH; - int32_t mHeight = DEFAULT_HEIGHT; - int32_t mVsyncPeriod = DEFAULT_VSYNC_PERIOD; + ui::Size mResolution = DEFAULT_RESOLUTION; + nsecs_t mVsyncPeriod = DEFAULT_VSYNC_PERIOD; int32_t mDpiX = DEFAULT_DPI; int32_t mDpiY = DEFAULT_DPI; int32_t mConfigGroup = DEFAULT_CONFIG_GROUP; @@ -723,12 +712,12 @@ public: class FakeDisplayDeviceInjector { public: FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger, - std::shared_ptr compositionDisplay, + std::shared_ptr display, std::optional connectionType, std::optional hwcDisplayId, bool isPrimary) : mFlinger(flinger), mCreationArgs(flinger.mFlinger.get(), flinger.mFlinger->getHwComposer(), - mDisplayToken, compositionDisplay), + mDisplayToken, display), mHwcDisplayId(hwcDisplayId) { mCreationArgs.connectionType = connectionType; mCreationArgs.isPrimary = isPrimary; @@ -805,49 +794,52 @@ public: } sp inject() NO_THREAD_SAFETY_ANALYSIS { + const auto displayId = mCreationArgs.compositionDisplay->getDisplayId(); + auto& modes = mCreationArgs.supportedModes; auto& activeModeId = mCreationArgs.activeModeId; - if (!mCreationArgs.refreshRateConfigs) { - if (modes.empty()) { - activeModeId = DisplayModeId(0); - modes.emplace_back( - DisplayMode::Builder(FakeHwcDisplayInjector::DEFAULT_ACTIVE_CONFIG) - .setId(activeModeId) - .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0)) - .setWidth(FakeHwcDisplayInjector::DEFAULT_WIDTH) - .setHeight(FakeHwcDisplayInjector::DEFAULT_HEIGHT) - .setVsyncPeriod(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD) - .setDpiX(FakeHwcDisplayInjector::DEFAULT_DPI) - .setDpiY(FakeHwcDisplayInjector::DEFAULT_DPI) - .setGroup(0) - .build()); + if (displayId && !mCreationArgs.refreshRateConfigs) { + if (const auto physicalId = PhysicalDisplayId::tryCast(*displayId)) { + if (modes.empty()) { + constexpr DisplayModeId kModeId{0}; + DisplayModePtr mode = + DisplayMode::Builder(FakeHwcDisplayInjector::DEFAULT_ACTIVE_CONFIG) + .setId(kModeId) + .setPhysicalDisplayId(*physicalId) + .setResolution(FakeHwcDisplayInjector::DEFAULT_RESOLUTION) + .setVsyncPeriod( + FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD) + .setDpiX(FakeHwcDisplayInjector::DEFAULT_DPI) + .setDpiY(FakeHwcDisplayInjector::DEFAULT_DPI) + .setGroup(FakeHwcDisplayInjector::DEFAULT_CONFIG_GROUP) + .build(); + + modes = ftl::init::map(kModeId, std::move(mode)); + activeModeId = kModeId; + } + + mCreationArgs.refreshRateConfigs = + std::make_shared(modes, activeModeId); } - - mCreationArgs.refreshRateConfigs = - std::make_shared(modes, activeModeId); } DisplayDeviceState state; if (const auto type = mCreationArgs.connectionType) { - const auto displayId = mCreationArgs.compositionDisplay->getDisplayId(); LOG_ALWAYS_FATAL_IF(!displayId); const auto physicalId = PhysicalDisplayId::tryCast(*displayId); LOG_ALWAYS_FATAL_IF(!physicalId); LOG_ALWAYS_FATAL_IF(!mHwcDisplayId); - const auto it = std::find_if(modes.begin(), modes.end(), - [&activeModeId](const DisplayModePtr& mode) { - return mode->getId() == activeModeId; - }); - LOG_ALWAYS_FATAL_IF(it == modes.end()); + const auto activeMode = modes.get(activeModeId); + LOG_ALWAYS_FATAL_IF(!activeMode); state.physical = {.id = *physicalId, .type = *type, .hwcDisplayId = *mHwcDisplayId, .deviceProductInfo = {}, .supportedModes = modes, - .activeMode = *it}; + .activeMode = activeMode->get()}; } state.isSecure = mCreationArgs.isSecure; diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h new file mode 100644 index 0000000000..a83ecbca26 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplayMode.h @@ -0,0 +1,36 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "DisplayHardware/DisplayMode.h" + +namespace android::mock { + +inline DisplayModePtr createDisplayMode( + DisplayModeId modeId, Fps refreshRate, int32_t group = 0, + ui::Size resolution = ui::Size(1920, 1080), + PhysicalDisplayId displayId = PhysicalDisplayId::fromPort(0)) { + return DisplayMode::Builder(hal::HWConfigId(modeId.value())) + .setId(modeId) + .setPhysicalDisplayId(displayId) + .setVsyncPeriod(refreshRate.getPeriodNsecs()) + .setGroup(group) + .setResolution(resolution) + .build(); +} + +} // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h index c90b8ed6c7..5083d561ac 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h +++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h @@ -25,7 +25,7 @@ namespace android::scheduler::mock { struct SchedulerCallback final : ISchedulerCallback { MOCK_METHOD(void, scheduleComposite, (FrameHint), (override)); MOCK_METHOD(void, setVsyncEnabled, (bool), (override)); - MOCK_METHOD(void, changeRefreshRate, (const RefreshRate&, DisplayModeEvent), (override)); + MOCK_METHOD(void, requestDisplayMode, (DisplayModePtr, DisplayModeEvent), (override)); MOCK_METHOD(void, kernelTimerChanged, (bool), (override)); MOCK_METHOD(void, triggerOnFrameRateOverridesChanged, (), (override)); }; @@ -33,7 +33,7 @@ struct SchedulerCallback final : ISchedulerCallback { struct NoOpSchedulerCallback final : ISchedulerCallback { void scheduleComposite(FrameHint) override {} void setVsyncEnabled(bool) override {} - void changeRefreshRate(const RefreshRate&, DisplayModeEvent) override {} + void requestDisplayMode(DisplayModePtr, DisplayModeEvent) override {} void kernelTimerChanged(bool) override {} void triggerOnFrameRateOverridesChanged() override {} }; -- cgit v1.2.3-59-g8ed1b From 8c4356c0ac57003787c20c3e4afda9dbf4f8a324 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Mon, 21 Mar 2022 08:19:54 -0700 Subject: SF: Clean up RefreshRateOverlay Flatten buffer cache, remove unused members, and fix conversion warnings. Skip animation transactions unless spinner is enabled. Bug: 185535769 Bug: 129481165 Test: Apply follow-up fix and toggle overlay. Change-Id: I14688f7b5d882f595322dfadd5cabbd5a8564301 --- services/surfaceflinger/DisplayDevice.cpp | 5 +- services/surfaceflinger/RefreshRateOverlay.cpp | 206 ++++++++++++++----------- services/surfaceflinger/RefreshRateOverlay.h | 67 +++----- 3 files changed, 139 insertions(+), 139 deletions(-) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index f5a4b3d6ca..9116fd335e 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -471,9 +471,8 @@ void DisplayDevice::enableRefreshRateOverlay(bool enable, bool showSpinnner) { return; } - const auto [lowFps, highFps] = mRefreshRateConfigs->getSupportedRefreshRateRange(); - mRefreshRateOverlay = std::make_unique(*mFlinger, lowFps.getIntValue(), - highFps.getIntValue(), showSpinnner); + const auto fpsRange = mRefreshRateConfigs->getSupportedRefreshRateRange(); + mRefreshRateOverlay = std::make_unique(fpsRange, showSpinnner); mRefreshRateOverlay->setLayerStack(getLayerStack()); mRefreshRateOverlay->setViewport(getSize()); mRefreshRateOverlay->changeRefreshRate(getActiveMode()->getFps()); diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 81c1566d71..80aa07231f 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -14,22 +14,20 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#pragma clang diagnostic ignored "-Wextra" - #include #include "RefreshRateOverlay.h" #include "Client.h" #include "Layer.h" -#include +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#include #include +#pragma clang diagnostic pop +#include #include #include -#include #include #include @@ -37,29 +35,40 @@ #define LOG_TAG "RefreshRateOverlay" namespace android { +namespace { + +constexpr int kDigitWidth = 64; +constexpr int kDigitHeight = 100; +constexpr int kDigitSpace = 16; -void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor& color, +// Layout is digit, space, digit, space, digit, space, spinner. +constexpr int kBufferWidth = 4 * kDigitWidth + 3 * kDigitSpace; +constexpr int kBufferHeight = kDigitHeight; + +} // namespace + +void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor color, SkCanvas& canvas) { const SkRect rect = [&]() { switch (segment) { case Segment::Upper: - return SkRect::MakeLTRB(left, 0, left + DIGIT_WIDTH, DIGIT_SPACE); + return SkRect::MakeLTRB(left, 0, left + kDigitWidth, kDigitSpace); case Segment::UpperLeft: - return SkRect::MakeLTRB(left, 0, left + DIGIT_SPACE, DIGIT_HEIGHT / 2); + return SkRect::MakeLTRB(left, 0, left + kDigitSpace, kDigitHeight / 2); case Segment::UpperRight: - return SkRect::MakeLTRB(left + DIGIT_WIDTH - DIGIT_SPACE, 0, left + DIGIT_WIDTH, - DIGIT_HEIGHT / 2); + return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, 0, left + kDigitWidth, + kDigitHeight / 2); case Segment::Middle: - return SkRect::MakeLTRB(left, DIGIT_HEIGHT / 2 - DIGIT_SPACE / 2, - left + DIGIT_WIDTH, DIGIT_HEIGHT / 2 + DIGIT_SPACE / 2); + return SkRect::MakeLTRB(left, kDigitHeight / 2 - kDigitSpace / 2, + left + kDigitWidth, kDigitHeight / 2 + kDigitSpace / 2); case Segment::LowerLeft: - return SkRect::MakeLTRB(left, DIGIT_HEIGHT / 2, left + DIGIT_SPACE, DIGIT_HEIGHT); + return SkRect::MakeLTRB(left, kDigitHeight / 2, left + kDigitSpace, kDigitHeight); case Segment::LowerRight: - return SkRect::MakeLTRB(left + DIGIT_WIDTH - DIGIT_SPACE, DIGIT_HEIGHT / 2, - left + DIGIT_WIDTH, DIGIT_HEIGHT); + return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, kDigitHeight / 2, + left + kDigitWidth, kDigitHeight); case Segment::Bottom: - return SkRect::MakeLTRB(left, DIGIT_HEIGHT - DIGIT_SPACE, left + DIGIT_WIDTH, - DIGIT_HEIGHT); + return SkRect::MakeLTRB(left, kDigitHeight - kDigitSpace, left + kDigitWidth, + kDigitHeight); } }(); @@ -69,7 +78,7 @@ void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int le canvas.drawRect(rect, paint); } -void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, SkColor& color, +void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, SkColor color, SkCanvas& canvas) { if (digit < 0 || digit > 9) return; @@ -94,37 +103,45 @@ void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, SkCo drawSegment(Segment::Bottom, left, color, canvas); } -std::vector> RefreshRateOverlay::SevenSegmentDrawer::draw( - int number, SkColor& color, ui::Transform::RotationFlags rotation, bool showSpinner) { +auto RefreshRateOverlay::SevenSegmentDrawer::draw(int number, SkColor color, + ui::Transform::RotationFlags rotation, + bool showSpinner) -> Buffers { if (number < 0 || number > 1000) return {}; const auto hundreds = number / 100; const auto tens = (number / 10) % 10; const auto ones = number % 10; - std::vector> buffers; - const auto loopCount = showSpinner ? 6 : 1; - for (int i = 0; i < loopCount; i++) { + const size_t loopCount = showSpinner ? 6 : 1; + + Buffers buffers; + buffers.reserve(loopCount); + + for (size_t i = 0; i < loopCount; i++) { // Pre-rotate the buffer before it reaches SurfaceFlinger. SkMatrix canvasTransform = SkMatrix(); - auto [bufferWidth, bufferHeight] = [&] { + const auto [bufferWidth, bufferHeight] = [&]() -> std::pair { switch (rotation) { case ui::Transform::ROT_90: - canvasTransform.setTranslate(BUFFER_HEIGHT, 0); - canvasTransform.preRotate(90); - return std::make_tuple(BUFFER_HEIGHT, BUFFER_WIDTH); + canvasTransform.setTranslate(kBufferHeight, 0); + canvasTransform.preRotate(90.f); + return {kBufferHeight, kBufferWidth}; case ui::Transform::ROT_270: - canvasTransform.setRotate(270, BUFFER_WIDTH / 2.0, BUFFER_WIDTH / 2.0); - return std::make_tuple(BUFFER_HEIGHT, BUFFER_WIDTH); + canvasTransform.setRotate(270.f, kBufferWidth / 2.f, kBufferWidth / 2.f); + return {kBufferHeight, kBufferWidth}; default: - return std::make_tuple(BUFFER_WIDTH, BUFFER_HEIGHT); + return {kBufferWidth, kBufferHeight}; } }(); + sp buffer = - new GraphicBuffer(bufferWidth, bufferHeight, HAL_PIXEL_FORMAT_RGBA_8888, 1, + new GraphicBuffer(static_cast(bufferWidth), + static_cast(bufferHeight), HAL_PIXEL_FORMAT_RGBA_8888, + 1, GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_TEXTURE, "RefreshRateOverlayBuffer"); + const status_t bufferStatus = buffer->initCheck(); LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d", bufferStatus); @@ -137,15 +154,15 @@ std::vector> RefreshRateOverlay::SevenSegmentDrawer::draw( if (hundreds != 0) { drawDigit(hundreds, left, color, *canvas); } - left += DIGIT_WIDTH + DIGIT_SPACE; + left += kDigitWidth + kDigitSpace; if (tens != 0) { drawDigit(tens, left, color, *canvas); } - left += DIGIT_WIDTH + DIGIT_SPACE; + left += kDigitWidth + kDigitSpace; drawDigit(ones, left, color, *canvas); - left += DIGIT_WIDTH + DIGIT_SPACE; + left += kDigitWidth + kDigitSpace; if (showSpinner) { switch (i) { @@ -172,51 +189,48 @@ std::vector> RefreshRateOverlay::SevenSegmentDrawer::draw( void* pixels = nullptr; buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast(&pixels)); + const SkImageInfo& imageInfo = surface->imageInfo(); - size_t dstRowBytes = buffer->getStride() * imageInfo.bytesPerPixel(); + const size_t dstRowBytes = + buffer->getStride() * static_cast(imageInfo.bytesPerPixel()); + canvas->readPixels(imageInfo, pixels, dstRowBytes, 0, 0); buffer->unlock(); - buffers.emplace_back(buffer); + buffers.push_back(std::move(buffer)); } return buffers; } -RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger, uint32_t lowFps, uint32_t highFps, - bool showSpinner) - : mFlinger(flinger), - mClient(new Client(&mFlinger)), +RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, bool showSpinner) + : mFpsRange(fpsRange), mShowSpinner(showSpinner), - mLowFps(lowFps), - mHighFps(highFps) { - createLayer(); -} - -bool RefreshRateOverlay::createLayer() { - mSurfaceControl = - SurfaceComposerClient::getDefault() - ->createSurface(String8("RefreshRateOverlay"), SevenSegmentDrawer::getWidth(), - SevenSegmentDrawer::getHeight(), PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceBufferState); - + mSurfaceControl(SurfaceComposerClient::getDefault() + ->createSurface(String8("RefreshRateOverlay"), kBufferWidth, + kBufferHeight, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState)) { if (!mSurfaceControl) { - ALOGE("failed to create buffer state layer"); - return false; + ALOGE("%s: Failed to create buffer state layer", __func__); + return; } + constexpr float kFrameRate = 0.f; + constexpr int8_t kCompatibility = static_cast(Layer::FrameRateCompatibility::NoVote); + constexpr int8_t kSeamlessness = ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS; + SurfaceComposerClient::Transaction() - .setFrameRate(mSurfaceControl, 0.0f, - static_cast(Layer::FrameRateCompatibility::NoVote), - static_cast(scheduler::Seamlessness::OnlySeamless)) + .setFrameRate(mSurfaceControl, kFrameRate, kCompatibility, kSeamlessness) .setLayer(mSurfaceControl, INT32_MAX - 2) .setTrustedOverlay(mSurfaceControl, true) .apply(); - - return true; } -const std::vector>& RefreshRateOverlay::getOrCreateBuffers(uint32_t fps) { - ui::Transform::RotationFlags transformHint = +auto RefreshRateOverlay::getOrCreateBuffers(Fps fps) -> const Buffers& { + static const Buffers kNoBuffers; + if (!mSurfaceControl) return kNoBuffers; + + const auto transformHint = static_cast(mSurfaceControl->getTransformHint()); + // Tell SurfaceFlinger about the pre-rotation on the buffer. const auto transform = [&] { switch (transformHint) { @@ -233,40 +247,49 @@ const std::vector>& RefreshRateOverlay::getOrCreateBuffers(uin t.setTransform(mSurfaceControl, transform); t.apply(); - if (mBufferCache.find(transformHint) == mBufferCache.end() || - mBufferCache.at(transformHint).find(fps) == mBufferCache.at(transformHint).end()) { - // Ensure the range is > 0, so we don't divide by 0. - const auto rangeLength = std::max(1u, mHighFps - mLowFps); - // Clip values outside the range [mLowFps, mHighFps]. The current fps may be outside - // of this range if the display has changed its set of supported refresh rates. - fps = std::max(fps, mLowFps); - fps = std::min(fps, mHighFps); - const auto fpsScale = static_cast(fps - mLowFps) / rangeLength; - SkColor4f colorBase = SkColor4f::FromColor(HIGH_FPS_COLOR) * fpsScale; - SkColor4f lowFpsColor = SkColor4f::FromColor(LOW_FPS_COLOR) * (1 - fpsScale); - colorBase.fR = colorBase.fR + lowFpsColor.fR; - colorBase.fG = colorBase.fG + lowFpsColor.fG; - colorBase.fB = colorBase.fB + lowFpsColor.fB; - colorBase.fA = ALPHA; - SkColor color = colorBase.toSkColor(); - auto buffers = SevenSegmentDrawer::draw(fps, color, transformHint, mShowSpinner); - mBufferCache[transformHint].emplace(fps, buffers); + BufferCache::const_iterator it = mBufferCache.find({fps.getIntValue(), transformHint}); + if (it == mBufferCache.end()) { + const int minFps = mFpsRange.min.getIntValue(); + const int maxFps = mFpsRange.max.getIntValue(); + + // Clamp to the range. The current fps may be outside of this range if the display has + // changed its set of supported refresh rates. + const int intFps = std::clamp(fps.getIntValue(), minFps, maxFps); + + // Ensure non-zero range to avoid division by zero. + const float fpsScale = static_cast(intFps - minFps) / std::max(1, maxFps - minFps); + + constexpr SkColor kMinFpsColor = SK_ColorRED; + constexpr SkColor kMaxFpsColor = SK_ColorGREEN; + constexpr float kAlpha = 0.8f; + + SkColor4f colorBase = SkColor4f::FromColor(kMaxFpsColor) * fpsScale; + const SkColor4f minFpsColor = SkColor4f::FromColor(kMinFpsColor) * (1 - fpsScale); + + colorBase.fR = colorBase.fR + minFpsColor.fR; + colorBase.fG = colorBase.fG + minFpsColor.fG; + colorBase.fB = colorBase.fB + minFpsColor.fB; + colorBase.fA = kAlpha; + + const SkColor color = colorBase.toSkColor(); + + auto buffers = SevenSegmentDrawer::draw(intFps, color, transformHint, mShowSpinner); + it = mBufferCache.try_emplace({intFps, transformHint}, std::move(buffers)).first; } - return mBufferCache[transformHint][fps]; + return it->second; } void RefreshRateOverlay::setViewport(ui::Size viewport) { constexpr int32_t kMaxWidth = 1000; - const auto width = std::min(kMaxWidth, std::min(viewport.width, viewport.height)); + const auto width = std::min({kMaxWidth, viewport.width, viewport.height}); const auto height = 2 * width; Rect frame((3 * width) >> 4, height >> 5); frame.offsetBy(width >> 5, height >> 4); SurfaceComposerClient::Transaction t; - t.setMatrix(mSurfaceControl, - frame.getWidth() / static_cast(SevenSegmentDrawer::getWidth()), 0, 0, - frame.getHeight() / static_cast(SevenSegmentDrawer::getHeight())); + t.setMatrix(mSurfaceControl, frame.getWidth() / static_cast(kBufferWidth), 0, 0, + frame.getHeight() / static_cast(kBufferHeight)); t.setPosition(mSurfaceControl, frame.left, frame.top); t.apply(); } @@ -278,25 +301,22 @@ void RefreshRateOverlay::setLayerStack(ui::LayerStack stack) { } void RefreshRateOverlay::changeRefreshRate(Fps fps) { - mCurrentFps = fps.getIntValue(); - auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame]; + mCurrentFps = fps; + const auto buffer = getOrCreateBuffers(fps)[mFrame]; SurfaceComposerClient::Transaction t; t.setBuffer(mSurfaceControl, buffer); t.apply(); } void RefreshRateOverlay::animate() { - if (!mCurrentFps.has_value()) return; + if (!mShowSpinner || !mCurrentFps) return; const auto& buffers = getOrCreateBuffers(*mCurrentFps); mFrame = (mFrame + 1) % buffers.size(); - auto buffer = buffers[mFrame]; + const auto buffer = buffers[mFrame]; SurfaceComposerClient::Transaction t; t.setBuffer(mSurfaceControl, buffer); t.apply(); } } // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index 381df37903..a465a36747 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -16,32 +16,27 @@ #pragma once -#include #include -#include +#include -#include -#include +#include #include -#include #include +#include #include #include +class SkCanvas; + namespace android { -class Client; class GraphicBuffer; -class IBinder; -class IGraphicBufferProducer; -class Layer; -class SurfaceFlinger; class SurfaceControl; class RefreshRateOverlay { public: - RefreshRateOverlay(SurfaceFlinger&, uint32_t lowFps, uint32_t highFps, bool showSpinner); + RefreshRateOverlay(FpsRange, bool showSpinner); void setLayerStack(ui::LayerStack); void setViewport(ui::Size); @@ -49,52 +44,38 @@ public: void animate(); private: + using Buffers = std::vector>; + class SevenSegmentDrawer { public: - static std::vector> draw(int number, SkColor& color, - ui::Transform::RotationFlags, bool showSpinner); - static uint32_t getHeight() { return BUFFER_HEIGHT; } - static uint32_t getWidth() { return BUFFER_WIDTH; } + static Buffers draw(int number, SkColor, ui::Transform::RotationFlags, bool showSpinner); private: enum class Segment { Upper, UpperLeft, UpperRight, Middle, LowerLeft, LowerRight, Bottom }; - static void drawSegment(Segment segment, int left, SkColor& color, SkCanvas& canvas); - static void drawDigit(int digit, int left, SkColor& color, SkCanvas& canvas); - - static constexpr uint32_t DIGIT_HEIGHT = 100; - static constexpr uint32_t DIGIT_WIDTH = 64; - static constexpr uint32_t DIGIT_SPACE = 16; - static constexpr uint32_t BUFFER_HEIGHT = DIGIT_HEIGHT; - static constexpr uint32_t BUFFER_WIDTH = - 4 * DIGIT_WIDTH + 3 * DIGIT_SPACE; // Digit|Space|Digit|Space|Digit|Space|Spinner + static void drawSegment(Segment, int left, SkColor, SkCanvas&); + static void drawDigit(int digit, int left, SkColor, SkCanvas&); }; - bool createLayer(); + const Buffers& getOrCreateBuffers(Fps); - const std::vector>& getOrCreateBuffers(uint32_t fps); + struct Key { + int fps; + ui::Transform::RotationFlags flags; - SurfaceFlinger& mFlinger; - const sp mClient; - sp mIBinder; - sp mGbp; + bool operator==(Key other) const { return fps == other.fps && flags == other.flags; } + }; - std::unordered_map>>> - mBufferCache; - std::optional mCurrentFps; - int mFrame = 0; - static constexpr float ALPHA = 0.8f; - const SkColor LOW_FPS_COLOR = SK_ColorRED; - const SkColor HIGH_FPS_COLOR = SK_ColorGREEN; + using BufferCache = ftl::SmallMap; + BufferCache mBufferCache; - const bool mShowSpinner; + std::optional mCurrentFps; + size_t mFrame = 0; - // Interpolate the colors between these values. - const uint32_t mLowFps; - const uint32_t mHighFps; + const FpsRange mFpsRange; // For color interpolation. + const bool mShowSpinner; - sp mSurfaceControl; + const sp mSurfaceControl; }; } // namespace android -- cgit v1.2.3-59-g8ed1b From a314038bf9b507517e75aeb346841e391927bc4e Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 24 Feb 2022 14:07:11 -0800 Subject: SF: Predict HWC composition strategy Asynchronously run ValidateDisplay to determine client composition strategy. If we can predict that the composition strategy will not change from frame to frame (for example by looking at whether the geometry of the layers is changing), the hwc call is run asynchronously with the gpu composition. If the result of the call is incorrectly predicted, the gpu composition is rerun. ValidateDisplay can take multiple milliseconds to complete and by making it non-blocking in cases where we can predict the strategy chosen by the hardware, we can jump start the client composition and shave valuable milliseconds from the frame time. This feature is disabled by default. Test: perfetto traces Bug: 220031739 Change-Id: Ia5f04f447455bba0bbebbe7642d8ade8313f381a --- .../surfaceflinger/CompositionEngine/Android.bp | 5 + .../include/compositionengine/DisplaySurface.h | 3 + .../include/compositionengine/Output.h | 21 +- .../include/compositionengine/RenderSurface.h | 3 + .../include/compositionengine/impl/Display.h | 11 +- .../compositionengine/impl/GpuCompositionResult.h | 38 +++ .../compositionengine/impl/HwcAsyncWorker.h | 55 ++++ .../include/compositionengine/impl/Output.h | 31 +- .../impl/OutputCompositionState.h | 6 + .../include/compositionengine/impl/RenderSurface.h | 1 + .../include/compositionengine/mock/Display.h | 1 + .../include/compositionengine/mock/Output.h | 19 +- .../include/compositionengine/mock/RenderSurface.h | 1 + .../CompositionEngine/src/Display.cpp | 57 ++-- .../CompositionEngine/src/DisplaySurface.cpp | 4 + .../CompositionEngine/src/HwcAsyncWorker.cpp | 71 +++++ .../CompositionEngine/src/Output.cpp | 216 ++++++++++++-- .../CompositionEngine/src/RenderSurface.cpp | 4 + .../CompositionEngine/tests/DisplayTest.cpp | 96 +++--- .../CompositionEngine/tests/OutputTest.cpp | 327 +++++++++++++++++++-- services/surfaceflinger/DisplayDevice.cpp | 1 + .../surfaceflinger/DisplayHardware/HWComposer.h | 7 + .../DisplayHardware/VirtualDisplaySurface.h | 3 + services/surfaceflinger/SurfaceFlinger.cpp | 3 + services/surfaceflinger/SurfaceFlinger.h | 5 + 25 files changed, 853 insertions(+), 136 deletions(-) create mode 100644 services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h create mode 100644 services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h create mode 100644 services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 516c3ef35b..11a9e19db8 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -42,6 +42,10 @@ cc_defaults { "libtonemap", "libtrace_proto", "libaidlcommonsupport", + "libprocessgroup", + "libcgrouprc", + "libjsoncpp", + "libcgrouprc_format", ], header_libs: [ "android.hardware.graphics.composer@2.1-command-buffer", @@ -69,6 +73,7 @@ cc_library { "src/DisplayColorProfile.cpp", "src/DisplaySurface.cpp", "src/DumpHelpers.cpp", + "src/HwcAsyncWorker.cpp", "src/HwcBufferCache.cpp", "src/LayerFECompositionState.cpp", "src/Output.cpp", diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h index c553fce85d..ca86f4c604 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h @@ -72,6 +72,9 @@ public: virtual void resizeBuffers(const ui::Size&) = 0; virtual const sp& getClientTargetAcquireFence() const = 0; + + // Returns true if the render surface supports client composition prediction. + virtual bool supportsCompositionStrategyPrediction() const; }; } // namespace compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index d8644a428d..5846e674f5 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -35,6 +35,7 @@ #include #include +#include "DisplayHardware/HWComposer.h" namespace android { @@ -54,6 +55,7 @@ struct LayerFECompositionState; namespace impl { struct OutputCompositionState; +struct GpuCompositionResult; } // namespace impl /** @@ -262,6 +264,9 @@ public: // Latches the front-end layer state for each output layer virtual void updateLayerStateFromFE(const CompositionRefreshArgs&) const = 0; + // Enables predicting composition strategy to run client composition earlier + virtual void setPredictCompositionStrategy(bool) = 0; + protected: virtual void setDisplayColorProfile(std::unique_ptr) = 0; virtual void setRenderSurface(std::unique_ptr) = 0; @@ -278,13 +283,22 @@ protected: virtual void updateColorProfile(const CompositionRefreshArgs&) = 0; virtual void beginFrame() = 0; virtual void prepareFrame() = 0; + + using GpuCompositionResult = compositionengine::impl::GpuCompositionResult; + // Runs prepare frame in another thread while running client composition using + // the previous frame's composition strategy. + virtual GpuCompositionResult prepareFrameAsync(const CompositionRefreshArgs&) = 0; virtual void devOptRepaintFlash(const CompositionRefreshArgs&) = 0; - virtual void finishFrame(const CompositionRefreshArgs&) = 0; + virtual void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) = 0; virtual std::optional composeSurfaces( - const Region&, const compositionengine::CompositionRefreshArgs& refreshArgs) = 0; + const Region&, const compositionengine::CompositionRefreshArgs&, + std::shared_ptr, base::unique_fd&) = 0; virtual void postFramebuffer() = 0; virtual void renderCachedSets(const CompositionRefreshArgs&) = 0; - virtual void chooseCompositionStrategy() = 0; + virtual bool chooseCompositionStrategy( + std::optional*) = 0; + virtual void applyCompositionStrategy( + const std::optional& changes) = 0; virtual bool getSkipColorTransform() const = 0; virtual FrameFences presentAndGetFrameFences() = 0; virtual std::vector generateClientCompositionRequests( @@ -295,6 +309,7 @@ protected: std::vector& clientCompositionLayers) = 0; virtual void setExpensiveRenderingExpected(bool enabled) = 0; virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0; + virtual bool canPredictCompositionStrategy(const CompositionRefreshArgs&) = 0; }; } // namespace compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h index daee83bd2c..9ee779cca1 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h @@ -100,6 +100,9 @@ public: // Debugging - gets the page flip count for the RenderSurface virtual std::uint32_t getPageFlipCount() const = 0; + + // Returns true if the render surface supports client composition prediction. + virtual bool supportsCompositionStrategyPrediction() const = 0; }; } // namespace compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index 8bb8e9244d..61a0e6a356 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -51,11 +52,16 @@ public: void setReleasedLayers(const CompositionRefreshArgs&) override; void setColorTransform(const CompositionRefreshArgs&) override; void setColorProfile(const ColorProfile&) override; - void chooseCompositionStrategy() override; + + void beginFrame() override; + using DeviceRequestedChanges = android::HWComposer::DeviceRequestedChanges; + bool chooseCompositionStrategy( + std::optional*) override; + void applyCompositionStrategy(const std::optional&) override; bool getSkipColorTransform() const override; compositionengine::Output::FrameFences presentAndGetFrameFences() override; void setExpensiveRenderingExpected(bool) override; - void finishFrame(const CompositionRefreshArgs&) override; + void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) override; // compositionengine::Display overrides DisplayId getId() const override; @@ -72,7 +78,6 @@ public: using DisplayRequests = android::HWComposer::DeviceRequestedChanges::DisplayRequests; using LayerRequests = android::HWComposer::DeviceRequestedChanges::LayerRequests; using ClientTargetProperty = android::HWComposer::DeviceRequestedChanges::ClientTargetProperty; - virtual bool anyLayersRequireClientComposition() const; virtual bool allLayersRequireClientComposition() const; virtual void applyChangedTypesToLayers(const ChangedTypes&); virtual void applyDisplayRequests(const DisplayRequests&); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h new file mode 100644 index 0000000000..ed1ddc172c --- /dev/null +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h @@ -0,0 +1,38 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace android::compositionengine::impl { + +struct GpuCompositionResult { + // True if composition strategy was predicted successfully. + bool succeeded = false; + + // Composition ready fence. + base::unique_fd fence{}; + + // Buffer to be used for gpu composition. If gpu composition was not successful, + // then we want to reuse the buffer instead of dequeuing another buffer. + std::shared_ptr buffer = nullptr; + + bool bufferAvailable() const { return buffer != nullptr; }; +}; + +} // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h new file mode 100644 index 0000000000..0c7da6ced7 --- /dev/null +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcAsyncWorker.h @@ -0,0 +1,55 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include "DisplayHardware/HWComposer.h" + +namespace android::compositionengine::impl { + +// HWC Validate call may take multiple milliseconds to complete and can account for +// a signification amount of time in the display hotpath. This helper class allows +// us to run the hwc validate function on a real time thread if we can predict what +// the composition strategy will be and if composition includes client composition. +// While the hwc validate runs, client composition is kicked off with the prediction. +// When the worker returns with a value, the composition continues if the prediction +// was successful otherwise the client composition is re-executed. +// +// Note: This does not alter the sequence between HWC and surfaceflinger. +class HwcAsyncWorker final { +public: + HwcAsyncWorker(); + ~HwcAsyncWorker(); + // Runs the provided function which calls hwc validate and returns the requested + // device changes as a future. + std::future send(std::function); + +private: + std::mutex mMutex; + std::condition_variable mCv GUARDED_BY(mMutex); + bool mDone GUARDED_BY(mMutex) = false; + bool mTaskRequested GUARDED_BY(mMutex) = false; + std::packaged_task mTask GUARDED_BY(mMutex); + std::thread mThread; + void run(); +}; + +} // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index a7a8e97be5..0feb9f7fb7 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -17,9 +17,13 @@ #pragma once #include +#include #include #include +#include +#include #include +#include #include #include #include @@ -92,25 +96,42 @@ public: void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override; void beginFrame() override; void prepareFrame() override; + GpuCompositionResult prepareFrameAsync(const CompositionRefreshArgs&) override; void devOptRepaintFlash(const CompositionRefreshArgs&) override; - void finishFrame(const CompositionRefreshArgs&) override; - std::optional composeSurfaces( - const Region&, const compositionengine::CompositionRefreshArgs& refreshArgs) override; + void finishFrame(const CompositionRefreshArgs&, GpuCompositionResult&&) override; + std::optional composeSurfaces(const Region&, + const compositionengine::CompositionRefreshArgs&, + std::shared_ptr, + base::unique_fd&) override; void postFramebuffer() override; void renderCachedSets(const CompositionRefreshArgs&) override; void cacheClientCompositionRequests(uint32_t) override; + bool canPredictCompositionStrategy(const CompositionRefreshArgs&) override; + void setPredictCompositionStrategy(bool) override; // Testing const ReleasedLayers& getReleasedLayersForTest() const; void setDisplayColorProfileForTest(std::unique_ptr); void setRenderSurfaceForTest(std::unique_ptr); bool plannerEnabled() const { return mPlanner != nullptr; } + virtual bool anyLayersRequireClientComposition() const; + virtual void updateProtectedContentState(); + virtual bool dequeueRenderBuffer(base::unique_fd*, + std::shared_ptr*); + virtual std::future chooseCompositionStrategyAsync( + std::optional*); + virtual void resetCompositionStrategy(); protected: std::unique_ptr createOutputLayer(const sp&) const; std::optional findCurrentOutputLayerForLayer( const sp&) const; - void chooseCompositionStrategy() override; + using DeviceRequestedChanges = android::HWComposer::DeviceRequestedChanges; + bool chooseCompositionStrategy( + std::optional*) override { + return true; + }; + void applyCompositionStrategy(const std::optional&) override{}; bool getSkipColorTransform() const override; compositionengine::Output::FrameFences presentAndGetFrameFences() override; std::vector generateClientCompositionRequests( @@ -131,6 +152,7 @@ protected: private: void dirtyEntireOutput(); compositionengine::OutputLayer* findLayerRequestingBackgroundComposition() const; + void finishPrepareFrame(); ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const; compositionengine::Output::ColorProfile pickColorProfile( const compositionengine::CompositionRefreshArgs&) const; @@ -144,6 +166,7 @@ private: OutputLayer* mLayerRequestingBackgroundBlur = nullptr; std::unique_ptr mClientCompositionRequestCache; std::unique_ptr mPlanner; + std::unique_ptr mHwComposerAsyncWorker; }; // This template factory function standardizes the implementation details of the diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 2438f80eb5..20e5d71350 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -38,6 +38,8 @@ #include #include +#include "DisplayHardware/HWComposer.h" + namespace android { namespace compositionengine::impl { @@ -115,6 +117,10 @@ struct OutputCompositionState { // Current target dataspace ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN}; + std::optional previousDeviceRequestedChanges{}; + + bool previousDeviceRequestedSuccess = false; + // The earliest time to send the present command to the HAL std::chrono::steady_clock::time_point earliestPresentTime; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h index a8a538003e..e4cb113645 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h @@ -63,6 +63,7 @@ public: void queueBuffer(base::unique_fd readyFence) override; void onPresentDisplayCompleted() override; void flip() override; + bool supportsCompositionStrategyPrediction() const override; // Debugging void dump(std::string& result) const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h index d90cc909ba..72e6f3bdbb 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h @@ -41,6 +41,7 @@ public: MOCK_METHOD1(createDisplayColorProfile, void(const DisplayColorProfileCreationArgs&)); MOCK_METHOD1(createRenderSurface, void(const RenderSurfaceCreationArgs&)); MOCK_METHOD1(createClientCompositionCache, void(uint32_t)); + MOCK_METHOD1(setPredictCompositionStrategy, void(bool)); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index b68b95d07b..fa86076b44 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -99,16 +100,24 @@ public: MOCK_METHOD0(beginFrame, void()); MOCK_METHOD0(prepareFrame, void()); - MOCK_METHOD0(chooseCompositionStrategy, void()); + MOCK_METHOD1(prepareFrameAsync, GpuCompositionResult(const CompositionRefreshArgs&)); + MOCK_METHOD1(chooseCompositionStrategy, + bool(std::optional*)); + MOCK_METHOD1(chooseCompositionStrategyAsync, + std::future(std::optional*)); + MOCK_METHOD1(applyCompositionStrategy, + void(const std::optional&)); MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&)); - MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&)); + MOCK_METHOD2(finishFrame, + void(const compositionengine::CompositionRefreshArgs&, GpuCompositionResult&&)); - MOCK_METHOD2(composeSurfaces, + MOCK_METHOD4(composeSurfaces, std::optional( const Region&, - const compositionengine::CompositionRefreshArgs& refreshArgs)); + const compositionengine::CompositionRefreshArgs& refreshArgs, + std::shared_ptr, base::unique_fd&)); MOCK_CONST_METHOD0(getSkipColorTransform, bool()); MOCK_METHOD0(postFramebuffer, void()); @@ -121,6 +130,8 @@ public: void(const Region&, std::vector&)); MOCK_METHOD1(setExpensiveRenderingExpected, void(bool)); MOCK_METHOD1(cacheClientCompositionRequests, void(uint32_t)); + MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&)); + MOCK_METHOD1(setPredictCompositionStrategy, void(bool)); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h index fe858c2817..e12aebb50c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h @@ -45,6 +45,7 @@ public: MOCK_METHOD0(flip, void()); MOCK_CONST_METHOD1(dump, void(std::string& result)); MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t()); + MOCK_CONST_METHOD0(supportsCompositionStrategyPrediction, bool()); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 54daf387bc..84c22cf9bc 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -207,16 +207,8 @@ void Display::setReleasedLayers(const compositionengine::CompositionRefreshArgs& setReleasedLayers(std::move(releasedLayers)); } -void Display::chooseCompositionStrategy() { - ATRACE_CALL(); - ALOGV(__FUNCTION__); - - if (mIsDisconnected) { - return; - } - - // Default to the base settings -- client composition only. - Output::chooseCompositionStrategy(); +void Display::beginFrame() { + Output::beginFrame(); // If we don't have a HWC display, then we are done. const auto halDisplayId = HalDisplayId::tryCast(mId); @@ -224,8 +216,6 @@ void Display::chooseCompositionStrategy() { return; } - // Get any composition changes requested by the HWC device, and apply them. - std::optional changes; auto& hwc = getCompositionEngine().getHwComposer(); if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId); physicalDisplayId && getState().displayBrightness) { @@ -237,17 +227,43 @@ void Display::chooseCompositionStrategy() { ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)", getName().c_str(), result, strerror(-result)); } + // Clear out the display brightness now that it's been communicated to composer. + editState().displayBrightness.reset(); +} + +bool Display::chooseCompositionStrategy( + std::optional* outChanges) { + ATRACE_CALL(); + ALOGV(__FUNCTION__); + + if (mIsDisconnected) { + return false; + } + // If we don't have a HWC display, then we are done. + const auto halDisplayId = HalDisplayId::tryCast(mId); + if (!halDisplayId) { + return false; + } + + // Get any composition changes requested by the HWC device, and apply them. + std::optional changes; + auto& hwc = getCompositionEngine().getHwComposer(); if (status_t result = hwc.getDeviceCompositionChanges(*halDisplayId, anyLayersRequireClientComposition(), getState().earliestPresentTime, getState().previousPresentFence, - getState().expectedPresentTime, &changes); + getState().expectedPresentTime, outChanges); result != NO_ERROR) { ALOGE("chooseCompositionStrategy failed for %s: %d (%s)", getName().c_str(), result, strerror(-result)); - return; + return false; } + + return true; +} + +void Display::applyCompositionStrategy(const std::optional& changes) { if (changes) { applyChangedTypesToLayers(changes->changedTypes); applyDisplayRequests(changes->displayRequests); @@ -259,8 +275,6 @@ void Display::chooseCompositionStrategy() { auto& state = editState(); state.usesClientComposition = anyLayersRequireClientComposition(); state.usesDeviceComposition = !allLayersRequireClientComposition(); - // Clear out the display brightness now that it's been communicated to composer. - state.displayBrightness.reset(); } bool Display::getSkipColorTransform() const { @@ -273,12 +287,6 @@ bool Display::getSkipColorTransform() const { return hwc.hasCapability(Capability::SKIP_CLIENT_COLOR_TRANSFORM); } -bool Display::anyLayersRequireClientComposition() const { - const auto layers = getOutputLayersOrderedByZ(); - return std::any_of(layers.begin(), layers.end(), - [](const auto& layer) { return layer->requiresClientComposition(); }); -} - bool Display::allLayersRequireClientComposition() const { const auto layers = getOutputLayersOrderedByZ(); return std::all_of(layers.begin(), layers.end(), @@ -379,7 +387,8 @@ void Display::setExpensiveRenderingExpected(bool enabled) { } } -void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) { +void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs, + GpuCompositionResult&& result) { // We only need to actually compose the display if: // 1) It is being handled by hardware composer, which may need this to // keep its virtual display state machine in sync, or @@ -389,7 +398,7 @@ void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refre return; } - impl::Output::finishFrame(refreshArgs); + impl::Output::finishFrame(refreshArgs, std::move(result)); } } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp index db6d4f2fed..28900af162 100644 --- a/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/DisplaySurface.cpp @@ -20,4 +20,8 @@ namespace android::compositionengine { DisplaySurface::~DisplaySurface() = default; +bool DisplaySurface::supportsCompositionStrategyPrediction() const { + return true; +} + } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp b/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp new file mode 100644 index 0000000000..6086f0be3f --- /dev/null +++ b/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace android::compositionengine::impl { + +HwcAsyncWorker::HwcAsyncWorker() { + mThread = std::thread(&HwcAsyncWorker::run, this); + pthread_setname_np(mThread.native_handle(), "HwcAsyncWorker"); +} + +HwcAsyncWorker::~HwcAsyncWorker() { + { + std::scoped_lock lock(mMutex); + mDone = true; + mCv.notify_all(); + } + if (mThread.joinable()) { + mThread.join(); + } +} +std::future HwcAsyncWorker::send(std::function task) { + std::unique_lock lock(mMutex); + android::base::ScopedLockAssertion assumeLock(mMutex); + mTask = std::packaged_task([task = std::move(task)]() { return task(); }); + mTaskRequested = true; + mCv.notify_one(); + return mTask.get_future(); +} + +void HwcAsyncWorker::run() { + set_sched_policy(0, SP_FOREGROUND); + struct sched_param param = {0}; + param.sched_priority = 2; + sched_setscheduler(gettid(), SCHED_FIFO, ¶m); + + std::unique_lock lock(mMutex); + android::base::ScopedLockAssertion assumeLock(mMutex); + while (!mDone) { + mCv.wait(lock); + if (mTaskRequested && mTask.valid()) { + mTask(); + mTaskRequested = false; + } + } +} + +} // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 25155b96f0..6595ed3fe5 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -434,9 +435,17 @@ void Output::present(const compositionengine::CompositionRefreshArgs& refreshArg writeCompositionState(refreshArgs); setColorTransform(refreshArgs); beginFrame(); - prepareFrame(); + + GpuCompositionResult result; + const bool predictCompositionStrategy = canPredictCompositionStrategy(refreshArgs); + if (predictCompositionStrategy) { + result = prepareFrameAsync(refreshArgs); + } else { + prepareFrame(); + } + devOptRepaintFlash(refreshArgs); - finishFrame(refreshArgs); + finishFrame(refreshArgs, std::move(result)); postFramebuffer(); renderCachedSets(refreshArgs); } @@ -953,19 +962,72 @@ void Output::prepareFrame() { ATRACE_CALL(); ALOGV(__FUNCTION__); - const auto& outputState = getState(); + auto& outputState = editState(); if (!outputState.isEnabled) { return; } - chooseCompositionStrategy(); + std::optional changes; + bool success = chooseCompositionStrategy(&changes); + resetCompositionStrategy(); + outputState.previousDeviceRequestedChanges = changes; + outputState.previousDeviceRequestedSuccess = success; + if (success) { + applyCompositionStrategy(changes); + } + finishPrepareFrame(); +} - if (mPlanner) { - mPlanner->reportFinalPlan(getOutputLayersOrderedByZ()); +std::future Output::chooseCompositionStrategyAsync( + std::optional* changes) { + return mHwComposerAsyncWorker->send( + [&, changes]() { return chooseCompositionStrategy(changes); }); +} + +GpuCompositionResult Output::prepareFrameAsync(const CompositionRefreshArgs& refreshArgs) { + ATRACE_CALL(); + ALOGV(__FUNCTION__); + auto& state = editState(); + const auto& previousChanges = state.previousDeviceRequestedChanges; + std::optional changes; + resetCompositionStrategy(); + auto hwcResult = chooseCompositionStrategyAsync(&changes); + if (state.previousDeviceRequestedSuccess) { + applyCompositionStrategy(previousChanges); + } + finishPrepareFrame(); + + base::unique_fd bufferFence; + std::shared_ptr buffer; + updateProtectedContentState(); + const bool dequeueSucceeded = dequeueRenderBuffer(&bufferFence, &buffer); + GpuCompositionResult compositionResult; + if (dequeueSucceeded) { + std::optional optFd = + composeSurfaces(Region::INVALID_REGION, refreshArgs, buffer, bufferFence); + if (optFd) { + compositionResult.fence = std::move(*optFd); + } } - mRenderSurface->prepareFrame(outputState.usesClientComposition, - outputState.usesDeviceComposition); + auto chooseCompositionSuccess = hwcResult.get(); + const bool predictionSucceeded = dequeueSucceeded && changes == previousChanges; + compositionResult.succeeded = predictionSucceeded; + if (!predictionSucceeded) { + ATRACE_NAME("CompositionStrategyPredictionMiss"); + resetCompositionStrategy(); + if (chooseCompositionSuccess) { + applyCompositionStrategy(changes); + } + finishPrepareFrame(); + // Track the dequeued buffer to reuse so we don't need to dequeue another one. + compositionResult.buffer = buffer; + } else { + ATRACE_NAME("CompositionStrategyPredictionHit"); + } + state.previousDeviceRequestedChanges = std::move(changes); + state.previousDeviceRequestedSuccess = chooseCompositionSuccess; + return compositionResult; } void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& refreshArgs) { @@ -975,7 +1037,11 @@ void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& if (getState().isEnabled) { if (const auto dirtyRegion = getDirtyRegion(); !dirtyRegion.isEmpty()) { - static_cast(composeSurfaces(dirtyRegion, refreshArgs)); + base::unique_fd bufferFence; + std::shared_ptr buffer; + updateProtectedContentState(); + dequeueRenderBuffer(&bufferFence, &buffer); + static_cast(composeSurfaces(dirtyRegion, refreshArgs, buffer, bufferFence)); mRenderSurface->queueBuffer(base::unique_fd()); } } @@ -987,7 +1053,7 @@ void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& prepareFrame(); } -void Output::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) { +void Output::finishFrame(const CompositionRefreshArgs& refreshArgs, GpuCompositionResult&& result) { ATRACE_CALL(); ALOGV(__FUNCTION__); @@ -995,9 +1061,25 @@ void Output::finishFrame(const compositionengine::CompositionRefreshArgs& refres return; } - // Repaint the framebuffer (if needed), getting the optional fence for when - // the composition completes. - auto optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs); + std::optional optReadyFence; + std::shared_ptr buffer; + base::unique_fd bufferFence; + if (result.succeeded) { + optReadyFence = std::move(result.fence); + } else { + if (result.bufferAvailable()) { + buffer = std::move(result.buffer); + bufferFence = std::move(result.fence); + } else { + updateProtectedContentState(); + if (!dequeueRenderBuffer(&bufferFence, &buffer)) { + return; + } + } + // Repaint the framebuffer (if needed), getting the optional fence for when + // the composition completes. + optReadyFence = composeSurfaces(Region::INVALID_REGION, refreshArgs, buffer, bufferFence); + } if (!optReadyFence) { return; } @@ -1006,16 +1088,8 @@ void Output::finishFrame(const compositionengine::CompositionRefreshArgs& refres mRenderSurface->queueBuffer(std::move(*optReadyFence)); } -std::optional Output::composeSurfaces( - const Region& debugRegion, const compositionengine::CompositionRefreshArgs& refreshArgs) { - ATRACE_CALL(); - ALOGV(__FUNCTION__); - +void Output::updateProtectedContentState() { const auto& outputState = getState(); - OutputCompositionState& outputCompositionState = editState(); - const TracedOrdinal hasClientComposition = {"hasClientComposition", - outputState.usesClientComposition}; - auto& renderEngine = getCompositionEngine().getRenderEngine(); const bool supportsProtectedContent = renderEngine.supportsProtectedContent(); @@ -1037,29 +1111,48 @@ std::optional Output::composeSurfaces( } else if (!outputState.isSecure && renderEngine.isProtected()) { renderEngine.useProtectedContext(false); } +} - base::unique_fd fd; - - std::shared_ptr tex; +bool Output::dequeueRenderBuffer(base::unique_fd* bufferFence, + std::shared_ptr* tex) { + const auto& outputState = getState(); // If we aren't doing client composition on this output, but do have a // flipClientTarget request for this frame on this output, we still need to // dequeue a buffer. - if (hasClientComposition || outputState.flipClientTarget) { - tex = mRenderSurface->dequeueBuffer(&fd); - if (tex == nullptr) { + if (outputState.usesClientComposition || outputState.flipClientTarget) { + *tex = mRenderSurface->dequeueBuffer(bufferFence); + if (*tex == nullptr) { ALOGW("Dequeuing buffer for display [%s] failed, bailing out of " "client composition for this frame", mName.c_str()); - return {}; + return false; } } + return true; +} +std::optional Output::composeSurfaces( + const Region& debugRegion, const compositionengine::CompositionRefreshArgs& refreshArgs, + std::shared_ptr tex, base::unique_fd& fd) { + ATRACE_CALL(); + ALOGV(__FUNCTION__); + + const auto& outputState = getState(); + const TracedOrdinal hasClientComposition = {"hasClientComposition", + outputState.usesClientComposition}; if (!hasClientComposition) { setExpensiveRenderingExpected(false); return base::unique_fd(); } + if (tex == nullptr) { + ALOGW("Buffer not valid for display [%s], bailing out of " + "client composition for this frame", + mName.c_str()); + return {}; + } + ALOGV("hasClientComposition"); renderengine::DisplaySettings clientCompositionDisplay; @@ -1088,6 +1181,8 @@ std::optional Output::composeSurfaces( outputState.usesDeviceComposition || getSkipColorTransform(); // Generate the client composition requests for the layers on this output. + auto& renderEngine = getCompositionEngine().getRenderEngine(); + const bool supportsProtectedContent = renderEngine.supportsProtectedContent(); std::vector clientCompositionLayersFE; std::vector clientCompositionLayers = generateClientCompositionRequests(supportsProtectedContent, @@ -1095,16 +1190,19 @@ std::optional Output::composeSurfaces( clientCompositionLayersFE); appendRegionFlashRequests(debugRegion, clientCompositionLayers); + OutputCompositionState& outputCompositionState = editState(); // Check if the client composition requests were rendered into the provided graphic buffer. If // so, we can reuse the buffer and avoid client composition. if (mClientCompositionRequestCache) { if (mClientCompositionRequestCache->exists(tex->getBuffer()->getId(), clientCompositionDisplay, clientCompositionLayers)) { + ATRACE_NAME("ClientCompositionCacheHit"); outputCompositionState.reusedClientComposition = true; setExpensiveRenderingExpected(false); return base::unique_fd(); } + ATRACE_NAME("ClientCompositionCacheMiss"); mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay, clientCompositionLayers); } @@ -1356,7 +1454,7 @@ void Output::dirtyEntireOutput() { outputState.dirtyRegion.set(outputState.displaySpace.getBoundsAsRect()); } -void Output::chooseCompositionStrategy() { +void Output::resetCompositionStrategy() { // The base output implementation can only do client composition auto& outputState = editState(); outputState.usesClientComposition = true; @@ -1376,5 +1474,63 @@ compositionengine::Output::FrameFences Output::presentAndGetFrameFences() { return result; } +void Output::setPredictCompositionStrategy(bool predict) { + if (predict) { + mHwComposerAsyncWorker = std::make_unique(); + } else { + mHwComposerAsyncWorker.reset(nullptr); + } +} + +bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) { + if (!getState().isEnabled || !mHwComposerAsyncWorker) { + ALOGV("canPredictCompositionStrategy disabled"); + return false; + } + + if (!getState().previousDeviceRequestedChanges) { + ALOGV("canPredictCompositionStrategy previous changes not available"); + return false; + } + + if (!mRenderSurface->supportsCompositionStrategyPrediction()) { + ALOGV("canPredictCompositionStrategy surface does not support"); + return false; + } + + if (refreshArgs.devOptFlashDirtyRegionsDelay) { + ALOGV("canPredictCompositionStrategy devOptFlashDirtyRegionsDelay"); + return false; + } + + // If no layer uses clientComposition, then don't predict composition strategy + // because we have less work to do in parallel. + if (!anyLayersRequireClientComposition()) { + ALOGV("canPredictCompositionStrategy no layer uses clientComposition"); + return false; + } + + if (!refreshArgs.updatingOutputGeometryThisFrame) { + return true; + } + + ALOGV("canPredictCompositionStrategy updatingOutputGeometryThisFrame"); + return false; +} + +bool Output::anyLayersRequireClientComposition() const { + const auto layers = getOutputLayersOrderedByZ(); + return std::any_of(layers.begin(), layers.end(), + [](const auto& layer) { return layer->requiresClientComposition(); }); +} + +void Output::finishPrepareFrame() { + const auto& state = getState(); + if (mPlanner) { + mPlanner->reportFinalPlan(getOutputLayersOrderedByZ()); + } + mRenderSurface->prepareFrame(state.usesClientComposition, state.usesDeviceComposition); +} + } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index 12c2c8eb38..5a3af7bfea 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -289,5 +289,9 @@ std::shared_ptr& RenderSurface::mutableTextureFor return mTexture; } +bool RenderSurface::supportsCompositionStrategyPrediction() const { + return mDisplaySurface->supportsCompositionStrategyPrediction(); +} + } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index d2c945c67b..9a616679f3 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -30,7 +30,9 @@ #include #include #include +#include #include + #include #include @@ -43,6 +45,7 @@ using aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::Composition; +using aidl::android::hardware::graphics::composer3::DimmingStage; namespace android::compositionengine { namespace { @@ -113,8 +116,9 @@ struct DisplayTestCommon : public testing::Test { return mCompositionEngine; }; + size_t getOutputLayerCount() const override { return 1u; } + // Mock implementation overrides - MOCK_CONST_METHOD0(getOutputLayerCount, size_t()); MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex, compositionengine::OutputLayer*(size_t)); MOCK_METHOD2(ensureOutputLayer, @@ -197,6 +201,26 @@ struct PartialMockDisplayTestCommon : public DisplayTestCommon { std::shared_ptr mDisplay = createPartialMockDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay()); + + android::HWComposer::DeviceRequestedChanges mDeviceRequestedChanges{ + {{nullptr, Composition::CLIENT}}, + hal::DisplayRequest::FLIP_CLIENT_TARGET, + {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}}, + {DEFAULT_DISPLAY_ID.value, + {aidl::android::hardware::graphics::common::PixelFormat::RGBA_8888, + aidl::android::hardware::graphics::common::Dataspace::UNKNOWN}, + -1.f, + DimmingStage::NONE}, + }; + + void chooseCompositionStrategy(Display* display) { + std::optional changes; + bool success = display->chooseCompositionStrategy(&changes); + display->resetCompositionStrategy(); + if (success) { + display->applyCompositionStrategy(changes); + } + } }; struct FullDisplayImplTestCommon : public DisplayTestCommon { @@ -213,6 +237,11 @@ struct DisplayWithLayersTestCommon : public FullDisplayImplTestCommon { std::unique_ptr(mLayer2.outputLayer)); mDisplay->injectOutputLayerForTest( std::unique_ptr(mLayer3.outputLayer)); + mResultWithBuffer.buffer = std::make_shared< + renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 1ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0ULL /*usage*/); } Layer mLayer1; @@ -221,6 +250,8 @@ struct DisplayWithLayersTestCommon : public FullDisplayImplTestCommon { StrictMock hwc2LayerUnknown; std::shared_ptr mDisplay = createDisplay(mCompositionEngine, getDisplayCreationArgsForPhysicalDisplay()); + impl::GpuCompositionResult mResultWithBuffer; + impl::GpuCompositionResult mResultWithoutBuffer; }; /* @@ -553,7 +584,7 @@ TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfGpuDisplay) { createPartialMockDisplay(mCompositionEngine, args); EXPECT_TRUE(GpuVirtualDisplayId::tryCast(gpuDisplay->getId())); - gpuDisplay->chooseCompositionStrategy(); + chooseCompositionStrategy(gpuDisplay.get()); auto& state = gpuDisplay->getState(); EXPECT_TRUE(state.usesClientComposition); @@ -566,11 +597,12 @@ TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutOnHwcError) { getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), false, _, _, _, _)) .WillOnce(Return(INVALID_OPERATION)); - mDisplay->chooseCompositionStrategy(); + chooseCompositionStrategy(mDisplay.get()); auto& state = mDisplay->getState(); EXPECT_TRUE(state.usesClientComposition); EXPECT_FALSE(state.usesDeviceComposition); + EXPECT_FALSE(state.previousDeviceRequestedChanges.has_value()); } TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) { @@ -587,10 +619,16 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) { EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _)) - .WillOnce(Return(NO_ERROR)); + .WillOnce(testing::DoAll(testing::SetArgPointee<5>(mDeviceRequestedChanges), + Return(NO_ERROR))); + EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes)) + .Times(1); + EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1); + EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests)) + .Times(1); EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); - mDisplay->chooseCompositionStrategy(); + chooseCompositionStrategy(mDisplay.get()); auto& state = mDisplay->getState(); EXPECT_FALSE(state.usesClientComposition); @@ -602,45 +640,23 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithDisplayBrightnes // values, use a Sequence to control the matching so the values are returned in a known // order. constexpr float kDisplayBrightness = 0.5f; - Sequence s; - EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(*mDisplay, anyLayersRequireClientComposition()) - .InSequence(s) - .WillOnce(Return(false)); EXPECT_CALL(mHwComposer, setDisplayBrightness(DEFAULT_DISPLAY_ID, kDisplayBrightness, Hwc2::Composer::DisplayBrightnessOptions{.applyImmediately = false})) .WillOnce(Return(ByMove(ftl::yield(NO_ERROR)))); - EXPECT_CALL(mHwComposer, - getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _)) - .WillOnce(Return(NO_ERROR)); - EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); - mDisplay->setNextBrightness(kDisplayBrightness); - mDisplay->chooseCompositionStrategy(); + mock::RenderSurface* renderSurface = new StrictMock(); + EXPECT_CALL(*renderSurface, beginFrame(_)).Times(1); + mDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); + mDisplay->beginFrame(); auto& state = mDisplay->getState(); - EXPECT_FALSE(state.usesClientComposition); - EXPECT_TRUE(state.usesDeviceComposition); EXPECT_FALSE(state.displayBrightness.has_value()); } TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { - android::HWComposer::DeviceRequestedChanges changes{ - {{nullptr, Composition::CLIENT}}, - hal::DisplayRequest::FLIP_CLIENT_TARGET, - {{nullptr, hal::LayerRequest::CLEAR_CLIENT_TARGET}}, - {.clientTargetProperty = - {aidl::android::hardware::graphics::common::PixelFormat::RGBA_8888, - aidl::android::hardware::graphics::common::Dataspace::UNKNOWN}, - .brightness = -1.f, - .dimmingStage = aidl::android::hardware::graphics::composer3::DimmingStage::NONE}, - }; - // Since two calls are made to anyLayersRequireClientComposition with different return // values, use a Sequence to control the matching so the values are returned in a known // order. @@ -654,13 +670,15 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(HalDisplayId(DEFAULT_DISPLAY_ID), true, _, _, _, _)) - .WillOnce(DoAll(SetArgPointee<5>(changes), Return(NO_ERROR))); - EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1); - EXPECT_CALL(*mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1); - EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1); + .WillOnce(DoAll(SetArgPointee<5>(mDeviceRequestedChanges), Return(NO_ERROR))); + EXPECT_CALL(*mDisplay, applyChangedTypesToLayers(mDeviceRequestedChanges.changedTypes)) + .Times(1); + EXPECT_CALL(*mDisplay, applyDisplayRequests(mDeviceRequestedChanges.displayRequests)).Times(1); + EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests)) + .Times(1); EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); - mDisplay->chooseCompositionStrategy(); + chooseCompositionStrategy(mDisplay.get()); auto& state = mDisplay->getState(); EXPECT_FALSE(state.usesClientComposition); @@ -938,7 +956,7 @@ TEST_F(DisplayFinishFrameTest, doesNotSkipCompositionIfNotDirtyOnHwcDisplay) { mDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1)); mDisplay->editState().dirtyRegion = Region::INVALID_REGION; - mDisplay->finishFrame({}); + mDisplay->finishFrame({}, std::move(mResultWithBuffer)); } TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) { @@ -956,7 +974,7 @@ TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) { gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1)); gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION; - gpuDisplay->finishFrame({}); + gpuDisplay->finishFrame({}, std::move(mResultWithoutBuffer)); } TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) { @@ -973,7 +991,7 @@ TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) { gpuDisplay->editState().usesClientComposition = false; gpuDisplay->editState().layerStackSpace.setContent(Rect(0, 0, 1, 1)); gpuDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1)); - gpuDisplay->finishFrame({}); + gpuDisplay->finishFrame({}, std::move(mResultWithBuffer)); } /* diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 66f37536fc..49be45e9d8 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -989,7 +990,9 @@ struct OutputPrepareFrameTest : public testing::Test { struct OutputPartialMock : public OutputPartialMockBase { // Sets up the helper functions called by the function under test to use // mock implementations. - MOCK_METHOD0(chooseCompositionStrategy, void()); + MOCK_METHOD1(chooseCompositionStrategy, + bool(std::optional*)); + MOCK_METHOD0(resetCompositionStrategy, void()); }; OutputPrepareFrameTest() { @@ -1015,7 +1018,8 @@ TEST_F(OutputPrepareFrameTest, delegatesToChooseCompositionStrategyAndRenderSurf mOutput.editState().usesClientComposition = false; mOutput.editState().usesDeviceComposition = true; - EXPECT_CALL(mOutput, chooseCompositionStrategy()).Times(1); + EXPECT_CALL(mOutput, chooseCompositionStrategy(_)).WillRepeatedly(Return(true)); + EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(1); EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)); @@ -1037,6 +1041,147 @@ TEST_F(OutputTest, prepareFrameSetsClientCompositionOnlyByDefault) { EXPECT_FALSE(mOutput->getState().usesDeviceComposition); } +struct OutputPrepareFrameAsyncTest : public testing::Test { + struct OutputPartialMock : public OutputPartialMockBase { + // Sets up the helper functions called by the function under test to use + // mock implementations. + MOCK_METHOD1(chooseCompositionStrategy, + bool(std::optional*)); + MOCK_METHOD0(updateProtectedContentState, void()); + MOCK_METHOD2(dequeueRenderBuffer, + bool(base::unique_fd*, std::shared_ptr*)); + MOCK_METHOD1( + chooseCompositionStrategyAsync, + std::future(std::optional*)); + MOCK_METHOD4(composeSurfaces, + std::optional( + const Region&, const compositionengine::CompositionRefreshArgs&, + std::shared_ptr, base::unique_fd&)); + MOCK_METHOD0(resetCompositionStrategy, void()); + }; + + OutputPrepareFrameAsyncTest() { + mOutput.setDisplayColorProfileForTest( + std::unique_ptr(mDisplayColorProfile)); + mOutput.setRenderSurfaceForTest(std::unique_ptr(mRenderSurface)); + } + + StrictMock mCompositionEngine; + mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock(); + mock::RenderSurface* mRenderSurface = new StrictMock(); + StrictMock mOutput; + CompositionRefreshArgs mRefreshArgs; +}; + +TEST_F(OutputPrepareFrameAsyncTest, delegatesToChooseCompositionStrategyAndRenderSurface) { + mOutput.editState().isEnabled = true; + mOutput.editState().usesClientComposition = false; + mOutput.editState().usesDeviceComposition = true; + mOutput.editState().previousDeviceRequestedChanges = + std::make_optional({}); + std::promise p; + p.set_value(true); + + EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(1); + EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); + EXPECT_CALL(mOutput, updateProtectedContentState()); + EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true)); + EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(1); + EXPECT_CALL(mOutput, chooseCompositionStrategyAsync(_)) + .WillOnce(DoAll(SetArgPointee<0>(mOutput.editState().previousDeviceRequestedChanges), + Return(ByMove(p.get_future())))); + EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _)); + + impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs); + EXPECT_TRUE(result.succeeded); + EXPECT_FALSE(result.bufferAvailable()); +} + +TEST_F(OutputPrepareFrameAsyncTest, skipCompositionOnDequeueFailure) { + mOutput.editState().isEnabled = true; + mOutput.editState().usesClientComposition = false; + mOutput.editState().usesDeviceComposition = true; + mOutput.editState().previousDeviceRequestedChanges = + std::make_optional({}); + std::promise p; + p.set_value(true); + + EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(2); + EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); + EXPECT_CALL(mOutput, updateProtectedContentState()); + EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(false)); + EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2); + EXPECT_CALL(mOutput, chooseCompositionStrategyAsync(_)) + .WillOnce(DoAll(SetArgPointee<0>(mOutput.editState().previousDeviceRequestedChanges), + Return(ByMove(p.get_future())))); + + impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs); + EXPECT_FALSE(result.succeeded); + EXPECT_FALSE(result.bufferAvailable()); +} + +// Tests that in the event of hwc error when choosing composition strategy, we would fall back +// client composition +TEST_F(OutputPrepareFrameAsyncTest, chooseCompositionStrategyFailureCallsPrepareFrame) { + mOutput.editState().isEnabled = true; + mOutput.editState().usesClientComposition = false; + mOutput.editState().usesDeviceComposition = true; + mOutput.editState().previousDeviceRequestedChanges = + std::make_optional({}); + std::promise p; + p.set_value(false); + std::shared_ptr tex = + std::make_shared(1, 1, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + 2); + EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(2); + EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); + EXPECT_CALL(mOutput, updateProtectedContentState()); + EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(tex), Return(true))); + EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2); + EXPECT_CALL(mOutput, chooseCompositionStrategyAsync(_)).WillOnce([&] { + return p.get_future(); + }); + EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _)); + + impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs); + EXPECT_FALSE(result.succeeded); + EXPECT_TRUE(result.bufferAvailable()); +} + +TEST_F(OutputPrepareFrameAsyncTest, predictionMiss) { + mOutput.editState().isEnabled = true; + mOutput.editState().usesClientComposition = false; + mOutput.editState().usesDeviceComposition = true; + mOutput.editState().previousDeviceRequestedChanges = + std::make_optional({}); + auto newDeviceRequestedChanges = + std::make_optional({}); + newDeviceRequestedChanges->displayRequests = static_cast(0); + std::promise p; + p.set_value(false); + std::shared_ptr tex = + std::make_shared(1, 1, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + 2); + + EXPECT_CALL(mOutput, resetCompositionStrategy()).Times(2); + EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); + EXPECT_CALL(mOutput, updateProtectedContentState()); + EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)) + .WillOnce(DoAll(SetArgPointee<1>(tex), Return(true))); + EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)).Times(2); + EXPECT_CALL(mOutput, chooseCompositionStrategyAsync(_)).WillOnce([&] { + return p.get_future(); + }); + EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _)); + + impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs); + EXPECT_FALSE(result.succeeded); + EXPECT_TRUE(result.bufferAvailable()); +} + /* * Output::prepare() */ @@ -1820,10 +1965,14 @@ struct OutputPresentTest : public testing::Test { MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&)); MOCK_METHOD0(beginFrame, void()); MOCK_METHOD0(prepareFrame, void()); + MOCK_METHOD1(prepareFrameAsync, GpuCompositionResult(const CompositionRefreshArgs&)); MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&)); - MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&)); + MOCK_METHOD2(finishFrame, + void(const compositionengine::CompositionRefreshArgs&, + GpuCompositionResult&&)); MOCK_METHOD0(postFramebuffer, void()); MOCK_METHOD1(renderCachedSets, void(const compositionengine::CompositionRefreshArgs&)); + MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&)); }; StrictMock mOutput; @@ -1839,9 +1988,30 @@ TEST_F(OutputPresentTest, justInvokesChildFunctionsInSequence) { EXPECT_CALL(mOutput, writeCompositionState(Ref(args))); EXPECT_CALL(mOutput, setColorTransform(Ref(args))); EXPECT_CALL(mOutput, beginFrame()); + EXPECT_CALL(mOutput, canPredictCompositionStrategy(Ref(args))).WillOnce(Return(false)); EXPECT_CALL(mOutput, prepareFrame()); EXPECT_CALL(mOutput, devOptRepaintFlash(Ref(args))); - EXPECT_CALL(mOutput, finishFrame(Ref(args))); + EXPECT_CALL(mOutput, finishFrame(Ref(args), _)); + EXPECT_CALL(mOutput, postFramebuffer()); + EXPECT_CALL(mOutput, renderCachedSets(Ref(args))); + + mOutput.present(args); +} + +TEST_F(OutputPresentTest, predictingCompositionStrategyInvokesPrepareFrameAsync) { + CompositionRefreshArgs args; + + InSequence seq; + EXPECT_CALL(mOutput, updateColorProfile(Ref(args))); + EXPECT_CALL(mOutput, updateCompositionState(Ref(args))); + EXPECT_CALL(mOutput, planComposition()); + EXPECT_CALL(mOutput, writeCompositionState(Ref(args))); + EXPECT_CALL(mOutput, setColorTransform(Ref(args))); + EXPECT_CALL(mOutput, beginFrame()); + EXPECT_CALL(mOutput, canPredictCompositionStrategy(Ref(args))).WillOnce(Return(true)); + EXPECT_CALL(mOutput, prepareFrameAsync(Ref(args))); + EXPECT_CALL(mOutput, devOptRepaintFlash(Ref(args))); + EXPECT_CALL(mOutput, finishFrame(Ref(args), _)); EXPECT_CALL(mOutput, postFramebuffer()); EXPECT_CALL(mOutput, renderCachedSets(Ref(args))); @@ -2739,11 +2909,15 @@ struct OutputDevOptRepaintFlashTest : public testing::Test { // Sets up the helper functions called by the function under test to use // mock implementations. MOCK_METHOD(Region, getDirtyRegion, (), (const)); - MOCK_METHOD2(composeSurfaces, + MOCK_METHOD4(composeSurfaces, std::optional( - const Region&, const compositionengine::CompositionRefreshArgs&)); + const Region&, const compositionengine::CompositionRefreshArgs&, + std::shared_ptr, base::unique_fd&)); MOCK_METHOD0(postFramebuffer, void()); MOCK_METHOD0(prepareFrame, void()); + MOCK_METHOD0(updateProtectedContentState, void()); + MOCK_METHOD2(dequeueRenderBuffer, + bool(base::unique_fd*, std::shared_ptr*)); }; OutputDevOptRepaintFlashTest() { @@ -2800,7 +2974,9 @@ TEST_F(OutputDevOptRepaintFlashTest, alsoComposesSurfacesAndQueuesABufferIfDirty InSequence seq; EXPECT_CALL(mOutput, getDirtyRegion()).WillOnce(Return(kNotEmptyRegion)); - EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs))); + EXPECT_CALL(mOutput, updateProtectedContentState()); + EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)); + EXPECT_CALL(mOutput, composeSurfaces(RegionEq(kNotEmptyRegion), Ref(mRefreshArgs), _, _)); EXPECT_CALL(*mRenderSurface, queueBuffer(_)); EXPECT_CALL(mOutput, postFramebuffer()); EXPECT_CALL(mOutput, prepareFrame()); @@ -2816,10 +2992,14 @@ struct OutputFinishFrameTest : public testing::Test { struct OutputPartialMock : public OutputPartialMockBase { // Sets up the helper functions called by the function under test to use // mock implementations. - MOCK_METHOD2(composeSurfaces, + MOCK_METHOD4(composeSurfaces, std::optional( - const Region&, const compositionengine::CompositionRefreshArgs&)); + const Region&, const compositionengine::CompositionRefreshArgs&, + std::shared_ptr, base::unique_fd&)); MOCK_METHOD0(postFramebuffer, void()); + MOCK_METHOD0(updateProtectedContentState, void()); + MOCK_METHOD2(dequeueRenderBuffer, + bool(base::unique_fd*, std::shared_ptr*)); }; OutputFinishFrameTest() { @@ -2837,27 +3017,63 @@ struct OutputFinishFrameTest : public testing::Test { TEST_F(OutputFinishFrameTest, ifNotEnabledDoesNothing) { mOutput.mState.isEnabled = false; - mOutput.finishFrame(mRefreshArgs); + impl::GpuCompositionResult result; + mOutput.finishFrame(mRefreshArgs, std::move(result)); } TEST_F(OutputFinishFrameTest, takesEarlyOutifComposeSurfacesReturnsNoFence) { mOutput.mState.isEnabled = true; + EXPECT_CALL(mOutput, updateProtectedContentState()); + EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true)); + EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _, _)); - InSequence seq; - EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _)); - - mOutput.finishFrame(mRefreshArgs); + impl::GpuCompositionResult result; + mOutput.finishFrame(mRefreshArgs, std::move(result)); } TEST_F(OutputFinishFrameTest, queuesBufferIfComposeSurfacesReturnsAFence) { mOutput.mState.isEnabled = true; InSequence seq; - EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _)) + EXPECT_CALL(mOutput, updateProtectedContentState()); + EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true)); + EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _, _)) .WillOnce(Return(ByMove(base::unique_fd()))); EXPECT_CALL(*mRenderSurface, queueBuffer(_)); - mOutput.finishFrame(mRefreshArgs); + impl::GpuCompositionResult result; + mOutput.finishFrame(mRefreshArgs, std::move(result)); +} + +TEST_F(OutputFinishFrameTest, predictionSucceeded) { + mOutput.mState.isEnabled = true; + + InSequence seq; + EXPECT_CALL(*mRenderSurface, queueBuffer(_)); + + impl::GpuCompositionResult result; + result.succeeded = true; + mOutput.finishFrame(mRefreshArgs, std::move(result)); +} + +TEST_F(OutputFinishFrameTest, predictionFailedAndBufferIsReused) { + mOutput.mState.isEnabled = true; + + InSequence seq; + + impl::GpuCompositionResult result; + result.succeeded = false; + result.buffer = + std::make_shared(1, 1, + HAL_PIXEL_FORMAT_RGBA_8888, 1, + 2); + + EXPECT_CALL(mOutput, + composeSurfaces(RegionEq(Region::INVALID_REGION), _, result.buffer, + Eq(ByRef(result.fence)))) + .WillOnce(Return(ByMove(base::unique_fd()))); + EXPECT_CALL(*mRenderSurface, queueBuffer(_)); + mOutput.finishFrame(mRefreshArgs, std::move(result)); } /* @@ -3104,8 +3320,15 @@ struct OutputComposeSurfacesTest : public testing::Test { struct ExecuteState : public CallOrderStateMachineHelper { auto execute() { - getInstance()->mReadyFence = - getInstance()->mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fence; + std::shared_ptr externalTexture; + const bool success = + getInstance()->mOutput.dequeueRenderBuffer(&fence, &externalTexture); + if (success) { + getInstance()->mReadyFence = + getInstance()->mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, + externalTexture, fence); + } return nextState(); } }; @@ -3728,7 +3951,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifDisplayIsNotSecure) EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true)); EXPECT_CALL(mRenderEngine, useProtectedContext(false)); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifRenderEngineDoesNotSupportIt) { @@ -3736,7 +3963,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifRenderEngineDoesNotS mLayer2.mLayerFEState.hasProtectedContent = true; EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false)); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNoProtectedContentLayers) { @@ -3748,7 +3979,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNoProtectedContentLa EXPECT_CALL(mRenderEngine, useProtectedContext(false)); EXPECT_CALL(*mRenderSurface, setProtected(false)); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) { @@ -3770,7 +4005,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) { .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEverywhere) { @@ -3780,7 +4019,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEveryw EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true)); EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true)); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifFailsToEnableInRenderEngine) { @@ -3791,7 +4034,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifFailsToEnableInRende EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false)); EXPECT_CALL(mRenderEngine, useProtectedContext(true)); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderEngine) { @@ -3802,7 +4049,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRend EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false)); EXPECT_CALL(*mRenderSurface, setProtected(true)); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderSurface) { @@ -3813,7 +4064,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRend EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true)); EXPECT_CALL(mRenderEngine, useProtectedContext(true)); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } struct OutputComposeSurfacesTest_SetsExpensiveRendering : public OutputComposeSurfacesTest { @@ -3843,7 +4098,11 @@ TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering, IfExepensiveOutputDatas .WillOnce(Return(ByMove( futureOf({NO_ERROR, base::unique_fd()})))); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs); + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } struct OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur @@ -3878,7 +4137,12 @@ TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur, IfBlursAreExpen mOutput.writeCompositionState(mRefreshArgs); EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)); - mOutput.composeSurfaces(kDebugRegion, mRefreshArgs); + + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, mRefreshArgs, tex, fd); } TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur, IfBlursAreNotExpensive) { @@ -3888,7 +4152,12 @@ TEST_F(OutputComposeSurfacesTest_SetsExpensiveRendering_ForBlur, IfBlursAreNotEx mOutput.writeCompositionState(mRefreshArgs); EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)).Times(0); - mOutput.composeSurfaces(kDebugRegion, mRefreshArgs); + + base::unique_fd fd; + std::shared_ptr tex; + mOutput.updateProtectedContentState(); + mOutput.dequeueRenderBuffer(&fd, &tex); + mOutput.composeSurfaces(kDebugRegion, mRefreshArgs, tex, fd); } /* diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 9116fd335e..3651c8b07f 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -91,6 +91,7 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) static_cast(SurfaceFlinger::maxFrameBufferAcquiredBuffers)); } + mCompositionDisplay->setPredictCompositionStrategy(mFlinger->mPredictCompositionStrategy); mCompositionDisplay->createDisplayColorProfile( compositionengine::DisplayColorProfileCreationArgsBuilder() .setHasWideColorGamut(args.hasWideColorGamut) diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 389c3be211..5e2ab784fa 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -280,6 +280,13 @@ public: virtual Hwc2::AidlTransform getPhysicalDisplayOrientation(PhysicalDisplayId) const = 0; }; +static inline bool operator==(const android::HWComposer::DeviceRequestedChanges& lhs, + const android::HWComposer::DeviceRequestedChanges& rhs) { + return lhs.changedTypes == rhs.changedTypes && lhs.displayRequests == rhs.displayRequests && + lhs.layerRequests == rhs.layerRequests && + lhs.clientTargetProperty == rhs.clientTargetProperty; +} + namespace impl { class HWComposer final : public android::HWComposer { diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 307da41667..e21095aa88 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -89,6 +89,9 @@ public: virtual void dumpAsString(String8& result) const; virtual void resizeBuffers(const ui::Size&) override; virtual const sp& getClientTargetAcquireFence() const override; + // Virtual display surface needs to prepare the frame based on composition type. Skip + // any client composition prediction. + virtual bool supportsCompositionStrategyPrediction() const override { return false; }; private: enum Source : size_t { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ff977b226a..9191d4903d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -411,6 +411,9 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("debug.sf.disable_client_composition_cache", value, "0"); mDisableClientCompositionCache = atoi(value); + property_get("debug.sf.predict_hwc_composition_strategy", value, "0"); + mPredictCompositionStrategy = atoi(value); + // We should be reading 'persist.sys.sf.color_saturation' here // but since /data may be encrypted, we need to wait until after vold // comes online to attempt to read the property. The property is diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index bc3d83e2b0..273cb91a38 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -342,6 +342,11 @@ public: void disableExpensiveRendering(); FloatRect getMaxDisplayBounds(); + // If set, composition engine tries to predict the composition strategy provided by HWC + // based on the previous frame. If the strategy can be predicted, gpu composition will + // run parallel to the hwc validateDisplay call and re-run if the predition is incorrect. + bool mPredictCompositionStrategy = false; + protected: // We're reference counted, never destroy SurfaceFlinger directly virtual ~SurfaceFlinger(); -- cgit v1.2.3-59-g8ed1b From 168f6ccfce328a1224297ba5b7af2779fcee0d9a Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Thu, 7 Apr 2022 20:58:00 +0000 Subject: Set better defaults for layer stack and oriented display space When the device is not logically rotated and there is a 90 degree or 270 degree physical installation, then the content rectangle and bounds of the layer stack space and the oriented display space must be consistent with the framebuffer space and un-oriented display space. That is, if the framebuffer space and un-oriented display space are in portrait, then the layer stack space and the oriented display space should be in landscape without any cropping effects. Prior to this patch, devices with a rotated physical install orientation would have its boot animation cropped due to the mismatch in the logical display space and physical display space Bug: 203165976 Test: boot animation is not cropped Change-Id: I965b6c0578e982fe1b2a4dbdb18c24b5922388a9 --- libs/ui/include/ui/Size.h | 12 ++++++ libs/ui/tests/Size_test.cpp | 32 ++++++++++++++ services/surfaceflinger/DisplayDevice.cpp | 30 ++++++------- .../unittests/DisplayDevice_SetProjectionTest.cpp | 50 ++++++++++++++++++++++ 4 files changed, 108 insertions(+), 16 deletions(-) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h index ecc192dcae..bdcbd569fc 100644 --- a/libs/ui/include/ui/Size.h +++ b/libs/ui/include/ui/Size.h @@ -23,6 +23,8 @@ #include #include +#include + namespace android::ui { // A simple value type representing a two-dimensional size. @@ -61,6 +63,16 @@ struct Size { set(Size(w, h)); } + // Applies a rotation onto the size + void rotate(Rotation rotation) { + if (rotation == ROTATION_90 || rotation == ROTATION_270) { + transpose(); + } + } + + // Swaps the width and height, emulating a 90 degree rotation. + void transpose() { std::swap(width, height); } + // Sets the value to kInvalidSize void makeInvalid(); diff --git a/libs/ui/tests/Size_test.cpp b/libs/ui/tests/Size_test.cpp index acef47fb97..0a236e60e4 100644 --- a/libs/ui/tests/Size_test.cpp +++ b/libs/ui/tests/Size_test.cpp @@ -61,6 +61,38 @@ TEST(SizeTest, BasicLessThanComparison) { EXPECT_FALSE(Size(1, 1) < Size(1, 1)); } +TEST(SizeTest, Transpose) { + Size s(123, 456); + s.transpose(); + EXPECT_EQ(s, Size(456, 123)); +} + +TEST(SizeTest, Rotate) { + { + Size s(123, 456); + s.rotate(Rotation::Rotation0); + EXPECT_EQ(s, Size(123, 456)); + } + + { + Size s(123, 456); + s.rotate(Rotation::Rotation90); + EXPECT_EQ(s, Size(456, 123)); + } + + { + Size s(123, 456); + s.rotate(Rotation::Rotation180); + EXPECT_EQ(s, Size(123, 456)); + } + + { + Size s(123, 456); + s.rotate(Rotation::Rotation270); + EXPECT_EQ(s, Size(456, 123)); + } +} + TEST(SizeTest, ValidAndEmpty) { { Size s; diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 3651c8b07f..65e7a7f79e 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -299,26 +299,24 @@ void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpace sPrimaryDisplayRotationFlags = ui::Transform::toRotationFlags(orientation); } + // We need to take care of display rotation for globalTransform for case if the panel is not + // installed aligned with device orientation. + const auto transformOrientation = orientation + mPhysicalOrientation; + + const auto& state = getCompositionDisplay()->getState(); + + // If the layer stack and destination frames have never been set, then configure them to be the + // same as the physical device, taking into account the total transform. if (!orientedDisplaySpaceRect.isValid()) { - // The destination frame can be invalid if it has never been set, - // in that case we assume the whole display size. - orientedDisplaySpaceRect = - getCompositionDisplay()->getState().displaySpace.getBoundsAsRect(); + ui::Size bounds = state.displaySpace.getBounds(); + bounds.rotate(transformOrientation); + orientedDisplaySpaceRect = Rect(bounds); } - if (layerStackSpaceRect.isEmpty()) { - // The layerStackSpaceRect can be invalid if it has never been set, in that case - // we assume the whole framebuffer size. - layerStackSpaceRect = - getCompositionDisplay()->getState().framebufferSpace.getBoundsAsRect(); - if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) { - std::swap(layerStackSpaceRect.right, layerStackSpaceRect.bottom); - } + ui::Size bounds = state.framebufferSpace.getBounds(); + bounds.rotate(transformOrientation); + layerStackSpaceRect = Rect(bounds); } - - // We need to take care of display rotation for globalTransform for case if the panel is not - // installed aligned with device orientation. - const auto transformOrientation = orientation + mPhysicalOrientation; getCompositionDisplay()->setProjection(transformOrientation, layerStackSpaceRect, orientedDisplaySpaceRect); } diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp index 3d24ecbf71..5734d34f81 100644 --- a/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp @@ -21,6 +21,7 @@ #include #include +#include namespace android { namespace { @@ -53,6 +54,11 @@ public: ui::Size swapWH(const ui::Size size) const { return ui::Size(size.height, size.width); } + void setDefaultProjection() { + // INVALID_RECT pulls from the physical display dimensions. + mDisplayDevice->setProjection(ui::ROTATION_0, Rect::INVALID_RECT, Rect::INVALID_RECT); + } + void setProjectionForRotation0() { // A logical rotation of 0 uses the SurfaceFlinger display size mDisplayDevice->setProjection(ui::ROTATION_0, Rect(mFlingerDisplaySize), @@ -79,6 +85,30 @@ public: Rect(swapWH(mFlingerDisplaySize))); } + void expectDefaultState() { + const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState(); + EXPECT_EQ(ui::Transform(ui::Transform::toRotationFlags(mPhysicalOrientation), + mHardwareDisplaySize.width, mHardwareDisplaySize.height), + compositionState.transform); + EXPECT_EQ(mPhysicalOrientation, compositionState.displaySpace.getOrientation()); + EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.getContent()); + EXPECT_EQ(mHardwareDisplaySize, compositionState.displaySpace.getBounds()); + EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.framebufferSpace.getContent()); + EXPECT_EQ(mHardwareDisplaySize, compositionState.framebufferSpace.getBounds()); + + const ui::Size expectedLogicalSize = (mPhysicalOrientation == ui::ROTATION_270 || + mPhysicalOrientation == ui::ROTATION_90) + ? swapWH(mHardwareDisplaySize) + : mHardwareDisplaySize; + + EXPECT_EQ(Rect(expectedLogicalSize), compositionState.orientedDisplaySpace.getContent()); + EXPECT_EQ(expectedLogicalSize, compositionState.orientedDisplaySpace.getBounds()); + EXPECT_EQ(Rect(expectedLogicalSize), compositionState.layerStackSpace.getContent()); + EXPECT_EQ(expectedLogicalSize, compositionState.layerStackSpace.getBounds()); + + EXPECT_EQ(false, compositionState.needsFiltering); + } + void expectStateForHardwareTransform0() { const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState(); EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_0, mHardwareDisplaySize.width, @@ -147,6 +177,11 @@ struct DisplayDeviceSetProjectionTest_Installed0 : public DisplayDeviceSetProjec ui::ROTATION_0) {} }; +TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkDefaultProjection) { + setDefaultProjection(); + expectDefaultState(); +} + TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith0OutputRotation) { setProjectionForRotation0(); expectStateForHardwareTransform0(); @@ -174,6 +209,11 @@ struct DisplayDeviceSetProjectionTest_Installed90 : public DisplayDeviceSetProje ui::ROTATION_90) {} }; +TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkDefaultProjection) { + setDefaultProjection(); + expectDefaultState(); +} + TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith0OutputRotation) { setProjectionForRotation0(); expectStateForHardwareTransform90(); @@ -201,6 +241,11 @@ struct DisplayDeviceSetProjectionTest_Installed180 : public DisplayDeviceSetProj ui::ROTATION_180) {} }; +TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkDefaultProjection) { + setDefaultProjection(); + expectDefaultState(); +} + TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith0OutputRotation) { setProjectionForRotation0(); expectStateForHardwareTransform180(); @@ -228,6 +273,11 @@ struct DisplayDeviceSetProjectionTest_Installed270 : public DisplayDeviceSetProj ui::ROTATION_270) {} }; +TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkDefaultProjection) { + setDefaultProjection(); + expectDefaultState(); +} + TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith0OutputRotation) { setProjectionForRotation0(); expectStateForHardwareTransform270(); -- cgit v1.2.3-59-g8ed1b From 0acc384bb994f7f8bbe9f4060d0b1b212744879f Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Thu, 7 Apr 2022 11:23:42 -0700 Subject: SF: Add dumpsys flags to dump displays Dump display configuration (--displays) and composition state (--comp- displays) separately. Use consistent formatting. Remove noise, e.g. repetitive display modes, physical display state that is expectedly missing for virtual displays. Bug: 182939859 Test: dumpsys SurfaceFlinger --displays Test: dumpsys SurfaceFlinger --comp-displays Change-Id: I787eedb82d76c74363e653a648ae88699096cc47 --- libs/ui/DeviceProductInfo.cpp | 2 +- .../include/compositionengine/ProjectionSpace.h | 14 +++--- .../impl/OutputCompositionState.h | 2 + .../CompositionEngine/src/Display.cpp | 12 ++--- .../CompositionEngine/src/DumpHelpers.cpp | 9 ++-- .../CompositionEngine/src/Output.cpp | 14 +++--- .../src/OutputCompositionState.cpp | 37 +++++++-------- services/surfaceflinger/DisplayDevice.cpp | 53 ++++++++++----------- .../DisplayHardware/FramebufferSurface.cpp | 20 ++------ .../Scheduler/RefreshRateConfigs.cpp | 55 ++++++++++++---------- services/surfaceflinger/SurfaceFlinger.cpp | 31 +++++++----- services/surfaceflinger/SurfaceFlinger.h | 4 ++ 12 files changed, 125 insertions(+), 128 deletions(-) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/libs/ui/DeviceProductInfo.cpp b/libs/ui/DeviceProductInfo.cpp index 4d6ce4306a..04d9d3c989 100644 --- a/libs/ui/DeviceProductInfo.cpp +++ b/libs/ui/DeviceProductInfo.cpp @@ -57,7 +57,7 @@ status_t DeviceProductInfo::unflatten(void const* buffer, size_t size) { } void DeviceProductInfo::dump(std::string& result) const { - StringAppendF(&result, "{name=%s, ", name.c_str()); + StringAppendF(&result, "{name=\"%s\", ", name.c_str()); StringAppendF(&result, "manufacturerPnpId=%s, ", manufacturerPnpId.data()); StringAppendF(&result, "productId=%s, ", productId.c_str()); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h index a63145a7fd..49013e0970 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h @@ -120,16 +120,16 @@ private: } // namespace compositionengine -inline std::string to_string(const android::compositionengine::ProjectionSpace& space) { - return android::base:: - StringPrintf("ProjectionSpace(bounds = %s, content = %s, orientation = %s)", - to_string(space.getBoundsAsRect()).c_str(), - to_string(space.getContent()).c_str(), toCString(space.getOrientation())); +inline std::string to_string(const compositionengine::ProjectionSpace& space) { + return base::StringPrintf("ProjectionSpace{bounds=%s, content=%s, orientation=%s}", + to_string(space.getBoundsAsRect()).c_str(), + to_string(space.getContent()).c_str(), + toCString(space.getOrientation())); } // Defining PrintTo helps with Google Tests. -inline void PrintTo(const android::compositionengine::ProjectionSpace& space, ::std::ostream* os) { +inline void PrintTo(const compositionengine::ProjectionSpace& space, std::ostream* os) { *os << to_string(space); } -} // namespace android \ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 5fa0d67e2d..61be983480 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -155,6 +155,8 @@ struct OutputCompositionState { SUCCESS = 1, // Composition strategy prediction failed for this frame. FAIL = 2, + + ftl_last = FAIL }; CompositionStrategyPredictionState strategyPrediction = diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index f5458865e8..b79b46b6ee 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -131,15 +131,11 @@ void Display::setColorProfile(const ColorProfile& colorProfile) { } void Display::dump(std::string& out) const { - using android::base::StringAppendF; - - StringAppendF(&out, " Composition Display State: [\"%s\"]", getName().c_str()); - - out.append("\n "); - dumpVal(out, "isVirtual", isVirtual()); - dumpVal(out, "DisplayId", to_string(mId)); - out.append("\n"); + const char* const type = isVirtual() ? "virtual" : "physical"; + base::StringAppendF(&out, "Display %s (%s, \"%s\")", to_string(mId).c_str(), type, + getName().c_str()); + out.append("\n Composition Display State:\n"); Output::dumpBase(out); } diff --git a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp index 01c368de88..290c710c9c 100644 --- a/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp +++ b/services/surfaceflinger/CompositionEngine/src/DumpHelpers.cpp @@ -89,7 +89,6 @@ void dumpVal(std::string& out, const char* name, const Region& region) { void dumpVal(std::string& out, const char* name, const ui::Transform& transform) { transform.dump(out, name); - out.append(" "); } void dumpVal(std::string& out, const char* name, const mat4& tr) { @@ -99,7 +98,7 @@ void dumpVal(std::string& out, const char* name, const mat4& tr) { "[%0.3f,%0.3f,%0.3f,%0.3f]" "[%0.3f,%0.3f,%0.3f,%0.3f]" "[%0.3f,%0.3f,%0.3f,%0.3f]" - "[%0.3f,%0.3f,%0.3f,%0.3f]]", + "[%0.3f,%0.3f,%0.3f,%0.3f]] ", name, tr[0][0], tr[1][0], tr[2][0], tr[3][0], tr[0][1], tr[1][1], tr[2][1], tr[3][1], @@ -109,9 +108,9 @@ void dumpVal(std::string& out, const char* name, const mat4& tr) { } void dumpVal(std::string& out, const char* name, const StretchEffect& effect) { - StringAppendF(&out, "%s={ width =%f, height = %f, vec=(%f, %f), max=(%f, %f) } ", name, - effect.width, effect.height, - effect.vectorX, effect.vectorY, effect.maxAmountX, effect.maxAmountY); + StringAppendF(&out, "%s={width=%f, height=%f, vec=(%f, %f), max=(%f, %f)} ", name, effect.width, + effect.height, effect.vectorX, effect.vectorY, effect.maxAmountX, + effect.maxAmountY); } } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index e99b70ff1e..c92c56932f 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -294,17 +294,15 @@ void Output::setDisplayBrightness(float sdrWhitePointNits, float displayBrightne } void Output::dump(std::string& out) const { - using android::base::StringAppendF; - - StringAppendF(&out, " Composition Output State: [\"%s\"]", mName.c_str()); - - out.append("\n "); + base::StringAppendF(&out, "Output \"%s\"", mName.c_str()); + out.append("\n Composition Output State:\n"); dumpBase(out); } void Output::dumpBase(std::string& out) const { dumpState(out); + out += '\n'; if (mDisplayColorProfile) { mDisplayColorProfile->dump(out); @@ -312,13 +310,15 @@ void Output::dumpBase(std::string& out) const { out.append(" No display color profile!\n"); } + out += '\n'; + if (mRenderSurface) { mRenderSurface->dump(out); } else { out.append(" No render surface!\n"); } - android::base::StringAppendF(&out, "\n %zu Layers\n", getOutputLayerCount()); + base::StringAppendF(&out, "\n %zu Layers\n", getOutputLayerCount()); for (const auto* outputLayer : getOutputLayersOrderedByZ()) { if (!outputLayer) { continue; @@ -329,7 +329,7 @@ void Output::dumpBase(std::string& out) const { void Output::dumpPlannerInfo(const Vector& args, std::string& out) const { if (!mPlanner) { - base::StringAppendF(&out, "Planner is disabled\n"); + out.append("Planner is disabled\n"); return; } base::StringAppendF(&out, "Planner info for display [%s]\n", mName.c_str()); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp index 7188281974..3b85e3b5b0 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp @@ -14,40 +14,30 @@ * limitations under the License. */ +#include + #include #include namespace android::compositionengine::impl { -using CompositionStrategyPredictionState = - OutputCompositionState::CompositionStrategyPredictionState; - -std::string toString(CompositionStrategyPredictionState state) { - switch (state) { - case CompositionStrategyPredictionState::DISABLED: - return "Disabled"; - case CompositionStrategyPredictionState::SUCCESS: - return "Success"; - case CompositionStrategyPredictionState::FAIL: - return "Fail"; - } -} void OutputCompositionState::dump(std::string& out) const { out.append(" "); dumpVal(out, "isEnabled", isEnabled); dumpVal(out, "isSecure", isSecure); + dumpVal(out, "usesDeviceComposition", usesDeviceComposition); + out.append("\n "); dumpVal(out, "usesClientComposition", usesClientComposition); - dumpVal(out, "usesDeviceComposition", usesDeviceComposition); dumpVal(out, "flipClientTarget", flipClientTarget); dumpVal(out, "reusedClientComposition", reusedClientComposition); - dumpVal(out, "layerFilter", layerFilter); out.append("\n "); - + dumpVal(out, "layerFilter", layerFilter); + out.append("\n "); dumpVal(out, "transform", transform); - out.append("\n "); + out.append(" "); // ui::Transform::dump appends EOL. dumpVal(out, "layerStackSpace", to_string(layerStackSpace)); out.append("\n "); dumpVal(out, "framebufferSpace", to_string(framebufferSpace)); @@ -59,19 +49,24 @@ void OutputCompositionState::dump(std::string& out) const { dumpVal(out, "needsFiltering", needsFiltering); out.append("\n "); - dumpVal(out, "colorMode", toString(colorMode), colorMode); dumpVal(out, "renderIntent", toString(renderIntent), renderIntent); dumpVal(out, "dataspace", toString(dataspace), dataspace); + dumpVal(out, "targetDataspace", toString(targetDataspace), targetDataspace); + + out.append("\n "); dumpVal(out, "colorTransformMatrix", colorTransformMatrix); - dumpVal(out, "target dataspace", toString(targetDataspace), targetDataspace); + + out.append("\n "); dumpVal(out, "displayBrightnessNits", displayBrightnessNits); dumpVal(out, "sdrWhitePointNits", sdrWhitePointNits); dumpVal(out, "clientTargetBrightness", clientTargetBrightness); dumpVal(out, "displayBrightness", displayBrightness); - dumpVal(out, "compositionStrategyPredictionState", toString(strategyPrediction)); - out.append("\n"); + out.append("\n "); + dumpVal(out, "compositionStrategyPredictionState", ftl::enum_string(strategyPrediction)); + + out += '\n'; } } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 65e7a7f79e..52529d6b04 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -24,7 +24,6 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include #include #include #include @@ -49,8 +48,6 @@ namespace android { namespace hal = hardware::graphics::composer::hal; -using android::base::StringAppendF; - ui::Transform::RotationFlags DisplayDevice::sPrimaryDisplayRotationFlags = ui::Transform::ROT_0; DisplayDeviceCreationArgs::DisplayDeviceCreationArgs( @@ -342,38 +339,40 @@ ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() { } std::string DisplayDevice::getDebugName() const { - const char* type = "virtual"; + using namespace std::string_literals; + + std::string name = "Display "s + to_string(getId()) + " ("s; + if (mConnectionType) { - type = isInternal() ? "internal" : "external"; + name += isInternal() ? "internal"s : "external"s; + } else { + name += "virtual"s; + } + + if (isPrimary()) { + name += ", primary"s; } - return base::StringPrintf("DisplayDevice{%s, %s%s, \"%s\"}", to_string(getId()).c_str(), type, - isPrimary() ? ", primary" : "", mDisplayName.c_str()); + return name + ", \""s + mDisplayName + "\")"s; } void DisplayDevice::dump(std::string& result) const { - StringAppendF(&result, "+ %s\n", getDebugName().c_str()); - StringAppendF(&result, " powerMode=%s (%d)\n", to_string(mPowerMode).c_str(), - static_cast(mPowerMode)); - const auto activeMode = getActiveMode(); - StringAppendF(&result, " activeMode=%s\n", - activeMode ? to_string(*activeMode).c_str() : "none"); - - result.append(" supportedModes=\n"); - for (const auto& [id, mode] : mSupportedModes) { - result.append(" "); - result.append(to_string(*mode)); - result.push_back('\n'); - } + using namespace std::string_literals; - StringAppendF(&result, " deviceProductInfo="); - if (mDeviceProductInfo) { - mDeviceProductInfo->dump(result); - } else { - result.append("{}"); + result += getDebugName(); + + if (!isVirtual()) { + result += "\n deviceProductInfo="s; + if (mDeviceProductInfo) { + mDeviceProductInfo->dump(result); + } else { + result += "{}"s; + } } - result.append("\n"); - getCompositionDisplay()->dump(result); + + result += "\n powerMode="s; + result += to_string(mPowerMode); + result += '\n'; if (mRefreshRateConfigs) { mRefreshRateConfigs->dump(result); diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 8d685cfbdd..eb14933a61 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -44,18 +44,10 @@ #include "HWComposer.h" #include "../SurfaceFlinger.h" -// ---------------------------------------------------------------------------- namespace android { -// ---------------------------------------------------------------------------- using ui::Dataspace; -/* - * This implements the (main) framebuffer management. This class is used - * mostly by SurfaceFlinger, but also by command line GL application. - * - */ - FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId, const sp& consumer, const ui::Size& size, const ui::Size& maxSize) @@ -205,14 +197,14 @@ ui::Size FramebufferSurface::limitSizeInternal(const ui::Size& size, const ui::S void FramebufferSurface::dumpAsString(String8& result) const { Mutex::Autolock lock(mMutex); - result.appendFormat(" FramebufferSurface: dataspace: %s(%d)\n", + result.append(" FramebufferSurface\n"); + result.appendFormat(" mDataSpace=%s (%d)\n", dataspaceDetails(static_cast(mDataSpace)).c_str(), mDataSpace); - ConsumerBase::dumpLocked(result, " "); + ConsumerBase::dumpLocked(result, " "); } -void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const -{ +void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const { ConsumerBase::dumpLocked(result, prefix); } @@ -220,9 +212,7 @@ const sp& FramebufferSurface::getClientTargetAcquireFence() const { return mCurrentFence; } -// ---------------------------------------------------------------------------- -}; // namespace android -// ---------------------------------------------------------------------------- +} // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 3226f22027..ca8349636b 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -133,9 +133,9 @@ bool canModesSupportFrameRateOverride(const std::vector& so } // namespace std::string RefreshRateConfigs::Policy::toString() const { - return base::StringPrintf("default mode ID: %d, allowGroupSwitching = %d" - ", primary range: %s, app request range: %s", - defaultMode.value(), allowGroupSwitching, + return base::StringPrintf("{defaultModeId=%d, allowGroupSwitching=%s" + ", primaryRange=%s, appRequestRange=%s}", + defaultMode.value(), allowGroupSwitching ? "true" : "false", to_string(primaryRange).c_str(), to_string(appRequestRange).c_str()); } @@ -922,41 +922,46 @@ bool RefreshRateConfigs::isFractionalPairOrMultiple(Fps smaller, Fps bigger) { } void RefreshRateConfigs::dump(std::string& result) const { + using namespace std::string_literals; + std::lock_guard lock(mLock); - base::StringAppendF(&result, "DesiredDisplayModeSpecs (DisplayManager): %s\n\n", - mDisplayManagerPolicy.toString().c_str()); - scheduler::RefreshRateConfigs::Policy currentPolicy = *getCurrentPolicyLocked(); - if (mOverridePolicy && currentPolicy != mDisplayManagerPolicy) { - base::StringAppendF(&result, "DesiredDisplayModeSpecs (Override): %s\n\n", - currentPolicy.toString().c_str()); - } - base::StringAppendF(&result, "Active mode: %s\n", to_string(*mActiveModeIt->second).c_str()); + const auto activeModeId = mActiveModeIt->first; + result += " activeModeId="s; + result += std::to_string(activeModeId.value()); - result.append("Display modes:\n"); + result += "\n displayModes=\n"s; for (const auto& [id, mode] : mDisplayModes) { - result.push_back('\t'); - result.append(to_string(*mode)); - result.push_back('\n'); + result += " "s; + result += to_string(*mode); + result += '\n'; } - base::StringAppendF(&result, "Supports Frame Rate Override By Content: %s\n", - mSupportsFrameRateOverrideByContent ? "yes" : "no"); + base::StringAppendF(&result, " displayManagerPolicy=%s\n", + mDisplayManagerPolicy.toString().c_str()); - result.append("Idle timer: "); - if (const auto controller = mConfig.kernelIdleTimerController) { - base::StringAppendF(&result, "(kernel via %s) ", ftl::enum_string(*controller).c_str()); - } else { - result.append("(platform) "); + if (const Policy& currentPolicy = *getCurrentPolicyLocked(); + mOverridePolicy && currentPolicy != mDisplayManagerPolicy) { + base::StringAppendF(&result, " overridePolicy=%s\n", currentPolicy.toString().c_str()); } + base::StringAppendF(&result, " supportsFrameRateOverrideByContent=%s\n", + mSupportsFrameRateOverrideByContent ? "true" : "false"); + + result += " idleTimer="s; if (mIdleTimer) { - result.append(mIdleTimer->dump()); + result += mIdleTimer->dump(); + } else { + result += "off"s; + } + + if (const auto controller = mConfig.kernelIdleTimerController) { + base::StringAppendF(&result, " (kernel via %s)", ftl::enum_string(*controller).c_str()); } else { - result.append("off"); + result += " (platform)"s; } - result.append("\n\n"); + result += '\n'; } std::chrono::milliseconds RefreshRateConfigs::getIdleTimerTimeout() { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f33ea5b983..2616203587 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4941,7 +4941,9 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { pid, uid); } else { static const std::unordered_map dumpers = { + {"--comp-displays"s, dumper(&SurfaceFlinger::dumpCompositionDisplays)}, {"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)}, + {"--displays"s, dumper(&SurfaceFlinger::dumpDisplays)}, {"--dispsync"s, dumper([this](std::string& s) { mScheduler->dumpVsync(s); })}, {"--edid"s, argsDumper(&SurfaceFlinger::dumpRawDisplayIdentificationData)}, {"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)}, @@ -5118,6 +5120,20 @@ void SurfaceFlinger::dumpFrameEventsLocked(std::string& result) { [&] (Layer* layer) { layer->dumpFrameEvents(result); }); } +void SurfaceFlinger::dumpCompositionDisplays(std::string& result) const { + for (const auto& [token, display] : mDisplays) { + display->getCompositionDisplay()->dump(result); + result += '\n'; + } +} + +void SurfaceFlinger::dumpDisplays(std::string& result) const { + for (const auto& [token, display] : mDisplays) { + display->dump(result); + result += '\n'; + } +} + void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const { for (const auto& [token, display] : mDisplays) { const auto displayId = PhysicalDisplayId::tryCast(display->getId()); @@ -5326,21 +5342,12 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co }); } - /* - * Dump Display state - */ - colorizer.bold(result); StringAppendF(&result, "Displays (%zu entries)\n", mDisplays.size()); colorizer.reset(result); - for (const auto& [token, display] : mDisplays) { - display->dump(result); - } - result.append("\n"); - - /* - * Dump CompositionEngine state - */ + dumpDisplays(result); + dumpCompositionDisplays(result); + result.push_back('\n'); mCompositionEngine->dump(result); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6aa54ff966..74e0407215 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1094,9 +1094,13 @@ private: void dumpStaticScreenStats(std::string& result) const; // Not const because each Layer needs to query Fences and cache timestamps. void dumpFrameEventsLocked(std::string& result); + + void dumpCompositionDisplays(std::string& result) const REQUIRES(mStateLock); + void dumpDisplays(std::string& result) const REQUIRES(mStateLock); void dumpDisplayIdentificationData(std::string& result) const REQUIRES(mStateLock); void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const; void dumpWideColorInfo(std::string& result) const REQUIRES(mStateLock); + LayersProto dumpDrawingStateProto(uint32_t traceFlags) const; void dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t traceFlags = LayerTracing::TRACE_ALL) const; -- cgit v1.2.3-59-g8ed1b From dda07d9be6dd032cd1bba422d94fa1fc6af69a4e Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 25 Apr 2022 22:39:25 +0000 Subject: Allow SurfaceFlinger to treat 170M as sRGB. Introduce a debug sysprop, defaulted to false, to allow for rewriting the transfer function to sRGB when set to true. This is due to several considerations: 1. SurfaceFlinger has not color managed SMPTE 170M properly ever since color management was introduced in Android O, and was only fixed in Android 13. This means that some camera -> encoding -> storage -> playback flows may be incorrectly calibrated on some devices since SMPTE 170M was reinterpreted as sRGB for a long time. 2. BT. 1886 recommends a reference EOTF of gamma 2.4 with tuneable parameters to approximate a CRT on a non-CRT display. Because the framework doesn't support BT. 1886 and it's too late to add support, casting as sRGB is probably okay for now and matches old behavior. 3. Typical Rec. 709 content is graded assuming a dim surround, but phone displays are used in a wide range of viewing environments, which means that viewing Rec. 709 content in a bright environment may appear to have lower contrast. Decoding as sRGB will push the dark codes into lower luminance levels, which will improve contrast in those scenarios. Note that it's better to adjust contrast based on the ambient viewing environment, but again it's too late for Android 13 to improve the color pipeline in the GPU. Bug: 229442032 Test: Photos playback after recording a video Change-Id: I64fc8f2ea77f8e595333de36fb9da2979d8316ca --- .../include/compositionengine/Output.h | 3 +++ .../include/compositionengine/impl/Output.h | 1 + .../compositionengine/impl/OutputCompositionState.h | 2 ++ .../include/compositionengine/mock/Output.h | 1 + .../surfaceflinger/CompositionEngine/src/Output.cpp | 4 ++++ .../CompositionEngine/src/OutputCompositionState.cpp | 3 +++ .../CompositionEngine/src/OutputLayer.cpp | 11 +++++++++++ .../CompositionEngine/tests/OutputLayerTest.cpp | 17 +++++++++++++++++ .../CompositionEngine/tests/OutputTest.cpp | 14 ++++++++++++++ services/surfaceflinger/DisplayDevice.cpp | 1 + services/surfaceflinger/Layer.cpp | 13 +++++++++++++ services/surfaceflinger/SurfaceFlinger.cpp | 3 +++ services/surfaceflinger/SurfaceFlinger.h | 6 ++++++ 13 files changed, 79 insertions(+) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 5846e674f5..db2fd1b500 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -267,6 +267,9 @@ public: // Enables predicting composition strategy to run client composition earlier virtual void setPredictCompositionStrategy(bool) = 0; + // Enables overriding the 170M trasnfer function as sRGB + virtual void setTreat170mAsSrgb(bool) = 0; + protected: virtual void setDisplayColorProfile(std::unique_ptr) = 0; virtual void setRenderSurface(std::unique_ptr) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 0feb9f7fb7..31c51e6a8d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -108,6 +108,7 @@ public: void cacheClientCompositionRequests(uint32_t) override; bool canPredictCompositionStrategy(const CompositionRefreshArgs&) override; void setPredictCompositionStrategy(bool) override; + void setTreat170mAsSrgb(bool) override; // Testing const ReleasedLayers& getReleasedLayersForTest() const; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 61be983480..c65d467b0d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -162,6 +162,8 @@ struct OutputCompositionState { CompositionStrategyPredictionState strategyPrediction = CompositionStrategyPredictionState::DISABLED; + bool treat170mAsSrgb = false; + // Debugging void dump(std::string& result) const; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index fa86076b44..cb9fbad8dd 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -132,6 +132,7 @@ public: MOCK_METHOD1(cacheClientCompositionRequests, void(uint32_t)); MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&)); MOCK_METHOD1(setPredictCompositionStrategy, void(bool)); + MOCK_METHOD1(setTreat170mAsSrgb, void(bool)); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index ec8673177f..4c30f99610 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -1488,6 +1488,10 @@ void Output::setPredictCompositionStrategy(bool predict) { } } +void Output::setTreat170mAsSrgb(bool enable) { + editState().treat170mAsSrgb = enable; +} + bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) { if (!getState().isEnabled || !mHwComposerAsyncWorker) { ALOGV("canPredictCompositionStrategy disabled"); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp index 3b85e3b5b0..948c0c90bf 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp @@ -66,6 +66,9 @@ void OutputCompositionState::dump(std::string& out) const { out.append("\n "); dumpVal(out, "compositionStrategyPredictionState", ftl::enum_string(strategyPrediction)); + out.append("\n "); + dumpVal(out, "treate170mAsSrgb", treat170mAsSrgb); + out += '\n'; } diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 3289d55870..61c53df38d 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -322,6 +322,17 @@ void OutputLayer::updateCompositionState( ? outputState.targetDataspace : layerFEState->dataspace; + // Override the dataspace transfer from 170M to sRGB if the device configuration requests this. + // We do this here instead of in buffer info so that dumpsys can still report layers that are + // using the 170M transfer. Also we only do this if the colorspace is not agnostic for the + // layer, in case the color profile uses a 170M transfer function. + if (outputState.treat170mAsSrgb && !layerFEState->isColorspaceAgnostic && + (state.dataspace & HAL_DATASPACE_TRANSFER_MASK) == HAL_DATASPACE_TRANSFER_SMPTE_170M) { + state.dataspace = static_cast( + (state.dataspace & HAL_DATASPACE_STANDARD_MASK) | + (state.dataspace & HAL_DATASPACE_RANGE_MASK) | HAL_DATASPACE_TRANSFER_SRGB); + } + // For hdr content, treat the white point as the display brightness - HDR content should not be // boosted or dimmed. // If the layer explicitly requests to disable dimming, then don't dim either. diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index ceee48c1ef..ca4f39729a 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -657,6 +657,23 @@ TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceCorrectly EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace); } +TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceWith170mReplacement) { + mLayerFEState.dataspace = ui::Dataspace::TRANSFER_SMPTE_170M; + mOutputState.targetDataspace = ui::Dataspace::V0_SCRGB; + mOutputState.treat170mAsSrgb = false; + mLayerFEState.isColorspaceAgnostic = false; + + mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0); + + EXPECT_EQ(ui::Dataspace::TRANSFER_SMPTE_170M, mOutputLayer.getState().dataspace); + + // Rewrite SMPTE 170M as sRGB + mOutputState.treat170mAsSrgb = true; + mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0); + + EXPECT_EQ(ui::Dataspace::TRANSFER_SRGB, mOutputLayer.getState().dataspace); +} + TEST_F(OutputLayerUpdateCompositionStateTest, setsWhitePointNitsAndDimmingRatioCorrectly) { mOutputState.sdrWhitePointNits = 200.f; mOutputState.displayBrightnessNits = 800.f; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 42c8b37710..3a3c91e518 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -247,6 +247,20 @@ TEST_F(OutputTest, setCompositionEnabledSetsDisabledAndDirtiesEntireOutput) { EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } +/* + * Output::setTreat170mAsSrgb() + */ + +TEST_F(OutputTest, setTreat170mAsSrgb) { + EXPECT_FALSE(mOutput->getState().treat170mAsSrgb); + + mOutput->setTreat170mAsSrgb(true); + EXPECT_TRUE(mOutput->getState().treat170mAsSrgb); + + mOutput->setTreat170mAsSrgb(false); + EXPECT_FALSE(mOutput->getState().treat170mAsSrgb); +} + /* * Output::setLayerCachingEnabled() */ diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 52529d6b04..a915b615d9 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -89,6 +89,7 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) } mCompositionDisplay->setPredictCompositionStrategy(mFlinger->mPredictCompositionStrategy); + mCompositionDisplay->setTreat170mAsSrgb(mFlinger->mTreat170mAsSrgb); mCompositionDisplay->createDisplayColorProfile( compositionengine::DisplayColorProfileCreationArgsBuilder() .setHasWideColorGamut(args.hasWideColorGamut) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 3a92ca49a2..e1eec8b97e 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -600,6 +601,18 @@ std::optional Layer::prepareClientCom layerSettings.alpha = alpha; layerSettings.sourceDataspace = getDataSpace(); + // Override the dataspace transfer from 170M to sRGB if the device configuration requests this. + // We do this here instead of in buffer info so that dumpsys can still report layers that are + // using the 170M transfer. + if (mFlinger->mTreat170mAsSrgb && + (layerSettings.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) == + HAL_DATASPACE_TRANSFER_SMPTE_170M) { + layerSettings.sourceDataspace = static_cast( + (layerSettings.sourceDataspace & HAL_DATASPACE_STANDARD_MASK) | + (layerSettings.sourceDataspace & HAL_DATASPACE_RANGE_MASK) | + HAL_DATASPACE_TRANSFER_SRGB); + } + layerSettings.whitePointNits = targetSettings.whitePointNits; switch (targetSettings.blurSetting) { case LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled: diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d39176be14..65c1c97efb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -419,6 +419,9 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("debug.sf.predict_hwc_composition_strategy", value, "1"); mPredictCompositionStrategy = atoi(value); + property_get("debug.sf.treat_170m_as_sRGB", value, "0"); + mTreat170mAsSrgb = atoi(value); + // We should be reading 'persist.sys.sf.color_saturation' here // but since /data may be encrypted, we need to wait until after vold // comes online to attempt to read the property. The property is diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 74e0407215..c70e1749ff 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -349,6 +349,12 @@ public: // run parallel to the hwc validateDisplay call and re-run if the predition is incorrect. bool mPredictCompositionStrategy = false; + // If true, then any layer with a SMPTE 170M transfer function is decoded using the sRGB + // transfer instead. This is mainly to preserve legacy behavior, where implementations treated + // SMPTE 170M as sRGB prior to color management being implemented, and now implementations rely + // on this behavior to increase contrast for some media sources. + bool mTreat170mAsSrgb = false; + protected: // We're reference counted, never destroy SurfaceFlinger directly virtual ~SurfaceFlinger(); -- cgit v1.2.3-59-g8ed1b