From c7ef21b0b83f6f215e81f3fd676137cfa820c162 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Tue, 29 Jan 2019 18:43:00 -0800 Subject: SF: Move/Refactor LayersNeedingFences Refactors the logic for handling layers that are being released by the current display refresh. This is in preparation for moving the logic over to CompositionEngine. Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: I52725b1310ecb324e2c1367f0cbd2eddafacbc4a --- services/surfaceflinger/DisplayDevice.cpp | 8 -------- 1 file changed, 8 deletions(-) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 4a13bfb7ae..d1365627cf 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -126,14 +126,6 @@ const Vector< sp >& DisplayDevice::getVisibleLayersSortedByZ() const { return mVisibleLayersSortedByZ; } -void DisplayDevice::setLayersNeedingFences(const Vector< sp >& layers) { - mLayersNeedingFences = layers; -} - -const Vector< sp >& DisplayDevice::getLayersNeedingFences() const { - return mLayersNeedingFences; -} - // ---------------------------------------------------------------------------- void DisplayDevice::setPowerMode(int mode) { mPowerMode = mode; -- cgit v1.2.3-59-g8ed1b From 688abd459a80ad7ec491eae024c330265f8fcc16 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Fri, 15 Feb 2019 15:42:24 -0800 Subject: SF: Move doComposeSurfaces to CompositionEngine Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: Iae3377a5ea018f9ec53c5a76ed6a86620f39b731 --- services/surfaceflinger/BufferLayer.cpp | 2 +- .../surfaceflinger/CompositionEngine/Android.bp | 1 + .../compositionengine/DisplayCreationArgs.h | 9 + .../include/compositionengine/LayerFE.h | 2 +- .../compositionengine/LayerFECompositionState.h | 6 + .../include/compositionengine/Output.h | 14 ++ .../include/compositionengine/OutputLayer.h | 3 + .../include/compositionengine/impl/Display.h | 5 + .../include/compositionengine/impl/Output.h | 7 + .../include/compositionengine/impl/OutputLayer.h | 1 + .../include/compositionengine/mock/Output.h | 9 + .../include/compositionengine/mock/OutputLayer.h | 1 + .../CompositionEngine/src/Display.cpp | 21 ++- .../src/LayerCompositionState.cpp | 2 + .../CompositionEngine/src/Output.cpp | 188 +++++++++++++++++++- .../CompositionEngine/src/OutputLayer.cpp | 7 + .../CompositionEngine/tests/DisplayTest.cpp | 37 +++- .../CompositionEngine/tests/MockPowerAdvisor.cpp | 34 ++++ .../CompositionEngine/tests/MockPowerAdvisor.h | 37 ++++ .../CompositionEngine/tests/OutputLayerTest.cpp | 18 ++ services/surfaceflinger/DisplayDevice.cpp | 2 +- services/surfaceflinger/DisplayDevice.h | 2 + services/surfaceflinger/Layer.cpp | 8 +- services/surfaceflinger/SurfaceFlinger.cpp | 194 +-------------------- services/surfaceflinger/SurfaceFlinger.h | 6 - 25 files changed, 411 insertions(+), 205 deletions(-) create mode 100644 services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp create mode 100644 services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 87bec11609..13c748f24c 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -167,7 +167,7 @@ std::optional BufferLayer::prepareClientComposition } return std::nullopt; } - bool blackOutLayer = (isProtected() && !targetSettings.supportProtectedContent) || + bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) || (isSecure() && !targetSettings.isSecure); const State& s(getDrawingState()); auto& layer = *result; diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 6f076ad11f..ae6bdbce60 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -94,6 +94,7 @@ cc_test { "tests/LayerTest.cpp", "tests/MockHWC2.cpp", "tests/MockHWComposer.cpp", + "tests/MockPowerAdvisor.cpp", "tests/OutputTest.cpp", "tests/OutputLayerTest.cpp", "tests/RenderSurfaceTest.cpp", diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h index 0b6b4e4f0f..0778936d24 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h @@ -20,6 +20,7 @@ #include #include "DisplayHardware/DisplayIdentification.h" +#include "DisplayHardware/PowerAdvisor.h" namespace android::compositionengine { @@ -37,6 +38,10 @@ struct DisplayCreationArgs { // Identifies the display to the HWC, if composition is supported by it std::optional displayId; + + // Optional pointer to the power advisor interface, if one is needed for + // this display. + Hwc2::PowerAdvisor* powerAdvisor = nullptr; }; /** @@ -68,6 +73,10 @@ public: mArgs.displayId = displayId; return *this; } + DisplayCreationArgsBuilder& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) { + mArgs.powerAdvisor = powerAdvisor; + return *this; + } private: DisplayCreationArgs mArgs; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index 94fab1fdf6..2a901ae68b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -59,7 +59,7 @@ public: const bool isSecure; // If set to true, the target buffer has protected content support. - const bool supportProtectedContent; + const bool supportsProtectedContent; // Modified by each call to prepareClientComposition to indicate the // region of the target buffer that should be cleared. diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index d96d58c1fa..d5763d5611 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -116,6 +116,12 @@ struct LayerFECompositionState { // The color transform mat4 colorTransform; bool colorTransformIsIdentity{true}; + + // True if the layer is completely opaque + bool isOpaque{true}; + + // True if the layer has protected content + bool hasProtectedContent{false}; }; } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 4dfcfa4593..f73304d211 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -156,6 +157,12 @@ public: // Prepares a frame for display virtual void prepareFrame() = 0; + // Performs client composition as needed for layers on the output. The + // output fence is set to a fence to signal when client composition is + // finished. + // Returns false if client composition cannot be performed. + virtual bool composeSurfaces(const Region& debugFence, base::unique_fd* outReadyFence) = 0; + // Posts the new frame, and sets release fences. virtual void postFramebuffer() = 0; @@ -163,7 +170,14 @@ protected: virtual void setDisplayColorProfile(std::unique_ptr) = 0; virtual void setRenderSurface(std::unique_ptr) = 0; virtual void chooseCompositionStrategy() = 0; + virtual bool getSkipColorTransform() const = 0; virtual FrameFences presentAndGetFrameFences() = 0; + virtual std::vector generateClientCompositionRequests( + bool supportsProtectedContent, Region& clearRegion) = 0; + virtual void appendRegionFlashRequests( + const Region& flashRegion, + std::vector& clientCompositionLayers) = 0; + virtual void setExpensiveRenderingExpected(bool enabled) = 0; }; } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h index d7f00a978a..5f62b32c9a 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -93,6 +93,9 @@ public: // Applies a HWC device layer request virtual void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) = 0; + // Returns true if the composition settings scale pixels + virtual bool needsFiltering() const = 0; + // Debugging virtual void dump(std::string& result) const = 0; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index 795061af28..36e4aac76e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -23,6 +23,7 @@ #include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/HWComposer.h" +#include "DisplayHardware/PowerAdvisor.h" namespace android::compositionengine { @@ -42,7 +43,9 @@ public: void setColorTransform(const mat4&) override; void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override; void chooseCompositionStrategy() override; + bool getSkipColorTransform() const override; compositionengine::Output::FrameFences presentAndGetFrameFences() override; + void setExpensiveRenderingExpected(bool) override; // compositionengine::Display overrides const std::optional& getId() const override; @@ -65,9 +68,11 @@ public: private: const bool mIsVirtual; std::optional mId; + Hwc2::PowerAdvisor* const mPowerAdvisor{nullptr}; }; std::shared_ptr createDisplay(const compositionengine::CompositionEngine&, compositionengine::DisplayCreationArgs&&); + } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 5f4a76440c..3972f2bcf4 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -77,6 +77,7 @@ public: void beginFrame() override; void prepareFrame() override; + bool composeSurfaces(const Region&, base::unique_fd*) override; void postFramebuffer() override; // Testing @@ -86,7 +87,13 @@ public: protected: const CompositionEngine& getCompositionEngine() const; void chooseCompositionStrategy() override; + bool getSkipColorTransform() const override; compositionengine::Output::FrameFences presentAndGetFrameFences() override; + std::vector generateClientCompositionRequests( + bool supportsProtectedContent, Region& clearRegion) override; + void appendRegionFlashRequests(const Region&, + std::vector&) override; + void setExpensiveRenderingExpected(bool enabled) override; void dumpBase(std::string&) const; private: diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index d8ad02aca3..4c3f9359b0 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -55,6 +55,7 @@ public: void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) override; void prepareForDeviceLayerRequests() override; void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override; + bool needsFiltering() const override; void dump(std::string& result) const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index d494413af5..c944becd22 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -77,8 +77,17 @@ public: MOCK_METHOD0(prepareFrame, void()); MOCK_METHOD0(chooseCompositionStrategy, void()); + MOCK_METHOD2(composeSurfaces, bool(const Region&, base::unique_fd*)); + MOCK_CONST_METHOD0(getSkipColorTransform, bool()); + MOCK_METHOD0(postFramebuffer, void()); MOCK_METHOD0(presentAndGetFrameFences, compositionengine::Output::FrameFences()); + + MOCK_METHOD2(generateClientCompositionRequests, + std::vector(bool, Region&)); + MOCK_METHOD2(appendRegionFlashRequests, + void(const Region&, std::vector&)); + MOCK_METHOD1(setExpensiveRenderingExpected, void(bool)); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h index 195648ff7c..d8d637d302 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h @@ -46,6 +46,7 @@ public: MOCK_METHOD1(applyDeviceCompositionTypeChange, void(Hwc2::IComposerClient::Composition)); MOCK_METHOD0(prepareForDeviceLayerRequests, void()); MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request)); + MOCK_CONST_METHOD0(needsFiltering, bool()); MOCK_CONST_METHOD1(dump, void(std::string&)); }; diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 68319013d7..6cd392eabd 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -26,6 +26,7 @@ #include #include "DisplayHardware/HWComposer.h" +#include "DisplayHardware/PowerAdvisor.h" namespace android::compositionengine::impl { @@ -38,7 +39,8 @@ std::shared_ptr createDisplay( Display::Display(const CompositionEngine& compositionEngine, DisplayCreationArgs&& args) : compositionengine::impl::Output(compositionEngine), mIsVirtual(args.isVirtual), - mId(args.displayId) { + mId(args.displayId), + mPowerAdvisor(args.powerAdvisor) { editState().isSecure = args.isSecure; } @@ -160,6 +162,15 @@ void Display::chooseCompositionStrategy() { state.usesDeviceComposition = !allLayersRequireClientComposition(); } +bool Display::getSkipColorTransform() const { + if (!mId) { + return false; + } + + auto& hwc = getCompositionEngine().getHwComposer(); + return hwc.hasDisplayCapability(*mId, HWC2::DisplayCapability::SkipClientColorTransform); +} + bool Display::anyLayersRequireClientComposition() const { const auto& layers = getOutputLayersOrderedByZ(); return std::any_of(layers.cbegin(), layers.cend(), @@ -240,4 +251,12 @@ compositionengine::Output::FrameFences Display::presentAndGetFrameFences() { return result; } +void Display::setExpensiveRenderingExpected(bool enabled) { + Output::setExpensiveRenderingExpected(enabled); + + if (mPowerAdvisor && mId) { + mPowerAdvisor->setExpensiveRenderingExpected(*mId, enabled); + } +} + } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp index 37d6eaa2f2..0dc4bf1559 100644 --- a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp @@ -71,6 +71,8 @@ void dumpFrontEnd(std::string& out, const LayerFECompositionState& state) { dumpVal(out, "color", state.color); out.append("\n "); + dumpVal(out, "isOpaque", state.isOpaque); + dumpVal(out, "hasProtectedContent", state.hasProtectedContent); dumpVal(out, "isColorspaceAgnostic", state.isColorspaceAgnostic); dumpVal(out, "dataspace", toString(state.dataspace), state.dataspace); dumpVal(out, "hdr metadata types", state.hdrMetadata.validTypes); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 6878e99b72..fb576e06f8 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -17,13 +17,20 @@ #include #include #include +#include #include #include +#include #include #include +#include +#include #include +#include #include +#include "TracedOrdinal.h" + namespace android::compositionengine { Output::~Output() = default; @@ -73,10 +80,10 @@ void Output::setProjection(const ui::Transform& transform, int32_t orientation, dirtyEntireOutput(); } -// TODO(lpique): Rename setSize() once more is moved. +// TODO(b/121291683): Rename setSize() once more is moved. void Output::setBounds(const ui::Size& size) { mRenderSurface->setDisplaySize(size); - // TODO(lpique): Rename mState.size once more is moved. + // TODO(b/121291683): Rename mState.size once more is moved. mState.bounds = Rect(mRenderSurface->getSize()); dirtyEntireOutput(); @@ -292,6 +299,179 @@ void Output::prepareFrame() { mRenderSurface->prepareFrame(mState.usesClientComposition, mState.usesDeviceComposition); } +bool Output::composeSurfaces(const Region& debugRegion, base::unique_fd* readyFence) { + ATRACE_CALL(); + ALOGV(__FUNCTION__); + + const TracedOrdinal hasClientComposition = {"hasClientComposition", + mState.usesClientComposition}; + if (!hasClientComposition) { + return true; + } + + ALOGV("hasClientComposition"); + + auto& renderEngine = mCompositionEngine.getRenderEngine(); + const bool supportsProtectedContent = renderEngine.supportsProtectedContent(); + + renderengine::DisplaySettings clientCompositionDisplay; + clientCompositionDisplay.physicalDisplay = mState.frame; + clientCompositionDisplay.clip = mState.scissor; + clientCompositionDisplay.globalTransform = mState.transform.asMatrix4(); + clientCompositionDisplay.orientation = mState.orientation; + clientCompositionDisplay.outputDataspace = + mDisplayColorProfile->hasWideColorGamut() ? mState.dataspace : ui::Dataspace::UNKNOWN; + clientCompositionDisplay.maxLuminance = + mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance(); + + // Compute the global color transform matrix. + if (!mState.usesDeviceComposition && !getSkipColorTransform()) { + clientCompositionDisplay.colorTransform = mState.colorTransformMat; + } + + // Note: Updated by generateClientCompositionRequests + clientCompositionDisplay.clearRegion = Region::INVALID_REGION; + + // Generate the client composition requests for the layers on this output. + std::vector clientCompositionLayers = + generateClientCompositionRequests(supportsProtectedContent, + clientCompositionDisplay.clearRegion); + appendRegionFlashRequests(debugRegion, clientCompositionLayers); + + // If we the display is secure, protected content support is enabled, and at + // least one layer has protected content, we need to use a secure back + // buffer. + if (mState.isSecure && supportsProtectedContent) { + bool needsProtected = + std::any_of(mOutputLayersOrderedByZ.begin(), mOutputLayersOrderedByZ.end(), + [](auto& layer) { + return layer->getLayer().getState().frontEnd.hasProtectedContent; + }); + if (needsProtected != renderEngine.isProtected()) { + renderEngine.useProtectedContext(needsProtected); + } + if (needsProtected != mRenderSurface->isProtected() && + needsProtected == renderEngine.isProtected()) { + mRenderSurface->setProtected(needsProtected); + } + } + + base::unique_fd fd; + sp buf = mRenderSurface->dequeueBuffer(&fd); + if (buf == nullptr) { + ALOGW("Dequeuing buffer for display [%s] failed, bailing out of " + "client composition for this frame", + mName.c_str()); + return false; + } + + // We boost GPU frequency here because there will be color spaces conversion + // and it's expensive. We boost the GPU frequency so that GPU composition can + // finish in time. We must reset GPU frequency afterwards, because high frequency + // consumes extra battery. + const bool expensiveRenderingExpected = + clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3; + if (expensiveRenderingExpected) { + setExpensiveRenderingExpected(true); + } + + renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers, + buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd), + readyFence); + + if (expensiveRenderingExpected) { + setExpensiveRenderingExpected(false); + } + + return true; +} + +std::vector Output::generateClientCompositionRequests( + bool supportsProtectedContent, Region& clearRegion) { + std::vector clientCompositionLayers; + ALOGV("Rendering client layers"); + + const Region viewportRegion(mState.viewport); + const bool useIdentityTransform = false; + bool firstLayer = true; + // Used when a layer clears part of the buffer. + Region dummyRegion; + + for (auto& layer : mOutputLayersOrderedByZ) { + const auto& layerState = layer->getState(); + const auto& layerFEState = layer->getLayer().getState().frontEnd; + auto& layerFE = layer->getLayerFE(); + + const Region clip(viewportRegion.intersect(layer->getState().visibleRegion)); + ALOGV("Layer: %s", layerFE.getDebugName()); + if (clip.isEmpty()) { + ALOGV(" Skipping for empty clip"); + firstLayer = false; + continue; + } + + bool clientComposition = layer->requiresClientComposition(); + + // We clear the client target for non-client composed layers if + // requested by the HWC. We skip this if the layer is not an opaque + // rectangle, as by definition the layer must blend with whatever is + // underneath. We also skip the first layer as the buffer target is + // guaranteed to start out cleared. + bool clearClientComposition = + layerState.clearClientTarget && layerFEState.isOpaque && !firstLayer; + + ALOGV(" Composition type: client %d clear %d", clientComposition, clearClientComposition); + + if (clientComposition || clearClientComposition) { + compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{ + clip, + useIdentityTransform, + layer->needsFiltering() || mState.needsFiltering, + mState.isSecure, + supportsProtectedContent, + clientComposition ? clearRegion : dummyRegion, + }; + if (auto result = layerFE.prepareClientComposition(targetSettings)) { + if (clearClientComposition) { + auto& layerSettings = *result; + layerSettings.source.buffer.buffer = nullptr; + layerSettings.source.solidColor = half3(0.0, 0.0, 0.0); + layerSettings.alpha = half(0.0); + layerSettings.disableBlending = true; + } + + clientCompositionLayers.push_back(*result); + } + } + + firstLayer = false; + } + + return clientCompositionLayers; +} + +void Output::appendRegionFlashRequests( + const Region& flashRegion, + std::vector& clientCompositionLayers) { + if (flashRegion.isEmpty()) { + return; + } + + renderengine::LayerSettings layerSettings; + layerSettings.source.buffer.buffer = nullptr; + layerSettings.source.solidColor = half3(1.0, 0.0, 1.0); + layerSettings.alpha = half(1.0); + + for (const auto& rect : flashRegion) { + layerSettings.geometry.boundaries = rect.toFloatRect(); + clientCompositionLayers.push_back(layerSettings); + } +} + +void Output::setExpensiveRenderingExpected(bool) { + // The base class does nothing with this call. +} + void Output::postFramebuffer() { ATRACE_CALL(); ALOGV(__FUNCTION__); @@ -353,6 +533,10 @@ void Output::chooseCompositionStrategy() { mState.usesDeviceComposition = false; } +bool Output::getSkipColorTransform() const { + return true; +} + compositionengine::Output::FrameFences Output::presentAndGetFrameFences() { compositionengine::Output::FrameFences result; if (mState.usesClientComposition) { diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 6e744b948f..e721cf5375 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -614,6 +614,13 @@ void OutputLayer::applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest re } } +bool OutputLayer::needsFiltering() const { + const auto& displayFrame = mState.displayFrame; + const auto& sourceCrop = mState.sourceCrop; + return sourceCrop.getHeight() != displayFrame.getHeight() || + sourceCrop.getWidth() != displayFrame.getWidth(); +} + void OutputLayer::dump(std::string& out) const { using android::base::StringAppendF; diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index e3be0d7a9c..743da8207a 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -30,6 +30,7 @@ #include "MockHWC2.h" #include "MockHWComposer.h" +#include "MockPowerAdvisor.h" namespace android::compositionengine { namespace { @@ -59,6 +60,7 @@ struct DisplayTest : public testing::Test { } StrictMock mHwComposer; + StrictMock mPowerAdvisor; StrictMock mCompositionEngine; sp mNativeWindow = new StrictMock(); StrictMock mHWC2Layer1; @@ -68,7 +70,10 @@ struct DisplayTest : public testing::Test { mock::OutputLayer* mLayer2 = new StrictMock(); mock::OutputLayer* mLayer3 = new StrictMock(); impl::Display mDisplay{mCompositionEngine, - DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()}; + DisplayCreationArgsBuilder() + .setDisplayId(DEFAULT_DISPLAY_ID) + .setPowerAdvisor(&mPowerAdvisor) + .build()}; }; /* @@ -343,6 +348,24 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { EXPECT_TRUE(state.usesDeviceComposition); } +/* + * Display::getSkipColorTransform() + */ + +TEST_F(DisplayTest, getSkipColorTransformDoesNothingIfNonHwcDisplay) { + auto nonHwcDisplay{ + impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; + EXPECT_FALSE(nonHwcDisplay->getSkipColorTransform()); +} + +TEST_F(DisplayTest, getSkipColorTransformChecksHwcCapability) { + EXPECT_CALL(mHwComposer, + hasDisplayCapability(std::make_optional(DEFAULT_DISPLAY_ID), + HWC2::DisplayCapability::SkipClientColorTransform)) + .WillOnce(Return(true)); + EXPECT_TRUE(mDisplay.getSkipColorTransform()); +} + /* * Display::anyLayersRequireClientComposition() */ @@ -502,5 +525,17 @@ TEST_F(DisplayTest, presentAndGetFrameFencesReturnsPresentAndLayerFences) { EXPECT_EQ(layer2Fence, result.layerFences[&mHWC2Layer2]); } +/* + * Display::setExpensiveRenderingExpected() + */ + +TEST_F(DisplayTest, setExpensiveRenderingExpectedForwardsToPowerAdvisor) { + EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, true)).Times(1); + mDisplay.setExpensiveRenderingExpected(true); + + EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, false)).Times(1); + mDisplay.setExpensiveRenderingExpected(false); +} + } // namespace } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp new file mode 100644 index 0000000000..85b94031c3 --- /dev/null +++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp @@ -0,0 +1,34 @@ +/* + * Copyright 2019 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 "MockPowerAdvisor.h" + +namespace android { +namespace Hwc2 { + +// This will go away once PowerAdvisor is moved into the "backend" library +PowerAdvisor::~PowerAdvisor() = default; + +namespace mock { + +// The Google Mock documentation recommends explicit non-header instantiations +// for better compile time performance. +PowerAdvisor::PowerAdvisor() = default; +PowerAdvisor::~PowerAdvisor() = default; + +} // namespace mock +} // namespace Hwc2 +} // namespace android diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h new file mode 100644 index 0000000000..c5a73f22f9 --- /dev/null +++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h @@ -0,0 +1,37 @@ +/* + * Copyright 2019 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 "DisplayHardware/PowerAdvisor.h" + +namespace android { +namespace Hwc2 { +namespace mock { + +class PowerAdvisor : public android::Hwc2::PowerAdvisor { +public: + PowerAdvisor(); + ~PowerAdvisor() override; + + MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected)); +}; + +} // namespace mock +} // namespace Hwc2 +} // namespace android diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index a5428ad993..c83cae65fb 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -875,5 +875,23 @@ TEST_F(OutputLayerTest, applyDeviceLayerRequestHandlesUnknownRequest) { EXPECT_FALSE(mOutputLayer.getState().clearClientTarget); } +/* + * OutputLayer::needsFiltering() + */ + +TEST_F(OutputLayerTest, needsFilteringReturnsFalseIfDisplaySizeSameAsSourceSize) { + mOutputLayer.editState().displayFrame = Rect(100, 100, 200, 200); + mOutputLayer.editState().sourceCrop = FloatRect{0.f, 0.f, 100.f, 100.f}; + + EXPECT_FALSE(mOutputLayer.needsFiltering()); +} + +TEST_F(OutputLayerTest, needsFilteringReturnsTrueIfDisplaySizeDifferentFromSourceSize) { + mOutputLayer.editState().displayFrame = Rect(100, 100, 200, 200); + mOutputLayer.editState().sourceCrop = FloatRect{0.f, 0.f, 100.1f, 100.1f}; + + EXPECT_TRUE(mOutputLayer.needsFiltering()); +} + } // namespace } // namespace android::compositionengine diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index d1365627cf..b6d79d41f2 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -60,7 +60,7 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args) mDisplayInstallOrientation(args.displayInstallOrientation), mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay( compositionengine::DisplayCreationArgs{args.isSecure, args.isVirtual, - args.displayId})}, + args.displayId, args.powerAdvisor})}, mIsVirtual(args.isVirtual), mOrientation(), mActiveConfig(0), diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 8bc19d4447..4321e3dd13 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -40,6 +40,7 @@ #include #include "DisplayHardware/DisplayIdentification.h" +#include "DisplayHardware/PowerAdvisor.h" #include "RenderArea.h" namespace android { @@ -241,6 +242,7 @@ struct DisplayDeviceCreationArgs { std::unordered_map> hwcColorModes; int initialPowerMode{HWC_POWER_MODE_NORMAL}; bool isPrimary{false}; + Hwc2::PowerAdvisor* powerAdvisor{nullptr}; }; class DisplayRenderArea : public RenderArea { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index e7fbfe936d..a2ee763c4a 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -440,6 +440,7 @@ void Layer::latchGeometry(compositionengine::LayerFECompositionState& compositio } void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compositionState) const { + const auto& drawingState{getDrawingState()}; compositionState.forceClientComposition = false; // TODO(lpique): b/121291683 Remove this one we are sure we don't need the @@ -451,9 +452,14 @@ void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compo compositionState.colorTransform = getColorTransform(); compositionState.colorTransformIsIdentity = !hasColorTransform(); compositionState.surfaceDamage = surfaceDamageRegion; + compositionState.hasProtectedContent = isProtected(); + + const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f; + compositionState.isOpaque = + isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf; // Force client composition for special cases known only to the front-end. - if (isHdrY410() || getRoundedCornerState().radius > 0.0f) { + if (isHdrY410() || usesRoundedCorners) { compositionState.forceClientComposition = true; } } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d2d9ea5d26..af4fa98b0d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1943,7 +1943,7 @@ void SurfaceFlinger::doDebugFlashRegions(const sp& displayDevice, if (!dirtyRegion.isEmpty()) { base::unique_fd readyFence; // redraw the whole screen - doComposeSurfaces(displayDevice, dirtyRegion, &readyFence); + display->composeSurfaces(dirtyRegion, &readyFence); display->getRenderSurface()->queueBuffer(std::move(readyFence)); } @@ -2488,6 +2488,7 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( creationArgs.displaySurface = dispSurface; creationArgs.hasWideColorGamut = false; creationArgs.supportedPerFrameMetadata = 0; + creationArgs.powerAdvisor = displayId ? &mPowerAdvisor : nullptr; const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked(); creationArgs.isPrimary = isInternalDisplay; @@ -3228,201 +3229,12 @@ void SurfaceFlinger::doDisplayComposition(const sp& displayDevice ALOGV("doDisplayComposition"); base::unique_fd readyFence; - if (!doComposeSurfaces(displayDevice, Region::INVALID_REGION, &readyFence)) return; + if (!display->composeSurfaces(Region::INVALID_REGION, &readyFence)) return; // swap buffers (presentation) display->getRenderSurface()->queueBuffer(std::move(readyFence)); } -bool SurfaceFlinger::doComposeSurfaces(const sp& displayDevice, - const Region& debugRegion, base::unique_fd* readyFence) { - ATRACE_CALL(); - ALOGV("doComposeSurfaces"); - - auto display = displayDevice->getCompositionDisplay(); - const auto& displayState = display->getState(); - const auto displayId = display->getId(); - auto& renderEngine = getRenderEngine(); - const bool supportProtectedContent = renderEngine.supportsProtectedContent(); - - const Region bounds(displayState.bounds); - const DisplayRenderArea renderArea(displayDevice); - const TracedOrdinal hasClientComposition = {"hasClientComposition", - displayState.usesClientComposition}; - bool applyColorMatrix = false; - - renderengine::DisplaySettings clientCompositionDisplay; - std::vector clientCompositionLayers; - sp buf; - base::unique_fd fd; - - if (hasClientComposition) { - ALOGV("hasClientComposition"); - - if (displayDevice->isPrimary() && supportProtectedContent) { - bool needsProtected = false; - for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { - // If the layer is a protected layer, mark protected context is needed. - if (layer->isProtected()) { - needsProtected = true; - break; - } - } - if (needsProtected != renderEngine.isProtected()) { - renderEngine.useProtectedContext(needsProtected); - } - if (needsProtected != display->getRenderSurface()->isProtected() && - needsProtected == renderEngine.isProtected()) { - display->getRenderSurface()->setProtected(needsProtected); - } - } - - buf = display->getRenderSurface()->dequeueBuffer(&fd); - - if (buf == nullptr) { - ALOGW("Dequeuing buffer for display [%s] failed, bailing out of " - "client composition for this frame", - displayDevice->getDisplayName().c_str()); - return false; - } - - clientCompositionDisplay.physicalDisplay = displayState.scissor; - clientCompositionDisplay.clip = displayState.scissor; - const ui::Transform& displayTransform = displayState.transform; - clientCompositionDisplay.globalTransform = displayTransform.asMatrix4(); - clientCompositionDisplay.orientation = displayState.orientation; - - const auto* profile = display->getDisplayColorProfile(); - Dataspace outputDataspace = Dataspace::UNKNOWN; - if (profile->hasWideColorGamut()) { - outputDataspace = displayState.dataspace; - } - clientCompositionDisplay.outputDataspace = outputDataspace; - clientCompositionDisplay.maxLuminance = - profile->getHdrCapabilities().getDesiredMaxLuminance(); - - const bool hasDeviceComposition = displayState.usesDeviceComposition; - const bool skipClientColorTransform = - getHwComposer() - .hasDisplayCapability(displayId, - HWC2::DisplayCapability::SkipClientColorTransform); - - // Compute the global color transform matrix. - applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform; - if (applyColorMatrix) { - clientCompositionDisplay.colorTransform = displayState.colorTransformMat; - } - } - - /* - * and then, render the layers targeted at the framebuffer - */ - - ALOGV("Rendering client layers"); - const bool useIdentityTransform = false; - bool firstLayer = true; - Region clearRegion = Region::INVALID_REGION; - for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) { - const Region viewportRegion(displayState.viewport); - const Region clip(viewportRegion.intersect(layer->visibleRegion)); - ALOGV("Layer: %s", layer->getName().string()); - ALOGV(" Composition type: %s", toString(layer->getCompositionType(displayDevice)).c_str()); - if (!clip.isEmpty()) { - switch (layer->getCompositionType(displayDevice)) { - case Hwc2::IComposerClient::Composition::CURSOR: - case Hwc2::IComposerClient::Composition::DEVICE: - case Hwc2::IComposerClient::Composition::SIDEBAND: - case Hwc2::IComposerClient::Composition::SOLID_COLOR: { - LOG_ALWAYS_FATAL_IF(!displayId); - const Layer::State& state(layer->getDrawingState()); - if (layer->getClearClientTarget(displayDevice) && !firstLayer && - layer->isOpaque(state) && (layer->getAlpha() == 1.0f) && - layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) { - // never clear the very first layer since we're - // guaranteed the FB is already cleared - Region dummyRegion; - compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{ - clip, - useIdentityTransform, - layer->needsFiltering(renderArea.getDisplayDevice()) || - renderArea.needsFiltering(), - renderArea.isSecure(), - supportProtectedContent, - dummyRegion, - }; - auto result = layer->prepareClientComposition(targetSettings); - - if (result) { - auto& layerSettings = *result; - layerSettings.source.buffer.buffer = nullptr; - layerSettings.source.solidColor = half3(0.0, 0.0, 0.0); - layerSettings.alpha = half(0.0); - layerSettings.disableBlending = true; - clientCompositionLayers.push_back(layerSettings); - } - } - break; - } - case Hwc2::IComposerClient::Composition::CLIENT: { - compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{ - clip, - useIdentityTransform, - layer->needsFiltering(renderArea.getDisplayDevice()) || - renderArea.needsFiltering(), - renderArea.isSecure(), - supportProtectedContent, - clearRegion, - }; - auto result = layer->prepareClientComposition(targetSettings); - if (result) { - clientCompositionLayers.push_back(*result); - } - break; - } - default: - break; - } - } else { - ALOGV(" Skipping for empty clip"); - } - firstLayer = false; - } - - // Perform some cleanup steps if we used client composition. - if (hasClientComposition) { - clientCompositionDisplay.clearRegion = clearRegion; - - // We boost GPU frequency here because there will be color spaces conversion - // and it's expensive. We boost the GPU frequency so that GPU composition can - // finish in time. We must reset GPU frequency afterwards, because high frequency - // consumes extra battery. - const bool expensiveRenderingExpected = - clientCompositionDisplay.outputDataspace == Dataspace::DISPLAY_P3; - if (expensiveRenderingExpected && displayId) { - mPowerAdvisor.setExpensiveRenderingExpected(*displayId, true); - } - if (!debugRegion.isEmpty()) { - Region::const_iterator it = debugRegion.begin(); - Region::const_iterator end = debugRegion.end(); - while (it != end) { - const Rect& rect = *it++; - renderengine::LayerSettings layerSettings; - layerSettings.source.buffer.buffer = nullptr; - layerSettings.source.solidColor = half3(1.0, 0.0, 1.0); - layerSettings.geometry.boundaries = rect.toFloatRect(); - layerSettings.alpha = half(1.0); - clientCompositionLayers.push_back(layerSettings); - } - } - renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers, - buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd), - readyFence); - } else if (displayId) { - mPowerAdvisor.setExpensiveRenderingExpected(*displayId, false); - } - return true; -} - status_t SurfaceFlinger::addClientLayer(const sp& client, const sp& handle, const sp& gbc, const sp& lbc, const sp& parentHandle, diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 64e87b14ed..ef096f85a5 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -768,12 +768,6 @@ private: void logLayerStats(); void doDisplayComposition(const sp& display, const Region& dirtyRegion); - // This fails if using GL and the surface has been destroyed. readyFence - // will be populated if using GL and native fence sync is supported, to - // signal when drawing has completed. - bool doComposeSurfaces(const sp& display, const Region& debugRegionm, - base::unique_fd* readyFence); - void postFrame(); /* ------------------------------------------------------------------------ -- cgit v1.2.3-59-g8ed1b From 306299821902c05dfc3121a7201404ac465419ee Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Thu, 7 Mar 2019 21:20:05 -0800 Subject: SF: Remove DisplayDevice visible layer members There are no longer any consumers of it, so the data and related functions are removed, and the bit of code that was still setting it is removed. Test: atest libsurfaceflinger_unittest libcompositionengine_test Bug: 121291683 Change-Id: If09254dc44645b816d88b89cda64284822dd43ed --- services/surfaceflinger/DisplayDevice.cpp | 11 ----------- services/surfaceflinger/DisplayDevice.h | 6 ------ services/surfaceflinger/SurfaceFlinger.cpp | 5 ----- services/surfaceflinger/tests/unittests/CompositionTest.cpp | 5 ----- 4 files changed, 27 deletions(-) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index b6d79d41f2..2ada86beca 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -116,16 +116,6 @@ uint32_t DisplayDevice::getPageFlipCount() const { return mCompositionDisplay->getRenderSurface()->getPageFlipCount(); } -// ---------------------------------------------------------------------------- - -void DisplayDevice::setVisibleLayersSortedByZ(const Vector< sp >& layers) { - mVisibleLayersSortedByZ = layers; -} - -const Vector< sp >& DisplayDevice::getVisibleLayersSortedByZ() const { - return mVisibleLayersSortedByZ; -} - // ---------------------------------------------------------------------------- void DisplayDevice::setPowerMode(int mode) { mPowerMode = mode; @@ -291,7 +281,6 @@ void DisplayDevice::dump(std::string& result) const { result.append(" "); StringAppendF(&result, "powerMode=%d, ", mPowerMode); StringAppendF(&result, "activeConfig=%d, ", mActiveConfig); - StringAppendF(&result, "numLayers=%zu\n", mVisibleLayersSortedByZ.size()); getCompositionDisplay()->dump(result); } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 4321e3dd13..52773204b9 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -87,9 +87,6 @@ public: int getHeight() const; int getInstallOrientation() const { return mDisplayInstallOrientation; } - void setVisibleLayersSortedByZ(const Vector< sp >& layers); - const Vector< sp >& getVisibleLayersSortedByZ() const; - void setLayerStack(uint32_t stack); void setDisplaySize(const int newWidth, const int newHeight); void setProjection(int orientation, const Rect& viewport, const Rect& frame); @@ -179,9 +176,6 @@ private: * don't need synchronization. */ - // list of visible layers on that display - Vector< sp > mVisibleLayersSortedByZ; - /* * Transaction state */ diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 34981aebb1..50440e8d3b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2093,7 +2093,6 @@ void SurfaceFlinger::rebuildLayerStacks() { Region dirtyRegion; compositionengine::Output::OutputLayers layersSortedByZ; compositionengine::Output::ReleasedLayers releasedLayers; - Vector> deprecated_layersSortedByZ; const ui::Transform& tr = displayState.transform; const Rect bounds = displayState.bounds; if (displayState.isEnabled) { @@ -2125,8 +2124,6 @@ void SurfaceFlinger::rebuildLayerStacks() { layersSortedByZ.emplace_back( display->getOrCreateOutputLayer(displayId, compositionLayer, layerFE)); - deprecated_layersSortedByZ.add(layer); - auto& outputLayerState = layersSortedByZ.back()->editState(); outputLayerState.visibleRegion = tr.transform(layer->visibleRegion.intersect(displayState.viewport)); @@ -2150,8 +2147,6 @@ void SurfaceFlinger::rebuildLayerStacks() { display->setOutputLayersOrderedByZ(std::move(layersSortedByZ)); display->setReleasedLayers(std::move(releasedLayers)); - displayDevice->setVisibleLayersSortedByZ(deprecated_layersSortedByZ); - Region undefinedRegion{bounds}; undefinedRegion.subtractSelf(tr.transform(opaqueRegion)); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 2e64a78458..425768e244 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -805,9 +805,6 @@ struct BaseLayerVariant { Mock::VerifyAndClear(test->mComposer); - Vector> layers; - layers.add(layer); - test->mDisplay->setVisibleLayersSortedByZ(layers); test->mFlinger.mutableDrawingState().layersSortedByZ.add(layer); } @@ -1096,8 +1093,6 @@ struct CompositionCase { for (auto& hwcDisplay : test->mFlinger.mFakeHwcDisplays) { hwcDisplay->mutableLayers().clear(); } - - test->mDisplay->setVisibleLayersSortedByZ(Vector>()); } }; -- cgit v1.2.3-59-g8ed1b From a38ea7e70d047eb5557e3b3425fd45bb4ca5c6a9 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Tue, 16 Apr 2019 18:10:26 -0700 Subject: CE: Allow the final class to set the types used Modifies the various CompositionEngine implementation classes so that they no longer store instances of the state structures they manipulate. Instead the implementation gets access to the state using an accessor, which is only implemented by a final derived class type. Doing this allows for implementation inheritance, where a derived implementation can leverage covariance to work with a more specialized type. Test: atest libsurfaceflinger_unittest libcompositionengine_test Test: go/wm-smoke Bug: 121291683 Change-Id: I26366900fc4c7869f4de91f25e43b3bec917f63d --- .../include/compositionengine/CompositionEngine.h | 4 +- .../include/compositionengine/Display.h | 4 +- .../compositionengine/DisplayCreationArgs.h | 9 +- .../include/compositionengine/Output.h | 6 - .../include/compositionengine/RenderSurface.h | 2 +- .../compositionengine/impl/CompositionEngine.h | 4 +- .../include/compositionengine/impl/Display.h | 34 ++- .../compositionengine/impl/DisplayColorProfile.h | 4 +- .../include/compositionengine/impl/Layer.h | 69 +++-- .../include/compositionengine/impl/Output.h | 91 ++++-- .../include/compositionengine/impl/OutputLayer.h | 81 ++++-- .../include/compositionengine/impl/RenderSurface.h | 6 +- .../compositionengine/mock/CompositionEngine.h | 4 +- .../include/compositionengine/mock/Display.h | 4 +- .../include/compositionengine/mock/RenderSurface.h | 2 +- .../CompositionEngine/src/CompositionEngine.cpp | 9 +- .../CompositionEngine/src/Display.cpp | 23 +- .../CompositionEngine/src/DisplayColorProfile.cpp | 6 +- .../surfaceflinger/CompositionEngine/src/Layer.cpp | 29 +- .../CompositionEngine/src/Output.cpp | 180 ++++++------ .../CompositionEngine/src/OutputLayer.cpp | 168 +++++------ .../CompositionEngine/src/RenderSurface.cpp | 9 +- .../CompositionEngine/tests/DisplayTest.cpp | 197 +++++++------ .../CompositionEngine/tests/LayerTest.cpp | 22 +- .../CompositionEngine/tests/OutputLayerTest.cpp | 43 ++- .../CompositionEngine/tests/OutputTest.cpp | 319 ++++++++++----------- services/surfaceflinger/DisplayDevice.cpp | 5 +- 27 files changed, 718 insertions(+), 616 deletions(-) (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h index a8e05cbe99..9898e35d25 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h @@ -46,8 +46,8 @@ public: virtual ~CompositionEngine(); // Create a composition Display - virtual std::shared_ptr createDisplay(DisplayCreationArgs&&) = 0; - virtual std::shared_ptr createLayer(LayerCreationArgs&&) = 0; + virtual std::shared_ptr createDisplay(const DisplayCreationArgs&) = 0; + virtual std::shared_ptr createLayer(const LayerCreationArgs&) = 0; virtual HWComposer& getHwComposer() const = 0; virtual void setHwComposer(std::unique_ptr) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h index dbcd3bd5f7..9193dc0e3f 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h @@ -47,10 +47,10 @@ public: virtual void disconnect() = 0; // Creates a render color mode for the display - virtual void createDisplayColorProfile(DisplayColorProfileCreationArgs&&) = 0; + virtual void createDisplayColorProfile(const DisplayColorProfileCreationArgs&) = 0; // Creates a render surface for the display - virtual void createRenderSurface(RenderSurfaceCreationArgs&&) = 0; + virtual void createRenderSurface(const RenderSurfaceCreationArgs&) = 0; protected: ~Display() = default; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h index 0778936d24..ced4227b44 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h @@ -30,9 +30,6 @@ class CompositionEngine; * A parameter object for creating Display instances */ struct DisplayCreationArgs { - // True if this display is secure - bool isSecure = false; - // True if this display is a virtual display bool isVirtual = false; @@ -54,17 +51,13 @@ struct DisplayCreationArgs { * * Prefer: * - * DisplayCreationArgsBuilder().setIsSecure(false).setIsVirtual(false) + * DisplayCreationArgsBuilder().setIsVirtual(false) * .setDisplayId(displayId).build(); */ class DisplayCreationArgsBuilder { public: DisplayCreationArgs build() { return std::move(mArgs); } - DisplayCreationArgsBuilder& setIsSecure(bool isSecure) { - mArgs.isSecure = isSecure; - return *this; - } DisplayCreationArgsBuilder& setIsVirtual(bool isVirtual) { mArgs.isVirtual = isVirtual; return *this; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index d374baa388..3830b0743c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -162,12 +162,6 @@ public: virtual std::unique_ptr createOutputLayer(const std::shared_ptr&, const sp&) const = 0; - // Gets the OutputLayer corresponding to the input Layer instance from the - // current ordered set of output layers. If there is no such layer, a new - // one is created and returned. - virtual std::unique_ptr getOrCreateOutputLayer(std::shared_ptr, - sp) = 0; - // Sets the new ordered set of output layers for this output virtual void setOutputLayersOrderedByZ(OutputLayers&&) = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h index 6859846faf..5ce2fdcf8c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h @@ -78,7 +78,7 @@ public: // Queues the drawn buffer for consumption by HWC. readyFence is the fence // which will fire when the buffer is ready for consumption. - virtual void queueBuffer(base::unique_fd&& readyFence) = 0; + virtual void queueBuffer(base::unique_fd readyFence) = 0; // Called after the HWC calls are made to present the display virtual void onPresentDisplayCompleted() = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h index 6340b1482a..76798f12a4 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h @@ -26,9 +26,9 @@ public: ~CompositionEngine() override; std::shared_ptr createDisplay( - compositionengine::DisplayCreationArgs&&) override; + const compositionengine::DisplayCreationArgs&) override; std::shared_ptr createLayer( - compositionengine::LayerCreationArgs&&) override; + const compositionengine::LayerCreationArgs&) override; HWComposer& getHwComposer() const override; void setHwComposer(std::unique_ptr) override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index b5d8325040..45a604ffeb 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include @@ -29,36 +30,37 @@ namespace android::compositionengine { class CompositionEngine; -struct DisplayCreationArgs; - namespace impl { -class Display : public compositionengine::impl::Output, public compositionengine::Display { +// The implementation class contains the common implementation, but does not +// actually contain the final display state. +class Display : public compositionengine::impl::Output, public virtual compositionengine::Display { public: - Display(const CompositionEngine&, compositionengine::DisplayCreationArgs&&); + explicit Display(const compositionengine::DisplayCreationArgs&); virtual ~Display(); // compositionengine::Output overrides void dump(std::string&) const override; std::unique_ptr createOutputLayer( - const std::shared_ptr&, const sp&) const override; + const std::shared_ptr&, const sp&) const override; using compositionengine::impl::Output::setReleasedLayers; - void setReleasedLayers(const compositionengine::CompositionRefreshArgs&) override; - void setColorTransform(const compositionengine::CompositionRefreshArgs&) override; + void setReleasedLayers(const CompositionRefreshArgs&) override; + void setColorTransform(const CompositionRefreshArgs&) override; void setColorProfile(const ColorProfile&) override; void chooseCompositionStrategy() override; bool getSkipColorTransform() const override; compositionengine::Output::FrameFences presentAndGetFrameFences() override; void setExpensiveRenderingExpected(bool) override; - void finishFrame(const compositionengine::CompositionRefreshArgs&) override; + void finishFrame(const CompositionRefreshArgs&) override; // compositionengine::Display overrides const std::optional& getId() const override; bool isSecure() const override; bool isVirtual() const override; void disconnect() override; - void createDisplayColorProfile(compositionengine::DisplayColorProfileCreationArgs&&) override; - void createRenderSurface(compositionengine::RenderSurfaceCreationArgs&&) override; + void createDisplayColorProfile( + const compositionengine::DisplayColorProfileCreationArgs&) override; + void createRenderSurface(const compositionengine::RenderSurfaceCreationArgs&) override; // Internal helpers used by chooseCompositionStrategy() using ChangedTypes = android::HWComposer::DeviceRequestedChanges::ChangedTypes; @@ -76,8 +78,18 @@ private: Hwc2::PowerAdvisor* const mPowerAdvisor{nullptr}; }; +// This template factory function standardizes the implementation details of the +// final class using the types actually required by the implementation. This is +// not possible to do in the base class as those types may not even be visible +// to the base code. +template +std::shared_ptr createDisplayTemplated(const CompositionEngine& compositionEngine, + const DisplayCreationArgs& args) { + return createOutputTemplated(compositionEngine, args); +} + std::shared_ptr createDisplay(const compositionengine::CompositionEngine&, - compositionengine::DisplayCreationArgs&&); + const compositionengine::DisplayCreationArgs&); } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h index e84a36ee67..9bc0e681c7 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h @@ -33,7 +33,7 @@ namespace impl { class DisplayColorProfile : public compositionengine::DisplayColorProfile { public: - DisplayColorProfile(DisplayColorProfileCreationArgs&&); + DisplayColorProfile(const DisplayColorProfileCreationArgs&); ~DisplayColorProfile() override; bool isValid() const override; @@ -91,7 +91,7 @@ private: }; std::unique_ptr createDisplayColorProfile( - DisplayColorProfileCreationArgs&&); + const DisplayColorProfileCreationArgs&); } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h index d441c9c1b6..46489fb9cd 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h @@ -19,43 +19,66 @@ #include #include -#include -#include +#include #include namespace android::compositionengine { -class CompositionEngine; -class LayerFE; - struct LayerCreationArgs; namespace impl { -class Display; - -class Layer : public compositionengine::Layer { +// The implementation class contains the common implementation, but does not +// actually contain the final layer state. +class Layer : public virtual compositionengine::Layer { public: - Layer(const CompositionEngine&, compositionengine::LayerCreationArgs&&); ~Layer() override; - sp getLayerFE() const override; - - const LayerFECompositionState& getFEState() const override; - LayerFECompositionState& editFEState() override; - - void dump(std::string& result) const override; - -private: - const compositionengine::CompositionEngine& mCompositionEngine; - const wp mLayerFE; + // compositionengine::Layer overrides + void dump(std::string&) const override; - // State obtained from calls to LayerFE::getCompositionState - LayerFECompositionState mFrontEndState; +protected: + // Implemented by the final implementation for the final state it uses. + virtual void dumpFEState(std::string&) const = 0; }; -std::shared_ptr createLayer(const compositionengine::CompositionEngine&, - compositionengine::LayerCreationArgs&&); +// This template factory function standardizes the implementation details of the +// final class using the types actually required by the implementation. This is +// not possible to do in the base class as those types may not even be visible +// to the base code. +template +std::shared_ptr createLayerTemplated(const LayerCreationArgs& args) { + class Layer final : public BaseLayer { + public: +// Clang incorrectly complains that these are unused. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-local-typedef" + using LayerFE = std::remove_pointer_t().layerFE)>().unsafe_get())>; + using LayerFECompositionState = std::remove_const_t< + std::remove_reference_t().getFEState())>>; +#pragma clang diagnostic pop + + explicit Layer(const LayerCreationArgs& args) : mLayerFE(args.layerFE) {} + ~Layer() override = default; + + private: + // compositionengine::Layer overrides + sp getLayerFE() const override { return mLayerFE.promote(); } + const LayerFECompositionState& getFEState() const override { return mFrontEndState; } + LayerFECompositionState& editFEState() override { return mFrontEndState; } + + // compositionengine::impl::Layer overrides + void dumpFEState(std::string& out) const override { mFrontEndState.dump(out); } + + const wp mLayerFE; + LayerFECompositionState mFrontEndState; + }; + + return std::make_shared(args); +} + +std::shared_ptr createLayer(const LayerCreationArgs&); } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index fa6cd27e1a..27665727a6 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -16,28 +16,24 @@ #pragma once -#include -#include -#include - +#include #include #include -namespace android::compositionengine { - -class CompositionEngine; -class Layer; -class OutputLayer; +#include +#include +#include -namespace impl { +namespace android::compositionengine::impl { +// The implementation class contains the common implementation, but does not +// actually contain the final output state. class Output : public virtual compositionengine::Output { public: - Output(const CompositionEngine&); ~Output() override; + // compositionengine::Output overrides bool isValid() const override; - void setCompositionEnabled(bool) override; void setProjection(const ui::Transform&, int32_t orientation, const Rect& frame, const Rect& viewport, const Rect& scissor, bool needsFiltering) override; @@ -58,9 +54,6 @@ public: compositionengine::RenderSurface* getRenderSurface() const override; void setRenderSurface(std::unique_ptr) override; - const OutputCompositionState& getState() const override; - OutputCompositionState& editState() override; - Region getDirtyRegion(bool repaintEverything) const override; bool belongsInOutput(std::optional, bool) const override; bool belongsInOutput(const compositionengine::Layer*) const override; @@ -69,19 +62,17 @@ public: compositionengine::Layer*) const override; std::unique_ptr createOutputLayer( const std::shared_ptr&, const sp&) const override; - std::unique_ptr getOrCreateOutputLayer( - std::shared_ptr, sp) override; void setOutputLayersOrderedByZ(OutputLayers&&) override; const OutputLayers& getOutputLayersOrderedByZ() const override; void setReleasedLayers(ReleasedLayers&&) override; ReleasedLayers takeReleasedLayers() override; - void prepare(const compositionengine::CompositionRefreshArgs&, LayerFESet&) override; - void present(const compositionengine::CompositionRefreshArgs&) override; + void prepare(const CompositionRefreshArgs&, LayerFESet&) override; + void present(const CompositionRefreshArgs&) override; - void rebuildLayerStacks(const compositionengine::CompositionRefreshArgs&, LayerFESet&) override; - void collectVisibleLayers(const compositionengine::CompositionRefreshArgs&, + void rebuildLayerStacks(const CompositionRefreshArgs&, LayerFESet&) override; + void collectVisibleLayers(const CompositionRefreshArgs&, compositionengine::Output::CoverageState&) override; std::unique_ptr getOutputLayerIfVisible( std::shared_ptr, @@ -93,8 +84,8 @@ public: void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override; void beginFrame() override; void prepareFrame() override; - void devOptRepaintFlash(const compositionengine::CompositionRefreshArgs&) override; - void finishFrame(const compositionengine::CompositionRefreshArgs&) override; + void devOptRepaintFlash(const CompositionRefreshArgs&) override; + void finishFrame(const CompositionRefreshArgs&) override; std::optional composeSurfaces(const Region&) override; void postFramebuffer() override; @@ -104,7 +95,7 @@ public: void setRenderSurfaceForTest(std::unique_ptr); protected: - const CompositionEngine& getCompositionEngine() const; + virtual const CompositionEngine& getCompositionEngine() const = 0; std::unique_ptr takeOutputLayerForLayer( compositionengine::Layer*); void chooseCompositionStrategy() override; @@ -117,18 +108,17 @@ protected: void setExpensiveRenderingExpected(bool enabled) override; void dumpBase(std::string&) const; + // Implemented by the final implementation for the final state it uses. + virtual void dumpState(std::string&) const = 0; + private: void dirtyEntireOutput(); ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const; compositionengine::Output::ColorProfile pickColorProfile( const compositionengine::CompositionRefreshArgs&) const; - const CompositionEngine& mCompositionEngine; - std::string mName; - OutputCompositionState mState; - std::unique_ptr mDisplayColorProfile; std::unique_ptr mRenderSurface; @@ -136,5 +126,46 @@ private: ReleasedLayers mReleasedLayers; }; -} // namespace impl -} // namespace android::compositionengine +// This template factory function standardizes the implementation details of the +// final class using the types actually required by the implementation. This is +// not possible to do in the base class as those types may not even be visible +// to the base code. +template +std::shared_ptr createOutputTemplated(const CompositionEngine& compositionEngine, + Args... args) { + class Output final : public BaseOutput { + public: +// Clang incorrectly complains that these are unused. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-local-typedef" + + using OutputCompositionState = std::remove_const_t< + std::remove_reference_t().getState())>>; + +#pragma clang diagnostic pop + + explicit Output(const CompositionEngine& compositionEngine, Args... args) + : BaseOutput(std::forward(args)...), mCompositionEngine(compositionEngine) {} + ~Output() override = default; + + private: + // compositionengine::Output overrides + const OutputCompositionState& getState() const override { return mState; } + OutputCompositionState& editState() override { return mState; } + + // compositionengine::impl::Output overrides + const CompositionEngine& getCompositionEngine() const override { + return mCompositionEngine; + }; + void dumpState(std::string& out) const override { mState.dump(out); } + + const CompositionEngine& mCompositionEngine; + OutputCompositionState mState; + }; + + return std::make_shared(compositionEngine, std::forward(args)...); +} + +std::shared_ptr createOutput(const compositionengine::CompositionEngine&); + +} // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index 1199fea71d..34dbfb777d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -20,7 +20,6 @@ #include #include -#include #include #include @@ -32,21 +31,14 @@ struct LayerFECompositionState; namespace impl { -class OutputLayer : public compositionengine::OutputLayer { +// The implementation class contains the common implementation, but does not +// actually contain the final layer state. +class OutputLayer : public virtual compositionengine::OutputLayer { public: - OutputLayer(const compositionengine::Output&, const std::shared_ptr&, - const sp&); ~OutputLayer() override; void setHwcLayer(std::shared_ptr) override; - const compositionengine::Output& getOutput() const override; - compositionengine::Layer& getLayer() const override; - compositionengine::LayerFE& getLayerFE() const override; - - const OutputLayerCompositionState& getState() const override; - OutputLayerCompositionState& editState() override; - void updateCompositionState(bool) override; void writeStateToHWC(bool) override; void writeCursorPositionToHWC() const override; @@ -59,12 +51,16 @@ public: void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override; bool needsFiltering() const override; - void dump(std::string& result) const override; + void dump(std::string&) const override; virtual FloatRect calculateOutputSourceCrop() const; virtual Rect calculateOutputDisplayFrame() const; virtual uint32_t calculateOutputRelativeBufferTransform() const; +protected: + // Implemented by the final implementation for the final state it uses. + virtual void dumpState(std::string&) const = 0; + private: Rect calculateInitialCrop() const; void writeOutputDependentGeometryStateToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition); @@ -77,17 +73,60 @@ private: void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition); void detectDisallowedCompositionTypeChange(Hwc2::IComposerClient::Composition from, Hwc2::IComposerClient::Composition to) const; - - const compositionengine::Output& mOutput; - std::shared_ptr mLayer; - sp mLayerFE; - - OutputLayerCompositionState mState; }; -std::unique_ptr createOutputLayer( - const compositionengine::Output&, const std::shared_ptr&, - const sp&); +// This template factory function standardizes the implementation details of the +// final class using the types actually required by the implementation. This is +// not possible to do in the base class as those types may not even be visible +// to the base code. +template +std::unique_ptr createOutputLayerTemplated(const Output& output, + std::shared_ptr layer, + sp layerFE) { + class OutputLayer final : public BaseOutputLayer { + public: +// Clang incorrectly complains that these are unused. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-local-typedef" + + using OutputLayerCompositionState = std::remove_const_t< + std::remove_reference_t().getState())>>; + using Output = std::remove_const_t< + std::remove_reference_t().getOutput())>>; + using Layer = std::remove_reference_t().getLayer())>; + using LayerFE = + std::remove_reference_t().getLayerFE())>; + +#pragma clang diagnostic pop + + OutputLayer(const Output& output, const std::shared_ptr& layer, + const sp& layerFE) + : mOutput(output), mLayer(layer), mLayerFE(layerFE) {} + ~OutputLayer() override = default; + + private: + // compositionengine::OutputLayer overrides + const Output& getOutput() const override { return mOutput; } + Layer& getLayer() const override { return *mLayer; } + LayerFE& getLayerFE() const override { return *mLayerFE; } + const OutputLayerCompositionState& getState() const override { return mState; } + OutputLayerCompositionState& editState() override { return mState; } + + // compositionengine::impl::OutputLayer overrides + void dumpState(std::string& out) const override { mState.dump(out); } + + const Output& mOutput; + const std::shared_ptr mLayer; + const sp mLayerFE; + OutputLayerCompositionState mState; + }; + + return std::make_unique(output, layer, layerFE); +} + +std::unique_ptr createOutputLayer(const compositionengine::Output&, + const std::shared_ptr&, + const sp&); } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h index 0a044629b3..692d78d825 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h @@ -39,7 +39,7 @@ namespace impl { class RenderSurface : public compositionengine::RenderSurface { public: RenderSurface(const CompositionEngine&, compositionengine::Display&, - compositionengine::RenderSurfaceCreationArgs&&); + const compositionengine::RenderSurfaceCreationArgs&); ~RenderSurface() override; bool isValid() const override; @@ -54,7 +54,7 @@ public: status_t beginFrame(bool mustRecompose) override; void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) override; sp dequeueBuffer(base::unique_fd* bufferFence) override; - void queueBuffer(base::unique_fd&& readyFence) override; + void queueBuffer(base::unique_fd readyFence) override; void onPresentDisplayCompleted() override; void flip() override; @@ -84,7 +84,7 @@ private: std::unique_ptr createRenderSurface( const compositionengine::CompositionEngine&, compositionengine::Display&, - compositionengine::RenderSurfaceCreationArgs&&); + const compositionengine::RenderSurfaceCreationArgs&); } // namespace impl } // namespace compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h index e3254acd9a..af7efdd40c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h @@ -32,8 +32,8 @@ public: CompositionEngine(); ~CompositionEngine() override; - MOCK_METHOD1(createDisplay, std::shared_ptr(DisplayCreationArgs&&)); - MOCK_METHOD1(createLayer, std::shared_ptr(LayerCreationArgs&&)); + MOCK_METHOD1(createDisplay, std::shared_ptr(const DisplayCreationArgs&)); + MOCK_METHOD1(createLayer, std::shared_ptr(const LayerCreationArgs&)); MOCK_CONST_METHOD0(getHwComposer, HWComposer&()); MOCK_METHOD1(setHwComposer, void(std::unique_ptr)); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h index d763aa6a23..57f33ae818 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h @@ -38,8 +38,8 @@ public: MOCK_METHOD0(disconnect, void()); - MOCK_METHOD1(createDisplayColorProfile, void(DisplayColorProfileCreationArgs&&)); - MOCK_METHOD1(createRenderSurface, void(RenderSurfaceCreationArgs&&)); + MOCK_METHOD1(createDisplayColorProfile, void(const DisplayColorProfileCreationArgs&)); + MOCK_METHOD1(createRenderSurface, void(const RenderSurfaceCreationArgs&)); }; } // 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 ba6746abb8..ed4d492654 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h @@ -39,7 +39,7 @@ public: MOCK_METHOD1(beginFrame, status_t(bool mustRecompose)); MOCK_METHOD2(prepareFrame, void(bool, bool)); MOCK_METHOD1(dequeueBuffer, sp(base::unique_fd*)); - MOCK_METHOD1(queueBuffer, void(base::unique_fd&&)); + MOCK_METHOD1(queueBuffer, void(base::unique_fd)); MOCK_METHOD0(onPresentDisplayCompleted, void()); MOCK_METHOD0(flip, void()); MOCK_CONST_METHOD1(dump, void(std::string& result)); diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp index 8391458e99..abf73adcbd 100644 --- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp +++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp @@ -39,12 +39,13 @@ CompositionEngine::CompositionEngine() = default; CompositionEngine::~CompositionEngine() = default; std::shared_ptr CompositionEngine::createDisplay( - DisplayCreationArgs&& args) { - return compositionengine::impl::createDisplay(*this, std::move(args)); + const DisplayCreationArgs& args) { + return compositionengine::impl::createDisplay(*this, args); } -std::shared_ptr CompositionEngine::createLayer(LayerCreationArgs&& args) { - return compositionengine::impl::createLayer(*this, std::move(args)); +std::shared_ptr CompositionEngine::createLayer( + const LayerCreationArgs& args) { + return compositionengine::impl::createLayer(args); } HWComposer& CompositionEngine::getHwComposer() const { diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index fe8fa21a8c..87df85846f 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -34,17 +34,12 @@ namespace android::compositionengine::impl { std::shared_ptr createDisplay( const compositionengine::CompositionEngine& compositionEngine, - compositionengine::DisplayCreationArgs&& args) { - return std::make_shared(compositionEngine, std::move(args)); + const compositionengine::DisplayCreationArgs& args) { + return createDisplayTemplated(compositionEngine, args); } -Display::Display(const CompositionEngine& compositionEngine, DisplayCreationArgs&& args) - : compositionengine::impl::Output(compositionEngine), - mIsVirtual(args.isVirtual), - mId(args.displayId), - mPowerAdvisor(args.powerAdvisor) { - editState().isSecure = args.isSecure; -} +Display::Display(const DisplayCreationArgs& args) + : mIsVirtual(args.isVirtual), mId(args.displayId), mPowerAdvisor(args.powerAdvisor) {} Display::~Display() = default; @@ -125,13 +120,13 @@ void Display::dump(std::string& out) const { Output::dumpBase(out); } -void Display::createDisplayColorProfile(DisplayColorProfileCreationArgs&& args) { - setDisplayColorProfile(compositionengine::impl::createDisplayColorProfile(std::move(args))); +void Display::createDisplayColorProfile(const DisplayColorProfileCreationArgs& args) { + setDisplayColorProfile(compositionengine::impl::createDisplayColorProfile(args)); } -void Display::createRenderSurface(RenderSurfaceCreationArgs&& args) { - setRenderSurface(compositionengine::impl::createRenderSurface(getCompositionEngine(), *this, - std::move(args))); +void Display::createRenderSurface(const RenderSurfaceCreationArgs& args) { + setRenderSurface( + compositionengine::impl::createRenderSurface(getCompositionEngine(), *this, args)); } std::unique_ptr Display::createOutputLayer( diff --git a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp index 5ef9097bff..a7c45129b1 100644 --- a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp +++ b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp @@ -184,11 +184,11 @@ RenderIntent getHwcRenderIntent(const std::vector& hwcIntents, Ren } // anonymous namespace std::unique_ptr createDisplayColorProfile( - DisplayColorProfileCreationArgs&& args) { - return std::make_unique(std::move(args)); + const DisplayColorProfileCreationArgs& args) { + return std::make_unique(args); } -DisplayColorProfile::DisplayColorProfile(DisplayColorProfileCreationArgs&& args) +DisplayColorProfile::DisplayColorProfile(const DisplayColorProfileCreationArgs& args) : mHasWideColorGamut(args.hasWideColorGamut), mSupportedPerFrameMetadata(args.supportedPerFrameMetadata) { populateColorModes(args.hwcColorModes); diff --git a/services/surfaceflinger/CompositionEngine/src/Layer.cpp b/services/surfaceflinger/CompositionEngine/src/Layer.cpp index 8a1cbe409b..ecacaeee9c 100644 --- a/services/surfaceflinger/CompositionEngine/src/Layer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Layer.cpp @@ -15,9 +15,8 @@ */ #include -#include -#include #include +#include #include namespace android::compositionengine { @@ -26,38 +25,18 @@ Layer::~Layer() = default; namespace impl { -std::shared_ptr createLayer( - const compositionengine::CompositionEngine& compositionEngine, - compositionengine::LayerCreationArgs&& args) { - return std::make_shared(compositionEngine, std::move(args)); -} - -Layer::Layer(const CompositionEngine& compositionEngine, LayerCreationArgs&& args) - : mCompositionEngine(compositionEngine), mLayerFE(args.layerFE) { - static_cast(mCompositionEngine); // Temporary use to prevent an unused warning +std::shared_ptr createLayer(const LayerCreationArgs& args) { + return compositionengine::impl::createLayerTemplated(args); } Layer::~Layer() = default; -sp Layer::getLayerFE() const { - return mLayerFE.promote(); -} - -const compositionengine::LayerFECompositionState& Layer::getFEState() const { - return mFrontEndState; -} - -compositionengine::LayerFECompositionState& Layer::editFEState() { - return mFrontEndState; -} - void Layer::dump(std::string& out) const { auto layerFE = getLayerFE(); android::base::StringAppendF(&out, "* compositionengine::Layer %p (%s)\n", this, layerFE ? layerFE->getDebugName() : ""); - out.append(" frontend:\n"); - mFrontEndState.dump(out); + dumpFEState(out); } } // namespace impl diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 02ebc1fc4f..c511306466 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -25,7 +25,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -61,15 +63,13 @@ Reversed reversed(const T& c) { } // namespace -Output::Output(const CompositionEngine& compositionEngine) - : mCompositionEngine(compositionEngine) {} +std::shared_ptr createOutput( + const compositionengine::CompositionEngine& compositionEngine) { + return createOutputTemplated(compositionEngine); +} Output::~Output() = default; -const CompositionEngine& Output::getCompositionEngine() const { - return mCompositionEngine; -} - bool Output::isValid() const { return mDisplayColorProfile && mDisplayColorProfile->isValid() && mRenderSurface && mRenderSurface->isValid(); @@ -84,22 +84,24 @@ void Output::setName(const std::string& name) { } void Output::setCompositionEnabled(bool enabled) { - if (mState.isEnabled == enabled) { + auto& outputState = editState(); + if (outputState.isEnabled == enabled) { return; } - mState.isEnabled = enabled; + outputState.isEnabled = enabled; dirtyEntireOutput(); } void Output::setProjection(const ui::Transform& transform, int32_t orientation, const Rect& frame, const Rect& viewport, const Rect& scissor, bool needsFiltering) { - mState.transform = transform; - mState.orientation = orientation; - mState.scissor = scissor; - mState.frame = frame; - mState.viewport = viewport; - mState.needsFiltering = needsFiltering; + auto& outputState = editState(); + outputState.transform = transform; + outputState.orientation = orientation; + outputState.scissor = scissor; + outputState.frame = frame; + outputState.viewport = viewport; + outputState.needsFiltering = needsFiltering; dirtyEntireOutput(); } @@ -107,44 +109,48 @@ void Output::setProjection(const ui::Transform& transform, int32_t orientation, // TODO(b/121291683): Rename setSize() once more is moved. void Output::setBounds(const ui::Size& size) { mRenderSurface->setDisplaySize(size); - // TODO(b/121291683): Rename mState.size once more is moved. - mState.bounds = Rect(mRenderSurface->getSize()); + // TODO(b/121291683): Rename outputState.size once more is moved. + editState().bounds = Rect(mRenderSurface->getSize()); dirtyEntireOutput(); } void Output::setLayerStackFilter(uint32_t layerStackId, bool isInternal) { - mState.layerStackId = layerStackId; - mState.layerStackInternal = isInternal; + auto& outputState = editState(); + outputState.layerStackId = layerStackId; + outputState.layerStackInternal = isInternal; dirtyEntireOutput(); } void Output::setColorTransform(const compositionengine::CompositionRefreshArgs& args) { - if (!args.colorTransformMatrix || mState.colorTransformMatrix == *args.colorTransformMatrix) { + auto& colorTransformMatrix = editState().colorTransformMatrix; + if (!args.colorTransformMatrix || colorTransformMatrix == args.colorTransformMatrix) { return; } - mState.colorTransformMatrix = *args.colorTransformMatrix; + colorTransformMatrix = *args.colorTransformMatrix; dirtyEntireOutput(); } void Output::setColorProfile(const ColorProfile& colorProfile) { - const ui::Dataspace targetDataspace = + ui::Dataspace targetDataspace = getDisplayColorProfile()->getTargetDataspace(colorProfile.mode, colorProfile.dataspace, colorProfile.colorSpaceAgnosticDataspace); - if (mState.colorMode == colorProfile.mode && mState.dataspace == colorProfile.dataspace && - mState.renderIntent == colorProfile.renderIntent && - mState.targetDataspace == targetDataspace) { + auto& outputState = editState(); + if (outputState.colorMode == colorProfile.mode && + outputState.dataspace == colorProfile.dataspace && + outputState.renderIntent == colorProfile.renderIntent && + outputState.targetDataspace == targetDataspace) { return; } - mState.colorMode = colorProfile.mode; - mState.dataspace = colorProfile.dataspace; - mState.renderIntent = colorProfile.renderIntent; - mState.targetDataspace = targetDataspace; + outputState.colorMode = colorProfile.mode; + outputState.dataspace = colorProfile.dataspace; + outputState.renderIntent = colorProfile.renderIntent; + outputState.targetDataspace = targetDataspace; mRenderSurface->setBufferDataspace(colorProfile.dataspace); @@ -166,7 +172,7 @@ void Output::dump(std::string& out) const { } void Output::dumpBase(std::string& out) const { - mState.dump(out); + dumpState(out); if (mDisplayColorProfile) { mDisplayColorProfile->dump(out); @@ -212,7 +218,7 @@ compositionengine::RenderSurface* Output::getRenderSurface() const { void Output::setRenderSurface(std::unique_ptr surface) { mRenderSurface = std::move(surface); - mState.bounds = Rect(mRenderSurface->getSize()); + editState().bounds = Rect(mRenderSurface->getSize()); dirtyEntireOutput(); } @@ -221,18 +227,11 @@ void Output::setRenderSurfaceForTest(std::unique_ptr layerStackId, bool internalOnly) const { // The layerStackId's must match, and also the layer must not be internal // only when not on an internal output. - return layerStackId && (*layerStackId == mState.layerStackId) && - (!internalOnly || mState.layerStackInternal); + const auto& outputState = getState(); + return layerStackId && (*layerStackId == outputState.layerStackId) && + (!internalOnly || outputState.layerStackInternal); } bool Output::belongsInOutput(const compositionengine::Layer* layer) const { @@ -274,15 +274,6 @@ std::unique_ptr Output::takeOutputLayerForLayer( return nullptr; } -std::unique_ptr Output::getOrCreateOutputLayer( - std::shared_ptr layer, sp layerFE) { - auto result = takeOutputLayerForLayer(layer.get()); - if (!result) { - result = createOutputLayer(layer, layerFE); - } - return result; -} - std::unique_ptr Output::createOutputLayer( const std::shared_ptr& layer, const sp& layerFE) const { @@ -332,8 +323,10 @@ void Output::rebuildLayerStacks(const compositionengine::CompositionRefreshArgs& ATRACE_CALL(); ALOGV(__FUNCTION__); + auto& outputState = editState(); + // Do nothing if this output is not enabled or there is no need to perform this update - if (!mState.isEnabled || CC_LIKELY(!refreshArgs.updatingOutputGeometryThisFrame)) { + if (!outputState.isEnabled || CC_LIKELY(!refreshArgs.updatingOutputGeometryThisFrame)) { return; } @@ -342,12 +335,12 @@ void Output::rebuildLayerStacks(const compositionengine::CompositionRefreshArgs& collectVisibleLayers(refreshArgs, coverage); // Compute the resulting coverage for this output, and store it for later - const ui::Transform& tr = mState.transform; - Region undefinedRegion{mState.bounds}; + const ui::Transform& tr = outputState.transform; + Region undefinedRegion{outputState.bounds}; undefinedRegion.subtractSelf(tr.transform(coverage.aboveOpaqueLayers)); - mState.undefinedRegion = undefinedRegion; - mState.dirtyRegion.orSelf(coverage.dirtyRegion); + outputState.undefinedRegion = undefinedRegion; + outputState.dirtyRegion.orSelf(coverage.dirtyRegion); } void Output::collectVisibleLayers(const compositionengine::CompositionRefreshArgs& refreshArgs, @@ -543,8 +536,9 @@ std::unique_ptr Output::getOutputLayerIfVisible( // Peform the final check to see if this layer is visible on this output // TODO(b/121291683): Why does this not use visibleRegion? (see outputSpaceVisibleRegion below) - Region drawRegion(mState.transform.transform(visibleNonTransparentRegion)); - drawRegion.andSelf(mState.bounds); + const auto& outputState = getState(); + Region drawRegion(outputState.transform.transform(visibleNonTransparentRegion)); + drawRegion.andSelf(outputState.bounds); if (drawRegion.isEmpty()) { return nullptr; } @@ -560,8 +554,8 @@ std::unique_ptr Output::getOutputLayerIfVisible( outputLayerState.visibleRegion = visibleRegion; outputLayerState.visibleNonTransparentRegion = visibleNonTransparentRegion; outputLayerState.coveredRegion = coveredRegion; - outputLayerState.outputSpaceVisibleRegion = - mState.transform.transform(outputLayerState.visibleRegion.intersect(mState.viewport)); + outputLayerState.outputSpaceVisibleRegion = outputState.transform.transform( + outputLayerState.visibleRegion.intersect(outputState.viewport)); return result; } @@ -706,9 +700,10 @@ compositionengine::Output::ColorProfile Output::pickColorProfile( } void Output::beginFrame() { + auto& outputState = editState(); const bool dirty = !getDirtyRegion(false).isEmpty(); const bool empty = mOutputLayersOrderedByZ.empty(); - const bool wasEmpty = !mState.lastCompositionHadVisibleLayers; + const bool wasEmpty = !outputState.lastCompositionHadVisibleLayers; // If nothing has changed (!dirty), don't recompose. // If something changed, but we don't currently have any visible layers, @@ -729,7 +724,7 @@ void Output::beginFrame() { mRenderSurface->beginFrame(mustRecompose); if (mustRecompose) { - mState.lastCompositionHadVisibleLayers = !empty; + outputState.lastCompositionHadVisibleLayers = !empty; } } @@ -737,13 +732,15 @@ void Output::prepareFrame() { ATRACE_CALL(); ALOGV(__FUNCTION__); - if (!mState.isEnabled) { + const auto& outputState = getState(); + if (!outputState.isEnabled) { return; } chooseCompositionStrategy(); - mRenderSurface->prepareFrame(mState.usesClientComposition, mState.usesDeviceComposition); + mRenderSurface->prepareFrame(outputState.usesClientComposition, + outputState.usesDeviceComposition); } void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& refreshArgs) { @@ -751,7 +748,7 @@ void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& return; } - if (mState.isEnabled) { + if (getState().isEnabled) { // transform the dirty region into this screen's coordinate space const Region dirtyRegion = getDirtyRegion(refreshArgs.repaintEverything); if (!dirtyRegion.isEmpty()) { @@ -774,7 +771,7 @@ void Output::finishFrame(const compositionengine::CompositionRefreshArgs&) { ATRACE_CALL(); ALOGV(__FUNCTION__); - if (!mState.isEnabled) { + if (!getState().isEnabled) { return; } @@ -793,32 +790,33 @@ std::optional Output::composeSurfaces(const Region& debugRegion ATRACE_CALL(); ALOGV(__FUNCTION__); + const auto& outputState = getState(); const TracedOrdinal hasClientComposition = {"hasClientComposition", - mState.usesClientComposition}; + outputState.usesClientComposition}; base::unique_fd readyFence; - if (!hasClientComposition) { return readyFence; } ALOGV("hasClientComposition"); - auto& renderEngine = mCompositionEngine.getRenderEngine(); + auto& renderEngine = getCompositionEngine().getRenderEngine(); const bool supportsProtectedContent = renderEngine.supportsProtectedContent(); renderengine::DisplaySettings clientCompositionDisplay; - clientCompositionDisplay.physicalDisplay = mState.scissor; - clientCompositionDisplay.clip = mState.scissor; - clientCompositionDisplay.globalTransform = mState.transform.asMatrix4(); - clientCompositionDisplay.orientation = mState.orientation; - clientCompositionDisplay.outputDataspace = - mDisplayColorProfile->hasWideColorGamut() ? mState.dataspace : ui::Dataspace::UNKNOWN; + clientCompositionDisplay.physicalDisplay = outputState.scissor; + clientCompositionDisplay.clip = outputState.scissor; + clientCompositionDisplay.globalTransform = outputState.transform.asMatrix4(); + clientCompositionDisplay.orientation = outputState.orientation; + clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut() + ? outputState.dataspace + : ui::Dataspace::UNKNOWN; clientCompositionDisplay.maxLuminance = mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance(); // Compute the global color transform matrix. - if (!mState.usesDeviceComposition && !getSkipColorTransform()) { - clientCompositionDisplay.colorTransform = mState.colorTransformMatrix; + if (!outputState.usesDeviceComposition && !getSkipColorTransform()) { + clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix; } // Note: Updated by generateClientCompositionRequests @@ -833,7 +831,7 @@ std::optional Output::composeSurfaces(const Region& debugRegion // If we the display is secure, protected content support is enabled, and at // least one layer has protected content, we need to use a secure back // buffer. - if (mState.isSecure && supportsProtectedContent) { + if (outputState.isSecure && supportsProtectedContent) { bool needsProtected = std::any_of(mOutputLayersOrderedByZ.begin(), mOutputLayersOrderedByZ.end(), [](auto& layer) { @@ -883,7 +881,8 @@ std::vector Output::generateClientCompositionReques std::vector clientCompositionLayers; ALOGV("Rendering client layers"); - const Region viewportRegion(mState.viewport); + const auto& outputState = getState(); + const Region viewportRegion(outputState.viewport); const bool useIdentityTransform = false; bool firstLayer = true; // Used when a layer clears part of the buffer. @@ -918,8 +917,8 @@ std::vector Output::generateClientCompositionReques compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{ clip, useIdentityTransform, - layer->needsFiltering() || mState.needsFiltering, - mState.isSecure, + layer->needsFiltering() || outputState.needsFiltering, + outputState.isSecure, supportsProtectedContent, clientComposition ? clearRegion : dummyRegion, }; @@ -972,14 +971,15 @@ void Output::postFramebuffer() { return; } - mState.dirtyRegion.clear(); + auto& outputState = editState(); + outputState.dirtyRegion.clear(); mRenderSurface->flip(); auto frame = presentAndGetFrameFences(); mRenderSurface->onPresentDisplayCompleted(); - for (auto& layer : getOutputLayersOrderedByZ()) { + for (auto& layer : mOutputLayersOrderedByZ) { // The layer buffer from the previous frame (if any) is released // by HWC only when the release fence from this frame (if any) is // signaled. Always get the release fence from HWC first. @@ -997,7 +997,7 @@ void Output::postFramebuffer() { // client target acquire fence when it is available, even though // this is suboptimal. // TODO(b/121291683): Track previous frame client target acquire fence. - if (mState.usesClientComposition) { + if (outputState.usesClientComposition) { releaseFence = Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence); } @@ -1006,7 +1006,7 @@ void Output::postFramebuffer() { } // We've got a list of layers needing fences, that are disjoint with - // getOutputLayersOrderedByZ. The best we can do is to + // mOutputLayersOrderedByZ. The best we can do is to // supply them with the present fence. for (auto& weakLayer : mReleasedLayers) { if (auto layer = weakLayer.promote(); layer != nullptr) { @@ -1019,13 +1019,15 @@ void Output::postFramebuffer() { } void Output::dirtyEntireOutput() { - mState.dirtyRegion.set(mState.bounds); + auto& outputState = editState(); + outputState.dirtyRegion.set(outputState.bounds); } void Output::chooseCompositionStrategy() { // The base output implementation can only do client composition - mState.usesClientComposition = true; - mState.usesDeviceComposition = false; + auto& outputState = editState(); + outputState.usesClientComposition = true; + outputState.usesDeviceComposition = false; } bool Output::getSkipColorTransform() const { @@ -1034,7 +1036,7 @@ bool Output::getSkipColorTransform() const { compositionengine::Output::FrameFences Output::presentAndGetFrameFences() { compositionengine::Output::FrameFences result; - if (mState.usesClientComposition) { + if (getState().usesClientComposition) { result.clientTargetAcquireFence = mRenderSurface->getClientTargetAcquireFence(); } return result; diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 43ab87a74a..0124e5b5d9 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -44,49 +44,26 @@ FloatRect reduce(const FloatRect& win, const Region& exclude) { } // namespace -std::unique_ptr createOutputLayer( +std::unique_ptr createOutputLayer( const compositionengine::Output& output, const std::shared_ptr& layer, const sp& layerFE) { - return std::make_unique(output, layer, layerFE); + return createOutputLayerTemplated(output, layer, layerFE); } -OutputLayer::OutputLayer(const Output& output, const std::shared_ptr& layer, - const sp& layerFE) - : mOutput(output), mLayer(layer), mLayerFE(layerFE) {} - OutputLayer::~OutputLayer() = default; void OutputLayer::setHwcLayer(std::shared_ptr hwcLayer) { + auto& state = editState(); if (hwcLayer) { - mState.hwc.emplace(hwcLayer); + state.hwc.emplace(std::move(hwcLayer)); } else { - mState.hwc.reset(); + state.hwc.reset(); } } -const compositionengine::Output& OutputLayer::getOutput() const { - return mOutput; -} - -compositionengine::Layer& OutputLayer::getLayer() const { - return *mLayer; -} - -compositionengine::LayerFE& OutputLayer::getLayerFE() const { - return *mLayerFE; -} - -const OutputLayerCompositionState& OutputLayer::getState() const { - return mState; -} - -OutputLayerCompositionState& OutputLayer::editState() { - return mState; -} - Rect OutputLayer::calculateInitialCrop() const { - const auto& layerState = mLayer->getFEState(); + const auto& layerState = getLayer().getFEState(); // apply the projection's clipping to the window crop in // layerstack space, and convert-back to layer space. @@ -96,7 +73,7 @@ Rect OutputLayer::calculateInitialCrop() const { FloatRect activeCropFloat = reduce(layerState.geomLayerBounds, layerState.transparentRegionHint); - const Rect& viewport = mOutput.getState().viewport; + const Rect& viewport = getOutput().getState().viewport; const ui::Transform& layerTransform = layerState.geomLayerTransform; const ui::Transform& inverseLayerTransform = layerState.geomInverseLayerTransform; // Transform to screen space. @@ -119,8 +96,8 @@ Rect OutputLayer::calculateInitialCrop() const { } FloatRect OutputLayer::calculateOutputSourceCrop() const { - const auto& layerState = mLayer->getFEState(); - const auto& outputState = mOutput.getState(); + const auto& layerState = getLayer().getFEState(); + const auto& outputState = getOutput().getState(); if (!layerState.geomUsesSourceCrop) { return {}; @@ -196,8 +173,8 @@ FloatRect OutputLayer::calculateOutputSourceCrop() const { } Rect OutputLayer::calculateOutputDisplayFrame() const { - const auto& layerState = mLayer->getFEState(); - const auto& outputState = mOutput.getState(); + const auto& layerState = getLayer().getFEState(); + const auto& outputState = getOutput().getState(); // apply the layer's transform, followed by the display's global transform // here we're guaranteed that the layer's transform preserves rects @@ -243,8 +220,8 @@ Rect OutputLayer::calculateOutputDisplayFrame() const { } uint32_t OutputLayer::calculateOutputRelativeBufferTransform() const { - const auto& layerState = mLayer->getFEState(); - const auto& outputState = mOutput.getState(); + const auto& layerState = getLayer().getFEState(); + const auto& outputState = getOutput().getState(); /* * Transformations are applied in this order: @@ -283,9 +260,10 @@ uint32_t OutputLayer::calculateOutputRelativeBufferTransform() const { } // namespace impl void OutputLayer::updateCompositionState(bool includeGeometry) { - const auto& layerFEState = mLayer->getFEState(); - const auto& outputState = mOutput.getState(); - const auto& profile = *mOutput.getDisplayColorProfile(); + const auto& layerFEState = getLayer().getFEState(); + const auto& outputState = getOutput().getState(); + const auto& profile = *getOutput().getDisplayColorProfile(); + auto& state = editState(); if (includeGeometry) { // Clear the forceClientComposition flag before it is set for any @@ -293,48 +271,49 @@ void OutputLayer::updateCompositionState(bool includeGeometry) { // updating the geometry state, we only clear it when updating the // geometry since those conditions for forcing client composition won't // go away otherwise. - mState.forceClientComposition = false; + state.forceClientComposition = false; - mState.displayFrame = calculateOutputDisplayFrame(); - mState.sourceCrop = calculateOutputSourceCrop(); - mState.bufferTransform = + state.displayFrame = calculateOutputDisplayFrame(); + state.sourceCrop = calculateOutputSourceCrop(); + state.bufferTransform = static_cast(calculateOutputRelativeBufferTransform()); if ((layerFEState.isSecure && !outputState.isSecure) || - (mState.bufferTransform & ui::Transform::ROT_INVALID)) { - mState.forceClientComposition = true; + (state.bufferTransform & ui::Transform::ROT_INVALID)) { + state.forceClientComposition = true; } } // Determine the output dependent dataspace for this layer. If it is // colorspace agnostic, it just uses the dataspace chosen for the output to // avoid the need for color conversion. - mState.dataspace = layerFEState.isColorspaceAgnostic && + state.dataspace = layerFEState.isColorspaceAgnostic && outputState.targetDataspace != ui::Dataspace::UNKNOWN ? outputState.targetDataspace : layerFEState.dataspace; // These are evaluated every frame as they can potentially change at any // time. - if (layerFEState.forceClientComposition || !profile.isDataspaceSupported(mState.dataspace)) { - mState.forceClientComposition = true; + if (layerFEState.forceClientComposition || !profile.isDataspaceSupported(state.dataspace)) { + state.forceClientComposition = true; } } void OutputLayer::writeStateToHWC(bool includeGeometry) { + const auto& state = getState(); // Skip doing this if there is no HWC interface - if (!mState.hwc) { + if (!state.hwc) { return; } - auto& hwcLayer = (*mState.hwc).hwcLayer; + auto& hwcLayer = (*state.hwc).hwcLayer; if (!hwcLayer) { ALOGE("[%s] failed to write composition state to HWC -- no hwcLayer for output %s", - mLayerFE->getDebugName(), mOutput.getName().c_str()); + getLayerFE().getDebugName(), getOutput().getName().c_str()); return; } - const auto& outputIndependentState = mLayer->getFEState(); + const auto& outputIndependentState = getLayer().getFEState(); auto requestedCompositionType = outputIndependentState.compositionType; if (includeGeometry) { @@ -355,7 +334,7 @@ void OutputLayer::writeOutputDependentGeometryStateToHWC( if (auto error = hwcLayer->setDisplayFrame(outputDependentState.displayFrame); error != HWC2::Error::None) { ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)", - mLayerFE->getDebugName(), outputDependentState.displayFrame.left, + getLayerFE().getDebugName(), outputDependentState.displayFrame.left, outputDependentState.displayFrame.top, outputDependentState.displayFrame.right, outputDependentState.displayFrame.bottom, to_string(error).c_str(), static_cast(error)); @@ -365,15 +344,15 @@ void OutputLayer::writeOutputDependentGeometryStateToHWC( error != HWC2::Error::None) { ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: " "%s (%d)", - mLayerFE->getDebugName(), outputDependentState.sourceCrop.left, + getLayerFE().getDebugName(), outputDependentState.sourceCrop.left, outputDependentState.sourceCrop.top, outputDependentState.sourceCrop.right, outputDependentState.sourceCrop.bottom, to_string(error).c_str(), static_cast(error)); } if (auto error = hwcLayer->setZOrder(outputDependentState.z); error != HWC2::Error::None) { - ALOGE("[%s] Failed to set Z %u: %s (%d)", mLayerFE->getDebugName(), outputDependentState.z, - to_string(error).c_str(), static_cast(error)); + ALOGE("[%s] Failed to set Z %u: %s (%d)", getLayerFE().getDebugName(), + outputDependentState.z, to_string(error).c_str(), static_cast(error)); } // Solid-color layers should always use an identity transform. @@ -383,7 +362,7 @@ void OutputLayer::writeOutputDependentGeometryStateToHWC( : static_cast(0); if (auto error = hwcLayer->setTransform(static_cast(bufferTransform)); error != HWC2::Error::None) { - ALOGE("[%s] Failed to set transform %s: %s (%d)", mLayerFE->getDebugName(), + ALOGE("[%s] Failed to set transform %s: %s (%d)", getLayerFE().getDebugName(), toString(outputDependentState.bufferTransform).c_str(), to_string(error).c_str(), static_cast(error)); } @@ -394,21 +373,21 @@ void OutputLayer::writeOutputIndependentGeometryStateToHWC( if (auto error = hwcLayer->setBlendMode( static_cast(outputIndependentState.blendMode)); error != HWC2::Error::None) { - ALOGE("[%s] Failed to set blend mode %s: %s (%d)", mLayerFE->getDebugName(), + ALOGE("[%s] Failed to set blend mode %s: %s (%d)", getLayerFE().getDebugName(), toString(outputIndependentState.blendMode).c_str(), to_string(error).c_str(), static_cast(error)); } if (auto error = hwcLayer->setPlaneAlpha(outputIndependentState.alpha); error != HWC2::Error::None) { - ALOGE("[%s] Failed to set plane alpha %.3f: %s (%d)", mLayerFE->getDebugName(), + ALOGE("[%s] Failed to set plane alpha %.3f: %s (%d)", getLayerFE().getDebugName(), outputIndependentState.alpha, to_string(error).c_str(), static_cast(error)); } if (auto error = hwcLayer->setInfo(outputIndependentState.type, outputIndependentState.appId); error != HWC2::Error::None) { - ALOGE("[%s] Failed to set info %s (%d)", mLayerFE->getDebugName(), to_string(error).c_str(), - static_cast(error)); + ALOGE("[%s] Failed to set info %s (%d)", getLayerFE().getDebugName(), + to_string(error).c_str(), static_cast(error)); } } @@ -419,14 +398,14 @@ void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) // state and should not change every frame. if (auto error = hwcLayer->setVisibleRegion(outputDependentState.outputSpaceVisibleRegion); error != HWC2::Error::None) { - ALOGE("[%s] Failed to set visible region: %s (%d)", mLayerFE->getDebugName(), + ALOGE("[%s] Failed to set visible region: %s (%d)", getLayerFE().getDebugName(), to_string(error).c_str(), static_cast(error)); outputDependentState.outputSpaceVisibleRegion.dump(LOG_TAG); } if (auto error = hwcLayer->setDataspace(outputDependentState.dataspace); error != HWC2::Error::None) { - ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mLayerFE->getDebugName(), + ALOGE("[%s] Failed to set dataspace %d: %s (%d)", getLayerFE().getDebugName(), outputDependentState.dataspace, to_string(error).c_str(), static_cast(error)); } @@ -441,13 +420,13 @@ void OutputLayer::writeOutputIndependentPerFrameStateToHWC( editState().forceClientComposition = true; break; default: - ALOGE("[%s] Failed to set color transform: %s (%d)", mLayerFE->getDebugName(), + ALOGE("[%s] Failed to set color transform: %s (%d)", getLayerFE().getDebugName(), to_string(error).c_str(), static_cast(error)); } if (auto error = hwcLayer->setSurfaceDamage(outputIndependentState.surfaceDamage); error != HWC2::Error::None) { - ALOGE("[%s] Failed to set surface damage: %s (%d)", mLayerFE->getDebugName(), + ALOGE("[%s] Failed to set surface damage: %s (%d)", getLayerFE().getDebugName(), to_string(error).c_str(), static_cast(error)); outputIndependentState.surfaceDamage.dump(LOG_TAG); } @@ -479,7 +458,7 @@ void OutputLayer::writeSolidColorStateToHWC(HWC2::Layer* hwcLayer, 255}; if (auto error = hwcLayer->setColor(color); error != HWC2::Error::None) { - ALOGE("[%s] Failed to set color: %s (%d)", mLayerFE->getDebugName(), + ALOGE("[%s] Failed to set color: %s (%d)", getLayerFE().getDebugName(), to_string(error).c_str(), static_cast(error)); } } @@ -488,7 +467,7 @@ void OutputLayer::writeSidebandStateToHWC(HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState) { if (auto error = hwcLayer->setSidebandStream(outputIndependentState.sidebandStream->handle()); error != HWC2::Error::None) { - ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mLayerFE->getDebugName(), + ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", getLayerFE().getDebugName(), outputIndependentState.sidebandStream->handle(), to_string(error).c_str(), static_cast(error)); } @@ -497,11 +476,11 @@ void OutputLayer::writeSidebandStateToHWC(HWC2::Layer* hwcLayer, void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState) { auto supportedPerFrameMetadata = - mOutput.getDisplayColorProfile()->getSupportedPerFrameMetadata(); + getOutput().getDisplayColorProfile()->getSupportedPerFrameMetadata(); if (auto error = hwcLayer->setPerFrameMetadata(supportedPerFrameMetadata, outputIndependentState.hdrMetadata); error != HWC2::Error::None && error != HWC2::Error::Unsupported) { - ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mLayerFE->getDebugName(), + ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", getLayerFE().getDebugName(), to_string(error).c_str(), static_cast(error)); } @@ -515,7 +494,7 @@ void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer, if (auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, outputIndependentState.acquireFence); error != HWC2::Error::None) { - ALOGE("[%s] Failed to set buffer %p: %s (%d)", mLayerFE->getDebugName(), + ALOGE("[%s] Failed to set buffer %p: %s (%d)", getLayerFE().getDebugName(), outputIndependentState.buffer->handle, to_string(error).c_str(), static_cast(error)); } @@ -537,7 +516,7 @@ void OutputLayer::writeCompositionTypeToHWC( if (auto error = hwcLayer->setCompositionType( static_cast(requestedCompositionType)); error != HWC2::Error::None) { - ALOGE("[%s] Failed to set composition type %s: %s (%d)", mLayerFE->getDebugName(), + ALOGE("[%s] Failed to set composition type %s: %s (%d)", getLayerFE().getDebugName(), toString(requestedCompositionType).c_str(), to_string(error).c_str(), static_cast(error)); } @@ -551,8 +530,8 @@ void OutputLayer::writeCursorPositionToHWC() const { return; } - const auto& layerFEState = mLayer->getFEState(); - const auto& outputState = mOutput.getState(); + const auto& layerFEState = getLayer().getFEState(); + const auto& outputState = getOutput().getState(); Rect frame = layerFEState.cursorFrame; frame.intersect(outputState.viewport, &frame); @@ -560,23 +539,26 @@ void OutputLayer::writeCursorPositionToHWC() const { if (auto error = hwcLayer->setCursorPosition(position.left, position.top); error != HWC2::Error::None) { - ALOGE("[%s] Failed to set cursor position to (%d, %d): %s (%d)", mLayerFE->getDebugName(), - position.left, position.top, to_string(error).c_str(), static_cast(error)); + ALOGE("[%s] Failed to set cursor position to (%d, %d): %s (%d)", + getLayerFE().getDebugName(), position.left, position.top, to_string(error).c_str(), + static_cast(error)); } } HWC2::Layer* OutputLayer::getHwcLayer() const { - return mState.hwc ? mState.hwc->hwcLayer.get() : nullptr; + const auto& state = getState(); + return state.hwc ? state.hwc->hwcLayer.get() : nullptr; } bool OutputLayer::requiresClientComposition() const { - return !mState.hwc || - mState.hwc->hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT; + const auto& state = getState(); + return !state.hwc || + state.hwc->hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT; } bool OutputLayer::isHardwareCursor() const { - return mState.hwc && - mState.hwc->hwcCompositionType == Hwc2::IComposerClient::Composition::CURSOR; + const auto& state = getState(); + return state.hwc && state.hwc->hwcCompositionType == Hwc2::IComposerClient::Composition::CURSOR; } void OutputLayer::detectDisallowedCompositionTypeChange( @@ -602,15 +584,16 @@ void OutputLayer::detectDisallowedCompositionTypeChange( if (!result) { ALOGE("[%s] Invalid device requested composition type change: %s (%d) --> %s (%d)", - mLayerFE->getDebugName(), toString(from).c_str(), static_cast(from), + getLayerFE().getDebugName(), toString(from).c_str(), static_cast(from), toString(to).c_str(), static_cast(to)); } } void OutputLayer::applyDeviceCompositionTypeChange( Hwc2::IComposerClient::Composition compositionType) { - LOG_FATAL_IF(!mState.hwc); - auto& hwcState = *mState.hwc; + auto& state = editState(); + LOG_FATAL_IF(!state.hwc); + auto& hwcState = *state.hwc; detectDisallowedCompositionTypeChange(hwcState.hwcCompositionType, compositionType); @@ -618,25 +601,28 @@ void OutputLayer::applyDeviceCompositionTypeChange( } void OutputLayer::prepareForDeviceLayerRequests() { - mState.clearClientTarget = false; + auto& state = editState(); + state.clearClientTarget = false; } void OutputLayer::applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) { + auto& state = editState(); switch (request) { case Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET: - mState.clearClientTarget = true; + state.clearClientTarget = true; break; default: - ALOGE("[%s] Unknown device layer request %s (%d)", mLayerFE->getDebugName(), + ALOGE("[%s] Unknown device layer request %s (%d)", getLayerFE().getDebugName(), toString(request).c_str(), static_cast(request)); break; } } bool OutputLayer::needsFiltering() const { - const auto& displayFrame = mState.displayFrame; - const auto& sourceCrop = mState.sourceCrop; + const auto& state = getState(); + const auto& displayFrame = state.displayFrame; + const auto& sourceCrop = state.sourceCrop; return sourceCrop.getHeight() != displayFrame.getHeight() || sourceCrop.getWidth() != displayFrame.getWidth(); } @@ -644,9 +630,9 @@ bool OutputLayer::needsFiltering() const { void OutputLayer::dump(std::string& out) const { using android::base::StringAppendF; - StringAppendF(&out, " - Output Layer %p (Composition layer %p) (%s)\n", this, mLayer.get(), - mLayerFE->getDebugName()); - mState.dump(out); + StringAppendF(&out, " - Output Layer %p (Composition layer %p) (%s)\n", this, &getLayer(), + getLayerFE().getDebugName()); + dumpState(out); } } // namespace impl diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index 1ce6b4c1c2..5ed21fc4b0 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -43,12 +43,13 @@ namespace impl { std::unique_ptr createRenderSurface( const compositionengine::CompositionEngine& compositionEngine, - compositionengine::Display& display, compositionengine::RenderSurfaceCreationArgs&& args) { - return std::make_unique(compositionEngine, display, std::move(args)); + compositionengine::Display& display, + const compositionengine::RenderSurfaceCreationArgs& args) { + return std::make_unique(compositionEngine, display, args); } RenderSurface::RenderSurface(const CompositionEngine& compositionEngine, Display& display, - RenderSurfaceCreationArgs&& args) + const RenderSurfaceCreationArgs& args) : mCompositionEngine(compositionEngine), mDisplay(display), mNativeWindow(args.nativeWindow), @@ -156,7 +157,7 @@ sp RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) { return mGraphicBuffer; } -void RenderSurface::queueBuffer(base::unique_fd&& readyFence) { +void RenderSurface::queueBuffer(base::unique_fd readyFence) { auto& state = mDisplay.getState(); if (state.usesClientComposition || state.flipClientTarget) { diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 74b3adaa95..8401f0827b 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -58,7 +58,7 @@ struct DisplayTest : public testing::Test { layers.emplace_back(mLayer1); layers.emplace_back(mLayer2); layers.emplace_back(mLayer3); - mDisplay.setOutputLayersOrderedByZ(std::move(layers)); + mDisplay->setOutputLayersOrderedByZ(std::move(layers)); } StrictMock mHwComposer; @@ -71,11 +71,12 @@ struct DisplayTest : public testing::Test { mock::OutputLayer* mLayer1 = new StrictMock(); mock::OutputLayer* mLayer2 = new StrictMock(); mock::OutputLayer* mLayer3 = new StrictMock(); - impl::Display mDisplay{mCompositionEngine, - DisplayCreationArgsBuilder() - .setDisplayId(DEFAULT_DISPLAY_ID) - .setPowerAdvisor(&mPowerAdvisor) - .build()}; + std::shared_ptr mDisplay = + impl::createDisplay(mCompositionEngine, + DisplayCreationArgsBuilder() + .setDisplayId(DEFAULT_DISPLAY_ID) + .setPowerAdvisor(&mPowerAdvisor) + .build()); }; /* @@ -95,12 +96,10 @@ TEST_F(DisplayTest, canInstantiateDisplay) { { constexpr DisplayId display2 = DisplayId{546u}; - auto display = impl::createDisplay(mCompositionEngine, - DisplayCreationArgsBuilder() - .setIsSecure(true) - .setDisplayId(display2) - .build()); - EXPECT_TRUE(display->isSecure()); + auto display = + impl::createDisplay(mCompositionEngine, + DisplayCreationArgsBuilder().setDisplayId(display2).build()); + EXPECT_FALSE(display->isSecure()); EXPECT_FALSE(display->isVirtual()); EXPECT_EQ(display2, display->getId()); } @@ -126,13 +125,13 @@ TEST_F(DisplayTest, disconnectDisconnectsDisplay) { // The first call to disconnect will disconnect the display with the HWC and // set mHwcId to -1. EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(1); - mDisplay.disconnect(); - EXPECT_FALSE(mDisplay.getId()); + mDisplay->disconnect(); + EXPECT_FALSE(mDisplay->getId()); // Subsequent calls will do nothing, EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(0); - mDisplay.disconnect(); - EXPECT_FALSE(mDisplay.getId()); + mDisplay->disconnect(); + EXPECT_FALSE(mDisplay->getId()); } /* @@ -143,7 +142,7 @@ TEST_F(DisplayTest, setColorTransformSetsTransform) { // No change does nothing CompositionRefreshArgs refreshArgs; refreshArgs.colorTransformMatrix = std::nullopt; - mDisplay.setColorTransform(refreshArgs); + mDisplay->setColorTransform(refreshArgs); // Identity matrix sets an identity state value const mat4 kIdentity; @@ -151,7 +150,7 @@ TEST_F(DisplayTest, setColorTransformSetsTransform) { EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, kIdentity)).Times(1); refreshArgs.colorTransformMatrix = kIdentity; - mDisplay.setColorTransform(refreshArgs); + mDisplay->setColorTransform(refreshArgs); // Non-identity matrix sets a non-identity state value const mat4 kNonIdentity = mat4() * 2; @@ -159,7 +158,7 @@ TEST_F(DisplayTest, setColorTransformSetsTransform) { EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, kNonIdentity)).Times(1); refreshArgs.colorTransformMatrix = kNonIdentity; - mDisplay.setColorTransform(refreshArgs); + mDisplay->setColorTransform(refreshArgs); } /* @@ -170,27 +169,27 @@ TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) { using ColorProfile = Output::ColorProfile; mock::RenderSurface* renderSurface = new StrictMock(); - mDisplay.setRenderSurfaceForTest(std::unique_ptr(renderSurface)); + mDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); mock::DisplayColorProfile* colorProfile = new StrictMock(); - mDisplay.setDisplayColorProfileForTest(std::unique_ptr(colorProfile)); + mDisplay->setDisplayColorProfileForTest(std::unique_ptr(colorProfile)); EXPECT_CALL(*colorProfile, getTargetDataspace(_, _, _)) .WillRepeatedly(Return(ui::Dataspace::UNKNOWN)); // These values are expected to be the initial state. - ASSERT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode); - ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace); - ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent); - ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace); + ASSERT_EQ(ui::ColorMode::NATIVE, mDisplay->getState().colorMode); + ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().dataspace); + ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay->getState().renderIntent); + ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().targetDataspace); - // If the set values are unchanged, nothing happens - mDisplay.setColorProfile(ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, - ui::RenderIntent::COLORIMETRIC, ui::Dataspace::UNKNOWN}); + // Otherwise if the values are unchanged, nothing happens + mDisplay->setColorProfile(ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, + ui::RenderIntent::COLORIMETRIC, ui::Dataspace::UNKNOWN}); - EXPECT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode); - EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace); - EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent); - EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace); + EXPECT_EQ(ui::ColorMode::NATIVE, mDisplay->getState().colorMode); + EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().dataspace); + EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay->getState().renderIntent); + EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().targetDataspace); // Otherwise if the values are different, updates happen EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1); @@ -199,24 +198,24 @@ TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) { ui::RenderIntent::TONE_MAP_COLORIMETRIC)) .Times(1); - mDisplay.setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC, - ui::Dataspace::UNKNOWN}); + mDisplay->setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, + ui::RenderIntent::TONE_MAP_COLORIMETRIC, + ui::Dataspace::UNKNOWN}); - EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mDisplay.getState().colorMode); - EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mDisplay.getState().dataspace); - EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mDisplay.getState().renderIntent); - EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace); + EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mDisplay->getState().colorMode); + EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mDisplay->getState().dataspace); + EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mDisplay->getState().renderIntent); + EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().targetDataspace); } TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) { using ColorProfile = Output::ColorProfile; - impl::Display virtualDisplay{mCompositionEngine, - DisplayCreationArgs{false, true, DEFAULT_DISPLAY_ID}}; + std::shared_ptr virtualDisplay{ + impl::createDisplay(mCompositionEngine, DisplayCreationArgs{true, DEFAULT_DISPLAY_ID})}; mock::DisplayColorProfile* colorProfile = new StrictMock(); - virtualDisplay.setDisplayColorProfileForTest( + virtualDisplay->setDisplayColorProfileForTest( std::unique_ptr(colorProfile)); EXPECT_CALL(*colorProfile, @@ -224,14 +223,14 @@ TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) { ui::Dataspace::UNKNOWN)) .WillOnce(Return(ui::Dataspace::UNKNOWN)); - virtualDisplay.setColorProfile( + virtualDisplay->setColorProfile( ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN}); - EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay.getState().colorMode); - EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay.getState().dataspace); - EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, virtualDisplay.getState().renderIntent); - EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace); + EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay->getState().colorMode); + EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay->getState().dataspace); + EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, virtualDisplay->getState().renderIntent); + EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay->getState().targetDataspace); } /* @@ -239,11 +238,11 @@ TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) { */ TEST_F(DisplayTest, createDisplayColorProfileSetsDisplayColorProfile) { - EXPECT_TRUE(mDisplay.getDisplayColorProfile() == nullptr); - mDisplay.createDisplayColorProfile( + EXPECT_TRUE(mDisplay->getDisplayColorProfile() == nullptr); + mDisplay->createDisplayColorProfile( DisplayColorProfileCreationArgs{false, HdrCapabilities(), 0, DisplayColorProfileCreationArgs::HwcColorModes()}); - EXPECT_TRUE(mDisplay.getDisplayColorProfile() != nullptr); + EXPECT_TRUE(mDisplay->getDisplayColorProfile() != nullptr); } /* @@ -252,9 +251,9 @@ TEST_F(DisplayTest, createDisplayColorProfileSetsDisplayColorProfile) { TEST_F(DisplayTest, createRenderSurfaceSetsRenderSurface) { EXPECT_CALL(*mNativeWindow, disconnect(NATIVE_WINDOW_API_EGL)).WillRepeatedly(Return(NO_ERROR)); - EXPECT_TRUE(mDisplay.getRenderSurface() == nullptr); - mDisplay.createRenderSurface(RenderSurfaceCreationArgs{640, 480, mNativeWindow, nullptr}); - EXPECT_TRUE(mDisplay.getRenderSurface() != nullptr); + EXPECT_TRUE(mDisplay->getRenderSurface() == nullptr); + mDisplay->createRenderSurface(RenderSurfaceCreationArgs{640, 480, mNativeWindow, nullptr}); + EXPECT_TRUE(mDisplay->getRenderSurface() != nullptr); } /* @@ -268,7 +267,7 @@ TEST_F(DisplayTest, createOutputLayerSetsHwcLayer) { EXPECT_CALL(mHwComposer, createLayer(DEFAULT_DISPLAY_ID)).WillOnce(Return(&hwcLayer)); - auto outputLayer = mDisplay.createOutputLayer(layer, layerFE); + auto outputLayer = mDisplay->createOutputLayer(layer, layerFE); EXPECT_EQ(&hwcLayer, outputLayer->getHwcLayer()); @@ -308,13 +307,13 @@ TEST_F(DisplayTest, setReleasedLayersDoesNothingIfNoLayersWithQueuedFrames) { { Output::ReleasedLayers releasedLayers; releasedLayers.emplace_back(layerXLayerFE); - mDisplay.setReleasedLayers(std::move(releasedLayers)); + mDisplay->setReleasedLayers(std::move(releasedLayers)); } CompositionRefreshArgs refreshArgs; - mDisplay.setReleasedLayers(refreshArgs); + mDisplay->setReleasedLayers(refreshArgs); - const auto& releasedLayers = mDisplay.getReleasedLayersForTest(); + const auto& releasedLayers = mDisplay->getReleasedLayersForTest(); ASSERT_EQ(1, releasedLayers.size()); } @@ -341,9 +340,9 @@ TEST_F(DisplayTest, setReleasedLayers) { refreshArgs.layersWithQueuedFrames.push_back(&layerXLayer); refreshArgs.layersWithQueuedFrames.push_back(nullptr); - mDisplay.setReleasedLayers(refreshArgs); + mDisplay->setReleasedLayers(refreshArgs); - const auto& releasedLayers = mDisplay.getReleasedLayersForTest(); + const auto& releasedLayers = mDisplay->getReleasedLayersForTest(); ASSERT_EQ(2, releasedLayers.size()); ASSERT_EQ(layer1LayerFE.get(), releasedLayers[0].promote().get()); ASSERT_EQ(layer2LayerFE.get(), releasedLayers[1].promote().get()); @@ -356,8 +355,8 @@ TEST_F(DisplayTest, setReleasedLayers) { struct DisplayChooseCompositionStrategyTest : public testing::Test { struct DisplayPartialMock : public impl::Display { DisplayPartialMock(const compositionengine::CompositionEngine& compositionEngine, - compositionengine::DisplayCreationArgs&& args) - : impl::Display(compositionEngine, std::move(args)) {} + const compositionengine::DisplayCreationArgs& args) + : impl::Display(args), mCompositionEngine(compositionEngine) {} // Sets up the helper functions called by chooseCompositionStrategy to // use a mock implementations. @@ -366,6 +365,21 @@ struct DisplayChooseCompositionStrategyTest : public testing::Test { MOCK_METHOD1(applyChangedTypesToLayers, void(const impl::Display::ChangedTypes&)); MOCK_METHOD1(applyDisplayRequests, void(const impl::Display::DisplayRequests&)); MOCK_METHOD1(applyLayerRequestsToLayers, void(const impl::Display::LayerRequests&)); + + // compositionengine::Output overrides + const OutputCompositionState& getState() const override { return mState; } + OutputCompositionState& editState() override { return mState; } + + // compositionengine::impl::Output overrides + const CompositionEngine& getCompositionEngine() const override { + return mCompositionEngine; + }; + + // These need implementations though are not expected to be called. + MOCK_CONST_METHOD1(dumpState, void(std::string&)); + + const compositionengine::CompositionEngine& mCompositionEngine; + impl::OutputCompositionState mState; }; DisplayChooseCompositionStrategyTest() { @@ -380,12 +394,13 @@ struct DisplayChooseCompositionStrategyTest : public testing::Test { }; TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfNotAHwcDisplay) { - impl::Display nonHwcDisplay{mCompositionEngine, DisplayCreationArgsBuilder().build()}; - EXPECT_FALSE(nonHwcDisplay.getId()); + std::shared_ptr nonHwcDisplay{ + impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())}; + EXPECT_FALSE(nonHwcDisplay->getId()); - nonHwcDisplay.chooseCompositionStrategy(); + nonHwcDisplay->chooseCompositionStrategy(); - auto& state = nonHwcDisplay.getState(); + auto& state = nonHwcDisplay->getState(); EXPECT_TRUE(state.usesClientComposition); EXPECT_FALSE(state.usesDeviceComposition); } @@ -466,7 +481,7 @@ TEST_F(DisplayTest, getSkipColorTransformChecksHwcCapability) { hasDisplayCapability(std::make_optional(DEFAULT_DISPLAY_ID), HWC2::DisplayCapability::SkipClientColorTransform)) .WillOnce(Return(true)); - EXPECT_TRUE(mDisplay.getSkipColorTransform()); + EXPECT_TRUE(mDisplay->getSkipColorTransform()); } /* @@ -478,14 +493,14 @@ TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsFalse) { EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(false)); EXPECT_CALL(*mLayer3, requiresClientComposition()).WillOnce(Return(false)); - EXPECT_FALSE(mDisplay.anyLayersRequireClientComposition()); + EXPECT_FALSE(mDisplay->anyLayersRequireClientComposition()); } TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsTrue) { EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(false)); EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(true)); - EXPECT_TRUE(mDisplay.anyLayersRequireClientComposition()); + EXPECT_TRUE(mDisplay->anyLayersRequireClientComposition()); } /* @@ -497,14 +512,14 @@ TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsTrue) { EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(true)); EXPECT_CALL(*mLayer3, requiresClientComposition()).WillOnce(Return(true)); - EXPECT_TRUE(mDisplay.allLayersRequireClientComposition()); + EXPECT_TRUE(mDisplay->allLayersRequireClientComposition()); } TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsFalse) { EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(true)); EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(false)); - EXPECT_FALSE(mDisplay.allLayersRequireClientComposition()); + EXPECT_FALSE(mDisplay->allLayersRequireClientComposition()); } /* @@ -512,7 +527,7 @@ TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsFalse) { */ TEST_F(DisplayTest, applyChangedTypesToLayersTakesEarlyOutIfNoChangedLayers) { - mDisplay.applyChangedTypesToLayers(impl::Display::ChangedTypes()); + mDisplay->applyChangedTypesToLayers(impl::Display::ChangedTypes()); } TEST_F(DisplayTest, applyChangedTypesToLayersAppliesChanges) { @@ -523,7 +538,7 @@ TEST_F(DisplayTest, applyChangedTypesToLayersAppliesChanges) { applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::DEVICE)) .Times(1); - mDisplay.applyChangedTypesToLayers(impl::Display::ChangedTypes{ + mDisplay->applyChangedTypesToLayers(impl::Display::ChangedTypes{ {&mHWC2Layer1, HWC2::Composition::Client}, {&mHWC2Layer2, HWC2::Composition::Device}, {&mHWC2LayerUnknown, HWC2::Composition::SolidColor}, @@ -535,30 +550,30 @@ TEST_F(DisplayTest, applyChangedTypesToLayersAppliesChanges) { */ TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesNoRequests) { - mDisplay.applyDisplayRequests(static_cast(0)); + mDisplay->applyDisplayRequests(static_cast(0)); - auto& state = mDisplay.getState(); + auto& state = mDisplay->getState(); EXPECT_FALSE(state.flipClientTarget); } TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesFlipClientTarget) { - mDisplay.applyDisplayRequests(HWC2::DisplayRequest::FlipClientTarget); + mDisplay->applyDisplayRequests(HWC2::DisplayRequest::FlipClientTarget); - auto& state = mDisplay.getState(); + auto& state = mDisplay->getState(); EXPECT_TRUE(state.flipClientTarget); } TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesWriteClientTargetToOutput) { - mDisplay.applyDisplayRequests(HWC2::DisplayRequest::WriteClientTargetToOutput); + mDisplay->applyDisplayRequests(HWC2::DisplayRequest::WriteClientTargetToOutput); - auto& state = mDisplay.getState(); + auto& state = mDisplay->getState(); EXPECT_FALSE(state.flipClientTarget); } TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesAllRequestFlagsSet) { - mDisplay.applyDisplayRequests(static_cast(~0)); + mDisplay->applyDisplayRequests(static_cast(~0)); - auto& state = mDisplay.getState(); + auto& state = mDisplay->getState(); EXPECT_TRUE(state.flipClientTarget); } @@ -571,7 +586,7 @@ TEST_F(DisplayTest, applyLayerRequestsToLayersPreparesAllLayers) { EXPECT_CALL(*mLayer2, prepareForDeviceLayerRequests()).Times(1); EXPECT_CALL(*mLayer3, prepareForDeviceLayerRequests()).Times(1); - mDisplay.applyLayerRequestsToLayers(impl::Display::LayerRequests()); + mDisplay->applyLayerRequestsToLayers(impl::Display::LayerRequests()); } TEST_F(DisplayTest, applyLayerRequestsToLayers2) { @@ -583,7 +598,7 @@ TEST_F(DisplayTest, applyLayerRequestsToLayers2) { applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET)) .Times(1); - mDisplay.applyLayerRequestsToLayers(impl::Display::LayerRequests{ + mDisplay->applyLayerRequestsToLayers(impl::Display::LayerRequests{ {&mHWC2Layer1, HWC2::LayerRequest::ClearClientTarget}, {&mHWC2LayerUnknown, HWC2::LayerRequest::ClearClientTarget}, }); @@ -617,7 +632,7 @@ TEST_F(DisplayTest, presentAndGetFrameFencesReturnsPresentAndLayerFences) { .WillOnce(Return(layer2Fence)); EXPECT_CALL(mHwComposer, clearReleaseFences(DEFAULT_DISPLAY_ID)).Times(1); - auto result = mDisplay.presentAndGetFrameFences(); + auto result = mDisplay->presentAndGetFrameFences(); EXPECT_EQ(presentFence, result.presentFence); @@ -634,10 +649,10 @@ TEST_F(DisplayTest, presentAndGetFrameFencesReturnsPresentAndLayerFences) { TEST_F(DisplayTest, setExpensiveRenderingExpectedForwardsToPowerAdvisor) { EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, true)).Times(1); - mDisplay.setExpensiveRenderingExpected(true); + mDisplay->setExpensiveRenderingExpected(true); EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, false)).Times(1); - mDisplay.setExpensiveRenderingExpected(false); + mDisplay->setExpensiveRenderingExpected(false); } /* @@ -646,20 +661,20 @@ TEST_F(DisplayTest, setExpensiveRenderingExpectedForwardsToPowerAdvisor) { TEST_F(DisplayTest, finishFrameDoesNotSkipCompositionIfNotDirtyOnHwcDisplay) { mock::RenderSurface* renderSurface = new StrictMock(); - mDisplay.setRenderSurfaceForTest(std::unique_ptr(renderSurface)); + mDisplay->setRenderSurfaceForTest(std::unique_ptr(renderSurface)); // We expect no calls to queueBuffer if composition was skipped. EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1); - mDisplay.editState().isEnabled = true; - mDisplay.editState().usesClientComposition = false; - mDisplay.editState().viewport = Rect(0, 0, 1, 1); - mDisplay.editState().dirtyRegion = Region::INVALID_REGION; + mDisplay->editState().isEnabled = true; + mDisplay->editState().usesClientComposition = false; + mDisplay->editState().viewport = Rect(0, 0, 1, 1); + mDisplay->editState().dirtyRegion = Region::INVALID_REGION; CompositionRefreshArgs refreshArgs; refreshArgs.repaintEverything = false; - mDisplay.finishFrame(refreshArgs); + mDisplay->finishFrame(refreshArgs); } TEST_F(DisplayTest, finishFrameSkipsCompositionIfNotDirty) { diff --git a/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp index 26115a344e..787f973215 100644 --- a/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -26,13 +27,28 @@ namespace { using testing::StrictMock; -class LayerTest : public testing::Test { -public: +struct LayerTest : public testing::Test { + struct Layer final : public impl::Layer { + explicit Layer(const LayerCreationArgs& args) : mLayerFE(args.layerFE) {} + ~Layer() override = default; + + // compositionengine::Layer overrides + sp getLayerFE() const { return mLayerFE.promote(); } + const LayerFECompositionState& getFEState() const override { return mFrontEndState; } + LayerFECompositionState& editFEState() override { return mFrontEndState; } + + // compositionengine::impl::Layer overrides + void dumpFEState(std::string& out) const override { mFrontEndState.dump(out); } + + const wp mLayerFE; + LayerFECompositionState mFrontEndState; + }; + ~LayerTest() override = default; StrictMock mCompositionEngine; sp mLayerFE = new StrictMock(); - impl::Layer mLayer{mCompositionEngine, LayerCreationArgs{mLayerFE}}; + Layer mLayer{LayerCreationArgs{mLayerFE}}; }; /* ------------------------------------------------------------------------ diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index a1c156a230..0347f759e7 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -55,6 +56,29 @@ MATCHER_P(ColorEq, expected, "") { } struct OutputLayerTest : public testing::Test { + struct OutputLayer final : public impl::OutputLayer { + OutputLayer(const compositionengine::Output& output, + std::shared_ptr layer, + sp layerFE) + : mOutput(output), mLayer(layer), mLayerFE(layerFE) {} + ~OutputLayer() override = default; + + // compositionengine::OutputLayer overrides + const compositionengine::Output& getOutput() const override { return mOutput; } + compositionengine::Layer& getLayer() const override { return *mLayer; } + compositionengine::LayerFE& getLayerFE() const override { return *mLayerFE; } + const impl::OutputLayerCompositionState& getState() const override { return mState; } + impl::OutputLayerCompositionState& editState() override { return mState; } + + // compositionengine::impl::OutputLayer overrides + void dumpState(std::string& out) const override { mState.dump(out); } + + const compositionengine::Output& mOutput; + std::shared_ptr mLayer; + sp mLayerFE; + impl::OutputLayerCompositionState mState; + }; + OutputLayerTest() { EXPECT_CALL(*mLayerFE, getDebugName()).WillRepeatedly(Return("Test LayerFE")); EXPECT_CALL(mOutput, getName()).WillRepeatedly(ReturnRef(kOutputName)); @@ -68,7 +92,7 @@ struct OutputLayerTest : public testing::Test { new StrictMock()}; sp mLayerFE{ new StrictMock()}; - impl::OutputLayer mOutputLayer{mOutput, mLayer, mLayerFE}; + OutputLayer mOutputLayer{mOutput, mLayer, mLayerFE}; LayerFECompositionState mLayerFEState; impl::OutputCompositionState mOutputState; @@ -413,11 +437,26 @@ struct OutputLayerPartialMockForUpdateCompositionState : public impl::OutputLaye OutputLayerPartialMockForUpdateCompositionState(const compositionengine::Output& output, std::shared_ptr layer, sp layerFE) - : impl::OutputLayer(output, layer, layerFE) {} + : mOutput(output), mLayer(layer), mLayerFE(layerFE) {} // Mock everything called by updateCompositionState to simplify testing it. MOCK_CONST_METHOD0(calculateOutputSourceCrop, FloatRect()); MOCK_CONST_METHOD0(calculateOutputDisplayFrame, Rect()); MOCK_CONST_METHOD0(calculateOutputRelativeBufferTransform, uint32_t()); + + // compositionengine::OutputLayer overrides + const compositionengine::Output& getOutput() const override { return mOutput; } + compositionengine::Layer& getLayer() const override { return *mLayer; } + compositionengine::LayerFE& getLayerFE() const override { return *mLayerFE; } + const impl::OutputLayerCompositionState& getState() const override { return mState; } + impl::OutputLayerCompositionState& editState() override { return mState; } + + // These need implementations though are not expected to be called. + MOCK_CONST_METHOD1(dumpState, void(std::string&)); + + const compositionengine::Output& mOutput; + std::shared_ptr mLayer; + sp mLayerFE; + impl::OutputLayerCompositionState mState; }; struct OutputLayerUpdateCompositionStateTest : public OutputLayerTest { diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 70c343bba6..635d77be8a 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -51,11 +51,11 @@ const mat4 kNonIdentityQuarter = mat4() * 0.25; struct OutputTest : public testing::Test { OutputTest() { - mOutput.setDisplayColorProfileForTest( + mOutput->setDisplayColorProfileForTest( std::unique_ptr(mDisplayColorProfile)); - mOutput.setRenderSurfaceForTest(std::unique_ptr(mRenderSurface)); + mOutput->setRenderSurfaceForTest(std::unique_ptr(mRenderSurface)); - mOutput.editState().bounds = kDefaultDisplaySize; + mOutput->editState().bounds = kDefaultDisplaySize; } static const Rect kDefaultDisplaySize; @@ -63,7 +63,7 @@ struct OutputTest : public testing::Test { StrictMock mCompositionEngine; mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock(); mock::RenderSurface* mRenderSurface = new StrictMock(); - impl::Output mOutput{mCompositionEngine}; + std::shared_ptr mOutput = impl::createOutput(mCompositionEngine); }; const Rect OutputTest::kDefaultDisplaySize{100, 200}; @@ -77,14 +77,14 @@ TEST_F(OutputTest, canInstantiateOutput) { EXPECT_CALL(*mDisplayColorProfile, isValid()).WillOnce(Return(true)); EXPECT_CALL(*mRenderSurface, isValid()).WillOnce(Return(true)); - EXPECT_TRUE(mOutput.isValid()); + EXPECT_TRUE(mOutput->isValid()); // If we take away the required components, it is no longer valid. - mOutput.setRenderSurfaceForTest(std::unique_ptr()); + mOutput->setRenderSurfaceForTest(std::unique_ptr()); EXPECT_CALL(*mDisplayColorProfile, isValid()).WillOnce(Return(true)); - EXPECT_FALSE(mOutput.isValid()); + EXPECT_FALSE(mOutput->isValid()); } /* @@ -92,30 +92,30 @@ TEST_F(OutputTest, canInstantiateOutput) { */ TEST_F(OutputTest, setCompositionEnabledDoesNothingIfAlreadyEnabled) { - mOutput.editState().isEnabled = true; + mOutput->editState().isEnabled = true; - mOutput.setCompositionEnabled(true); + mOutput->setCompositionEnabled(true); - EXPECT_TRUE(mOutput.getState().isEnabled); - EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region())); + EXPECT_TRUE(mOutput->getState().isEnabled); + EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region())); } TEST_F(OutputTest, setCompositionEnabledSetsEnabledAndDirtiesEntireOutput) { - mOutput.editState().isEnabled = false; + mOutput->editState().isEnabled = false; - mOutput.setCompositionEnabled(true); + mOutput->setCompositionEnabled(true); - EXPECT_TRUE(mOutput.getState().isEnabled); - EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); + EXPECT_TRUE(mOutput->getState().isEnabled); + EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } TEST_F(OutputTest, setCompositionEnabledSetsDisabledAndDirtiesEntireOutput) { - mOutput.editState().isEnabled = true; + mOutput->editState().isEnabled = true; - mOutput.setCompositionEnabled(false); + mOutput->setCompositionEnabled(false); - EXPECT_FALSE(mOutput.getState().isEnabled); - EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); + EXPECT_FALSE(mOutput->getState().isEnabled); + EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } /* @@ -130,14 +130,14 @@ TEST_F(OutputTest, setProjectionTriviallyWorks) { const Rect scissor{9, 10, 11, 12}; const bool needsFiltering = true; - mOutput.setProjection(transform, orientation, frame, viewport, scissor, needsFiltering); + mOutput->setProjection(transform, orientation, frame, viewport, scissor, needsFiltering); - EXPECT_THAT(mOutput.getState().transform, TransformEq(transform)); - EXPECT_EQ(orientation, mOutput.getState().orientation); - EXPECT_EQ(frame, mOutput.getState().frame); - EXPECT_EQ(viewport, mOutput.getState().viewport); - EXPECT_EQ(scissor, mOutput.getState().scissor); - EXPECT_EQ(needsFiltering, mOutput.getState().needsFiltering); + EXPECT_THAT(mOutput->getState().transform, TransformEq(transform)); + EXPECT_EQ(orientation, mOutput->getState().orientation); + EXPECT_EQ(frame, mOutput->getState().frame); + EXPECT_EQ(viewport, mOutput->getState().viewport); + EXPECT_EQ(scissor, mOutput->getState().scissor); + EXPECT_EQ(needsFiltering, mOutput->getState().needsFiltering); } /* @@ -150,11 +150,11 @@ TEST_F(OutputTest, setBoundsSetsSizeAndDirtiesEntireOutput) { EXPECT_CALL(*mRenderSurface, setDisplaySize(displaySize)).Times(1); EXPECT_CALL(*mRenderSurface, getSize()).WillOnce(ReturnRef(displaySize)); - mOutput.setBounds(displaySize); + mOutput->setBounds(displaySize); - EXPECT_EQ(Rect(displaySize), mOutput.getState().bounds); + EXPECT_EQ(Rect(displaySize), mOutput->getState().bounds); - EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(Rect(displaySize)))); + EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(Rect(displaySize)))); } /* @@ -163,12 +163,12 @@ TEST_F(OutputTest, setBoundsSetsSizeAndDirtiesEntireOutput) { TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) { const uint32_t layerStack = 123u; - mOutput.setLayerStackFilter(layerStack, true); + mOutput->setLayerStackFilter(layerStack, true); - EXPECT_TRUE(mOutput.getState().layerStackInternal); - EXPECT_EQ(layerStack, mOutput.getState().layerStackId); + EXPECT_TRUE(mOutput->getState().layerStackInternal); + EXPECT_EQ(layerStack, mOutput->getState().layerStackId); - EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); + EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } /* @@ -176,84 +176,84 @@ TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) { */ TEST_F(OutputTest, setColorTransformWithNoChangeFlaggedSkipsUpdates) { - mOutput.editState().colorTransformMatrix = kIdentity; + mOutput->editState().colorTransformMatrix = kIdentity; // If no colorTransformMatrix is set the update should be skipped. CompositionRefreshArgs refreshArgs; refreshArgs.colorTransformMatrix = std::nullopt; - mOutput.setColorTransform(refreshArgs); + mOutput->setColorTransform(refreshArgs); // The internal state should be unchanged - EXPECT_EQ(kIdentity, mOutput.getState().colorTransformMatrix); + EXPECT_EQ(kIdentity, mOutput->getState().colorTransformMatrix); // No dirty region should be set - EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region())); + EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region())); } TEST_F(OutputTest, setColorTransformWithNoActualChangeSkipsUpdates) { - mOutput.editState().colorTransformMatrix = kIdentity; + mOutput->editState().colorTransformMatrix = kIdentity; // Attempting to set the same colorTransformMatrix that is already set should // also skip the update. CompositionRefreshArgs refreshArgs; refreshArgs.colorTransformMatrix = kIdentity; - mOutput.setColorTransform(refreshArgs); + mOutput->setColorTransform(refreshArgs); // The internal state should be unchanged - EXPECT_EQ(kIdentity, mOutput.getState().colorTransformMatrix); + EXPECT_EQ(kIdentity, mOutput->getState().colorTransformMatrix); // No dirty region should be set - EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region())); + EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region())); } TEST_F(OutputTest, setColorTransformPerformsUpdateToIdentity) { - mOutput.editState().colorTransformMatrix = kNonIdentityHalf; + mOutput->editState().colorTransformMatrix = kNonIdentityHalf; // Setting a different colorTransformMatrix should perform the update. CompositionRefreshArgs refreshArgs; refreshArgs.colorTransformMatrix = kIdentity; - mOutput.setColorTransform(refreshArgs); + mOutput->setColorTransform(refreshArgs); // The internal state should have been updated - EXPECT_EQ(kIdentity, mOutput.getState().colorTransformMatrix); + EXPECT_EQ(kIdentity, mOutput->getState().colorTransformMatrix); // The dirtyRegion should be set to the full display size - EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); + EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } TEST_F(OutputTest, setColorTransformPerformsUpdateForIdentityToHalf) { - mOutput.editState().colorTransformMatrix = kIdentity; + mOutput->editState().colorTransformMatrix = kIdentity; // Setting a different colorTransformMatrix should perform the update. CompositionRefreshArgs refreshArgs; refreshArgs.colorTransformMatrix = kNonIdentityHalf; - mOutput.setColorTransform(refreshArgs); + mOutput->setColorTransform(refreshArgs); // The internal state should have been updated - EXPECT_EQ(kNonIdentityHalf, mOutput.getState().colorTransformMatrix); + EXPECT_EQ(kNonIdentityHalf, mOutput->getState().colorTransformMatrix); // The dirtyRegion should be set to the full display size - EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); + EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } TEST_F(OutputTest, setColorTransformPerformsUpdateForHalfToQuarter) { - mOutput.editState().colorTransformMatrix = kNonIdentityHalf; + mOutput->editState().colorTransformMatrix = kNonIdentityHalf; // Setting a different colorTransformMatrix should perform the update. CompositionRefreshArgs refreshArgs; refreshArgs.colorTransformMatrix = kNonIdentityQuarter; - mOutput.setColorTransform(refreshArgs); + mOutput->setColorTransform(refreshArgs); // The internal state should have been updated - EXPECT_EQ(kNonIdentityQuarter, mOutput.getState().colorTransformMatrix); + EXPECT_EQ(kNonIdentityQuarter, mOutput->getState().colorTransformMatrix); // The dirtyRegion should be set to the full display size - EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); + EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } /* @@ -269,16 +269,16 @@ TEST_F(OutputTest, setColorModeSetsStateAndDirtiesOutputIfChanged) { .WillOnce(Return(ui::Dataspace::UNKNOWN)); EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1); - mOutput.setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC, - ui::Dataspace::UNKNOWN}); + mOutput->setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, + ui::RenderIntent::TONE_MAP_COLORIMETRIC, + ui::Dataspace::UNKNOWN}); - EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mOutput.getState().colorMode); - EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutput.getState().dataspace); - EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mOutput.getState().renderIntent); - EXPECT_EQ(ui::Dataspace::UNKNOWN, mOutput.getState().targetDataspace); + EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mOutput->getState().colorMode); + EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutput->getState().dataspace); + EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mOutput->getState().renderIntent); + EXPECT_EQ(ui::Dataspace::UNKNOWN, mOutput->getState().targetDataspace); - EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); + EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } TEST_F(OutputTest, setColorModeDoesNothingIfNoChange) { @@ -289,16 +289,16 @@ TEST_F(OutputTest, setColorModeDoesNothingIfNoChange) { ui::Dataspace::UNKNOWN)) .WillOnce(Return(ui::Dataspace::UNKNOWN)); - mOutput.editState().colorMode = ui::ColorMode::DISPLAY_P3; - mOutput.editState().dataspace = ui::Dataspace::DISPLAY_P3; - mOutput.editState().renderIntent = ui::RenderIntent::TONE_MAP_COLORIMETRIC; - mOutput.editState().targetDataspace = ui::Dataspace::UNKNOWN; + mOutput->editState().colorMode = ui::ColorMode::DISPLAY_P3; + mOutput->editState().dataspace = ui::Dataspace::DISPLAY_P3; + mOutput->editState().renderIntent = ui::RenderIntent::TONE_MAP_COLORIMETRIC; + mOutput->editState().targetDataspace = ui::Dataspace::UNKNOWN; - mOutput.setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC, - ui::Dataspace::UNKNOWN}); + mOutput->setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, + ui::RenderIntent::TONE_MAP_COLORIMETRIC, + ui::Dataspace::UNKNOWN}); - EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region())); + EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region())); } /* @@ -311,9 +311,9 @@ TEST_F(OutputTest, setRenderSurfaceResetsBounds) { mock::RenderSurface* renderSurface = new StrictMock(); EXPECT_CALL(*renderSurface, getSize()).WillOnce(ReturnRef(newDisplaySize)); - mOutput.setRenderSurface(std::unique_ptr(renderSurface)); + mOutput->setRenderSurface(std::unique_ptr(renderSurface)); - EXPECT_EQ(Rect(newDisplaySize), mOutput.getState().bounds); + EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().bounds); } /* @@ -322,11 +322,11 @@ TEST_F(OutputTest, setRenderSurfaceResetsBounds) { TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingTrue) { const Rect viewport{100, 200}; - mOutput.editState().viewport = viewport; - mOutput.editState().dirtyRegion.set(50, 300); + mOutput->editState().viewport = viewport; + mOutput->editState().dirtyRegion.set(50, 300); { - Region result = mOutput.getDirtyRegion(true); + Region result = mOutput->getDirtyRegion(true); EXPECT_THAT(result, RegionEq(Region(viewport))); } @@ -334,11 +334,11 @@ TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingTrue) { TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingFalse) { const Rect viewport{100, 200}; - mOutput.editState().viewport = viewport; - mOutput.editState().dirtyRegion.set(50, 300); + mOutput->editState().viewport = viewport; + mOutput->editState().dirtyRegion.set(50, 300); { - Region result = mOutput.getDirtyRegion(false); + Region result = mOutput->getDirtyRegion(false); // The dirtyRegion should be clipped to the display bounds. EXPECT_THAT(result, RegionEq(Region(Rect(50, 200)))); @@ -354,26 +354,26 @@ TEST_F(OutputTest, belongsInOutputFiltersAsExpected) { const uint32_t layerStack2 = 456u; // If the output accepts layerStack1 and internal-only layers.... - mOutput.setLayerStackFilter(layerStack1, true); + mOutput->setLayerStackFilter(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)); + EXPECT_FALSE(mOutput->belongsInOutput(std::nullopt, false)); + EXPECT_FALSE(mOutput->belongsInOutput(std::nullopt, 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)); + EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, false)); + EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, true)); + EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, true)); + EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, false)); // If the output accepts layerStack21 but not internal-only layers... - mOutput.setLayerStackFilter(layerStack1, false); + mOutput->setLayerStackFilter(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)); + EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, false)); + EXPECT_FALSE(mOutput->belongsInOutput(layerStack1, true)); + EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, true)); + EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, false)); } TEST_F(OutputTest, belongsInOutputFiltersLayersAsExpected) { @@ -386,59 +386,59 @@ TEST_F(OutputTest, belongsInOutputFiltersLayersAsExpected) { const uint32_t layerStack2 = 456u; // If the output accepts layerStack1 and internal-only layers.... - mOutput.setLayerStackFilter(layerStack1, true); + mOutput->setLayerStackFilter(layerStack1, true); // A null layer pointer does not belong to the output - EXPECT_FALSE(mOutput.belongsInOutput(nullptr)); + EXPECT_FALSE(mOutput->belongsInOutput(nullptr)); // A layer with no layerStack does not belong to it, internal-only or not. layerFEState.layerStackId = std::nullopt; layerFEState.internalOnly = false; - EXPECT_FALSE(mOutput.belongsInOutput(&layer)); + EXPECT_FALSE(mOutput->belongsInOutput(&layer)); layerFEState.layerStackId = std::nullopt; layerFEState.internalOnly = true; - EXPECT_FALSE(mOutput.belongsInOutput(&layer)); + EXPECT_FALSE(mOutput->belongsInOutput(&layer)); // Any layer with layerStack1 belongs to it, internal-only or not. layerFEState.layerStackId = layerStack1; layerFEState.internalOnly = false; - EXPECT_TRUE(mOutput.belongsInOutput(&layer)); + EXPECT_TRUE(mOutput->belongsInOutput(&layer)); layerFEState.layerStackId = layerStack1; layerFEState.internalOnly = true; - EXPECT_TRUE(mOutput.belongsInOutput(&layer)); + EXPECT_TRUE(mOutput->belongsInOutput(&layer)); layerFEState.layerStackId = layerStack2; layerFEState.internalOnly = true; - EXPECT_FALSE(mOutput.belongsInOutput(&layer)); + EXPECT_FALSE(mOutput->belongsInOutput(&layer)); layerFEState.layerStackId = layerStack2; layerFEState.internalOnly = false; - EXPECT_FALSE(mOutput.belongsInOutput(&layer)); + EXPECT_FALSE(mOutput->belongsInOutput(&layer)); // If the output accepts layerStack1 but not internal-only layers... - mOutput.setLayerStackFilter(layerStack1, false); + mOutput->setLayerStackFilter(layerStack1, false); // A null layer pointer does not belong to the output - EXPECT_FALSE(mOutput.belongsInOutput(nullptr)); + EXPECT_FALSE(mOutput->belongsInOutput(nullptr)); // Only non-internal layers with layerStack1 belong to it. layerFEState.layerStackId = layerStack1; layerFEState.internalOnly = false; - EXPECT_TRUE(mOutput.belongsInOutput(&layer)); + EXPECT_TRUE(mOutput->belongsInOutput(&layer)); layerFEState.layerStackId = layerStack1; layerFEState.internalOnly = true; - EXPECT_FALSE(mOutput.belongsInOutput(&layer)); + EXPECT_FALSE(mOutput->belongsInOutput(&layer)); layerFEState.layerStackId = layerStack2; layerFEState.internalOnly = true; - EXPECT_FALSE(mOutput.belongsInOutput(&layer)); + EXPECT_FALSE(mOutput->belongsInOutput(&layer)); layerFEState.layerStackId = layerStack2; layerFEState.internalOnly = false; - EXPECT_FALSE(mOutput.belongsInOutput(&layer)); + EXPECT_FALSE(mOutput->belongsInOutput(&layer)); } /* @@ -453,71 +453,24 @@ TEST_F(OutputTest, getOutputLayerForLayerWorks) { outputLayers.emplace_back(std::unique_ptr(outputLayer1)); outputLayers.emplace_back(nullptr); outputLayers.emplace_back(std::unique_ptr(outputLayer2)); - mOutput.setOutputLayersOrderedByZ(std::move(outputLayers)); + mOutput->setOutputLayersOrderedByZ(std::move(outputLayers)); StrictMock layer; StrictMock otherLayer; // If the input layer matches the first OutputLayer, it will be returned. EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(layer)); - EXPECT_EQ(outputLayer1, mOutput.getOutputLayerForLayer(&layer)); + EXPECT_EQ(outputLayer1, mOutput->getOutputLayerForLayer(&layer)); // If the input layer matches the second OutputLayer, it will be returned. EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(otherLayer)); EXPECT_CALL(*outputLayer2, getLayer()).WillOnce(ReturnRef(layer)); - EXPECT_EQ(outputLayer2, mOutput.getOutputLayerForLayer(&layer)); + EXPECT_EQ(outputLayer2, mOutput->getOutputLayerForLayer(&layer)); // If the input layer does not match an output layer, null will be returned. EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(otherLayer)); EXPECT_CALL(*outputLayer2, getLayer()).WillOnce(ReturnRef(otherLayer)); - EXPECT_EQ(nullptr, mOutput.getOutputLayerForLayer(&layer)); -} - -/* - * Output::getOrCreateOutputLayer() - */ - -TEST_F(OutputTest, getOrCreateOutputLayerWorks) { - mock::OutputLayer* existingOutputLayer = new StrictMock(); - - Output::OutputLayers outputLayers; - outputLayers.emplace_back(nullptr); - outputLayers.emplace_back(std::unique_ptr(existingOutputLayer)); - mOutput.setOutputLayersOrderedByZ(std::move(outputLayers)); - - std::shared_ptr layer{new StrictMock()}; - sp layerFE{new StrictMock()}; - - StrictMock otherLayer; - - { - // If there is no OutputLayer corresponding to the input layer, a - // new OutputLayer is constructed and returned. - EXPECT_CALL(*existingOutputLayer, getLayer()).WillOnce(ReturnRef(otherLayer)); - auto result = mOutput.getOrCreateOutputLayer(layer, layerFE); - EXPECT_NE(existingOutputLayer, result.get()); - EXPECT_TRUE(result.get() != nullptr); - EXPECT_EQ(layer.get(), &result->getLayer()); - EXPECT_EQ(layerFE.get(), &result->getLayerFE()); - - // The entries in the ordered array should be unchanged. - auto& outputLayers = mOutput.getOutputLayersOrderedByZ(); - EXPECT_EQ(nullptr, outputLayers[0].get()); - EXPECT_EQ(existingOutputLayer, outputLayers[1].get()); - } - - { - // If there is an existing OutputLayer for the requested layer, an owned - // pointer is returned - EXPECT_CALL(*existingOutputLayer, getLayer()).WillOnce(ReturnRef(*layer)); - auto result = mOutput.getOrCreateOutputLayer(layer, layerFE); - EXPECT_EQ(existingOutputLayer, result.get()); - - // The corresponding entry in the ordered array should be cleared. - auto& outputLayers = mOutput.getOutputLayersOrderedByZ(); - EXPECT_EQ(nullptr, outputLayers[0].get()); - EXPECT_EQ(nullptr, outputLayers[1].get()); - } + EXPECT_EQ(nullptr, mOutput->getOutputLayerForLayer(&layer)); } /* @@ -526,12 +479,19 @@ TEST_F(OutputTest, getOrCreateOutputLayerWorks) { struct OutputPrepareFrameTest : public testing::Test { struct OutputPartialMock : public impl::Output { - OutputPartialMock(const compositionengine::CompositionEngine& compositionEngine) - : impl::Output(compositionEngine) {} - // Sets up the helper functions called by prepareFrame to use a mock // implementations. MOCK_METHOD0(chooseCompositionStrategy, void()); + + // compositionengine::Output overrides + const OutputCompositionState& getState() const override { return mState; } + OutputCompositionState& editState() override { return mState; } + + // These need implementations though are not expected to be called. + MOCK_CONST_METHOD1(dumpState, void(std::string&)); + MOCK_CONST_METHOD0(getCompositionEngine, const CompositionEngine&()); + + impl::OutputCompositionState mState; }; OutputPrepareFrameTest() { @@ -543,7 +503,7 @@ struct OutputPrepareFrameTest : public testing::Test { StrictMock mCompositionEngine; mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock(); mock::RenderSurface* mRenderSurface = new StrictMock(); - StrictMock mOutput{mCompositionEngine}; + StrictMock mOutput; }; TEST_F(OutputPrepareFrameTest, takesEarlyOutIfNotEnabled) { @@ -566,16 +526,16 @@ TEST_F(OutputPrepareFrameTest, delegatesToChooseCompositionStrategyAndRenderSurf // Note: Use OutputTest and not OutputPrepareFrameTest, so the real // base chooseCompositionStrategy() is invoked. TEST_F(OutputTest, prepareFrameSetsClientCompositionOnlyByDefault) { - mOutput.editState().isEnabled = true; - mOutput.editState().usesClientComposition = false; - mOutput.editState().usesDeviceComposition = true; + mOutput->editState().isEnabled = true; + mOutput->editState().usesClientComposition = false; + mOutput->editState().usesDeviceComposition = true; EXPECT_CALL(*mRenderSurface, prepareFrame(true, false)); - mOutput.prepareFrame(); + mOutput->prepareFrame(); - EXPECT_TRUE(mOutput.getState().usesClientComposition); - EXPECT_FALSE(mOutput.getState().usesDeviceComposition); + EXPECT_TRUE(mOutput->getState().usesClientComposition); + EXPECT_FALSE(mOutput->getState().usesDeviceComposition); } /* @@ -592,9 +552,6 @@ struct OutputComposeSurfacesTest : public testing::Test { static const mat4 kDefaultColorTransformMat; struct OutputPartialMock : public impl::Output { - OutputPartialMock(const compositionengine::CompositionEngine& compositionEngine) - : impl::Output(compositionEngine) {} - // Sets up the helper functions called by composeSurfaces to use a mock // implementations. MOCK_CONST_METHOD0(getSkipColorTransform, bool()); @@ -603,6 +560,16 @@ struct OutputComposeSurfacesTest : public testing::Test { MOCK_METHOD2(appendRegionFlashRequests, void(const Region&, std::vector&)); MOCK_METHOD1(setExpensiveRenderingExpected, void(bool)); + + // compositionengine::Output overrides + const OutputCompositionState& getState() const override { return mState; } + OutputCompositionState& editState() override { return mState; } + + // These need implementations though are not expected to be called. + MOCK_CONST_METHOD1(dumpState, void(std::string&)); + MOCK_CONST_METHOD0(getCompositionEngine, const CompositionEngine&()); + + impl::OutputCompositionState mState; }; OutputComposeSurfacesTest() { @@ -627,6 +594,7 @@ struct OutputComposeSurfacesTest : public testing::Test { mOutput.editState().usesClientComposition = true; mOutput.editState().usesDeviceComposition = false; + EXPECT_CALL(mOutput, getCompositionEngine()).WillRepeatedly(ReturnRef(mCompositionEngine)); EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine)); } @@ -636,7 +604,7 @@ struct OutputComposeSurfacesTest : public testing::Test { mock::RenderSurface* mRenderSurface = new StrictMock(); mock::OutputLayer* mOutputLayer1 = new StrictMock(); mock::OutputLayer* mOutputLayer2 = new StrictMock(); - StrictMock mOutput{mCompositionEngine}; + StrictMock mOutput; sp mOutputBuffer = new GraphicBuffer(); }; @@ -691,14 +659,22 @@ TEST_F(OutputComposeSurfacesTest, worksIfNoClientLayersQueued) { struct GenerateClientCompositionRequestsTest : public testing::Test { struct OutputPartialMock : public impl::Output { - OutputPartialMock(const compositionengine::CompositionEngine& compositionEngine) - : impl::Output(compositionEngine) {} + // compositionengine::Output overrides std::vector generateClientCompositionRequests( bool supportsProtectedContent, Region& clearRegion) override { return impl::Output::generateClientCompositionRequests(supportsProtectedContent, clearRegion); } + + const OutputCompositionState& getState() const override { return mState; } + OutputCompositionState& editState() override { return mState; } + + // These need implementations though are not expected to be called. + MOCK_CONST_METHOD1(dumpState, void(std::string&)); + MOCK_CONST_METHOD0(getCompositionEngine, const CompositionEngine&()); + + impl::OutputCompositionState mState; }; GenerateClientCompositionRequestsTest() { @@ -707,10 +683,9 @@ struct GenerateClientCompositionRequestsTest : public testing::Test { mOutput.setRenderSurfaceForTest(std::unique_ptr(mRenderSurface)); } - StrictMock mCompositionEngine; mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock(); mock::RenderSurface* mRenderSurface = new StrictMock(); - StrictMock mOutput{mCompositionEngine}; + StrictMock mOutput; }; // TODO(b/121291683): Add more unit test coverage for generateClientCompositionRequests diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 2ada86beca..b1fcff2663 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -59,12 +59,13 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args) mSequenceId(args.sequenceId), mDisplayInstallOrientation(args.displayInstallOrientation), mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay( - compositionengine::DisplayCreationArgs{args.isSecure, args.isVirtual, - args.displayId, args.powerAdvisor})}, + compositionengine::DisplayCreationArgs{args.isVirtual, args.displayId, + args.powerAdvisor})}, mIsVirtual(args.isVirtual), mOrientation(), mActiveConfig(0), mIsPrimary(args.isPrimary) { + mCompositionDisplay->editState().isSecure = args.isSecure; mCompositionDisplay->createRenderSurface( compositionengine::RenderSurfaceCreationArgs{ANativeWindow_getWidth( args.nativeWindow.get()), -- cgit v1.2.3-59-g8ed1b From 2139f73d98f3f0d31f0f90bcca7f4537c66e5e70 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 13 Nov 2019 18:56:40 -0800 Subject: SurfaceFlinger: use config groups Composer 2.4 adds a new attribute for configs groups. This change groups configs according to their group and store them in RefreshRateConfigs. Test: rev up composer to 2.4 and test refresh rate switching Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest Test: adb shell /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test Bug: 141329414 Fixes: 139751853 Change-Id: Ic0bcd3da4bf6b73efa11a60c2594948ce030362f --- services/surfaceflinger/BufferQueueLayer.cpp | 3 +- services/surfaceflinger/BufferStateLayer.cpp | 3 +- services/surfaceflinger/DisplayDevice.cpp | 6 +- services/surfaceflinger/DisplayDevice.h | 7 +- services/surfaceflinger/RefreshRateOverlay.cpp | 6 +- services/surfaceflinger/RefreshRateOverlay.h | 4 +- services/surfaceflinger/Scheduler/EventThread.cpp | 8 +- services/surfaceflinger/Scheduler/EventThread.h | 5 +- services/surfaceflinger/Scheduler/HwcStrongTypes.h | 27 +++ services/surfaceflinger/Scheduler/LayerHistory.cpp | 11 +- services/surfaceflinger/Scheduler/LayerHistory.h | 3 +- services/surfaceflinger/Scheduler/LayerInfo.h | 4 - services/surfaceflinger/Scheduler/PhaseOffsets.cpp | 30 +-- services/surfaceflinger/Scheduler/PhaseOffsets.h | 20 +- .../Scheduler/RefreshRateConfigs.cpp | 208 ++++++++++++--------- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 134 +++++++++---- .../surfaceflinger/Scheduler/RefreshRateStats.h | 29 ++- services/surfaceflinger/Scheduler/Scheduler.cpp | 121 +++++------- services/surfaceflinger/Scheduler/Scheduler.h | 34 ++-- services/surfaceflinger/Scheduler/StrongTyping.h | 20 +- services/surfaceflinger/Scheduler/VSyncDispatch.h | 2 +- .../Scheduler/VSyncDispatchTimerQueue.h | 3 +- .../surfaceflinger/Scheduler/VSyncModulator.cpp | 11 +- services/surfaceflinger/Scheduler/VSyncModulator.h | 3 - services/surfaceflinger/SurfaceFlinger.cpp | 160 +++++++++------- services/surfaceflinger/SurfaceFlinger.h | 21 ++- .../tests/unittests/DisplayTransactionTest.cpp | 2 +- .../tests/unittests/EventThreadTest.cpp | 10 +- .../tests/unittests/FakePhaseOffsets.h | 10 +- .../tests/unittests/LayerHistoryTest.cpp | 44 ++--- .../tests/unittests/RefreshRateConfigsTest.cpp | 195 +++++++++++++++---- .../tests/unittests/RefreshRateStatsTest.cpp | 29 +-- .../tests/unittests/SchedulerTest.cpp | 9 +- .../tests/unittests/StrongTypingTest.cpp | 14 +- .../tests/unittests/TestableSurfaceFlinger.h | 25 +-- .../tests/unittests/mock/MockEventThread.h | 2 +- 36 files changed, 735 insertions(+), 488 deletions(-) create mode 100644 services/surfaceflinger/Scheduler/HwcStrongTypes.h (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index d51d34b3c5..8957e90034 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -399,8 +399,7 @@ 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; - const bool isHDR = item.mHdrMetadata.validTypes != 0; - mFlinger->mScheduler->recordLayerHistory(this, presentTime, isHDR); + mFlinger->mScheduler->recordLayerHistory(this, presentTime); 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 d68fe8e3a5..1e471e53ff 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -247,8 +247,7 @@ bool BufferStateLayer::setBuffer(const sp& buffer, nsecs_t postTi FrameTracer::FrameEvent::POST); mCurrentState.desiredPresentTime = desiredPresentTime; - const bool isHDR = mCurrentState.hdrMetadata.validTypes != 0; - mFlinger->mScheduler->recordLayerHistory(this, desiredPresentTime, isHDR); + mFlinger->mScheduler->recordLayerHistory(this, desiredPresentTime); return true; } diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 89123df46c..84ec597d2f 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -132,11 +132,11 @@ bool DisplayDevice::isPoweredOn() const { } // ---------------------------------------------------------------------------- -void DisplayDevice::setActiveConfig(int mode) { +void DisplayDevice::setActiveConfig(HwcConfigIndexType mode) { mActiveConfig = mode; } -int DisplayDevice::getActiveConfig() const { +HwcConfigIndexType DisplayDevice::getActiveConfig() const { return mActiveConfig; } @@ -285,7 +285,7 @@ void DisplayDevice::dump(std::string& result) const { result.append(" "); StringAppendF(&result, "powerMode=%d, ", mPowerMode); - StringAppendF(&result, "activeConfig=%d, ", mActiveConfig); + StringAppendF(&result, "activeConfig=%d, ", mActiveConfig.value()); getCompositionDisplay()->dump(result); } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index ce4e1e6b09..2d0875b0c5 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -43,6 +43,7 @@ #include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/PowerAdvisor.h" #include "RenderArea.h" +#include "Scheduler/HwcStrongTypes.h" namespace android { @@ -141,8 +142,8 @@ public: /* ------------------------------------------------------------------------ * Display active config management. */ - int getActiveConfig() const; - void setActiveConfig(int mode); + HwcConfigIndexType getActiveConfig() const; + void setActiveConfig(HwcConfigIndexType mode); // release HWC resources (if any) for removable displays void disconnect(); @@ -186,7 +187,7 @@ private: // Current power mode int mPowerMode; // Current active config - int mActiveConfig; + HwcConfigIndexType mActiveConfig; // TODO(b/74619554): Remove special cases for primary display. const bool mIsPrimary; diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 976fedb58a..38a80a798a 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -20,8 +20,6 @@ namespace android { -using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; - RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger) : mFlinger(flinger), mClient(new Client(&mFlinger)) { createLayer(); @@ -51,8 +49,8 @@ bool RefreshRateOverlay::createLayer() { return true; } -void RefreshRateOverlay::changeRefreshRate(RefreshRateType type) { - const half3& color = (type == RefreshRateType::PERFORMANCE) ? GREEN : RED; +void RefreshRateOverlay::changeRefreshRate(const RefreshRate& refreshRate) { + const half3& color = (refreshRate.fps > 65.0f) ? GREEN : RED; mLayer->setColor(color); mFlinger.mTransactionFlags.fetch_or(eTransactionMask); } diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index ce29bc3243..414bc47ac9 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -19,13 +19,13 @@ namespace android { -using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; +using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; class RefreshRateOverlay { public: RefreshRateOverlay(SurfaceFlinger& flinger); - void changeRefreshRate(RefreshRateType type); + void changeRefreshRate(const RefreshRate& refreshRate); private: bool createLayer(); diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 8d9adc8525..ff800c3dbf 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -36,6 +36,7 @@ #include #include "EventThread.h" +#include "HwcStrongTypes.h" using namespace std::chrono_literals; @@ -101,10 +102,11 @@ DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t times return event; } -DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId, int32_t configId) { +DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId, + HwcConfigIndexType configId) { DisplayEventReceiver::Event event; event.header = {DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, displayId, systemTime()}; - event.config.configId = configId; + event.config.configId = configId.value(); return event; } @@ -290,7 +292,7 @@ void EventThread::onHotplugReceived(PhysicalDisplayId displayId, bool connected) mCondition.notify_all(); } -void EventThread::onConfigChanged(PhysicalDisplayId displayId, int32_t configId) { +void EventThread::onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId) { std::lock_guard lock(mMutex); mPendingEvents.push_back(makeConfigChanged(displayId, configId)); diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index a029586088..a42546c7df 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -33,6 +33,7 @@ #include #include +#include "HwcStrongTypes.h" // --------------------------------------------------------------------------- namespace android { @@ -109,7 +110,7 @@ public: virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0; // called when SF changes the active config and apps needs to be notified about the change - virtual void onConfigChanged(PhysicalDisplayId displayId, int32_t configId) = 0; + virtual void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId) = 0; virtual void dump(std::string& result) const = 0; @@ -146,7 +147,7 @@ public: void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override; - void onConfigChanged(PhysicalDisplayId displayId, int32_t configId) override; + void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId) override; void dump(std::string& result) const override; diff --git a/services/surfaceflinger/Scheduler/HwcStrongTypes.h b/services/surfaceflinger/Scheduler/HwcStrongTypes.h new file mode 100644 index 0000000000..cfbbdfe4fd --- /dev/null +++ b/services/surfaceflinger/Scheduler/HwcStrongTypes.h @@ -0,0 +1,27 @@ +/* + * Copyright 2019 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 "StrongTyping.h" + +namespace android { + +// Strong types for the different indexes as they are referring to a different base. +using HwcConfigIndexType = StrongTyping; +using HwcConfigGroupType = StrongTyping; + +} // namespace android \ No newline at end of file diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 8b717289c6..146ec1bce0 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -39,7 +39,7 @@ namespace android::scheduler { namespace { bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) { - return layer.isVisible() && (info.isHDR() || info.getLastUpdatedTime() >= threshold); + return layer.isVisible() && info.getLastUpdatedTime() >= threshold; } bool traceEnabled() { @@ -69,7 +69,7 @@ void LayerHistory::registerLayer(Layer* layer, float lowRefreshRate, float highR mLayerInfos.emplace_back(layer, std::move(info)); } -void LayerHistory::record(Layer* layer, nsecs_t presentTime, bool isHDR, nsecs_t now) { +void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now) { std::lock_guard lock(mLock); const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(), @@ -78,7 +78,6 @@ void LayerHistory::record(Layer* layer, nsecs_t presentTime, bool isHDR, nsecs_t const auto& info = it->second; info->setLastPresentTime(presentTime, now); - info->setIsHDR(isHDR); // Activate layer if inactive. if (const auto end = activeLayers().end(); it >= end) { @@ -89,7 +88,6 @@ void LayerHistory::record(Layer* layer, nsecs_t presentTime, bool isHDR, nsecs_t LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { float maxRefreshRate = 0; - bool isHDR = false; std::lock_guard lock(mLock); @@ -108,13 +106,12 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { trace(layer, std::round(refreshRate)); } } - isHDR |= info->isHDR(); } if (CC_UNLIKELY(mTraceEnabled)) { - ALOGD("%s: maxRefreshRate=%.2f, isHDR=%d", __FUNCTION__, maxRefreshRate, isHDR); + ALOGD("%s: maxRefreshRate=%.2f", __FUNCTION__, maxRefreshRate); } - return {maxRefreshRate, isHDR}; + return {maxRefreshRate}; } void LayerHistory::partitionLayers(nsecs_t now) { diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index bd9aca1aed..745c4c16ee 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -46,11 +46,10 @@ public: void registerLayer(Layer*, float lowRefreshRate, float highRefreshRate); // Marks the layer as active, and records the given state to its history. - void record(Layer*, nsecs_t presentTime, bool isHDR, nsecs_t now); + void record(Layer*, nsecs_t presentTime, nsecs_t now); struct Summary { float maxRefreshRate; // Maximum refresh rate among recently active layers. - bool isHDR; // True if any recently active layer has HDR content. }; // Rebuilds sets of active/inactive layers, and accumulates stats for active layers. diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index b86709fc9c..cb81ca2840 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -140,9 +140,6 @@ public: // updated time, the updated time is the present time. void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now); - bool isHDR() const { return mIsHDR; } - void setIsHDR(bool isHDR) { mIsHDR = isHDR; } - bool isRecentlyActive(nsecs_t now) const { return mPresentTimeHistory.isRecentlyActive(now); } bool isFrequent(nsecs_t now) const { return mPresentTimeHistory.isFrequent(now); } @@ -167,7 +164,6 @@ private: nsecs_t mLastPresentTime = 0; RefreshRateHistory mRefreshRateHistory{mHighRefreshRate}; PresentTimeHistory mPresentTimeHistory; - bool mIsHDR = false; }; } // namespace scheduler diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp index 6be88f89f9..12832a690a 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp @@ -48,16 +48,18 @@ PhaseOffsets::PhaseOffsets() { getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns") .value_or(std::numeric_limits::max()); - const Offsets defaultOffsets = getDefaultOffsets(thresholdForNextVsync); - const Offsets highFpsOffsets = getHighFpsOffsets(thresholdForNextVsync); - - mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets}); - mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets}); + mDefaultOffsets = getDefaultOffsets(thresholdForNextVsync); + mHighFpsOffsets = getHighFpsOffsets(thresholdForNextVsync); } -PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate( - RefreshRateType refreshRateType) const { - return mOffsets.at(refreshRateType); +PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(float fps) const { + // TODO(145561086): Once offsets are common for all refresh rates we can remove the magic + // number for refresh rate + if (fps > 65.0f) { + return mHighFpsOffsets; + } else { + return mDefaultOffsets; + } } void PhaseOffsets::dump(std::string& result) const { @@ -80,13 +82,13 @@ PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t thresholdForNextVs const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns"); const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns"); - return {{RefreshRateType::DEFAULT, earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs), + return {{earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs), earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs)}, - {RefreshRateType::DEFAULT, earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs), + {earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs), earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs)}, - {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}, + {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs}, thresholdForNextVsync}; } @@ -104,13 +106,13 @@ PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t thresholdForNextVs const auto highFpsEarlyGlAppOffsetNs = getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns"); - return {{RefreshRateType::PERFORMANCE, highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs), + return {{highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs), highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs)}, - {RefreshRateType::PERFORMANCE, highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs), + {highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs), highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs)}, - {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}, + {highFpsLateSfOffsetNs, highFpsLateAppOffsetNs}, thresholdForNextVsync}; } diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h index 2c52432448..7747f0cfcc 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.h +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h @@ -32,7 +32,6 @@ namespace android::scheduler { class PhaseOffsets { public: using Offsets = VSyncModulator::OffsetsConfig; - using RefreshRateType = RefreshRateConfigs::RefreshRateType; virtual ~PhaseOffsets(); @@ -43,9 +42,9 @@ public: } virtual Offsets getCurrentOffsets() const = 0; - virtual Offsets getOffsetsForRefreshRate(RefreshRateType) const = 0; + virtual Offsets getOffsetsForRefreshRate(float fps) const = 0; - virtual void setRefreshRateType(RefreshRateType) = 0; + virtual void setRefreshRateFps(float fps) = 0; virtual void dump(std::string& result) const = 0; }; @@ -57,18 +56,14 @@ public: PhaseOffsets(); // Returns early, early GL, and late offsets for Apps and SF for a given refresh rate. - Offsets getOffsetsForRefreshRate(RefreshRateType) const override; + Offsets getOffsetsForRefreshRate(float fps) const override; // Returns early, early GL, and late offsets for Apps and SF. - Offsets getCurrentOffsets() const override { - return getOffsetsForRefreshRate(mRefreshRateType); - } + Offsets getCurrentOffsets() const override { return getOffsetsForRefreshRate(mRefreshRateFps); } // This function should be called when the device is switching between different // refresh rates, to properly update the offsets. - void setRefreshRateType(RefreshRateType refreshRateType) override { - mRefreshRateType = refreshRateType; - } + void setRefreshRateFps(float fps) override { mRefreshRateFps = fps; } // Returns current offsets in human friendly format. void dump(std::string& result) const override; @@ -77,9 +72,10 @@ private: static Offsets getDefaultOffsets(nsecs_t thresholdForNextVsync); static Offsets getHighFpsOffsets(nsecs_t thresholdForNextVsync); - std::atomic mRefreshRateType = RefreshRateType::DEFAULT; + std::atomic mRefreshRateFps = 0; - std::unordered_map mOffsets; + Offsets mDefaultOffsets; + Offsets mHighFpsOffsets; }; } // namespace impl diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 7dc98cce94..23fb96a38b 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -13,135 +13,169 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +// #define LOG_NDEBUG 0 #include "RefreshRateConfigs.h" namespace android::scheduler { + +using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType; using RefreshRate = RefreshRateConfigs::RefreshRate; -using RefreshRateType = RefreshRateConfigs::RefreshRateType; // Returns the refresh rate map. This map won't be modified at runtime, so it's safe to access // from multiple threads. This can only be called if refreshRateSwitching() returns true. // TODO(b/122916473): Get this information from configs prepared by vendors, instead of // baking them in. -const std::map& RefreshRateConfigs::getRefreshRateMap() const { - LOG_ALWAYS_FATAL_IF(!mRefreshRateSwitchingSupported); - return mRefreshRateMap; -} - -const RefreshRate& RefreshRateConfigs::getRefreshRateFromType(RefreshRateType type) const { - if (!mRefreshRateSwitchingSupported) { - return getCurrentRefreshRate().second; - } else { - auto refreshRate = mRefreshRateMap.find(type); - LOG_ALWAYS_FATAL_IF(refreshRate == mRefreshRateMap.end()); - return refreshRate->second; - } -} - -std::pair RefreshRateConfigs::getCurrentRefreshRate() const { - int currentConfig = mCurrentConfig; - if (mRefreshRateSwitchingSupported) { - for (const auto& [type, refresh] : mRefreshRateMap) { - if (refresh.configId == currentConfig) { - return {type, refresh}; +const RefreshRate& RefreshRateConfigs::getRefreshRateForContent(float contentFramerate) const { + std::lock_guard lock(mLock); + // Find the appropriate refresh rate with minimal error + auto iter = min_element(mAvailableRefreshRates.cbegin(), mAvailableRefreshRates.cend(), + [contentFramerate](const auto& lhs, const auto& rhs) -> bool { + return std::abs(lhs->fps - contentFramerate) < + std::abs(rhs->fps - contentFramerate); + }); + + // Some content aligns better on higher refresh rate. For example for 45fps we should choose + // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't + // align well with both + const RefreshRate* bestSoFar = *iter; + constexpr float MARGIN = 0.05f; + float ratio = (*iter)->fps / contentFramerate; + if (std::abs(std::round(ratio) - ratio) > MARGIN) { + while (iter != mAvailableRefreshRates.cend()) { + ratio = (*iter)->fps / contentFramerate; + + if (std::abs(std::round(ratio) - ratio) <= MARGIN) { + bestSoFar = *iter; + break; } + ++iter; } - LOG_ALWAYS_FATAL(); } - return {RefreshRateType::DEFAULT, mRefreshRates[currentConfig]}; + + return *bestSoFar; } -const RefreshRate& RefreshRateConfigs::getRefreshRateFromConfigId(int configId) const { - LOG_ALWAYS_FATAL_IF(configId >= mRefreshRates.size()); - return mRefreshRates[configId]; +const AllRefreshRatesMapType& RefreshRateConfigs::getAllRefreshRates() const { + return mRefreshRates; } -RefreshRateType RefreshRateConfigs::getRefreshRateTypeFromHwcConfigId(hwc2_config_t hwcId) const { - if (!mRefreshRateSwitchingSupported) return RefreshRateType::DEFAULT; +const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const { + std::lock_guard lock(mLock); + if (!mRefreshRateSwitching) { + return *mCurrentRefreshRate; + } else { + return *mAvailableRefreshRates.front(); + } +} - for (const auto& [type, refreshRate] : mRefreshRateMap) { - if (refreshRate.hwcId == hwcId) { - return type; - } +const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const { + std::lock_guard lock(mLock); + if (!mRefreshRateSwitching) { + return *mCurrentRefreshRate; + } else { + return *mAvailableRefreshRates.back(); } +} - return RefreshRateType::DEFAULT; +const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const { + std::lock_guard lock(mLock); + return *mCurrentRefreshRate; } -void RefreshRateConfigs::setCurrentConfig(int config) { - LOG_ALWAYS_FATAL_IF(config >= mRefreshRates.size()); - mCurrentConfig = config; +void RefreshRateConfigs::setCurrentConfigId(HwcConfigIndexType configId) { + std::lock_guard lock(mLock); + mCurrentRefreshRate = &mRefreshRates.at(configId); } RefreshRateConfigs::RefreshRateConfigs(bool refreshRateSwitching, - const std::vector& configs, int currentConfig) { - init(refreshRateSwitching, configs, currentConfig); + const std::vector& configs, + HwcConfigIndexType currentHwcConfig) + : mRefreshRateSwitching(refreshRateSwitching) { + init(configs, currentHwcConfig); } RefreshRateConfigs::RefreshRateConfigs( bool refreshRateSwitching, const std::vector>& configs, - int currentConfig) { + HwcConfigIndexType currentConfigId) + : mRefreshRateSwitching(refreshRateSwitching) { std::vector inputConfigs; - for (const auto& config : configs) { - inputConfigs.push_back({config->getId(), config->getVsyncPeriod()}); + for (auto configId = HwcConfigIndexType(0); configId < HwcConfigIndexType(configs.size()); + ++configId) { + auto configGroup = HwcConfigGroupType(configs[configId.value()]->getConfigGroup()); + inputConfigs.push_back( + {configId, configGroup, configs[configId.value()]->getVsyncPeriod()}); } - init(refreshRateSwitching, inputConfigs, currentConfig); + init(inputConfigs, currentConfigId); } -void RefreshRateConfigs::init(bool refreshRateSwitching, const std::vector& configs, - int currentConfig) { - mRefreshRateSwitchingSupported = refreshRateSwitching; - LOG_ALWAYS_FATAL_IF(configs.empty()); - LOG_ALWAYS_FATAL_IF(currentConfig >= configs.size()); - mCurrentConfig = currentConfig; - - auto buildRefreshRate = [&](int configId) -> RefreshRate { - const nsecs_t vsyncPeriod = configs[configId].vsyncPeriod; - const float fps = 1e9 / vsyncPeriod; - return {configId, base::StringPrintf("%2.ffps", fps), static_cast(fps), - vsyncPeriod, configs[configId].hwcId}; - }; +void RefreshRateConfigs::setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate, + float maxRefreshRate) { + std::lock_guard lock(mLock); + mCurrentGroupId = mRefreshRates.at(defaultConfigId).configGroup; + mMinRefreshRateFps = minRefreshRate; + mMaxRefreshRateFps = maxRefreshRate; + constructAvailableRefreshRates(); +} - for (int i = 0; i < configs.size(); ++i) { - mRefreshRates.push_back(buildRefreshRate(i)); +void RefreshRateConfigs::getSortedRefreshRateList( + const std::function& shouldAddRefreshRate, + std::vector* outRefreshRates) { + outRefreshRates->clear(); + outRefreshRates->reserve(mRefreshRates.size()); + for (const auto& [type, refreshRate] : mRefreshRates) { + if (shouldAddRefreshRate(refreshRate)) { + ALOGV("getSortedRefreshRateList: config %d added to list policy", + refreshRate.configId.value()); + outRefreshRates->push_back(&refreshRate); + } } - if (!mRefreshRateSwitchingSupported) return; + std::sort(outRefreshRates->begin(), outRefreshRates->end(), + [](const auto refreshRate1, const auto refreshRate2) { + return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod; + }); +} - auto findDefaultAndPerfConfigs = [&]() -> std::optional> { - if (configs.size() < 2) { - return {}; - } +void RefreshRateConfigs::constructAvailableRefreshRates() { + // Filter configs based on current policy and sort based on vsync period + ALOGV("constructRefreshRateMap: group %d min %.2f max %.2f", mCurrentGroupId.value(), + mMinRefreshRateFps, mMaxRefreshRateFps); + getSortedRefreshRateList( + [this](const RefreshRate& refreshRate) REQUIRES(mLock) { + return refreshRate.configGroup == mCurrentGroupId && + refreshRate.fps >= mMinRefreshRateFps && + refreshRate.fps <= mMaxRefreshRateFps; + }, + &mAvailableRefreshRates); +} - std::vector sortedRefreshRates; - for (const auto& refreshRate : mRefreshRates) { - sortedRefreshRates.push_back(&refreshRate); - } - std::sort(sortedRefreshRates.begin(), sortedRefreshRates.end(), - [](const RefreshRate* refreshRate1, const RefreshRate* refreshRate2) { - return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod; - }); - - // When the configs are ordered by the resync rate, we assume that - // the first one is DEFAULT and the second one is PERFORMANCE, - // i.e. the higher rate. - if (sortedRefreshRates[0]->vsyncPeriod == 0 || sortedRefreshRates[1]->vsyncPeriod == 0) { - return {}; - } +// NO_THREAD_SAFETY_ANALYSIS since this is called from the constructor +void RefreshRateConfigs::init(const std::vector& configs, + HwcConfigIndexType currentHwcConfig) NO_THREAD_SAFETY_ANALYSIS { + LOG_ALWAYS_FATAL_IF(configs.empty()); + LOG_ALWAYS_FATAL_IF(currentHwcConfig.value() >= configs.size()); - return std::pair(sortedRefreshRates[0]->configId, - sortedRefreshRates[1]->configId); + auto buildRefreshRate = [&](InputConfig config) -> RefreshRate { + const float fps = 1e9f / config.vsyncPeriod; + return RefreshRate(config.configId, config.vsyncPeriod, config.configGroup, + base::StringPrintf("%2.ffps", fps), fps); }; - auto defaultAndPerfConfigs = findDefaultAndPerfConfigs(); - if (!defaultAndPerfConfigs) { - mRefreshRateSwitchingSupported = false; - return; + for (const auto& config : configs) { + mRefreshRates.emplace(config.configId, buildRefreshRate(config)); + if (config.configId == currentHwcConfig) { + mCurrentRefreshRate = &mRefreshRates.at(config.configId); + mCurrentGroupId = config.configGroup; + } } - mRefreshRateMap[RefreshRateType::DEFAULT] = mRefreshRates[defaultAndPerfConfigs->first]; - mRefreshRateMap[RefreshRateType::PERFORMANCE] = mRefreshRates[defaultAndPerfConfigs->second]; + std::vector sortedConfigs; + getSortedRefreshRateList([](const RefreshRate&) { return true; }, &sortedConfigs); + mMinSupportedRefreshRate = sortedConfigs.front(); + mMaxSupportedRefreshRate = sortedConfigs.back(); + constructAvailableRefreshRates(); } -} // namespace android::scheduler \ No newline at end of file +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 90bba24332..fb14dc7a9a 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -23,7 +23,9 @@ #include #include "DisplayHardware/HWComposer.h" +#include "HwcStrongTypes.h" #include "Scheduler/SchedulerUtils.h" +#include "Scheduler/StrongTyping.h" namespace android::scheduler { @@ -41,71 +43,123 @@ inline RefreshRateConfigEvent operator|(RefreshRateConfigEvent lhs, RefreshRateC */ class RefreshRateConfigs { public: - // Enum to indicate which vsync rate to run at. Default is the old 60Hz, and performance - // is the new 90Hz. Eventually we want to have a way for vendors to map these in the configs. - enum class RefreshRateType { DEFAULT, PERFORMANCE }; - struct RefreshRate { + RefreshRate(HwcConfigIndexType configId, nsecs_t vsyncPeriod, + HwcConfigGroupType configGroup, std::string name, float fps) + : configId(configId), + vsyncPeriod(vsyncPeriod), + configGroup(configGroup), + name(std::move(name)), + fps(fps) {} // This config ID corresponds to the position of the config in the vector that is stored // on the device. - int configId; - // Human readable name of the refresh rate. - std::string name; - // Refresh rate in frames per second, rounded to the nearest integer. - uint32_t fps = 0; + const HwcConfigIndexType configId; // Vsync period in nanoseconds. - nsecs_t vsyncPeriod; - // Hwc config Id (returned from HWC2::Display::Config::getId()) - hwc2_config_t hwcId; + const nsecs_t vsyncPeriod; + // This configGroup for the config. + const HwcConfigGroupType configGroup; + // Human readable name of the refresh rate. + const std::string name; + // Refresh rate in frames per second + const float fps = 0; + + bool operator!=(const RefreshRate& other) const { + return configId != other.configId || vsyncPeriod != other.vsyncPeriod || + configGroup != other.configGroup; + } + + bool operator==(const RefreshRate& other) const { return !(*this != other); } }; + using AllRefreshRatesMapType = std::unordered_map; + + // Sets the current policy to choose refresh rates. + void setPolicy(HwcConfigIndexType defaultConfigId, float minRefreshRate, float maxRefreshRate) + EXCLUDES(mLock); + // Returns true if this device is doing refresh rate switching. This won't change at runtime. - bool refreshRateSwitchingSupported() const { return mRefreshRateSwitchingSupported; } + bool refreshRateSwitchingSupported() const { return mRefreshRateSwitching; } + + // Returns all available refresh rates according to the current policy. + const RefreshRate& getRefreshRateForContent(float contentFramerate) const EXCLUDES(mLock); + + // Returns all the refresh rates supported by the device. This won't change at runtime. + const AllRefreshRatesMapType& getAllRefreshRates() const EXCLUDES(mLock); - // Returns the refresh rate map. This map won't be modified at runtime, so it's safe to access - // from multiple threads. This can only be called if refreshRateSwitching() returns true. - // TODO(b/122916473): Get this information from configs prepared by vendors, instead of - // baking them in. - const std::map& getRefreshRateMap() const; + // Returns the lowest refresh rate supported by the device. This won't change at runtime. + const RefreshRate& getMinRefreshRate() const { return *mMinSupportedRefreshRate; } - const RefreshRate& getRefreshRateFromType(RefreshRateType type) const; + // Returns the lowest refresh rate according to the current policy. May change in runtime. + const RefreshRate& getMinRefreshRateByPolicy() const EXCLUDES(mLock); - std::pair getCurrentRefreshRate() const; + // Returns the highest refresh rate supported by the device. This won't change at runtime. + const RefreshRate& getMaxRefreshRate() const { return *mMaxSupportedRefreshRate; } - const RefreshRate& getRefreshRateFromConfigId(int configId) const; + // Returns the highest refresh rate according to the current policy. May change in runtime. + const RefreshRate& getMaxRefreshRateByPolicy() const EXCLUDES(mLock); - RefreshRateType getRefreshRateTypeFromHwcConfigId(hwc2_config_t hwcId) const; + // Returns the current refresh rate + const RefreshRate& getCurrentRefreshRate() const EXCLUDES(mLock); - void setCurrentConfig(int config); + // Returns the refresh rate that corresponds to a HwcConfigIndexType. This won't change at + // runtime. + const RefreshRate& getRefreshRateFromConfigId(HwcConfigIndexType configId) const { + return mRefreshRates.at(configId); + }; + + // Stores the current configId the device operates at + void setCurrentConfigId(HwcConfigIndexType configId) EXCLUDES(mLock); struct InputConfig { - hwc2_config_t hwcId = 0; + HwcConfigIndexType configId = HwcConfigIndexType(0); + HwcConfigGroupType configGroup = HwcConfigGroupType(0); nsecs_t vsyncPeriod = 0; }; RefreshRateConfigs(bool refreshRateSwitching, const std::vector& configs, - int currentConfig); - + HwcConfigIndexType currentHwcConfig); RefreshRateConfigs(bool refreshRateSwitching, const std::vector>& configs, - int currentConfig); + HwcConfigIndexType currentConfigId); private: - void init(bool refreshRateSwitching, const std::vector& configs, - int currentConfig); - // Whether this device is doing refresh rate switching or not. This must not change after this - // object is initialized. - bool mRefreshRateSwitchingSupported; + void init(const std::vector& configs, HwcConfigIndexType currentHwcConfig); + + void constructAvailableRefreshRates() REQUIRES(mLock); + + void getSortedRefreshRateList( + const std::function& shouldAddRefreshRate, + std::vector* outRefreshRates); + // The list of refresh rates, indexed by display config ID. This must not change after this // object is initialized. - std::vector mRefreshRates; - // The mapping of refresh rate type to RefreshRate. This must not change after this object is - // initialized. - std::map mRefreshRateMap; - // The ID of the current config. 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, so it's - // atomic. - std::atomic mCurrentConfig; + AllRefreshRatesMapType mRefreshRates; + + // The list of refresh rates which are available in the current policy, ordered by vsyncPeriod + // (the first element is the lowest refresh rate) + std::vector mAvailableRefreshRates GUARDED_BY(mLock); + + // The current config. 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); + + // The current config group. 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. + HwcConfigGroupType mCurrentGroupId GUARDED_BY(mLock); + + // The min and max FPS allowed by the policy. This will change at runtime and set by + // SurfaceFlinger on the main thread. + float mMinRefreshRateFps GUARDED_BY(mLock) = 0; + float mMaxRefreshRateFps GUARDED_BY(mLock) = std::numeric_limits::max(); + + // The min and max refresh rates supported by the device. + // This will not change at runtime. + const RefreshRate* mMinSupportedRefreshRate; + const RefreshRate* mMaxSupportedRefreshRate; + + const bool mRefreshRateSwitching; + + mutable std::mutex mLock; }; } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h index 8afc93e8db..a384dbe29b 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateStats.h +++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h @@ -25,8 +25,7 @@ #include "android-base/stringprintf.h" #include "utils/Timers.h" -namespace android { -namespace scheduler { +namespace android::scheduler { /** * Class to encapsulate statistics about refresh rates that the display is using. When the power @@ -42,10 +41,10 @@ class RefreshRateStats { public: RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats, - int currentConfigMode, int currentPowerMode) + HwcConfigIndexType currentConfigId, int currentPowerMode) : mRefreshRateConfigs(refreshRateConfigs), mTimeStats(timeStats), - mCurrentConfigMode(currentConfigMode), + mCurrentConfigMode(currentConfigId), mCurrentPowerMode(currentPowerMode) {} // Sets power mode. @@ -59,12 +58,12 @@ public: // Sets config mode. If the mode has changed, it records how much time was spent in the previous // mode. - void setConfigMode(int mode) { - if (mCurrentConfigMode == mode) { + void setConfigMode(HwcConfigIndexType configId) { + if (mCurrentConfigMode == configId) { return; } flushTime(); - mCurrentConfigMode = mode; + mCurrentConfigMode = configId; } // Returns a map between human readable refresh rate and number of seconds the device spent in @@ -78,11 +77,11 @@ public: std::unordered_map totalTime; // Multiple configs may map to the same name, e.g. "60fps". Add the // times for such configs together. - for (const auto& [config, time] : mConfigModesTotalTime) { - totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(config).name] = 0; + for (const auto& [configId, time] : mConfigModesTotalTime) { + totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(configId).name] = 0; } - for (const auto& [config, time] : mConfigModesTotalTime) { - totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(config).name] += time; + for (const auto& [configId, time] : mConfigModesTotalTime) { + totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(configId).name] += time; } totalTime["ScreenOff"] = mScreenOffTime; return totalTime; @@ -139,14 +138,14 @@ private: // Aggregate refresh rate statistics for telemetry. TimeStats& mTimeStats; - int mCurrentConfigMode; + HwcConfigIndexType mCurrentConfigMode; int32_t mCurrentPowerMode; - std::unordered_map mConfigModesTotalTime; + std::unordered_map + mConfigModesTotalTime; int64_t mScreenOffTime = 0; nsecs_t mPreviousRecordedTime = systemTime(); }; -} // namespace scheduler -} // namespace android +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 55fd6032f2..1d50fe1dd4 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -182,7 +182,7 @@ void Scheduler::onScreenReleased(ConnectionHandle handle) { } void Scheduler::onConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId, - int32_t configId) { + HwcConfigIndexType configId) { RETURN_IF_INVALID_HANDLE(handle); mConnections[handle].thread->onConfigChanged(displayId, configId); } @@ -280,8 +280,7 @@ void Scheduler::resync() { const nsecs_t last = mLastResyncTime.exchange(now); if (now - last > kIgnoreDelay) { - resyncToHardwareVsync(false, - mRefreshRateConfigs.getCurrentRefreshRate().second.vsyncPeriod); + resyncToHardwareVsync(false, mRefreshRateConfigs.getCurrentRefreshRate().vsyncPeriod); } } @@ -332,53 +331,49 @@ nsecs_t Scheduler::getDispSyncExpectedPresentTime() { void Scheduler::registerLayer(Layer* layer) { if (!mLayerHistory) return; - const auto type = layer->getWindowType() == InputWindowInfo::TYPE_WALLPAPER - ? RefreshRateType::DEFAULT - : RefreshRateType::PERFORMANCE; - - const auto lowFps = mRefreshRateConfigs.getRefreshRateFromType(RefreshRateType::DEFAULT).fps; - const auto highFps = mRefreshRateConfigs.getRefreshRateFromType(type).fps; + const auto lowFps = mRefreshRateConfigs.getMinRefreshRate().fps; + const auto highFps = layer->getWindowType() == InputWindowInfo::TYPE_WALLPAPER + ? lowFps + : mRefreshRateConfigs.getMaxRefreshRate().fps; mLayerHistory->registerLayer(layer, lowFps, highFps); } -void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime, bool isHDR) { +void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime) { if (mLayerHistory) { - mLayerHistory->record(layer, presentTime, isHDR, systemTime()); + mLayerHistory->record(layer, presentTime, systemTime()); } } void Scheduler::chooseRefreshRateForContent() { if (!mLayerHistory) return; - auto [refreshRate, isHDR] = mLayerHistory->summarize(systemTime()); + auto [refreshRate] = mLayerHistory->summarize(systemTime()); const uint32_t refreshRateRound = std::round(refreshRate); - RefreshRateType newRefreshRateType; + HwcConfigIndexType newConfigId; { std::lock_guard lock(mFeatureStateLock); - if (mFeatures.contentRefreshRate == refreshRateRound && mFeatures.isHDRContent == isHDR) { + if (mFeatures.contentRefreshRate == refreshRateRound) { return; } mFeatures.contentRefreshRate = refreshRateRound; ATRACE_INT("ContentFPS", refreshRateRound); - mFeatures.isHDRContent = isHDR; - ATRACE_INT("ContentHDR", isHDR); - mFeatures.contentDetection = refreshRateRound > 0 ? ContentDetectionState::On : ContentDetectionState::Off; - newRefreshRateType = calculateRefreshRateType(); - if (mFeatures.refreshRateType == newRefreshRateType) { + newConfigId = calculateRefreshRateType(); + if (mFeatures.configId == newConfigId) { return; } - mFeatures.refreshRateType = newRefreshRateType; - } - changeRefreshRate(newRefreshRateType, ConfigEvent::Changed); + mFeatures.configId = newConfigId; + }; + auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId); + changeRefreshRate(newRefreshRate, ConfigEvent::Changed); } -void Scheduler::setChangeRefreshRateCallback(ChangeRefreshRateCallback&& callback) { +void Scheduler::setSchedulerCallback(android::Scheduler::ISchedulerCallback* callback) { std::lock_guard lock(mCallbackLock); - mChangeRefreshRateCallback = std::move(callback); + mSchedulerCallback = callback; } void Scheduler::resetIdleTimer() { @@ -423,13 +418,16 @@ void Scheduler::setDisplayPowerState(bool normal) { void Scheduler::kernelIdleTimerCallback(TimerState state) { ATRACE_INT("ExpiredKernelIdleTimer", static_cast(state)); + // TODO(145561154): cleanup the kernel idle timer implementation and the refresh rate + // magic number const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate(); - if (state == TimerState::Reset && refreshRate.first == RefreshRateType::PERFORMANCE) { + constexpr float FPS_THRESHOLD_FOR_KERNEL_TIMER = 65.0f; + if (state == TimerState::Reset && refreshRate.fps > 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.second.vsyncPeriod); - } else if (state == TimerState::Expired && refreshRate.first != RefreshRateType::PERFORMANCE) { + resyncToHardwareVsync(true /* makeAvailable */, refreshRate.vsyncPeriod); + } else if (state == TimerState::Expired && refreshRate.fps <= 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 DispSync model anyway. @@ -471,96 +469,67 @@ void Scheduler::dump(std::string& result) const { template void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) { ConfigEvent event = ConfigEvent::None; - RefreshRateType newRefreshRateType; + HwcConfigIndexType newConfigId; { std::lock_guard lock(mFeatureStateLock); if (*currentState == newState) { return; } *currentState = newState; - newRefreshRateType = calculateRefreshRateType(); - if (mFeatures.refreshRateType == newRefreshRateType) { + newConfigId = calculateRefreshRateType(); + if (mFeatures.configId == newConfigId) { return; } - mFeatures.refreshRateType = newRefreshRateType; + mFeatures.configId = newConfigId; if (eventOnContentDetection && mFeatures.contentDetection == ContentDetectionState::On) { event = ConfigEvent::Changed; } } - changeRefreshRate(newRefreshRateType, event); + const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId); + changeRefreshRate(newRefreshRate, event); } -Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { +HwcConfigIndexType Scheduler::calculateRefreshRateType() { if (!mRefreshRateConfigs.refreshRateSwitchingSupported()) { - return RefreshRateType::DEFAULT; - } - - // HDR content is not supported on PERFORMANCE mode - if (mForceHDRContentToDefaultRefreshRate && mFeatures.isHDRContent) { - return RefreshRateType::DEFAULT; + return mRefreshRateConfigs.getCurrentRefreshRate().configId; } // 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 (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset) { - return RefreshRateType::PERFORMANCE; + return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId; } // As long as touch is active we want to be in performance mode if (mFeatures.touch == TouchState::Active) { - return RefreshRateType::PERFORMANCE; + return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId; } // If timer has expired as it means there is no new content on the screen if (mFeatures.idleTimer == TimerState::Expired) { - return RefreshRateType::DEFAULT; + return mRefreshRateConfigs.getMinRefreshRateByPolicy().configId; } // If content detection is off we choose performance as we don't know the content fps if (mFeatures.contentDetection == ContentDetectionState::Off) { - return RefreshRateType::PERFORMANCE; + return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId; } // Content detection is on, find the appropriate refresh rate with minimal error - // TODO(b/139751853): Scan allowed refresh rates only (SurfaceFlinger::mAllowedDisplayConfigs) - const float rate = static_cast(mFeatures.contentRefreshRate); - auto iter = min_element(mRefreshRateConfigs.getRefreshRateMap().cbegin(), - mRefreshRateConfigs.getRefreshRateMap().cend(), - [rate](const auto& lhs, const auto& rhs) -> bool { - return std::abs(lhs.second.fps - rate) < - std::abs(rhs.second.fps - rate); - }); - RefreshRateType currRefreshRateType = iter->first; - - // Some content aligns better on higher refresh rate. For example for 45fps we should choose - // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't - // align well with both - constexpr float MARGIN = 0.05f; - float ratio = mRefreshRateConfigs.getRefreshRateFromType(currRefreshRateType).fps / rate; - if (std::abs(std::round(ratio) - ratio) > MARGIN) { - while (iter != mRefreshRateConfigs.getRefreshRateMap().cend()) { - ratio = iter->second.fps / rate; - - if (std::abs(std::round(ratio) - ratio) <= MARGIN) { - currRefreshRateType = iter->first; - break; - } - ++iter; - } - } - - return currRefreshRateType; + return mRefreshRateConfigs + .getRefreshRateForContent(static_cast(mFeatures.contentRefreshRate)) + .configId; } -Scheduler::RefreshRateType Scheduler::getPreferredRefreshRateType() { +std::optional Scheduler::getPreferredConfigId() { std::lock_guard lock(mFeatureStateLock); - return mFeatures.refreshRateType; + return mFeatures.configId; } -void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) { +void Scheduler::changeRefreshRate(const RefreshRate& refreshRate, ConfigEvent configEvent) { std::lock_guard lock(mCallbackLock); - if (mChangeRefreshRateCallback) { - mChangeRefreshRateCallback(refreshRateType, configEvent); + if (mSchedulerCallback) { + mSchedulerCallback->changeRefreshRate(refreshRate, configEvent); } } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 346896c44f..04a83906b1 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -34,6 +34,8 @@ namespace android { +using namespace std::chrono_literals; + class DispSync; class FenceTime; class InjectVSyncSource; @@ -41,10 +43,14 @@ struct DisplayStateInfo; class Scheduler { public: - using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; + using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; using ConfigEvent = scheduler::RefreshRateConfigEvent; - using ChangeRefreshRateCallback = std::function; + class ISchedulerCallback { + public: + virtual ~ISchedulerCallback() = default; + virtual void changeRefreshRate(const RefreshRate&, ConfigEvent) = 0; + }; // Indicates whether to start the transaction early, or at vsync time. enum class TransactionStart { EARLY, NORMAL }; @@ -67,7 +73,7 @@ public: sp getEventConnection(ConnectionHandle); void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected); - void onConfigChanged(ConnectionHandle, PhysicalDisplayId, int32_t configId); + void onConfigChanged(ConnectionHandle, PhysicalDisplayId, HwcConfigIndexType configId); void onScreenAcquired(ConnectionHandle); void onScreenReleased(ConnectionHandle); @@ -103,13 +109,13 @@ public: // Layers are registered on creation, and unregistered when the weak reference expires. void registerLayer(Layer*); - void recordLayerHistory(Layer*, nsecs_t presentTime, bool isHDR); + void recordLayerHistory(Layer*, nsecs_t presentTime); // Detects content using layer history, and selects a matching refresh rate. void chooseRefreshRateForContent(); - // Called by Scheduler to change refresh rate. - void setChangeRefreshRateCallback(ChangeRefreshRateCallback&&); + // Called by Scheduler to control SurfaceFlinger operations. + void setSchedulerCallback(ISchedulerCallback*); bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); } void resetIdleTimer(); @@ -122,8 +128,8 @@ public: void dump(std::string&) const; void dump(ConnectionHandle, std::string&) const; - // Get the appropriate refresh type for current conditions. - RefreshRateType getPreferredRefreshRateType(); + // Get the appropriate refresh for current conditions. + std::optional getPreferredConfigId(); private: friend class TestableScheduler; @@ -158,9 +164,9 @@ private: void setVsyncPeriod(nsecs_t period); - RefreshRateType calculateRefreshRateType() REQUIRES(mFeatureStateLock); + HwcConfigIndexType calculateRefreshRateType() REQUIRES(mFeatureStateLock); // Acquires a lock and calls the ChangeRefreshRateCallback with given parameters. - void changeRefreshRate(RefreshRateType, ConfigEvent); + void changeRefreshRate(const RefreshRate&, ConfigEvent); // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection. struct Connection { @@ -198,7 +204,7 @@ private: std::optional mDisplayPowerTimer; std::mutex mCallbackLock; - ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock); + ISchedulerCallback* mSchedulerCallback GUARDED_BY(mCallbackLock) = nullptr; // 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. @@ -210,17 +216,13 @@ private: TouchState touch = TouchState::Inactive; TimerState displayPowerTimer = TimerState::Expired; - RefreshRateType refreshRateType = RefreshRateType::DEFAULT; + std::optional configId; uint32_t contentRefreshRate = 0; - bool isHDRContent = false; bool isDisplayPowerStateNormal = true; } mFeatures GUARDED_BY(mFeatureStateLock); const scheduler::RefreshRateConfigs& mRefreshRateConfigs; - - // Global config to force HDR content to work on DEFAULT refreshRate - static constexpr bool mForceHDRContentToDefaultRefreshRate = false; }; } // namespace android diff --git a/services/surfaceflinger/Scheduler/StrongTyping.h b/services/surfaceflinger/Scheduler/StrongTyping.h index 02db022e08..e8ca0ba836 100644 --- a/services/surfaceflinger/Scheduler/StrongTyping.h +++ b/services/surfaceflinger/Scheduler/StrongTyping.h @@ -51,13 +51,22 @@ struct Compare : Ability { inline bool operator>(T const& other) const { return !(*this < other || *this == other); } }; +template +struct Hash : Ability { + [[nodiscard]] std::size_t hash() const { + return std::hashbase().value())>::type>::type>{}( + this->base().value()); + } +}; + template class... Ability> struct StrongTyping : Ability>... { StrongTyping() : mValue(0) {} explicit StrongTyping(T const& value) : mValue(value) {} StrongTyping(StrongTyping const&) = default; StrongTyping& operator=(StrongTyping const&) = default; - inline operator T() const { return mValue; } + explicit inline operator T() const { return mValue; } T const& value() const { return mValue; } T& value() { return mValue; } @@ -65,3 +74,12 @@ private: T mValue; }; } // namespace android + +namespace std { +template class... Ability> +struct hash> { + std::size_t operator()(android::StrongTyping const& k) const { + return k.hash(); + } +}; +} // namespace std diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h index 4a4bef8b2e..e001080015 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatch.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h @@ -34,7 +34,7 @@ enum class CancelResult { Cancelled, TooLate, Error }; */ class VSyncDispatch { public: - using CallbackToken = StrongTyping; + using CallbackToken = StrongTyping; virtual ~VSyncDispatch(); diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h index f0580999c6..0e12e7f321 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h @@ -106,7 +106,8 @@ private: VSyncDispatchTimerQueue(VSyncDispatchTimerQueue const&) = delete; VSyncDispatchTimerQueue& operator=(VSyncDispatchTimerQueue const&) = delete; - using CallbackMap = std::unordered_map>; + using CallbackMap = + std::unordered_map>; void timerCallback(); void setTimer(nsecs_t, nsecs_t) REQUIRES(mMutex); diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp index 27fd76cba3..8de35b1c2f 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp +++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp @@ -134,18 +134,13 @@ void VSyncModulator::updateOffsetsLocked() { return; } - const bool isDefault = mOffsets.fpsMode == RefreshRateType::DEFAULT; - const bool isPerformance = mOffsets.fpsMode == RefreshRateType::PERFORMANCE; const bool isEarly = &offsets == &mOffsetsConfig.early; const bool isEarlyGl = &offsets == &mOffsetsConfig.earlyGl; const bool isLate = &offsets == &mOffsetsConfig.late; - ATRACE_INT("Vsync-EarlyOffsetsOn", isDefault && isEarly); - ATRACE_INT("Vsync-EarlyGLOffsetsOn", isDefault && isEarlyGl); - ATRACE_INT("Vsync-LateOffsetsOn", isDefault && isLate); - ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn", isPerformance && isEarly); - ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn", isPerformance && isEarlyGl); - ATRACE_INT("Vsync-HighFpsLateOffsetsOn", isPerformance && isLate); + ATRACE_INT("Vsync-EarlyOffsetsOn", isEarly); + ATRACE_INT("Vsync-EarlyGLOffsetsOn", isEarlyGl); + ATRACE_INT("Vsync-LateOffsetsOn", isLate); } } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index 727cef26fe..63c0feb9cc 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -37,13 +37,10 @@ private: // switch in and out of gl composition. static constexpr int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2; - using RefreshRateType = RefreshRateConfigs::RefreshRateType; - public: // Wrapper for a collection of surfaceflinger/app offsets for a particular // configuration. struct Offsets { - RefreshRateType fpsMode; nsecs_t sf; nsecs_t app; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index bf3b4c9f01..5aa2447419 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -542,14 +542,8 @@ void SurfaceFlinger::bootFinished() if (mRefreshRateConfigs->refreshRateSwitchingSupported()) { // set the refresh rate according to the policy - const auto& performanceRefreshRate = - mRefreshRateConfigs->getRefreshRateFromType(RefreshRateType::PERFORMANCE); - - if (isDisplayConfigAllowed(performanceRefreshRate.configId)) { - setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None); - } else { - setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None); - } + const auto& performanceRefreshRate = mRefreshRateConfigs->getMaxRefreshRateByPolicy(); + changeRefreshRateLocked(performanceRefreshRate, Scheduler::ConfigEvent::None); } })); } @@ -821,9 +815,8 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& displayToken, info.xdpi = xdpi; info.ydpi = ydpi; info.fps = 1e9 / hwConfig->getVsyncPeriod(); - const auto refreshRateType = - mRefreshRateConfigs->getRefreshRateTypeFromHwcConfigId(hwConfig->getId()); - const auto offset = mPhaseOffsets->getOffsetsForRefreshRate(refreshRateType); + + const auto offset = mPhaseOffsets->getOffsetsForRefreshRate(info.fps); info.appVsyncOffset = offset.late.app; // This is how far in advance a buffer must be queued for @@ -873,17 +866,17 @@ int SurfaceFlinger::getActiveConfig(const sp& displayToken) { if (display->isPrimary()) { std::lock_guard lock(mActiveConfigLock); if (mDesiredActiveConfigChanged) { - return mDesiredActiveConfig.configId; - } else { - return display->getActiveConfig(); + return mDesiredActiveConfig.configId.value(); } - } else { - return display->getActiveConfig(); } + + return display->getActiveConfig().value(); } void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { ATRACE_CALL(); + auto refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(info.configId); + ALOGV("setDesiredActiveConfig(%s)", refreshRate.name.c_str()); // Don't check against the current mode yet. Worst case we set the desired // config twice. However event generation config might have changed so we need to update it @@ -902,13 +895,14 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { // As we called to set period, we will call to onRefreshRateChangeCompleted once // DispSync model is locked. mVSyncModulator->onRefreshRateChangeInitiated(); - mPhaseOffsets->setRefreshRateType(info.type); + + mPhaseOffsets->setRefreshRateFps(refreshRate.fps); mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets()); } mDesiredActiveConfigChanged = true; if (mRefreshRateOverlay) { - mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type); + mRefreshRateOverlay->changeRefreshRate(refreshRate); } } @@ -930,14 +924,15 @@ void SurfaceFlinger::setActiveConfigInternal() { } std::lock_guard lock(mActiveConfigLock); - mRefreshRateConfigs->setCurrentConfig(mUpcomingActiveConfig.configId); + mRefreshRateConfigs->setCurrentConfigId(mUpcomingActiveConfig.configId); mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId); - display->setActiveConfig(mUpcomingActiveConfig.configId); - mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type); + auto refreshRate = + mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId); + mPhaseOffsets->setRefreshRateFps(refreshRate.fps); mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets()); - ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId); + ATRACE_INT("ActiveConfigFPS", refreshRate.fps); if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) { mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, @@ -951,12 +946,15 @@ void SurfaceFlinger::desiredActiveConfigChangeDone() { mDesiredActiveConfigChanged = false; mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); - mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type); + auto refreshRate = + mRefreshRateConfigs->getRefreshRateFromConfigId(mDesiredActiveConfig.configId); + mPhaseOffsets->setRefreshRateFps(refreshRate.fps); mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets()); } bool SurfaceFlinger::performSetActiveConfig() { ATRACE_CALL(); + ALOGV("performSetActiveConfig"); if (mCheckPendingFence) { if (previousFrameMissed()) { // fence has not signaled yet. wait for the next invalidate @@ -980,6 +978,10 @@ bool SurfaceFlinger::performSetActiveConfig() { desiredActiveConfig = mDesiredActiveConfig; } + auto refreshRate = + mRefreshRateConfigs->getRefreshRateFromConfigId(desiredActiveConfig.configId); + ALOGV("performSetActiveConfig changing active config to %d(%s)", refreshRate.configId.value(), + refreshRate.name.c_str()); const auto display = getDefaultDisplayDeviceLocked(); if (!display || display->getActiveConfig() == desiredActiveConfig.configId) { // display is not valid or we are already in the requested mode @@ -1000,8 +1002,8 @@ bool SurfaceFlinger::performSetActiveConfig() { const auto displayId = display->getId(); LOG_ALWAYS_FATAL_IF(!displayId); - ATRACE_INT("ActiveConfigModeHWC", mUpcomingActiveConfig.configId); - getHwComposer().setActiveConfig(*displayId, mUpcomingActiveConfig.configId); + ATRACE_INT("ActiveConfigFPS_HWC", refreshRate.fps); + getHwComposer().setActiveConfig(*displayId, mUpcomingActiveConfig.configId.value()); // we need to submit an empty frame to HWC to start the process mCheckPendingFence = true; @@ -1396,11 +1398,12 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { *compositorTiming = getBE().mCompositorTiming; } -bool SurfaceFlinger::isDisplayConfigAllowed(int32_t configId) const { +bool SurfaceFlinger::isDisplayConfigAllowed(HwcConfigIndexType configId) const { return mAllowedDisplayConfigs.empty() || mAllowedDisplayConfigs.count(configId); } -void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::ConfigEvent event) { +void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate, + Scheduler::ConfigEvent event) { const auto display = getDefaultDisplayDeviceLocked(); if (!display || mBootStage != BootStage::FINISHED) { return; @@ -1408,15 +1411,13 @@ void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::Co ATRACE_CALL(); // Don't do any updating if the current fps is the same as the new one. - const auto& refreshRateConfig = mRefreshRateConfigs->getRefreshRateFromType(refreshRate); - const int desiredConfigId = refreshRateConfig.configId; - - if (!isDisplayConfigAllowed(desiredConfigId)) { - ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId); + if (!isDisplayConfigAllowed(refreshRate.configId)) { + ALOGV("Skipping config %d as it is not part of allowed configs", + refreshRate.configId.value()); return; } - setDesiredActiveConfig({refreshRate, desiredConfigId, event}); + setDesiredActiveConfig({refreshRate.configId, event}); } void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId, @@ -2180,7 +2181,8 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( Dataspace::UNKNOWN}); if (!state.isVirtual()) { LOG_ALWAYS_FATAL_IF(!displayId); - display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId)); + auto activeConfigId = HwcConfigIndexType(getHwComposer().getActiveConfigIndex(*displayId)); + display->setActiveConfig(activeConfigId); } display->setLayerStack(state.layerStack); @@ -2520,6 +2522,12 @@ void SurfaceFlinger::updateCursorAsync() mCompositionEngine->updateCursorAsync(refreshArgs); } +void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, + Scheduler::ConfigEvent event) { + Mutex::Autolock lock(mStateLock); + changeRefreshRateLocked(refreshRate, event); +} + void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { if (mScheduler) { // In practice it's not allowed to hotplug in/out the primary display once it's been @@ -2528,7 +2536,7 @@ void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { return; } - int currentConfig = getHwComposer().getActiveConfigIndex(primaryDisplayId); + auto currentConfig = HwcConfigIndexType(getHwComposer().getActiveConfigIndex(primaryDisplayId)); mRefreshRateConfigs = std::make_unique(refresh_rate_switching(false), getHwComposer().getConfigs( @@ -2562,11 +2570,7 @@ void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) { new RegionSamplingThread(*this, *mScheduler, RegionSamplingThread::EnvironmentTimingTunables()); - mScheduler->setChangeRefreshRateCallback( - [this](RefreshRateType type, Scheduler::ConfigEvent event) { - Mutex::Autolock lock(mStateLock); - setRefreshRateTo(type, event); - }); + mScheduler->setSchedulerCallback(this); } void SurfaceFlinger::commitTransaction() @@ -3966,9 +3970,10 @@ void SurfaceFlinger::dumpVSync(std::string& result) const { dispSyncPresentTimeOffset, getVsyncPeriod()); StringAppendF(&result, "Allowed Display Configs: "); - for (int32_t configId : mAllowedDisplayConfigs) { + for (auto configId : mAllowedDisplayConfigs) { StringAppendF(&result, "%" PRIu32 " Hz, ", - mRefreshRateConfigs->getRefreshRateFromConfigId(configId).fps); + static_cast( + mRefreshRateConfigs->getRefreshRateFromConfigId(configId).fps)); } StringAppendF(&result, "(config override by backdoor: %s)\n\n", mDebugDisplayConfigSetByBackdoor ? "yes" : "no"); @@ -4809,13 +4814,9 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r n = data.readInt32(); if (n && !mRefreshRateOverlay && mRefreshRateConfigs->refreshRateSwitchingSupported()) { - RefreshRateType type; - { - std::lock_guard lock(mActiveConfigLock); - type = mDesiredActiveConfig.type; - } mRefreshRateOverlay = std::make_unique(*this); - mRefreshRateOverlay->changeRefreshRate(type); + auto current = mRefreshRateConfigs->getCurrentRefreshRate(); + mRefreshRateOverlay->changeRefreshRate(current); } else if (!n) { mRefreshRateOverlay.reset(); } @@ -5417,28 +5418,48 @@ void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp& d mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, display->getActiveConfig()); + // Prepare the parameters needed for RefreshRateConfigs::setPolicy. This will change to just + // passthrough once DisplayManager provide these parameters directly. + const auto refreshRate = + mRefreshRateConfigs->getRefreshRateFromConfigId(HwcConfigIndexType(allowedConfigs[0])); + const auto defaultModeId = refreshRate.configId; + auto minRefreshRateFps = refreshRate.fps; + auto maxRefreshRateFps = minRefreshRateFps; + + for (auto config : allowedConfigs) { + const auto configRefreshRate = + mRefreshRateConfigs->getRefreshRateFromConfigId(HwcConfigIndexType(config)); + if (configRefreshRate.fps < minRefreshRateFps) { + minRefreshRateFps = configRefreshRate.fps; + } else if (configRefreshRate.fps > maxRefreshRateFps) { + maxRefreshRateFps = configRefreshRate.fps; + } + } + mRefreshRateConfigs->setPolicy(defaultModeId, minRefreshRateFps, maxRefreshRateFps); + if (mRefreshRateConfigs->refreshRateSwitchingSupported()) { - const auto& type = mScheduler->getPreferredRefreshRateType(); - const auto& config = mRefreshRateConfigs->getRefreshRateFromType(type); - if (isDisplayConfigAllowed(config.configId)) { - ALOGV("switching to Scheduler preferred config %d", config.configId); - setDesiredActiveConfig({type, config.configId, Scheduler::ConfigEvent::Changed}); + auto configId = mScheduler->getPreferredConfigId(); + auto preferredRefreshRate = configId + ? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId) + : mRefreshRateConfigs->getMinRefreshRateByPolicy(); + ALOGV("trying to switch to Scheduler preferred config %d (%s)", + preferredRefreshRate.configId.value(), preferredRefreshRate.name.c_str()); + if (isDisplayConfigAllowed(preferredRefreshRate.configId)) { + ALOGV("switching to Scheduler preferred config %d", + preferredRefreshRate.configId.value()); + setDesiredActiveConfig( + {preferredRefreshRate.configId, Scheduler::ConfigEvent::Changed}); } else { - // Set the highest allowed config by iterating backwards on available refresh rates - const auto& refreshRates = mRefreshRateConfigs->getRefreshRateMap(); - for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) { - if (isDisplayConfigAllowed(iter->second.configId)) { - ALOGV("switching to allowed config %d", iter->second.configId); - setDesiredActiveConfig( - {iter->first, iter->second.configId, Scheduler::ConfigEvent::Changed}); - break; - } - } + // Set the highest allowed config + setDesiredActiveConfig({mRefreshRateConfigs->getMaxRefreshRateByPolicy().configId, + Scheduler::ConfigEvent::Changed}); + } + } else { + if (!allowedConfigs.empty()) { + ALOGV("switching to config %d", allowedConfigs[0]); + auto configId = HwcConfigIndexType(allowedConfigs[0]); + setDesiredActiveConfig({configId, Scheduler::ConfigEvent::Changed}); } - } else if (!allowedConfigs.empty()) { - ALOGV("switching to config %d", allowedConfigs[0]); - setDesiredActiveConfig( - {RefreshRateType::DEFAULT, allowedConfigs[0], Scheduler::ConfigEvent::Changed}); } } @@ -5487,7 +5508,10 @@ status_t SurfaceFlinger::getAllowedDisplayConfigs(const sp& displayToke } if (display->isPrimary()) { - outAllowedConfigs->assign(mAllowedDisplayConfigs.begin(), mAllowedDisplayConfigs.end()); + outAllowedConfigs->reserve(mAllowedDisplayConfigs.size()); + for (auto configId : mAllowedDisplayConfigs) { + outAllowedConfigs->push_back(configId.value()); + } } return NO_ERROR; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8e1199ca59..900c5f7f71 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -174,7 +174,8 @@ class SurfaceFlinger : public BnSurfaceComposer, public PriorityDumper, public ClientCache::ErasedRecipient, private IBinder::DeathRecipient, - private HWC2::ComposerCallback { + private HWC2::ComposerCallback, + private Scheduler::ISchedulerCallback { public: SurfaceFlingerBE& getBE() { return mBE; } const SurfaceFlingerBE& getBE() const { return mBE; } @@ -494,6 +495,10 @@ private: int32_t sequenceId, hwc2_display_t display, const hwc_vsync_period_change_timeline_t& updatedTimeline) override; + /* ------------------------------------------------------------------------ + * Scheduler::ISchedulerCallback + */ + void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ConfigEvent) override; /* ------------------------------------------------------------------------ * Message handling */ @@ -504,15 +509,14 @@ private: void signalLayerUpdate(); void signalRefresh(); - using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType; + using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate; struct ActiveConfigInfo { - RefreshRateType type = RefreshRateType::DEFAULT; - int configId = 0; + HwcConfigIndexType configId; Scheduler::ConfigEvent event = Scheduler::ConfigEvent::None; bool operator!=(const ActiveConfigInfo& other) const { - return type != other.type || configId != other.configId || event != other.event; + return configId != other.configId || event != other.event; } }; @@ -787,9 +791,10 @@ private: // Sets the refresh rate by switching active configs, if they are available for // the desired refresh rate. - void setRefreshRateTo(RefreshRateType, Scheduler::ConfigEvent event) REQUIRES(mStateLock); + void changeRefreshRateLocked(const RefreshRate&, Scheduler::ConfigEvent event) + REQUIRES(mStateLock); - bool isDisplayConfigAllowed(int32_t configId) const REQUIRES(mStateLock); + bool isDisplayConfigAllowed(HwcConfigIndexType configId) const REQUIRES(mStateLock); bool previousFrameMissed(int graceTimeMs = 0); @@ -1113,7 +1118,7 @@ private: std::atomic mExpectedPresentTime = 0; // All configs are allowed if the set is empty. - using DisplayConfigs = std::set; + using DisplayConfigs = std::set; DisplayConfigs mAllowedDisplayConfigs GUARDED_BY(mStateLock); std::mutex mActiveConfigLock; diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index db7d04c8e3..76e8171255 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -1427,7 +1427,7 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { // Note: This is not Case::Display::HWC_ACTIVE_CONFIG_ID as the ids are // remapped, and the test only ever sets up one config. If there were an error // looking up the remapped index, device->getActiveConfig() would be -1 instead. - EXPECT_EQ(0, device->getActiveConfig()); + EXPECT_EQ(0, device->getActiveConfig().value()); EXPECT_EQ(Case::PerFrameMetadataSupport::PER_FRAME_METADATA_KEYS, device->getSupportedPerFrameMetadata()); } diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 2662f52581..80bca021ab 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -26,6 +26,7 @@ #include "AsyncCallRecorder.h" #include "Scheduler/EventThread.h" +#include "Scheduler/HwcStrongTypes.h" using namespace std::chrono_literals; using namespace std::placeholders; @@ -34,6 +35,7 @@ using testing::_; using testing::Invoke; namespace android { + namespace { constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = 111; @@ -448,17 +450,17 @@ TEST_F(EventThreadTest, postHotplugExternalConnect) { } TEST_F(EventThreadTest, postConfigChangedPrimary) { - mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 7); + mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(7)); expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7); } TEST_F(EventThreadTest, postConfigChangedExternal) { - mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, 5); + mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, HwcConfigIndexType(5)); expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5); } TEST_F(EventThreadTest, postConfigChangedPrimary64bit) { - mThread->onConfigChanged(DISPLAY_ID_64BIT, 7); + mThread->onConfigChanged(DISPLAY_ID_64BIT, HwcConfigIndexType(7)); expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7); } @@ -468,7 +470,7 @@ TEST_F(EventThreadTest, suppressConfigChanged) { createConnection(suppressConnectionEventRecorder, ISurfaceComposer::eConfigChangedSuppress); - mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 9); + mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(9)); expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9); auto args = suppressConnectionEventRecorder.waitForCall(); diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h index 66c7f6b81f..da4eea0221 100644 --- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h +++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h @@ -25,16 +25,16 @@ namespace android::scheduler { struct FakePhaseOffsets : PhaseOffsets { static constexpr nsecs_t FAKE_PHASE_OFFSET_NS = 0; - Offsets getOffsetsForRefreshRate(RefreshRateType) const override { return getCurrentOffsets(); } + Offsets getOffsetsForRefreshRate(float) const override { return getCurrentOffsets(); } Offsets getCurrentOffsets() const override { - return {{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, - {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, - {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + return {{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, + {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}, FAKE_PHASE_OFFSET_NS}; } - void setRefreshRateType(RefreshRateType) override {} + void setRefreshRateFps(float) override {} void dump(std::string&) const override {} }; diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index e93d31e7f2..d95252b67f 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -44,9 +44,15 @@ protected: auto createLayer() { return sp(new mock::MockLayer(mFlinger.flinger())); } RefreshRateConfigs mConfigs{true, - {RefreshRateConfigs::InputConfig{0, LO_FPS_PERIOD}, - RefreshRateConfigs::InputConfig{1, HI_FPS_PERIOD}}, - 0}; + { + RefreshRateConfigs::InputConfig{HwcConfigIndexType(0), + HwcConfigGroupType(0), + LO_FPS_PERIOD}, + RefreshRateConfigs::InputConfig{HwcConfigIndexType(1), + HwcConfigGroupType(0), + HI_FPS_PERIOD}, + }, + HwcConfigIndexType(0)}; TestableScheduler* const mScheduler{new TestableScheduler(mConfigs)}; TestableSurfaceFlinger mFlinger; @@ -57,7 +63,6 @@ namespace { TEST_F(LayerHistoryTest, oneLayer) { const auto layer = createLayer(); - constexpr bool isHDR = false; EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_EQ(1, layerCount()); @@ -69,14 +74,14 @@ TEST_F(LayerHistoryTest, oneLayer) { // 0 FPS is returned if active layers have insufficient history. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) { - history().record(layer.get(), 0, isHDR, mTime); + history().record(layer.get(), 0, mTime); EXPECT_FLOAT_EQ(0, history().summarize(mTime).maxRefreshRate); EXPECT_EQ(1, activeLayerCount()); } // High FPS is returned once enough history has been recorded. for (int i = 0; i < 10; i++) { - history().record(layer.get(), 0, isHDR, mTime); + history().record(layer.get(), 0, mTime); EXPECT_FLOAT_EQ(HI_FPS, history().summarize(mTime).maxRefreshRate); EXPECT_EQ(1, activeLayerCount()); } @@ -84,29 +89,25 @@ TEST_F(LayerHistoryTest, oneLayer) { TEST_F(LayerHistoryTest, oneHDRLayer) { const auto layer = createLayer(); - constexpr bool isHDR = true; EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); - history().record(layer.get(), 0, isHDR, mTime); + history().record(layer.get(), 0, mTime); auto summary = history().summarize(mTime); EXPECT_FLOAT_EQ(0, summary.maxRefreshRate); - EXPECT_TRUE(summary.isHDR); EXPECT_EQ(1, activeLayerCount()); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false)); summary = history().summarize(mTime); EXPECT_FLOAT_EQ(0, summary.maxRefreshRate); - EXPECT_FALSE(summary.isHDR); EXPECT_EQ(0, activeLayerCount()); } TEST_F(LayerHistoryTest, explicitTimestamp) { const auto layer = createLayer(); - constexpr bool isHDR = false; EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_EQ(1, layerCount()); @@ -114,7 +115,7 @@ TEST_F(LayerHistoryTest, explicitTimestamp) { nsecs_t time = mTime; for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { - history().record(layer.get(), time, isHDR, time); + history().record(layer.get(), time, time); time += LO_FPS_PERIOD; } @@ -127,7 +128,6 @@ TEST_F(LayerHistoryTest, multipleLayers) { auto layer1 = createLayer(); auto layer2 = createLayer(); auto layer3 = createLayer(); - constexpr bool isHDR = false; EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true)); @@ -141,7 +141,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { // layer1 is active but infrequent. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { - history().record(layer1.get(), time, isHDR, time); + history().record(layer1.get(), time, time); time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); } @@ -151,12 +151,12 @@ TEST_F(LayerHistoryTest, multipleLayers) { // layer2 is frequent and has high refresh rate. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { - history().record(layer2.get(), time, isHDR, time); + history().record(layer2.get(), time, time); time += HI_FPS_PERIOD; } // layer1 is still active but infrequent. - history().record(layer1.get(), time, isHDR, time); + history().record(layer1.get(), time, time); EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time).maxRefreshRate); EXPECT_EQ(2, activeLayerCount()); @@ -165,7 +165,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { // layer1 is no longer active. // layer2 is frequent and has low refresh rate. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { - history().record(layer2.get(), time, isHDR, time); + history().record(layer2.get(), time, time); time += LO_FPS_PERIOD; } @@ -178,10 +178,10 @@ TEST_F(LayerHistoryTest, multipleLayers) { constexpr int RATIO = LO_FPS_PERIOD / HI_FPS_PERIOD; for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) { if (i % RATIO == 0) { - history().record(layer2.get(), time, isHDR, time); + history().record(layer2.get(), time, time); } - history().record(layer3.get(), time, isHDR, time); + history().record(layer3.get(), time, time); time += HI_FPS_PERIOD; } @@ -190,7 +190,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { EXPECT_EQ(2, frequentLayerCount(time)); // layer3 becomes recently active. - history().record(layer3.get(), time, isHDR, time); + history().record(layer3.get(), time, time); EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time).maxRefreshRate); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(2, frequentLayerCount(time)); @@ -205,7 +205,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { // layer2 still has low refresh rate. // layer3 becomes inactive. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { - history().record(layer2.get(), time, isHDR, time); + history().record(layer2.get(), time, time); time += LO_FPS_PERIOD; } @@ -222,7 +222,7 @@ TEST_F(LayerHistoryTest, multipleLayers) { // layer3 becomes active and has high refresh rate. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { - history().record(layer3.get(), time, isHDR, time); + history().record(layer3.get(), time, time); time += HI_FPS_PERIOD; } diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index f315a8a86c..546e65c1ea 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -30,27 +30,19 @@ using testing::_; namespace android { namespace scheduler { -using RefreshRateType = RefreshRateConfigs::RefreshRateType; using RefreshRate = RefreshRateConfigs::RefreshRate; class RefreshRateConfigsTest : public testing::Test { protected: - static constexpr int CONFIG_ID_60 = 0; - static constexpr hwc2_config_t HWC2_CONFIG_ID_60 = 0; - static constexpr int CONFIG_ID_90 = 1; - static constexpr hwc2_config_t HWC2_CONFIG_ID_90 = 1; + static inline const HwcConfigIndexType HWC_CONFIG_ID_60 = HwcConfigIndexType(0); + static inline const HwcConfigIndexType HWC_CONFIG_ID_90 = HwcConfigIndexType(1); + static inline const HwcConfigGroupType HWC_GROUP_ID_0 = HwcConfigGroupType(0); + static inline const HwcConfigGroupType HWC_GROUP_ID_1 = HwcConfigGroupType(1); static constexpr int64_t VSYNC_60 = 16666667; static constexpr int64_t VSYNC_90 = 11111111; RefreshRateConfigsTest(); ~RefreshRateConfigsTest(); - - void assertRatesEqual(const RefreshRate& left, const RefreshRate& right) { - ASSERT_EQ(left.configId, right.configId); - ASSERT_EQ(left.name, right.name); - ASSERT_EQ(left.fps, right.fps); - ASSERT_EQ(left.vsyncPeriod, right.vsyncPeriod); - } }; RefreshRateConfigsTest::RefreshRateConfigsTest() { @@ -69,40 +61,173 @@ namespace { /* ------------------------------------------------------------------------ * Test cases */ -TEST_F(RefreshRateConfigsTest, oneDeviceConfig_isRejected) { - std::vector configs{{HWC2_CONFIG_ID_60, VSYNC_60}}; +TEST_F(RefreshRateConfigsTest, oneDeviceConfig_SwitchingSupported) { + std::vector configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}}; auto refreshRateConfigs = std::make_unique(/*refreshRateSwitching=*/true, configs, - /*currentConfig=*/0); + /*currentConfigId=*/HWC_CONFIG_ID_60); + ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); +} + +TEST_F(RefreshRateConfigsTest, oneDeviceConfig_SwitchingNotSupported) { + std::vector configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}}; + auto refreshRateConfigs = + std::make_unique(/*refreshRateSwitching=*/false, configs, + /*currentConfigId=*/HWC_CONFIG_ID_60); ASSERT_FALSE(refreshRateConfigs->refreshRateSwitchingSupported()); } TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) { - std::vector configs{{HWC2_CONFIG_ID_60, VSYNC_60}, - {HWC2_CONFIG_ID_90, VSYNC_90}}; + std::vector configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; auto refreshRateConfigs = std::make_unique(/*refreshRateSwitching=*/true, configs, - /*currentConfig=*/0); + /*currentConfigId=*/HWC_CONFIG_ID_60); ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); - const auto& rates = refreshRateConfigs->getRefreshRateMap(); - ASSERT_EQ(2, rates.size()); - const auto& defaultRate = rates.find(RefreshRateType::DEFAULT); - const auto& performanceRate = rates.find(RefreshRateType::PERFORMANCE); - ASSERT_NE(rates.end(), defaultRate); - ASSERT_NE(rates.end(), performanceRate); - - RefreshRate expectedDefaultConfig = {CONFIG_ID_60, "60fps", 60, VSYNC_60, HWC2_CONFIG_ID_60}; - assertRatesEqual(expectedDefaultConfig, defaultRate->second); - RefreshRate expectedPerformanceConfig = {CONFIG_ID_90, "90fps", 90, VSYNC_90, - HWC2_CONFIG_ID_90}; - assertRatesEqual(expectedPerformanceConfig, performanceRate->second); - - assertRatesEqual(expectedDefaultConfig, - refreshRateConfigs->getRefreshRateFromType(RefreshRateType::DEFAULT)); - assertRatesEqual(expectedPerformanceConfig, - refreshRateConfigs->getRefreshRateFromType(RefreshRateType::PERFORMANCE)); + + const auto minRate = refreshRateConfigs->getMinRefreshRate(); + const auto performanceRate = refreshRateConfigs->getMaxRefreshRate(); + + RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60}; + ASSERT_EQ(expectedDefaultConfig, minRate); + RefreshRate expectedPerformanceConfig = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", + 90}; + ASSERT_EQ(expectedPerformanceConfig, performanceRate); + + const auto minRateByPolicy = refreshRateConfigs->getMinRefreshRateByPolicy(); + const auto performanceRateByPolicy = refreshRateConfigs->getMaxRefreshRateByPolicy(); + ASSERT_EQ(minRateByPolicy, minRate); + ASSERT_EQ(performanceRateByPolicy, performanceRate); } + +TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differentGroups) { + std::vector configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_1, VSYNC_90}}}; + auto refreshRateConfigs = + std::make_unique(/*refreshRateSwitching=*/true, configs, + /*currentConfigId=*/HWC_CONFIG_ID_60); + + ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + const auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy(); + const auto performanceRate = refreshRateConfigs->getMaxRefreshRate(); + const auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy(); + const auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy(); + + RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60}; + ASSERT_EQ(expectedDefaultConfig, minRate); + ASSERT_EQ(expectedDefaultConfig, minRate60); + ASSERT_EQ(expectedDefaultConfig, performanceRate60); + + refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 60, 90); + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); + + ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + const auto minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy(); + const auto performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy(); + + RefreshRate expectedPerformanceConfig = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_1, "90fps", + 90}; + ASSERT_EQ(expectedPerformanceConfig, performanceRate); + ASSERT_EQ(expectedPerformanceConfig, minRate90); + ASSERT_EQ(expectedPerformanceConfig, performanceRate90); +} + +TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_policyChange) { + std::vector configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; + auto refreshRateConfigs = + std::make_unique(/*refreshRateSwitching=*/true, configs, + /*currentConfigId=*/HWC_CONFIG_ID_60); + ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy(); + auto performanceRate = refreshRateConfigs->getMaxRefreshRateByPolicy(); + + RefreshRate expectedDefaultConfig = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60}; + ASSERT_EQ(expectedDefaultConfig, minRate); + RefreshRate expectedPerformanceConfig = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", + 90}; + ASSERT_EQ(expectedPerformanceConfig, performanceRate); + + refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60); + ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + + auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy(); + auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy(); + ASSERT_EQ(expectedDefaultConfig, minRate60); + ASSERT_EQ(expectedDefaultConfig, performanceRate60); +} + +TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getCurrentRefreshRate) { + std::vector configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; + auto refreshRateConfigs = + std::make_unique(/*refreshRateSwitching=*/true, configs, + /*currentConfigId=*/HWC_CONFIG_ID_60); + { + auto current = refreshRateConfigs->getCurrentRefreshRate(); + EXPECT_EQ(current.configId, HWC_CONFIG_ID_60); + } + + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); + { + auto current = refreshRateConfigs->getCurrentRefreshRate(); + EXPECT_EQ(current.configId, HWC_CONFIG_ID_90); + } + + refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 90, 90); + { + auto current = refreshRateConfigs->getCurrentRefreshRate(); + EXPECT_EQ(current.configId, HWC_CONFIG_ID_90); + } +} + +TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { + std::vector configs{ + {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}, + {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}}; + auto refreshRateConfigs = + std::make_unique(/*refreshRateSwitching=*/true, configs, + /*currentConfigId=*/HWC_CONFIG_ID_60); + + ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported()); + + RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60}; + RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90}; + + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(90.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(60.0f)); + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(45.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(30.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(24.0f)); + + refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(90.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(60.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(45.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(30.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(24.0f)); + + refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 90, 90); + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(90.0f)); + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(60.0f)); + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(45.0f)); + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(30.0f)); + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(24.0f)); + refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 0, 120); + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(90.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(60.0f)); + ASSERT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(45.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(30.0f)); + ASSERT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(24.0f)); +} + } // namespace } // namespace scheduler } // namespace android diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index cec0b32a6b..ef4699f628 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -33,8 +33,9 @@ namespace scheduler { class RefreshRateStatsTest : public testing::Test { protected: - static constexpr int CONFIG_ID_90 = 0; - static constexpr int CONFIG_ID_60 = 1; + static inline const auto CONFIG_ID_0 = HwcConfigIndexType(0); + static inline const auto CONFIG_ID_1 = HwcConfigIndexType(1); + static inline const auto CONFIG_GROUP_0 = HwcConfigGroupType(0); static constexpr int64_t VSYNC_90 = 11111111; static constexpr int64_t VSYNC_60 = 16666667; @@ -43,10 +44,10 @@ protected: void init(const std::vector& configs) { mRefreshRateConfigs = std::make_unique( - /*refreshRateSwitching=*/true, configs, /*currentConfig=*/0); + /*refreshRateSwitching=*/true, configs, /*currentConfig=*/CONFIG_ID_0); mRefreshRateStats = std::make_unique(*mRefreshRateConfigs, mTimeStats, - /*currentConfig=*/0, + /*currentConfigId=*/CONFIG_ID_0, /*currentPowerMode=*/HWC_POWER_MODE_OFF); } @@ -72,7 +73,7 @@ namespace { * Test cases */ TEST_F(RefreshRateStatsTest, oneConfigTest) { - init({{CONFIG_ID_90, VSYNC_90}}); + init({{{CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90}}}); EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); @@ -91,7 +92,7 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(0u, times.count("90fps")); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); + mRefreshRateStats->setConfigMode(CONFIG_ID_0); mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL); screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); @@ -107,7 +108,7 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); + mRefreshRateStats->setConfigMode(CONFIG_ID_0); screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); @@ -118,7 +119,7 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { } TEST_F(RefreshRateStatsTest, twoConfigsTest) { - init({{CONFIG_ID_90, VSYNC_90}, {CONFIG_ID_60, VSYNC_60}}); + init({{{CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90}, {CONFIG_ID_1, CONFIG_GROUP_0, VSYNC_60}}}); EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1)); @@ -137,7 +138,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); + mRefreshRateStats->setConfigMode(CONFIG_ID_0); mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL); screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); @@ -147,7 +148,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { EXPECT_LT(0, times["90fps"]); // When power mode is normal, time for configs updates. - mRefreshRateStats->setConfigMode(CONFIG_ID_60); + mRefreshRateStats->setConfigMode(CONFIG_ID_1); int ninety = mRefreshRateStats->getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); @@ -156,7 +157,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { ASSERT_EQ(1u, times.count("60fps")); EXPECT_LT(0, times["60fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); + mRefreshRateStats->setConfigMode(CONFIG_ID_0); int sixty = mRefreshRateStats->getTotalTimes()["60fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); @@ -164,7 +165,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { EXPECT_LT(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_60); + mRefreshRateStats->setConfigMode(CONFIG_ID_1); ninety = mRefreshRateStats->getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); @@ -175,7 +176,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config // does not update refresh rates that come from the config. mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); + mRefreshRateStats->setConfigMode(CONFIG_ID_0); sixty = mRefreshRateStats->getTotalTimes()["60fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); @@ -183,7 +184,7 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { EXPECT_EQ(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_60); + mRefreshRateStats->setConfigMode(CONFIG_ID_1); screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; 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 b4cc1e15e8..40536abc5d 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -50,10 +50,11 @@ SchedulerTest::SchedulerTest() { ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - std::vector configs{{/*hwcId=*/0, 16666667}}; - mRefreshRateConfigs = - std::make_unique(/*refreshRateSwitching=*/false, configs, - /*currentConfig=*/0); + std::vector configs{ + {{HwcConfigIndexType(0), HwcConfigGroupType(0), 16666667}}}; + mRefreshRateConfigs = std::make_unique< + scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs, + /*currentConfig=*/HwcConfigIndexType(0)); mScheduler = std::make_unique(*mRefreshRateConfigs); diff --git a/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp b/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp index b9ddcd77d0..54068797a1 100644 --- a/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp +++ b/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp @@ -56,18 +56,18 @@ TEST(StrongTypeTest, addition) { EXPECT_THAT(f1 + f2, Eq(FunkyType(32))); EXPECT_THAT(f2 + f1, Eq(FunkyType(32))); - EXPECT_THAT(++f1, Eq(11)); - EXPECT_THAT(f1, Eq(11)); - EXPECT_THAT(f1++, Eq(11)); - EXPECT_THAT(f1++, Eq(12)); - EXPECT_THAT(f1, Eq(13)); + EXPECT_THAT(++f1.value(), Eq(11)); + EXPECT_THAT(f1.value(), Eq(11)); + EXPECT_THAT(f1++.value(), Eq(11)); + EXPECT_THAT(f1++.value(), Eq(12)); + EXPECT_THAT(f1.value(), Eq(13)); auto f3 = f1; EXPECT_THAT(f1, Eq(f3)); EXPECT_THAT(f1, Lt(f2)); f3 += f1; - EXPECT_THAT(f1, Eq(13)); - EXPECT_THAT(f3, Eq(26)); + EXPECT_THAT(f1.value(), Eq(13)); + EXPECT_THAT(f3.value(), Eq(26)); } } // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 94fc5f7273..c4b8408202 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -193,15 +193,15 @@ public: std::unique_ptr eventControlThread, std::unique_ptr appEventThread, std::unique_ptr sfEventThread) { - std::vector configs{{/*hwcId=*/0, 16666667}}; - mFlinger->mRefreshRateConfigs = - std::make_unique(/*refreshRateSwitching=*/false, - configs, /*currentConfig=*/0); - mFlinger->mRefreshRateStats = - std::make_unique(*mFlinger->mRefreshRateConfigs, - *mFlinger->mTimeStats, - /*currentConfig=*/0, - /*powerMode=*/HWC_POWER_MODE_OFF); + std::vector configs{ + {{HwcConfigIndexType(0), HwcConfigGroupType(0), 16666667}}}; + mFlinger->mRefreshRateConfigs = std::make_unique< + scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs, + /*currentConfig=*/HwcConfigIndexType(0)); + mFlinger->mRefreshRateStats = std::make_unique< + scheduler::RefreshRateStats>(*mFlinger->mRefreshRateConfigs, *mFlinger->mTimeStats, + /*currentConfig=*/HwcConfigIndexType(0), + /*powerMode=*/HWC_POWER_MODE_OFF); mScheduler = new TestableScheduler(std::move(primaryDispSync), std::move(eventControlThread), @@ -429,6 +429,7 @@ public: static constexpr int32_t DEFAULT_WIDTH = 1920; static constexpr int32_t DEFAULT_HEIGHT = 1280; static constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'666; + static constexpr int32_t DEFAULT_CONFIG_GROUP = 7; static constexpr int32_t DEFAULT_DPI = 320; static constexpr int32_t DEFAULT_ACTIVE_CONFIG = 0; static constexpr int32_t DEFAULT_POWER_MODE = 2; @@ -452,7 +453,7 @@ public: return *this; } - auto& setRefreshRate(int32_t refreshRate) { + auto& setRefreshRate(uint32_t refreshRate) { mRefreshRate = refreshRate; return *this; } @@ -499,6 +500,7 @@ public: config.setVsyncPeriod(mRefreshRate); config.setDpiX(mDpiX); config.setDpiY(mDpiY); + config.setConfigGroup(mConfigGroup); display->mutableConfigs().emplace(mActiveConfig, config.build()); display->mutableIsConnected() = true; display->setPowerMode(static_cast(mPowerMode)); @@ -522,8 +524,9 @@ public: hwc2_display_t mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID; int32_t mWidth = DEFAULT_WIDTH; int32_t mHeight = DEFAULT_HEIGHT; - int32_t mRefreshRate = DEFAULT_REFRESH_RATE; + uint32_t mRefreshRate = DEFAULT_REFRESH_RATE; int32_t mDpiX = DEFAULT_DPI; + int32_t mConfigGroup = DEFAULT_CONFIG_GROUP; int32_t mDpiY = DEFAULT_DPI; int32_t mActiveConfig = DEFAULT_ACTIVE_CONFIG; int32_t mPowerMode = DEFAULT_POWER_MODE; diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index ed35ebf2b6..f7c380490b 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_METHOD2(onConfigChanged, void(PhysicalDisplayId, int32_t)); + MOCK_METHOD2(onConfigChanged, void(PhysicalDisplayId, HwcConfigIndexType)); MOCK_CONST_METHOD1(dump, void(std::string&)); MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset)); MOCK_METHOD1(registerDisplayEventConnection, -- cgit v1.2.3-59-g8ed1b From 718f9601c611f657fd872f84f27d5cc9aec533b4 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Sat, 9 Nov 2019 20:01:35 -0800 Subject: ui: Deduplicate rotation types Introduce ui::Rotation, replacing ISurfaceComposer::Rotation as well as DISPLAY_ORIENTATION_* and DisplayState::eOrientation* constants. libinput has widespread use of int32_t for orientation, so move DISPLAY_ORIENTATION_* to input/DisplayViewport.h for now. Bug: 144601064 Test: go/wm-smoke Test: screencap Change-Id: Ic4b8494e37c9d79c00d5b4be5eb88585f09efebf --- cmds/surfacereplayer/replayer/Replayer.cpp | 2 +- include/input/DisplayViewport.h | 13 +- include/input/TouchVideoFrame.h | 1 - libs/gui/ISurfaceComposer.cpp | 9 +- libs/gui/LayerState.cpp | 5 +- libs/gui/SurfaceComposerClient.cpp | 39 +++-- libs/gui/include/gui/ISurfaceComposer.h | 22 +-- libs/gui/include/gui/LayerState.h | 12 +- libs/gui/include/gui/SurfaceComposerClient.h | 33 ++-- libs/gui/tests/BLASTBufferQueue_test.cpp | 10 +- libs/gui/tests/Surface_test.cpp | 9 +- libs/input/TouchVideoFrame.cpp | 1 + libs/input/tests/TouchVideoFrame_test.cpp | 1 + libs/ui/include/ui/DisplayInfo.h | 11 +- libs/ui/include/ui/Rotation.h | 57 +++++++ libs/ui/include/ui/Transform.h | 39 +++-- libs/ui/include_vndk/ui/Rotation.h | 1 + opengl/tests/lib/WindowSurface.cpp | 3 +- services/surfaceflinger/BufferLayer.cpp | 6 +- services/surfaceflinger/BufferStateLayer.cpp | 2 +- services/surfaceflinger/DisplayDevice.cpp | 75 +++------ services/surfaceflinger/DisplayDevice.h | 169 +++++++++------------ services/surfaceflinger/LayerRejecter.cpp | 2 +- services/surfaceflinger/RegionSamplingThread.cpp | 14 +- services/surfaceflinger/RenderArea.h | 16 +- services/surfaceflinger/SurfaceFlinger.cpp | 101 ++++++------ services/surfaceflinger/SurfaceFlinger.h | 10 +- services/surfaceflinger/SurfaceInterceptor.cpp | 8 +- services/surfaceflinger/tests/Credentials_test.cpp | 3 +- .../tests/LayerRenderTypeTransaction_test.cpp | 4 +- .../surfaceflinger/tests/LayerTransaction_test.cpp | 2 +- .../tests/unittests/DisplayTransactionTest.cpp | 12 +- .../tests/unittests/TestableSurfaceFlinger.h | 1 - 33 files changed, 329 insertions(+), 364 deletions(-) create mode 100644 libs/ui/include/ui/Rotation.h create mode 120000 libs/ui/include_vndk/ui/Rotation.h (limited to 'services/surfaceflinger/DisplayDevice.cpp') diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index 0d6c31ee2f..675aad6f81 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -606,7 +606,7 @@ void Replayer::setDisplayProjection(SurfaceComposerClient::Transaction& t, pc.viewport().bottom()); Rect frame = Rect(pc.frame().left(), pc.frame().top(), pc.frame().right(), pc.frame().bottom()); - t.setDisplayProjection(mDisplays[id], pc.orientation(), viewport, frame); + t.setDisplayProjection(mDisplays[id], ui::toRotation(pc.orientation()), viewport, frame); } status_t Replayer::createSurfaceControl( diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h index fa456bb213..610062697c 100644 --- a/include/input/DisplayViewport.h +++ b/include/input/DisplayViewport.h @@ -17,16 +17,23 @@ #ifndef _LIBINPUT_DISPLAY_VIEWPORT_H #define _LIBINPUT_DISPLAY_VIEWPORT_H +#include +#include + #include -#include #include