diff options
| author | 2025-02-26 11:55:07 -0800 | |
|---|---|---|
| committer | 2025-02-26 11:55:07 -0800 | |
| commit | 98bdc04b7658fde0a99403fc052d1d18e7d48ea6 (patch) | |
| tree | eddfcd420408117ba0399a190f75c13cf2db0036 /services/surfaceflinger | |
| parent | 7ba28a3a24fadce84a590a6f4a94907840fe814c (diff) | |
| parent | 8c6afcf151af438342729f2399c43560ae1f353c (diff) | |
Merge 25Q1 (ab/12770256) to aosp-main-future
Bug: 385190204
Merged-In: I0fb567cbcca67a2fc6c088f652c8af570b8d7e53
Change-Id: Iaae8cd491ff963cf422f4b19c54be33e1244a9a1
Diffstat (limited to 'services/surfaceflinger')
143 files changed, 4283 insertions, 2338 deletions
diff --git a/services/surfaceflinger/ActivePictureUpdater.cpp b/services/surfaceflinger/ActivePictureUpdater.cpp new file mode 100644 index 0000000000..210e948a49 --- /dev/null +++ b/services/surfaceflinger/ActivePictureUpdater.cpp @@ -0,0 +1,66 @@ +/* + * Copyright 2024 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 "ActivePictureUpdater.h" + +#include <algorithm> + +#include "Layer.h" +#include "LayerFE.h" + +namespace android { + +void ActivePictureUpdater::onLayerComposed(const Layer& layer, const LayerFE& layerFE, + const CompositionResult& result) { + if (result.wasPictureProfileCommitted) { + gui::ActivePicture picture; + picture.layerId = int32_t(layer.sequence); + picture.ownerUid = int32_t(layer.getOwnerUid()); + // TODO(b/337330263): Why does LayerFE coming from SF have a null composition state? + if (layerFE.getCompositionState()) { + picture.pictureProfileId = layerFE.getCompositionState()->pictureProfileHandle.getId(); + } else { + picture.pictureProfileId = result.pictureProfileHandle.getId(); + } + mNewActivePictures.push_back(picture); + } +} + +bool ActivePictureUpdater::updateAndHasChanged() { + bool hasChanged = true; + if (mNewActivePictures.size() == mOldActivePictures.size()) { + auto compare = [](const gui::ActivePicture& lhs, const gui::ActivePicture& rhs) -> int { + if (lhs.layerId == rhs.layerId) { + return lhs.pictureProfileId < rhs.pictureProfileId; + } + return lhs.layerId < rhs.layerId; + }; + std::sort(mNewActivePictures.begin(), mNewActivePictures.end(), compare); + if (std::equal(mNewActivePictures.begin(), mNewActivePictures.end(), + mOldActivePictures.begin())) { + hasChanged = false; + } + } + std::swap(mOldActivePictures, mNewActivePictures); + mNewActivePictures.resize(0); + return hasChanged; +} + +const std::vector<gui::ActivePicture>& ActivePictureUpdater::getActivePictures() const { + return mOldActivePictures; +} + +} // namespace android diff --git a/services/surfaceflinger/ActivePictureUpdater.h b/services/surfaceflinger/ActivePictureUpdater.h new file mode 100644 index 0000000000..20779bb0ff --- /dev/null +++ b/services/surfaceflinger/ActivePictureUpdater.h @@ -0,0 +1,47 @@ +/* + * Copyright 2024 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 <vector> + +#include <android/gui/ActivePicture.h> + +namespace android { + +class Layer; +class LayerFE; +struct CompositionResult; + +// Keeps track of active pictures - layers that are undergoing picture processing. +class ActivePictureUpdater { +public: + // Called for each visible layer when SurfaceFlinger finishes composing. + void onLayerComposed(const Layer& layer, const LayerFE& layerFE, + const CompositionResult& result); + + // Update internals and return whether the set of active pictures have changed. + bool updateAndHasChanged(); + + // The current set of active pictures. + const std::vector<gui::ActivePicture>& getActivePictures() const; + +private: + std::vector<gui::ActivePicture> mOldActivePictures; + std::vector<gui::ActivePicture> mNewActivePictures; +}; + +} // namespace android diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index c2a9880d87..3f3d2c6cc6 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -82,6 +82,7 @@ cc_defaults { "libpowermanager", "libprocessgroup", "libprotobuf-cpp-lite", + "libstatslog_surfaceflinger", "libsync", "libui", "libutils", @@ -147,6 +148,46 @@ cc_defaults { }, } +// libsurfaceflinger_backend_{headers|sources} are a step towards pulling out +// the "backend" sources to clean up the dependency graph between +// CompositionEngine and SurfaceFlinger. Completing the cleanup would require +// moving the headers in particular so that the dependency can strictly be a +// DAG. There would certainly be additional cleanups: VirtualDisplaySurface.cpp +// and FrameBufferSurface.cpp likely belong in CompositionEngine for example. +cc_library_headers { + name: "libsurfaceflinger_backend_headers", + export_include_dirs: ["."], + static_libs: ["libserviceutils"], + export_static_lib_headers: ["libserviceutils"], + + shared_libs: [ + "android.hardware.configstore-utils", + "android.hardware.configstore@1.0", + "android.hardware.configstore@1.1", + "libbinder_ndk", + ], + export_shared_lib_headers: [ + "android.hardware.configstore-utils", + "android.hardware.configstore@1.0", + "android.hardware.configstore@1.1", + "libbinder_ndk", + ], +} + +filegroup { + name: "libsurfaceflinger_backend_sources", + srcs: [ + "PowerAdvisor/*.cpp", + "DisplayHardware/AidlComposerHal.cpp", + "DisplayHardware/ComposerHal.cpp", + "DisplayHardware/FramebufferSurface.cpp", + "DisplayHardware/HWC2.cpp", + "DisplayHardware/HWComposer.cpp", + "DisplayHardware/HidlComposerHal.cpp", + "DisplayHardware/VirtualDisplaySurface.cpp", + ], +} + cc_library_headers { name: "libsurfaceflinger_headers", export_include_dirs: ["."], @@ -157,23 +198,16 @@ cc_library_headers { filegroup { name: "libsurfaceflinger_sources", srcs: [ + ":libsurfaceflinger_backend_sources", + "ActivePictureUpdater.cpp", "BackgroundExecutor.cpp", "Client.cpp", "ClientCache.cpp", "Display/DisplayModeController.cpp", "Display/DisplaySnapshot.cpp", "DisplayDevice.cpp", - "DisplayHardware/AidlComposerHal.cpp", - "DisplayHardware/ComposerHal.cpp", - "DisplayHardware/FramebufferSurface.cpp", - "DisplayHardware/HWC2.cpp", - "DisplayHardware/HWComposer.cpp", - "DisplayHardware/HidlComposerHal.cpp", - "DisplayHardware/PowerAdvisor.cpp", - "DisplayHardware/VirtualDisplaySurface.cpp", "DisplayRenderArea.cpp", "Effects/Daltonizer.cpp", - "EventLog/EventLog.cpp", "FrontEnd/LayerCreationArgs.cpp", "FrontEnd/LayerHandle.cpp", "FrontEnd/LayerSnapshot.cpp", @@ -251,7 +285,6 @@ cc_defaults { ], static_libs: [ "android.frameworks.displayservice@1.0", - "libc++fs", "libdisplayservicehidl", "libserviceutils", ], @@ -279,7 +312,7 @@ cc_binary { "libSurfaceFlingerProp", ], - logtags: ["EventLog/EventLogTags.logtags"], + logtags: ["surfaceflinger.logtags"], } subdirs = [ @@ -314,3 +347,37 @@ cc_library_shared { "libSurfaceFlingerProperties", ], } + +cc_library { + name: "libstatslog_surfaceflinger", + generated_sources: ["statslog_surfaceflinger.cpp"], + generated_headers: ["statslog_surfaceflinger.h"], + export_generated_headers: ["statslog_surfaceflinger.h"], + shared_libs: [ + "libbinder", + "libstatsbootstrap", + "libutils", + "android.os.statsbootstrap_aidl-cpp", + ], +} + +genrule { + name: "statslog_surfaceflinger.h", + tools: ["stats-log-api-gen"], + cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog_surfaceflinger.h" + + " --module surfaceflinger --namespace android,surfaceflinger,stats --bootstrap", + out: [ + "statslog_surfaceflinger.h", + ], +} + +genrule { + name: "statslog_surfaceflinger.cpp", + tools: ["stats-log-api-gen"], + cmd: "$(location stats-log-api-gen) --cpp $(genDir)/statslog_surfaceflinger.cpp" + + " --module surfaceflinger --namespace android,surfaceflinger,stats" + + " --importHeader statslog_surfaceflinger.h --bootstrap", + out: [ + "statslog_surfaceflinger.cpp", + ], +} diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 141a228b13..82eafd4fa8 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -42,6 +42,7 @@ cc_defaults { "libutils", ], static_libs: [ + "libguiflags", "libmath", "librenderengine", "libtimestats", @@ -57,7 +58,7 @@ cc_defaults { "android.hardware.graphics.composer@2.3-command-buffer", "android.hardware.graphics.composer@2.4-command-buffer", "android.hardware.graphics.composer3-command-buffer", - "libsurfaceflinger_headers", + "libsurfaceflinger_backend_headers", ], } @@ -139,6 +140,8 @@ cc_test { ], srcs: [ ":libcompositionengine_sources", + ":libsurfaceflinger_backend_mock_sources", + ":libsurfaceflinger_backend_sources", "tests/planner/CachedSetTest.cpp", "tests/planner/FlattenerTest.cpp", "tests/planner/LayerStateTest.cpp", @@ -149,14 +152,14 @@ cc_test { "tests/DisplayTest.cpp", "tests/HwcAsyncWorkerTest.cpp", "tests/HwcBufferCacheTest.cpp", - "tests/MockHWC2.cpp", - "tests/MockHWComposer.cpp", - "tests/MockPowerAdvisor.cpp", "tests/OutputLayerTest.cpp", "tests/OutputTest.cpp", "tests/ProjectionSpaceTest.cpp", "tests/RenderSurfaceTest.cpp", ], + header_libs: [ + "libsurfaceflinger_backend_mock_headers", + ], static_libs: [ "libcompositionengine_mocks", "libgui_mocks", @@ -165,6 +168,7 @@ cc_test { "libgtest", ], shared_libs: [ + "libbinder_ndk", // For some reason, libvulkan isn't picked up from librenderengine // Probably ASAN related? "libvulkan", diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h index 6e60839dd9..252adaa8e3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h @@ -24,7 +24,7 @@ #include <ui/Size.h> #include <ui/StaticDisplayInfo.h> -#include "DisplayHardware/PowerAdvisor.h" +#include "PowerAdvisor/PowerAdvisor.h" namespace android::compositionengine { @@ -46,9 +46,15 @@ struct DisplayCreationArgs { // content. bool isProtected = false; + // True if this display has picture processing hardware and pipelines. + bool hasPictureProcessing = false; + + // The number of layer-specific picture-processing pipelines. + int32_t maxLayerPictureProfiles = 0; + // Optional pointer to the power advisor interface, if one is needed for // this display. - Hwc2::PowerAdvisor* powerAdvisor = nullptr; + adpf::PowerAdvisor* powerAdvisor = nullptr; // Debugging. Human readable name for the display. std::string name; @@ -82,7 +88,17 @@ public: return *this; } - DisplayCreationArgsBuilder& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) { + DisplayCreationArgsBuilder& setHasPictureProcessing(bool hasPictureProcessing) { + mArgs.hasPictureProcessing = hasPictureProcessing; + return *this; + } + + DisplayCreationArgsBuilder& setMaxLayerPictureProfiles(int32_t maxLayerPictureProfiles) { + mArgs.maxLayerPictureProfiles = maxLayerPictureProfiles; + return *this; + } + + DisplayCreationArgsBuilder& setPowerAdvisor(adpf::PowerAdvisor* powerAdvisor) { mArgs.powerAdvisor = powerAdvisor; return *this; } diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index 4e080b356b..cda4edc216 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -148,9 +148,6 @@ public: virtual std::optional<LayerSettings> prepareClientComposition( ClientCompositionTargetSettings&) const = 0; - // Called after the layer is displayed to update the presentation fence - virtual void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack layerStack) = 0; - // Initializes a promise for a buffer release fence and provides the future for that // fence. This should only be called when a promise has not yet been created, or // after the previous promise has already been fulfilled. Attempting to call this @@ -164,6 +161,9 @@ public: // Checks if the buffer's release fence has been set virtual LayerFE::ReleaseFencePromiseStatus getReleaseFencePromiseStatus() = 0; + // Indicates that the picture profile request was applied to this layer. + virtual void onPictureProfileCommitted() = 0; + // Gets some kind of identifier for the layer for debug purposes. virtual const char* getDebugName() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index d1429a2ec6..fb8fed0743 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -19,11 +19,13 @@ #include <cstdint> #include <android/gui/CachingHint.h> +#include <gui/DisplayLuts.h> #include <gui/HdrMetadata.h> #include <math/mat4.h> #include <ui/BlurRegion.h> #include <ui/FloatRect.h> #include <ui/LayerStack.h> +#include <ui/PictureProfileHandle.h> #include <ui/Rect.h> #include <ui/Region.h> #include <ui/ShadowSettings.h> @@ -155,7 +157,7 @@ struct LayerFECompositionState { uint32_t geomBufferTransform{0}; Rect geomBufferSize; Rect geomContentCrop; - Rect geomCrop; + FloatRect geomCrop; GenericLayerMetadataMap metadata; @@ -218,7 +220,18 @@ struct LayerFECompositionState { float currentHdrSdrRatio = 1.f; float desiredHdrSdrRatio = 1.f; + // A picture profile handle refers to a PictureProfile configured on the display, which is a + // set of parameters that configures the picture processing hardware that is used to enhance + // the quality of buffer contents. + PictureProfileHandle pictureProfileHandle{PictureProfileHandle::NONE}; + + // A layer's priority in terms of limited picture processing pipeline utilization. + int64_t pictureProfilePriority; + gui::CachingHint cachingHint = gui::CachingHint::Enabled; + + std::shared_ptr<gui::DisplayLuts> luts; + virtual ~LayerFECompositionState(); // Debugging diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 191d475e5d..bda7856596 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -16,6 +16,8 @@ #pragma once +#include <ftl/future.h> +#include <ftl/optional.h> #include <cstdint> #include <iterator> #include <optional> @@ -26,18 +28,18 @@ #include <vector> #include <compositionengine/LayerFE.h> -#include <ftl/future.h> #include <renderengine/LayerSettings.h> +#include <ui/DisplayIdentification.h> #include <ui/Fence.h> #include <ui/FenceTime.h> #include <ui/GraphicTypes.h> #include <ui/LayerStack.h> +#include <ui/PictureProfileHandle.h> #include <ui/Region.h> #include <ui/Transform.h> #include <utils/StrongPointer.h> #include <utils/Vector.h> -#include <ui/DisplayIdentification.h> #include "DisplayHardware/HWComposer.h" namespace android { @@ -167,7 +169,7 @@ public: virtual bool isValid() const = 0; // Returns the DisplayId the output represents, if it has one - virtual std::optional<DisplayId> getDisplayId() const = 0; + virtual ftl::Optional<DisplayId> getDisplayId() const = 0; // Enables (or disables) composition on this output virtual void setCompositionEnabled(bool) = 0; @@ -329,6 +331,11 @@ protected: virtual bool isPowerHintSessionGpuReportingEnabled() = 0; virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0; virtual bool canPredictCompositionStrategy(const CompositionRefreshArgs&) = 0; + virtual const aidl::android::hardware::graphics::composer3::OverlayProperties* + getOverlaySupport() = 0; + virtual bool hasPictureProcessing() const = 0; + virtual int32_t getMaxLayerPictureProfiles() const = 0; + virtual void applyPictureProfile() = 0; }; } // namespace compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h index 4dbf8d2fce..2e7a7d9c5a 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -21,6 +21,7 @@ #include <string> #include <vector> +#include <ui/PictureProfileHandle.h> #include <ui/Transform.h> #include <utils/StrongPointer.h> @@ -86,6 +87,16 @@ public: // longer cares about. virtual void uncacheBuffers(const std::vector<uint64_t>& bufferIdsToUncache) = 0; + // Get the relative priority of the layer's picture profile with respect to the importance of + // the visual content to the user experience. Lower is higher priority. + virtual int64_t getPictureProfilePriority() const = 0; + + // The picture profile handle for the layer. + virtual const PictureProfileHandle& getPictureProfileHandle() const = 0; + + // Commit the picture profile to the composition state. + virtual void commitPictureProfileToCompositionState() = 0; + // Recalculates the state of the output layer from the output-independent // layer. If includeGeometry is false, the geometry state can be skipped. // internalDisplayRotationFlags must be set to the rotation flags for the @@ -93,7 +104,10 @@ public: // transform, if needed. virtual void updateCompositionState( bool includeGeometry, bool forceClientComposition, - ui::Transform::RotationFlags internalDisplayRotationFlags) = 0; + ui::Transform::RotationFlags internalDisplayRotationFlags, + const std::optional<std::vector< + std::optional<aidl::android::hardware::graphics::composer3::LutProperties>>> + properties) = 0; // Writes the geometry state to the HWC, or does nothing if this layer does // not use the HWC. If includeGeometry is false, the geometry state can be @@ -128,6 +142,12 @@ public: // Applies a HWC device layer request virtual void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) = 0; + // Applies a HWC device layer lut + virtual void applyDeviceLayerLut( + ndk::ScopedFileDescriptor, + std::vector<std::pair< + int, aidl::android::hardware::graphics::composer3::LutProperties>>) = 0; + // Returns true if the composition settings scale pixels virtual bool needsFiltering() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index d1eff241d3..5519aafe11 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -30,7 +30,7 @@ #include <ui/DisplayIdentification.h> #include "DisplayHardware/HWComposer.h" -#include "DisplayHardware/PowerAdvisor.h" +#include "PowerAdvisor/PowerAdvisor.h" namespace android::compositionengine { @@ -45,7 +45,7 @@ public: virtual ~Display(); // compositionengine::Output overrides - std::optional<DisplayId> getDisplayId() const override; + ftl::Optional<DisplayId> getDisplayId() const override; bool isValid() const override; void dump(std::string&) const override; using compositionengine::impl::Output::setReleasedLayers; @@ -82,11 +82,13 @@ public: using DisplayRequests = android::HWComposer::DeviceRequestedChanges::DisplayRequests; using LayerRequests = android::HWComposer::DeviceRequestedChanges::LayerRequests; using ClientTargetProperty = android::HWComposer::DeviceRequestedChanges::ClientTargetProperty; + using LayerLuts = android::HWComposer::DeviceRequestedChanges::LayerLuts; virtual bool allLayersRequireClientComposition() const; virtual void applyChangedTypesToLayers(const ChangedTypes&); virtual void applyDisplayRequests(const DisplayRequests&); virtual void applyLayerRequestsToLayers(const LayerRequests&); virtual void applyClientTargetRequests(const ClientTargetProperty&); + virtual void applyLayerLutsToLayers(const LayerLuts&); // Internal virtual void setConfiguration(const compositionengine::DisplayCreationArgs&); @@ -98,9 +100,16 @@ private: void setHintSessionGpuStart(TimePoint startTime) override; void setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) override; void setHintSessionRequiresRenderEngine(bool requiresRenderEngine) override; + const aidl::android::hardware::graphics::composer3::OverlayProperties* getOverlaySupport() + override; + bool hasPictureProcessing() const override; + int32_t getMaxLayerPictureProfiles() const override; + DisplayId mId; bool mIsDisconnected = false; - Hwc2::PowerAdvisor* mPowerAdvisor = nullptr; + adpf::PowerAdvisor* mPowerAdvisor = nullptr; + bool mHasPictureProcessing = false; + int32_t mMaxLayerPictureProfiles = 0; }; // This template factory function standardizes the implementation details of the diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 9990a742db..0ccdd22919 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -16,6 +16,11 @@ #pragma once +#include <ftl/optional.h> +#include <memory> +#include <utility> +#include <vector> + #include <compositionengine/CompositionEngine.h> #include <compositionengine/LayerFECompositionState.h> #include <compositionengine/Output.h> @@ -28,10 +33,6 @@ #include <renderengine/DisplaySettings.h> #include <renderengine/LayerSettings.h> -#include <memory> -#include <utility> -#include <vector> - namespace android::compositionengine::impl { // The implementation class contains the common implementation, but does not @@ -43,7 +44,7 @@ public: // compositionengine::Output overrides bool isValid() const override; - std::optional<DisplayId> getDisplayId() const override; + ftl::Optional<DisplayId> getDisplayId() const override; void setCompositionEnabled(bool) override; void setLayerCachingEnabled(bool) override; void setLayerCachingTexturePoolEnabled(bool) override; @@ -84,13 +85,14 @@ public: bool supportsOffloadPresent() const override { return false; } void offloadPresentNextFrame() override; - void uncacheBuffers(const std::vector<uint64_t>& bufferIdsToUncache) override; void rebuildLayerStacks(const CompositionRefreshArgs&, LayerFESet&) override; void collectVisibleLayers(const CompositionRefreshArgs&, compositionengine::Output::CoverageState&) override; void ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>&, compositionengine::Output::CoverageState&) override; void setReleasedLayers(const compositionengine::CompositionRefreshArgs&) override; + void uncacheBuffers(const std::vector<uint64_t>& bufferIdsToUncache) override; + void commitPictureProfilesToCompositionState(); void updateCompositionState(const compositionengine::CompositionRefreshArgs&) override; void planComposition() override; @@ -151,6 +153,9 @@ protected: void setHintSessionRequiresRenderEngine(bool requiresRenderEngine) override; bool isPowerHintSessionEnabled() override; bool isPowerHintSessionGpuReportingEnabled() override; + bool hasPictureProcessing() const override; + int32_t getMaxLayerPictureProfiles() const override; + void applyPictureProfile() override; void dumpBase(std::string&) const; // Implemented by the final implementation for the final state it uses. @@ -164,6 +169,8 @@ protected: bool mustRecompose() const; const std::string& getNamePlusId() const { return mNamePlusId; } + const aidl::android::hardware::graphics::composer3::OverlayProperties* getOverlaySupport() + override; private: void dirtyEntireOutput(); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index f8ffde1e51..c76b34481b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -35,6 +35,7 @@ #include <compositionengine/CompositionRefreshArgs.h> #include <compositionengine/ProjectionSpace.h> #include <ui/LayerStack.h> +#include <ui/PictureProfileHandle.h> #include <ui/Rect.h> #include <ui/Region.h> #include <ui/Transform.h> @@ -170,6 +171,8 @@ struct OutputCompositionState { ICEPowerCallback* powerCallback = nullptr; + PictureProfileHandle pictureProfileHandle; + // Debugging void dump(std::string& result) const; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index f383392e55..712b55123f 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -25,12 +25,15 @@ #include <compositionengine/LayerFE.h> #include <compositionengine/OutputLayer.h> #include <ui/FloatRect.h> +#include <ui/PictureProfileHandle.h> #include <ui/Rect.h> #include <ui/DisplayIdentification.h> #include <aidl/android/hardware/graphics/composer3/Composition.h> +using aidl::android::hardware::graphics::composer3::LutProperties; + namespace android::compositionengine { struct LayerFECompositionState; @@ -46,9 +49,14 @@ public: void setHwcLayer(std::shared_ptr<HWC2::Layer>) override; void uncacheBuffers(const std::vector<uint64_t>& bufferIdsToUncache) override; + int64_t getPictureProfilePriority() const override; + const PictureProfileHandle& getPictureProfileHandle() const override; + void commitPictureProfileToCompositionState() override; void updateCompositionState(bool includeGeometry, bool forceClientComposition, - ui::Transform::RotationFlags) override; + ui::Transform::RotationFlags, + const std::optional<std::vector<std::optional<LutProperties>>> + properties = std::nullopt) override; void writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, bool zIsOverridden, bool isPeekingThrough) override; void writeCursorPositionToHWC() const override; @@ -60,6 +68,8 @@ public: aidl::android::hardware::graphics::composer3::Composition) override; void prepareForDeviceLayerRequests() override; void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override; + void applyDeviceLayerLut(ndk::ScopedFileDescriptor, + std::vector<std::pair<int, LutProperties>>) override; bool needsFiltering() const override; std::optional<LayerFE::LayerSettings> getOverrideCompositionSettings() const override; @@ -90,10 +100,13 @@ private: void writeCompositionTypeToHWC(HWC2::Layer*, aidl::android::hardware::graphics::composer3::Composition, bool isPeekingThrough, bool skipLayer); + void writeLutToHWC(HWC2::Layer*, const LayerFECompositionState&); void detectDisallowedCompositionTypeChange( aidl::android::hardware::graphics::composer3::Composition from, aidl::android::hardware::graphics::composer3::Composition to) const; bool isClientCompositionForced(bool isPeekingThrough) const; + void updateLuts(const LayerFECompositionState&, + const std::optional<std::vector<std::optional<LutProperties>>>& properties); }; // This template factory function standardizes the implementation details of the diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h index 6c419da716..c558739464 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h @@ -18,9 +18,11 @@ #include <compositionengine/ProjectionSpace.h> #include <compositionengine/impl/HwcBufferCache.h> +#include <gui/DisplayLuts.h> #include <renderengine/ExternalTexture.h> #include <ui/FloatRect.h> #include <ui/GraphicTypes.h> +#include <ui/PictureProfileHandle.h> #include <ui/Rect.h> #include <ui/Region.h> @@ -100,6 +102,9 @@ struct OutputLayerCompositionState { // order to save power. Region outputSpaceBlockingRegionHint; + // The picture profile for this layer. + PictureProfileHandle pictureProfileHandle; + // Overrides the buffer, acquire fence, and display frame stored in LayerFECompositionState struct { std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr; @@ -151,6 +156,9 @@ struct OutputLayerCompositionState { // True when this layer was skipped as part of SF-side layer caching. bool layerSkipped = false; + + // lut information + std::shared_ptr<gui::DisplayLuts> luts; }; // The HWC state is optional, and is only set up if there is any potential diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index 05a5d3838c..272fa3eef7 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -50,9 +50,6 @@ public: std::optional<compositionengine::LayerFE::LayerSettings>( compositionengine::LayerFE::ClientCompositionTargetSettings&)); - MOCK_METHOD(void, onLayerDisplayed, (ftl::SharedFuture<FenceResult>, ui::LayerStack), - (override)); - MOCK_METHOD0(createReleaseFenceFuture, ftl::Future<FenceResult>()); MOCK_METHOD1(setReleaseFence, void(const FenceResult&)); MOCK_METHOD0(getReleaseFencePromiseStatus, LayerFE::ReleaseFencePromiseStatus()); @@ -61,6 +58,7 @@ public: MOCK_CONST_METHOD0(hasRoundedCorners, bool()); MOCK_CONST_METHOD0(getMetadata, gui::LayerMetadata*()); MOCK_CONST_METHOD0(getRelativeMetadata, gui::LayerMetadata*()); + MOCK_METHOD0(onPictureProfileCommitted, void()); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index d5bf2b5090..f2c265ad2e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -34,7 +34,7 @@ public: virtual ~Output(); MOCK_CONST_METHOD0(isValid, bool()); - MOCK_CONST_METHOD0(getDisplayId, std::optional<DisplayId>()); + MOCK_CONST_METHOD0(getDisplayId, ftl::Optional<DisplayId>()); MOCK_METHOD1(setCompositionEnabled, void(bool)); MOCK_METHOD1(setLayerCachingEnabled, void(bool)); @@ -140,6 +140,11 @@ public: MOCK_METHOD(void, setHintSessionRequiresRenderEngine, (bool requiresRenderEngine)); MOCK_METHOD(bool, isPowerHintSessionEnabled, ()); MOCK_METHOD(bool, isPowerHintSessionGpuReportingEnabled, ()); + MOCK_METHOD((const aidl::android::hardware::graphics::composer3::OverlayProperties*), + getOverlaySupport, ()); + MOCK_METHOD(bool, hasPictureProcessing, (), (const)); + MOCK_METHOD(int32_t, getMaxLayerPictureProfiles, (), (const)); + MOCK_METHOD(void, applyPictureProfile, ()); }; } // 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 5fef63a510..9333ebb8cd 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h @@ -43,7 +43,10 @@ public: MOCK_CONST_METHOD0(getState, const impl::OutputLayerCompositionState&()); MOCK_METHOD0(editState, impl::OutputLayerCompositionState&()); - MOCK_METHOD3(updateCompositionState, void(bool, bool, ui::Transform::RotationFlags)); + MOCK_METHOD(void, updateCompositionState, + (bool, bool, ui::Transform::RotationFlags, + (const std::optional<std::vector<std::optional< + aidl::android::hardware::graphics::composer3::LutProperties>>>))); MOCK_METHOD5(writeStateToHWC, void(bool, bool, uint32_t, bool, bool)); MOCK_CONST_METHOD0(writeCursorPositionToHWC, void()); @@ -56,7 +59,13 @@ public: MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request)); MOCK_CONST_METHOD0(needsFiltering, bool()); MOCK_CONST_METHOD0(getOverrideCompositionSettings, std::optional<LayerFE::LayerSettings>()); - + MOCK_METHOD(void, applyDeviceLayerLut, + (ndk::ScopedFileDescriptor, + (std::vector<std::pair< + int, aidl::android::hardware::graphics::composer3::LutProperties>>))); + MOCK_METHOD(int64_t, getPictureProfilePriority, (), (const)); + MOCK_METHOD(const PictureProfileHandle&, getPictureProfileHandle, (), (const)); + MOCK_METHOD(void, commitPictureProfileToCompositionState, ()); MOCK_CONST_METHOD1(dump, void(std::string&)); }; diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp index 5c5d0cd74d..cfcce473a2 100644 --- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp +++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp @@ -198,25 +198,23 @@ void CompositionEngine::preComposition(CompositionRefreshArgs& args) { // these buffers and fire a NO_FENCE to release it. This ensures that all // promises for buffer releases are fulfilled at the end of composition. void CompositionEngine::postComposition(CompositionRefreshArgs& args) { - if (FlagManager::getInstance().ce_fence_promise()) { - SFTRACE_CALL(); - ALOGV(__FUNCTION__); - - for (auto& layerFE : args.layers) { - if (layerFE->getReleaseFencePromiseStatus() == - LayerFE::ReleaseFencePromiseStatus::INITIALIZED) { - layerFE->setReleaseFence(Fence::NO_FENCE); - } + SFTRACE_CALL(); + ALOGV(__FUNCTION__); + + for (auto& layerFE : args.layers) { + if (layerFE->getReleaseFencePromiseStatus() == + LayerFE::ReleaseFencePromiseStatus::INITIALIZED) { + layerFE->setReleaseFence(Fence::NO_FENCE); } + } - // List of layersWithQueuedFrames does not necessarily overlap with - // list of layers, so those layersWithQueuedFrames also need any - // unfulfilled promises to be resolved for completeness. - for (auto& layerFE : args.layersWithQueuedFrames) { - if (layerFE->getReleaseFencePromiseStatus() == - LayerFE::ReleaseFencePromiseStatus::INITIALIZED) { - layerFE->setReleaseFence(Fence::NO_FENCE); - } + // List of layersWithQueuedFrames does not necessarily overlap with + // list of layers, so those layersWithQueuedFrames also need any + // unfulfilled promises to be resolved for completeness. + for (auto& layerFE : args.layersWithQueuedFrames) { + if (layerFE->getReleaseFencePromiseStatus() == + LayerFE::ReleaseFencePromiseStatus::INITIALIZED) { + layerFE->setReleaseFence(Fence::NO_FENCE); } } } diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 77b1940e23..e37ce0a0eb 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -36,7 +36,7 @@ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion" -#include "DisplayHardware/PowerAdvisor.h" +#include "PowerAdvisor/PowerAdvisor.h" using aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::DisplayCapability; @@ -54,6 +54,8 @@ Display::~Display() = default; void Display::setConfiguration(const compositionengine::DisplayCreationArgs& args) { mId = args.id; mPowerAdvisor = args.powerAdvisor; + mHasPictureProcessing = args.hasPictureProcessing; + mMaxLayerPictureProfiles = args.maxLayerPictureProfiles; editState().isSecure = args.isSecure; editState().isProtected = args.isProtected; editState().displaySpace.setBounds(args.pixels); @@ -80,7 +82,7 @@ bool Display::isVirtual() const { return mId.isVirtual(); } -std::optional<DisplayId> Display::getDisplayId() const { +ftl::Optional<DisplayId> Display::getDisplayId() const { return mId; } @@ -203,15 +205,16 @@ void Display::setReleasedLayers(const compositionengine::CompositionRefreshArgs& } void Display::applyDisplayBrightness(bool applyImmediately) { - if (const auto displayId = ftl::Optional(getDisplayId()).and_then(PhysicalDisplayId::tryCast); - displayId && getState().displayBrightness) { + if (!getState().displayBrightness) { + return; + } + if (auto displayId = PhysicalDisplayId::tryCast(mId)) { auto& hwc = getCompositionEngine().getHwComposer(); - const status_t result = - hwc.setDisplayBrightness(*displayId, *getState().displayBrightness, - getState().displayBrightnessNits, - Hwc2::Composer::DisplayBrightnessOptions{ - .applyImmediately = applyImmediately}) - .get(); + status_t result = hwc.setDisplayBrightness(*displayId, *getState().displayBrightness, + getState().displayBrightnessNits, + Hwc2::Composer::DisplayBrightnessOptions{ + .applyImmediately = applyImmediately}) + .get(); ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)", getName().c_str(), result, strerror(-result)); } @@ -278,6 +281,7 @@ void Display::applyCompositionStrategy(const std::optional<DeviceRequestedChange applyDisplayRequests(changes->displayRequests); applyLayerRequestsToLayers(changes->layerRequests); applyClientTargetRequests(changes->clientTargetProperty); + applyLayerLutsToLayers(changes->layerLuts); } // Determine what type of composition we are doing from the final state @@ -287,8 +291,8 @@ void Display::applyCompositionStrategy(const std::optional<DeviceRequestedChange } bool Display::getSkipColorTransform() const { - const auto& hwc = getCompositionEngine().getHwComposer(); - if (const auto halDisplayId = HalDisplayId::tryCast(mId)) { + auto& hwc = getCompositionEngine().getHwComposer(); + if (auto halDisplayId = HalDisplayId::tryCast(mId)) { return hwc.hasDisplayCapability(*halDisplayId, DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM); } @@ -359,6 +363,25 @@ void Display::applyClientTargetRequests(const ClientTargetProperty& clientTarget static_cast<ui::PixelFormat>(clientTargetProperty.clientTargetProperty.pixelFormat)); } +void Display::applyLayerLutsToLayers(const LayerLuts& layerLuts) { + auto& mapper = getCompositionEngine().getHwComposer().getLutFileDescriptorMapper(); + for (auto* layer : getOutputLayersOrderedByZ()) { + auto hwcLayer = layer->getHwcLayer(); + if (!hwcLayer) { + continue; + } + + if (auto lutsIt = layerLuts.find(hwcLayer); lutsIt != layerLuts.end()) { + if (auto mapperIt = mapper.find(hwcLayer); mapperIt != mapper.end()) { + layer->applyDeviceLayerLut(ndk::ScopedFileDescriptor(mapperIt->second.release()), + lutsIt->second); + } + } + } + + mapper.clear(); +} + void Display::executeCommands() { const auto halDisplayIdOpt = HalDisplayId::tryCast(mId); if (mIsDisconnected || !halDisplayIdOpt) { @@ -437,6 +460,19 @@ void Display::setHintSessionRequiresRenderEngine(bool requiresRenderEngine) { mPowerAdvisor->setRequiresRenderEngine(mId, requiresRenderEngine); } +const aidl::android::hardware::graphics::composer3::OverlayProperties* +Display::getOverlaySupport() { + return &getCompositionEngine().getHwComposer().getOverlaySupport(); +} + +bool Display::hasPictureProcessing() const { + return mHasPictureProcessing; +} + +int32_t Display::getMaxLayerPictureProfiles() const { + return mMaxLayerPictureProfiles; +} + void Display::finishFrame(GpuCompositionResult&& result) { // We only need to actually compose the display if: // 1) It is being handled by hardware composer, which may need this to @@ -451,8 +487,8 @@ void Display::finishFrame(GpuCompositionResult&& result) { } bool Display::supportsOffloadPresent() const { - if (const auto halDisplayId = HalDisplayId::tryCast(mId)) { - const auto& hwc = getCompositionEngine().getHwComposer(); + if (auto halDisplayId = HalDisplayId::tryCast(mId)) { + auto& hwc = getCompositionEngine().getHwComposer(); return hwc.hasDisplayCapability(*halDisplayId, DisplayCapability::MULTI_THREADED_PRESENT); } diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp index 2d10866db3..348111d06e 100644 --- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp @@ -127,6 +127,9 @@ void LayerFECompositionState::dump(std::string& out) const { } dumpVal(out, "colorTransform", colorTransform); dumpVal(out, "caching hint", toString(cachingHint)); + if (pictureProfileHandle) { + dumpVal(out, "pictureProfile", toString(pictureProfileHandle)); + } out.append("\n"); } diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 2d8f98f2a4..f9ed92d1ee 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -32,9 +32,12 @@ #include <compositionengine/impl/planner/Planner.h> #include <ftl/algorithm.h> #include <ftl/future.h> +#include <ftl/optional.h> #include <scheduler/FrameTargeter.h> #include <scheduler/Time.h> +#include <com_android_graphics_libgui_flags.h> + #include <optional> #include <thread> @@ -111,7 +114,7 @@ bool Output::isValid() const { mRenderSurface->isValid(); } -std::optional<DisplayId> Output::getDisplayId() const { +ftl::Optional<DisplayId> Output::getDisplayId() const { return {}; } @@ -433,7 +436,7 @@ void Output::prepare(const compositionengine::CompositionRefreshArgs& refreshArg ftl::Future<std::monostate> Output::present( const compositionengine::CompositionRefreshArgs& refreshArgs) { const auto stringifyExpectedPresentTime = [this, &refreshArgs]() -> std::string { - return ftl::Optional(getDisplayId()) + return getDisplayId() .and_then(PhysicalDisplayId::tryCast) .and_then([&refreshArgs](PhysicalDisplayId id) { return refreshArgs.frameTargets.get(id); @@ -500,15 +503,6 @@ void Output::offloadPresentNextFrame() { updateHwcAsyncWorker(); } -void Output::uncacheBuffers(std::vector<uint64_t> const& bufferIdsToUncache) { - if (bufferIdsToUncache.empty()) { - return; - } - for (auto outputLayer : getOutputLayersOrderedByZ()) { - outputLayer->uncacheBuffers(bufferIdsToUncache); - } -} - void Output::rebuildLayerStacks(const compositionengine::CompositionRefreshArgs& refreshArgs, LayerFESet& layerFESet) { auto& outputState = editState(); @@ -776,11 +770,11 @@ void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE, // The layer is visible. Either reuse the existing outputLayer if we have // one, or create a new one if we do not. - auto result = ensureOutputLayer(prevOutputLayerIndex, layerFE); + auto outputLayer = ensureOutputLayer(prevOutputLayerIndex, layerFE); // Store the layer coverage information into the layer state as some of it // is useful later. - auto& outputLayerState = result->editState(); + auto& outputLayerState = outputLayer->editState(); outputLayerState.visibleRegion = visibleRegion; outputLayerState.visibleNonTransparentRegion = visibleNonTransparentRegion; outputLayerState.coveredRegion = coveredRegion; @@ -798,6 +792,54 @@ void Output::ensureOutputLayerIfVisible(sp<compositionengine::LayerFE>& layerFE, } } +void Output::uncacheBuffers(std::vector<uint64_t> const& bufferIdsToUncache) { + if (bufferIdsToUncache.empty()) { + return; + } + for (auto outputLayer : getOutputLayersOrderedByZ()) { + outputLayer->uncacheBuffers(bufferIdsToUncache); + } +} + +void Output::commitPictureProfilesToCompositionState() { + if (!com_android_graphics_libgui_flags_apply_picture_profiles()) { + return; + } + if (!hasPictureProcessing()) { + return; + } + auto compare = [](const ::android::compositionengine::OutputLayer* lhs, + const ::android::compositionengine::OutputLayer* rhs) { + return lhs->getPictureProfilePriority() > rhs->getPictureProfilePriority(); + }; + std::priority_queue<::android::compositionengine::OutputLayer*, + std::vector<::android::compositionengine::OutputLayer*>, decltype(compare)> + layersWithProfiles; + for (auto outputLayer : getOutputLayersOrderedByZ()) { + if (outputLayer->getPictureProfileHandle()) { + layersWithProfiles.push(outputLayer); + } + } + + // TODO(b/337330263): Use the default display picture profile from SurfaceFlinger + editState().pictureProfileHandle = PictureProfileHandle::NONE; + + // When layer-specific picture processing is supported, apply as many high priority profiles as + // possible to the layers, and ignore the low priority layers. + if (getMaxLayerPictureProfiles() > 0) { + for (int i = 0; i < getMaxLayerPictureProfiles() && !layersWithProfiles.empty(); + layersWithProfiles.pop(), ++i) { + layersWithProfiles.top()->commitPictureProfileToCompositionState(); + layersWithProfiles.top()->getLayerFE().onPictureProfileCommitted(); + } + // No layer-specific picture processing, so apply the highest priority picture profile to + // the entire display. + } else if (!layersWithProfiles.empty()) { + editState().pictureProfileHandle = layersWithProfiles.top()->getPictureProfileHandle(); + layersWithProfiles.top()->getLayerFE().onPictureProfileCommitted(); + } +} + void Output::setReleasedLayers(const compositionengine::CompositionRefreshArgs&) { // The base class does nothing with this call. } @@ -813,16 +855,20 @@ void Output::updateCompositionState(const compositionengine::CompositionRefreshA mLayerRequestingBackgroundBlur = findLayerRequestingBackgroundComposition(); bool forceClientComposition = mLayerRequestingBackgroundBlur != nullptr; + auto* properties = getOverlaySupport(); + for (auto* layer : getOutputLayersOrderedByZ()) { layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame, refreshArgs.devOptForceClientComposition || forceClientComposition, - refreshArgs.internalDisplayRotationFlags); + refreshArgs.internalDisplayRotationFlags, + properties ? properties->lutProperties : std::nullopt); if (mLayerRequestingBackgroundBlur == layer) { forceClientComposition = false; } } + commitPictureProfilesToCompositionState(); } void Output::planComposition() { @@ -844,17 +890,25 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr return; } - if (auto frameTargetPtrOpt = ftl::Optional(getDisplayId()) + if (auto frameTargetPtrOpt = getDisplayId() .and_then(PhysicalDisplayId::tryCast) .and_then([&refreshArgs](PhysicalDisplayId id) { return refreshArgs.frameTargets.get(id); })) { editState().earliestPresentTime = frameTargetPtrOpt->get()->earliestPresentTime(); editState().expectedPresentTime = frameTargetPtrOpt->get()->expectedPresentTime().ns(); + const auto debugPresentDelay = frameTargetPtrOpt->get()->debugPresentDelay(); + if (debugPresentDelay) { + SFTRACE_FORMAT_INSTANT("DEBUG delaying presentation by %.2fms", + debugPresentDelay->ns() / 1e6f); + editState().expectedPresentTime += debugPresentDelay->ns(); + } } editState().frameInterval = refreshArgs.frameInterval; editState().powerCallback = refreshArgs.powerCallback; + applyPictureProfile(); + compositionengine::OutputLayer* peekThroughLayer = nullptr; sp<GraphicBuffer> previousOverride = nullptr; bool includeGeometry = refreshArgs.updatingGeometryThisFrame; @@ -1610,13 +1664,7 @@ void Output::presentFrameAndReleaseLayers(bool flushEvenWhenDisabled) { releaseFence = Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence); } - if (FlagManager::getInstance().ce_fence_promise()) { - layer->getLayerFE().setReleaseFence(releaseFence); - } else { - layer->getLayerFE() - .onLayerDisplayed(ftl::yield<FenceResult>(std::move(releaseFence)).share(), - outputState.layerFilter.layerStack); - } + layer->getLayerFE().setReleaseFence(releaseFence); } // We've got a list of layers needing fences, that are disjoint with @@ -1624,12 +1672,7 @@ void Output::presentFrameAndReleaseLayers(bool flushEvenWhenDisabled) { // supply them with the present fence. for (auto& weakLayer : mReleasedLayers) { if (const auto layer = weakLayer.promote()) { - if (FlagManager::getInstance().ce_fence_promise()) { - layer->setReleaseFence(frame.presentFence); - } else { - layer->onLayerDisplayed(ftl::yield<FenceResult>(frame.presentFence).share(), - outputState.layerFilter.layerStack); - } + layer->setReleaseFence(frame.presentFence); } } @@ -1689,6 +1732,10 @@ void Output::setTreat170mAsSrgb(bool enable) { editState().treat170mAsSrgb = enable; } +const aidl::android::hardware::graphics::composer3::OverlayProperties* Output::getOverlaySupport() { + return nullptr; +} + bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) { uint64_t lastOutputLayerHash = getState().lastOutputLayerHash; uint64_t outputLayerHash = getState().outputLayerHash; @@ -1767,5 +1814,34 @@ float Output::getHdrSdrRatio(const std::shared_ptr<renderengine::ExternalTexture return getState().displayBrightnessNits / getState().sdrWhitePointNits; } +bool Output::hasPictureProcessing() const { + return false; +} + +int32_t Output::getMaxLayerPictureProfiles() const { + return 0; +} + +void Output::applyPictureProfile() { + if (!com_android_graphics_libgui_flags_apply_picture_profiles()) { + return; + } + + // TODO(b/337330263): Move this into the Display class and add a Display unit test. + if (!getState().pictureProfileHandle) { + return; + } + if (!getDisplayId()) { + return; + } + if (auto displayId = PhysicalDisplayId::tryCast(*getDisplayId())) { + auto& hwc = getCompositionEngine().getHwComposer(); + const status_t error = + hwc.setDisplayPictureProfileHandle(*displayId, getState().pictureProfileHandle); + ALOGE_IF(error, "setDisplayPictureProfileHandle failed for %s: %d, (%s)", getName().c_str(), + error, strerror(-error)); + } +} + } // namespace impl } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 091c207464..a040c88e78 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #include <DisplayHardware/Hal.h> #include <android-base/stringprintf.h> #include <compositionengine/DisplayColorProfile.h> @@ -22,10 +23,13 @@ #include <compositionengine/impl/OutputCompositionState.h> #include <compositionengine/impl/OutputLayer.h> #include <compositionengine/impl/OutputLayerCompositionState.h> +#include <ui/FloatRect.h> +#include <ui/HdrRenderTypeUtils.h> #include <cstdint> +#include <limits> #include "system/graphics-base-v1.0.h" -#include <ui/HdrRenderTypeUtils.h> +#include <com_android_graphics_libgui_flags.h> // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push @@ -37,6 +41,7 @@ #pragma clang diagnostic pop // ignored "-Wconversion" using aidl::android::hardware::graphics::composer3::Composition; +using aidl::android::hardware::graphics::composer3::Luts; namespace android::compositionengine { @@ -185,35 +190,35 @@ Rect OutputLayer::calculateOutputDisplayFrame() const { const auto& layerState = *getLayerFE().getCompositionState(); const auto& outputState = getOutput().getState(); + // Convert from layer space to layerStackSpace // apply the layer's transform, followed by the display's global transform // here we're guaranteed that the layer's transform preserves rects - Region activeTransparentRegion = layerState.transparentRegionHint; const ui::Transform& layerTransform = layerState.geomLayerTransform; - const ui::Transform& inverseLayerTransform = layerState.geomInverseLayerTransform; - const Rect& bufferSize = layerState.geomBufferSize; - Rect activeCrop = layerState.geomCrop; - if (!activeCrop.isEmpty() && bufferSize.isValid()) { - activeCrop = layerTransform.transform(activeCrop); - if (!activeCrop.intersect(outputState.layerStackSpace.getContent(), &activeCrop)) { - activeCrop.clear(); - } - activeCrop = inverseLayerTransform.transform(activeCrop, true); - // This needs to be here as transform.transform(Rect) computes the - // transformed rect and then takes the bounding box of the result before - // returning. This means - // transform.inverse().transform(transform.transform(Rect)) != Rect - // in which case we need to make sure the final rect is clipped to the - // display bounds. - if (!activeCrop.intersect(bufferSize, &activeCrop)) { - activeCrop.clear(); - } + Region activeTransparentRegion = layerTransform.transform(layerState.transparentRegionHint); + if (!layerState.geomCrop.isEmpty() && layerState.geomBufferSize.isValid()) { + FloatRect activeCrop = layerTransform.transform(layerState.geomCrop); + activeCrop = activeCrop.intersect(outputState.layerStackSpace.getContent().toFloatRect()); + const FloatRect& bufferSize = + layerTransform.transform(layerState.geomBufferSize.toFloatRect()); + activeCrop = activeCrop.intersect(bufferSize); + // mark regions outside the crop as transparent - activeTransparentRegion.orSelf(Rect(0, 0, bufferSize.getWidth(), activeCrop.top)); - activeTransparentRegion.orSelf( - Rect(0, activeCrop.bottom, bufferSize.getWidth(), bufferSize.getHeight())); - activeTransparentRegion.orSelf(Rect(0, activeCrop.top, activeCrop.left, activeCrop.bottom)); - activeTransparentRegion.orSelf( - Rect(activeCrop.right, activeCrop.top, bufferSize.getWidth(), activeCrop.bottom)); + Rect topRegion = Rect(layerTransform.transform( + FloatRect(0, 0, layerState.geomBufferSize.getWidth(), layerState.geomCrop.top))); + Rect bottomRegion = Rect(layerTransform.transform( + FloatRect(0, layerState.geomCrop.bottom, layerState.geomBufferSize.getWidth(), + layerState.geomBufferSize.getHeight()))); + Rect leftRegion = Rect(layerTransform.transform(FloatRect(0, layerState.geomCrop.top, + layerState.geomCrop.left, + layerState.geomCrop.bottom))); + Rect rightRegion = Rect(layerTransform.transform( + FloatRect(layerState.geomCrop.right, layerState.geomCrop.top, + layerState.geomBufferSize.getWidth(), layerState.geomCrop.bottom))); + + activeTransparentRegion.orSelf(topRegion); + activeTransparentRegion.orSelf(bottomRegion); + activeTransparentRegion.orSelf(leftRegion); + activeTransparentRegion.orSelf(rightRegion); } // reduce uses a FloatRect to provide more accuracy during the @@ -223,19 +228,22 @@ Rect OutputLayer::calculateOutputDisplayFrame() const { // Some HWCs may clip client composited input to its displayFrame. Make sure // that this does not cut off the shadow. if (layerState.forceClientComposition && layerState.shadowSettings.length > 0.0f) { - const auto outset = layerState.shadowSettings.length; + // RenderEngine currently blurs shadows to smooth out edges, so outset by + // 2x the length instead of 1x to compensate + const auto outset = layerState.shadowSettings.length * 2; geomLayerBounds.left -= outset; geomLayerBounds.top -= outset; geomLayerBounds.right += outset; geomLayerBounds.bottom += outset; } - Rect frame{layerTransform.transform(reduce(geomLayerBounds, activeTransparentRegion))}; - if (!frame.intersect(outputState.layerStackSpace.getContent(), &frame)) { - frame.clear(); - } - const ui::Transform displayTransform{outputState.transform}; - return displayTransform.transform(frame); + geomLayerBounds = layerTransform.transform(geomLayerBounds); + FloatRect frame = reduce(geomLayerBounds, activeTransparentRegion); + frame = frame.intersect(outputState.layerStackSpace.getContent().toFloatRect()); + + // convert from layerStackSpace to displaySpace + const ui::Transform displayTransform{outputState.transform}; + return Rect(displayTransform.transform(frame)); } uint32_t OutputLayer::calculateOutputRelativeBufferTransform( @@ -280,9 +288,55 @@ uint32_t OutputLayer::calculateOutputRelativeBufferTransform( return transform.getOrientation(); } +void OutputLayer::updateLuts( + const LayerFECompositionState& layerFEState, + const std::optional<std::vector<std::optional<LutProperties>>>& properties) { + auto& luts = layerFEState.luts; + if (!luts) { + return; + } + + auto& state = editState(); + + if (!properties) { + // GPU composition if no Hwc Luts + state.forceClientComposition = true; + return; + } + + std::vector<LutProperties> hwcLutProperties; + for (auto& p : *properties) { + if (p) { + hwcLutProperties.emplace_back(*p); + } + } + + for (const auto& inputLut : luts->lutProperties) { + bool foundInHwcLuts = false; + for (const auto& hwcLut : hwcLutProperties) { + if (static_cast<int32_t>(hwcLut.dimension) == + static_cast<int32_t>(inputLut.dimension) && + hwcLut.size == inputLut.size && + std::find(hwcLut.samplingKeys.begin(), hwcLut.samplingKeys.end(), + static_cast<LutProperties::SamplingKey>(inputLut.samplingKey)) != + hwcLut.samplingKeys.end()) { + foundInHwcLuts = true; + break; + } + } + // if any lut properties of luts can not be found in hwcLutProperties, + // GPU composition instead + if (!foundInHwcLuts) { + state.forceClientComposition = true; + return; + } + } +} + void OutputLayer::updateCompositionState( bool includeGeometry, bool forceClientComposition, - ui::Transform::RotationFlags internalDisplayRotationFlags) { + ui::Transform::RotationFlags internalDisplayRotationFlags, + const std::optional<std::vector<std::optional<LutProperties>>> properties) { const auto* layerFEState = getLayerFE().getCompositionState(); if (!layerFEState) { return; @@ -345,11 +399,22 @@ void OutputLayer::updateCompositionState( // For hdr content, treat the white point as the display brightness - HDR content should not be // boosted or dimmed. // If the layer explicitly requests to disable dimming, then don't dim either. - if (hdrRenderType == HdrRenderType::GENERIC_HDR || - getOutput().getState().displayBrightnessNits == getOutput().getState().sdrWhitePointNits || - getOutput().getState().displayBrightnessNits == 0.f || !layerFEState->dimmingEnabled) { + if (getOutput().getState().displayBrightnessNits == getOutput().getState().sdrWhitePointNits || + getOutput().getState().displayBrightnessNits <= 0.f || !layerFEState->dimmingEnabled) { state.dimmingRatio = 1.f; state.whitePointNits = getOutput().getState().displayBrightnessNits; + } else if (hdrRenderType == HdrRenderType::GENERIC_HDR) { + float deviceHeadroom = getOutput().getState().displayBrightnessNits / + getOutput().getState().sdrWhitePointNits; + float idealizedMaxHeadroom = deviceHeadroom; + + if (FlagManager::getInstance().begone_bright_hlg()) { + idealizedMaxHeadroom = + std::min(idealizedMaxHeadroom, getIdealizedMaxHeadroom(state.dataspace)); + } + + state.dimmingRatio = std::min(idealizedMaxHeadroom / deviceHeadroom, 1.0f); + state.whitePointNits = getOutput().getState().displayBrightnessNits * state.dimmingRatio; } else { float layerBrightnessNits = getOutput().getState().sdrWhitePointNits; // RANGE_EXTENDED can "self-promote" to HDR, but is still rendered for a particular @@ -363,6 +428,8 @@ void OutputLayer::updateCompositionState( state.whitePointNits = layerBrightnessNits; } + updateLuts(*layerFEState, properties); + // These are evaluated every frame as they can potentially change at any // time. if (layerFEState->forceClientComposition || !profile.isDataspaceSupported(state.dataspace) || @@ -371,6 +438,16 @@ void OutputLayer::updateCompositionState( } } +void OutputLayer::commitPictureProfileToCompositionState() { + if (!com_android_graphics_libgui_flags_apply_picture_profiles()) { + return; + } + const auto* layerState = getLayerFE().getCompositionState(); + if (layerState) { + editState().pictureProfileHandle = layerState->pictureProfileHandle; + } +} + void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, bool zIsOverridden, bool isPeekingThrough) { const auto& state = getState(); @@ -415,6 +492,8 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough, skipLayer); + writeLutToHWC(hwcLayer.get(), *outputIndependentState); + if (requestedCompositionType == Composition::SOLID_COLOR) { writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState); } @@ -508,6 +587,40 @@ void OutputLayer::writeOutputIndependentGeometryStateToHWC( } } +void OutputLayer::writeLutToHWC(HWC2::Layer* hwcLayer, + const LayerFECompositionState& outputIndependentState) { + if (!outputIndependentState.luts) { + return; + } + auto& lutFileDescriptor = outputIndependentState.luts->getLutFileDescriptor(); + auto lutOffsets = outputIndependentState.luts->offsets; + auto& lutProperties = outputIndependentState.luts->lutProperties; + + std::vector<LutProperties> aidlProperties; + aidlProperties.reserve(lutProperties.size()); + for (size_t i = 0; i < lutOffsets.size(); i++) { + LutProperties properties; + properties.dimension = static_cast<LutProperties::Dimension>(lutProperties[i].dimension); + properties.size = lutProperties[i].size; + properties.samplingKeys = { + static_cast<LutProperties::SamplingKey>(lutProperties[i].samplingKey)}; + aidlProperties.emplace_back(properties); + } + + Luts luts; + luts.pfd = ndk::ScopedFileDescriptor(dup(lutFileDescriptor.get())); + luts.offsets = lutOffsets; + luts.lutProperties = std::move(aidlProperties); + + switch (auto error = hwcLayer->setLuts(luts)) { + case hal::Error::NONE: + break; + default: + ALOGE("[%s] Failed to set Luts: %s (%d)", getLayerFE().getDebugName(), + to_string(error).c_str(), static_cast<int32_t>(error)); + } +} + void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) { const auto& outputDependentState = getState(); @@ -556,6 +669,21 @@ void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) ALOGE("[%s] Failed to set brightness %f: %s (%d)", getLayerFE().getDebugName(), dimmingRatio, to_string(error).c_str(), static_cast<int32_t>(error)); } + + if (com_android_graphics_libgui_flags_apply_picture_profiles() && + outputDependentState.pictureProfileHandle) { + if (auto error = + hwcLayer->setPictureProfileHandle(outputDependentState.pictureProfileHandle); + error != hal::Error::NONE) { + ALOGE("[%s] Failed to set picture profile handle: %s (%d)", getLayerFE().getDebugName(), + toString(outputDependentState.pictureProfileHandle).c_str(), + static_cast<int32_t>(error)); + } + // Reset the picture profile state, as it needs to be re-committed on each present cycle + // when Output decides that the limited picture-processing hardware should be used by this + // layer. + editState().pictureProfileHandle = PictureProfileHandle::NONE; + } } void OutputLayer::writeOutputIndependentPerFrameStateToHWC( @@ -661,6 +789,16 @@ void OutputLayer::uncacheBuffers(const std::vector<uint64_t>& bufferIdsToUncache } } +int64_t OutputLayer::getPictureProfilePriority() const { + const auto* layerState = getLayerFE().getCompositionState(); + return layerState ? layerState->pictureProfilePriority : 0; +} + +const PictureProfileHandle& OutputLayer::getPictureProfileHandle() const { + const auto* layerState = getLayerFE().getCompositionState(); + return layerState ? layerState->pictureProfileHandle : PictureProfileHandle::NONE; +} + void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState, bool skipLayer) { @@ -743,14 +881,14 @@ void OutputLayer::writeCursorPositionToHWC() const { return; } - const auto* layerFEState = getLayerFE().getCompositionState(); - if (!layerFEState) { + const auto* layerState = getLayerFE().getCompositionState(); + if (!layerState) { return; } const auto& outputState = getOutput().getState(); - Rect frame = layerFEState->cursorFrame; + Rect frame = layerState->cursorFrame; frame.intersect(outputState.layerStackSpace.getContent(), &frame); Rect position = outputState.transform.transform(frame); @@ -844,6 +982,31 @@ void OutputLayer::applyDeviceLayerRequest(hal::LayerRequest request) { } } +void OutputLayer::applyDeviceLayerLut( + ndk::ScopedFileDescriptor lutFileDescriptor, + std::vector<std::pair<int, LutProperties>> lutOffsetsAndProperties) { + auto& state = editState(); + LOG_FATAL_IF(!state.hwc); + auto& hwcState = *state.hwc; + std::vector<int32_t> offsets; + std::vector<int32_t> dimensions; + std::vector<int32_t> sizes; + std::vector<int32_t> samplingKeys; + for (const auto& [offset, properties] : lutOffsetsAndProperties) { + // The Lut(s) that comes back through CommandResultPayload should be + // only one sampling key. + if (properties.samplingKeys.size() == 1) { + offsets.emplace_back(offset); + dimensions.emplace_back(static_cast<int32_t>(properties.dimension)); + sizes.emplace_back(static_cast<int32_t>(properties.size)); + samplingKeys.emplace_back(static_cast<int32_t>(properties.samplingKeys[0])); + } + } + hwcState.luts = std::make_shared<gui::DisplayLuts>(base::unique_fd(lutFileDescriptor.release()), + std::move(offsets), std::move(dimensions), + std::move(sizes), std::move(samplingKeys)); +} + bool OutputLayer::needsFiltering() const { const auto& state = getState(); const auto& sourceCrop = state.sourceCrop; diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp index da1f7e49f8..deef74728d 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp @@ -72,6 +72,9 @@ void OutputLayerCompositionState::dump(std::string& out) const { dumpVal(out, "dataspace", toString(dataspace), dataspace); dumpVal(out, "whitePointNits", whitePointNits); dumpVal(out, "dimmingRatio", dimmingRatio); + if (pictureProfileHandle) { + dumpVal(out, "pictureProfile", toString(pictureProfileHandle)); + } dumpVal(out, "override buffer", overrideInfo.buffer.get()); dumpVal(out, "override acquire fence", overrideInfo.acquireFence.get()); dumpVal(out, "override display frame", overrideInfo.displayFrame); diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp index 639164d8c9..3e0c390a5d 100644 --- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp @@ -26,11 +26,8 @@ #include <gtest/gtest.h> #include <renderengine/mock/RenderEngine.h> -#include "MockHWComposer.h" #include "TimeStats/TimeStats.h" -#include "gmock/gmock.h" - -#include <variant> +#include "mock/DisplayHardware/MockHWComposer.h" using namespace com::android::graphics::surfaceflinger; @@ -494,9 +491,6 @@ struct CompositionEnginePostCompositionTest : public CompositionEngineTest { }; TEST_F(CompositionEnginePostCompositionTest, postCompositionReleasesAllFences) { - SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::ce_fence_promise, true); - ASSERT_TRUE(FlagManager::getInstance().ce_fence_promise()); - EXPECT_CALL(*mLayer1FE, getReleaseFencePromiseStatus) .WillOnce(Return(LayerFE::ReleaseFencePromiseStatus::FULFILLED)); EXPECT_CALL(*mLayer2FE, getReleaseFencePromiseStatus) diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 39163ea60f..c1e59d01de 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -36,10 +36,10 @@ #include <ui/Rect.h> #include <ui/StaticDisplayInfo.h> -#include "MockHWC2.h" -#include "MockHWComposer.h" -#include "MockPowerAdvisor.h" #include "ftl/future.h" +#include "mock/DisplayHardware/MockHWC2.h" +#include "mock/DisplayHardware/MockHWComposer.h" +#include "mock/PowerAdvisor/MockPowerAdvisor.h" #include <aidl/android/hardware/graphics/composer3/Composition.h> @@ -133,6 +133,7 @@ struct DisplayTestCommon : 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&)); + MOCK_METHOD1(applyLayerLutsToLayers, void(const impl::Display::LayerLuts&)); const compositionengine::CompositionEngine& mCompositionEngine; impl::OutputCompositionState mState; @@ -191,7 +192,7 @@ struct DisplayTestCommon : public testing::Test { } StrictMock<android::mock::HWComposer> mHwComposer; - StrictMock<Hwc2::mock::PowerAdvisor> mPowerAdvisor; + StrictMock<adpf::mock::PowerAdvisor> mPowerAdvisor; StrictMock<renderengine::mock::RenderEngine> mRenderEngine; StrictMock<mock::CompositionEngine> mCompositionEngine; sp<mock::NativeWindow> mNativeWindow = sp<StrictMock<mock::NativeWindow>>::make(); @@ -212,6 +213,7 @@ struct PartialMockDisplayTestCommon : public DisplayTestCommon { aidl::android::hardware::graphics::common::Dataspace::UNKNOWN}, -1.f, DimmingStage::NONE}, + {}, }; void chooseCompositionStrategy(Display* display) { @@ -615,6 +617,7 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) { EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests)) .Times(1); EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); + EXPECT_CALL(*mDisplay, applyLayerLutsToLayers(mDeviceRequestedChanges.layerLuts)).Times(1); chooseCompositionStrategy(mDisplay.get()); @@ -667,6 +670,7 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests)) .Times(1); EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); + EXPECT_CALL(*mDisplay, applyLayerLutsToLayers(mDeviceRequestedChanges.layerLuts)).Times(1); chooseCompositionStrategy(mDisplay.get()); @@ -1031,7 +1035,7 @@ struct DisplayFunctionalTest : public testing::Test { } NiceMock<android::mock::HWComposer> mHwComposer; - NiceMock<Hwc2::mock::PowerAdvisor> mPowerAdvisor; + NiceMock<adpf::mock::PowerAdvisor> mPowerAdvisor; NiceMock<mock::CompositionEngine> mCompositionEngine; sp<mock::NativeWindow> mNativeWindow = sp<NiceMock<mock::NativeWindow>>::make(); sp<mock::DisplaySurface> mDisplaySurface = sp<NiceMock<mock::DisplaySurface>>::make(); diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.cpp b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.cpp deleted file mode 100644 index 0baa79d0bb..0000000000 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 "MockHWC2.h" - -namespace android::HWC2 { - -// This will go away once HWC2::Layer is moved into the "backend" library -Layer::~Layer() = default; - -namespace mock { - -// The Google Mock documentation recommends explicit non-header instantiations -// for better compile time performance. -Layer::Layer() = default; -Layer::~Layer() = default; - -} // namespace mock -} // namespace android::HWC2 diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h deleted file mode 100644 index eb6e677117..0000000000 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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 <gmock/gmock.h> -#include <ui/Fence.h> -#include <ui/FloatRect.h> -#include <ui/GraphicBuffer.h> -#include <ui/Rect.h> -#include <ui/Region.h> -#include <ui/Transform.h> - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#pragma clang diagnostic ignored "-Wextra" - -#include <ui/GraphicTypes.h> -#include "DisplayHardware/HWC2.h" - -#include <aidl/android/hardware/graphics/composer3/Composition.h> -#include <aidl/android/hardware/graphics/composer3/Lut.h> - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" - -namespace android { -namespace HWC2 { -namespace mock { - -namespace hal = android::hardware::graphics::composer::hal; - -using Error = hal::Error; - -class Layer : public HWC2::Layer { -public: - Layer(); - ~Layer() override; - - MOCK_CONST_METHOD0(getId, hal::HWLayerId()); - - MOCK_METHOD2(setCursorPosition, Error(int32_t, int32_t)); - MOCK_METHOD3(setBuffer, - Error(uint32_t, const android::sp<android::GraphicBuffer>&, - const android::sp<android::Fence>&)); - MOCK_METHOD2(setBufferSlotsToClear, Error(const std::vector<uint32_t>&, uint32_t)); - MOCK_METHOD1(setSurfaceDamage, Error(const android::Region&)); - MOCK_METHOD1(setBlendMode, Error(hal::BlendMode)); - MOCK_METHOD1(setColor, Error(aidl::android::hardware::graphics::composer3::Color)); - MOCK_METHOD1(setCompositionType, - Error(aidl::android::hardware::graphics::composer3::Composition)); - MOCK_METHOD1(setDataspace, Error(android::ui::Dataspace)); - MOCK_METHOD2(setPerFrameMetadata, Error(const int32_t, const android::HdrMetadata&)); - MOCK_METHOD1(setDisplayFrame, Error(const android::Rect&)); - MOCK_METHOD1(setPlaneAlpha, Error(float)); - MOCK_METHOD1(setSidebandStream, Error(const native_handle_t*)); - MOCK_METHOD1(setSourceCrop, Error(const android::FloatRect&)); - MOCK_METHOD1(setTransform, Error(hal::Transform)); - MOCK_METHOD1(setVisibleRegion, Error(const android::Region&)); - MOCK_METHOD1(setZOrder, Error(uint32_t)); - - MOCK_METHOD1(setColorTransform, Error(const android::mat4&)); - MOCK_METHOD3(setLayerGenericMetadata, - Error(const std::string&, bool, const std::vector<uint8_t>&)); - MOCK_METHOD1(setBrightness, Error(float)); - MOCK_METHOD1(setBlockingRegion, Error(const android::Region&)); - MOCK_METHOD(Error, setLuts, (std::vector<aidl::android::hardware::graphics::composer3::Lut>&)); -}; - -} // namespace mock -} // namespace HWC2 -} // namespace android diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h deleted file mode 100644 index e910c72e2e..0000000000 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2018 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 <compositionengine/Output.h> -#include <gmock/gmock.h> - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#pragma clang diagnostic ignored "-Wextra" - -#include "DisplayHardware/HWComposer.h" - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" - -namespace android { -namespace mock { - -namespace hal = android::hardware::graphics::composer::hal; - -class HWComposer : public android::HWComposer { -public: - HWComposer(); - ~HWComposer() override; - - MOCK_METHOD1(setCallback, void(HWC2::ComposerCallback&)); - MOCK_CONST_METHOD3(getDisplayIdentificationData, - bool(hal::HWDisplayId, uint8_t*, DisplayIdentificationData*)); - MOCK_CONST_METHOD1(hasCapability, - bool(aidl::android::hardware::graphics::composer3::Capability)); - MOCK_CONST_METHOD2(hasDisplayCapability, - bool(HalDisplayId, - aidl::android::hardware::graphics::composer3::DisplayCapability)); - - MOCK_CONST_METHOD0(getMaxVirtualDisplayCount, size_t()); - MOCK_CONST_METHOD0(getMaxVirtualDisplayDimension, size_t()); - MOCK_METHOD3(allocateVirtualDisplay, bool(HalVirtualDisplayId, ui::Size, ui::PixelFormat*)); - MOCK_METHOD3(allocatePhysicalDisplay, - void(hal::HWDisplayId, PhysicalDisplayId, std::optional<ui::Size>)); - - MOCK_METHOD1(createLayer, std::shared_ptr<HWC2::Layer>(HalDisplayId)); - MOCK_METHOD(status_t, getDeviceCompositionChanges, - (HalDisplayId, bool, std::optional<std::chrono::steady_clock::time_point>, nsecs_t, - Fps, std::optional<android::HWComposer::DeviceRequestedChanges>*)); - MOCK_METHOD(status_t, setClientTarget, - (HalDisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&, ui::Dataspace, - float), - (override)); - MOCK_METHOD2(presentAndGetReleaseFences, - status_t(HalDisplayId, std::optional<std::chrono::steady_clock::time_point>)); - MOCK_METHOD(status_t, executeCommands, (HalDisplayId)); - MOCK_METHOD2(setPowerMode, status_t(PhysicalDisplayId, hal::PowerMode)); - MOCK_METHOD2(setActiveConfig, status_t(HalDisplayId, size_t)); - MOCK_METHOD2(setColorTransform, status_t(HalDisplayId, const mat4&)); - MOCK_METHOD1(disconnectDisplay, void(HalDisplayId)); - MOCK_CONST_METHOD1(hasDeviceComposition, bool(const std::optional<DisplayId>&)); - MOCK_CONST_METHOD1(getPresentFence, sp<Fence>(HalDisplayId)); - MOCK_METHOD(nsecs_t, getPresentTimestamp, (PhysicalDisplayId), (const, override)); - MOCK_CONST_METHOD2(getLayerReleaseFence, sp<Fence>(HalDisplayId, HWC2::Layer*)); - MOCK_METHOD3(setOutputBuffer, - status_t(HalVirtualDisplayId, const sp<Fence>&, const sp<GraphicBuffer>&)); - MOCK_METHOD1(clearReleaseFences, void(HalDisplayId)); - MOCK_METHOD2(getHdrCapabilities, status_t(HalDisplayId, HdrCapabilities*)); - MOCK_CONST_METHOD1(getSupportedPerFrameMetadata, int32_t(HalDisplayId)); - MOCK_CONST_METHOD2(getRenderIntents, - std::vector<ui::RenderIntent>(HalDisplayId, ui::ColorMode)); - MOCK_METHOD2(getDataspaceSaturationMatrix, mat4(HalDisplayId, ui::Dataspace)); - MOCK_METHOD4(getDisplayedContentSamplingAttributes, - status_t(HalDisplayId, ui::PixelFormat*, ui::Dataspace*, uint8_t*)); - MOCK_METHOD4(setDisplayContentSamplingEnabled, status_t(HalDisplayId, bool, uint8_t, uint64_t)); - MOCK_METHOD4(getDisplayedContentSample, - status_t(HalDisplayId, uint64_t, uint64_t, DisplayedFrameStats*)); - MOCK_METHOD(ftl::Future<status_t>, setDisplayBrightness, - (PhysicalDisplayId, float, float, const Hwc2::Composer::DisplayBrightnessOptions&), - (override)); - MOCK_METHOD2(getDisplayBrightnessSupport, status_t(PhysicalDisplayId, bool*)); - - MOCK_METHOD2(onHotplug, - std::optional<DisplayIdentificationInfo>(hal::HWDisplayId, hal::Connection)); - MOCK_CONST_METHOD0(updatesDeviceProductInfoOnHotplugReconnect, bool()); - MOCK_METHOD(std::optional<PhysicalDisplayId>, onVsync, (hal::HWDisplayId, int64_t)); - MOCK_METHOD2(setVsyncEnabled, void(PhysicalDisplayId, hal::Vsync)); - MOCK_CONST_METHOD1(isConnected, bool(PhysicalDisplayId)); - MOCK_CONST_METHOD2(getModes, - std::vector<HWComposer::HWCDisplayMode>(PhysicalDisplayId, int32_t)); - MOCK_CONST_METHOD1(getActiveMode, ftl::Expected<hal::HWConfigId, status_t>(PhysicalDisplayId)); - MOCK_CONST_METHOD1(getColorModes, std::vector<ui::ColorMode>(PhysicalDisplayId)); - MOCK_METHOD3(setActiveColorMode, status_t(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent)); - MOCK_CONST_METHOD0(isUsingVrComposer, bool()); - MOCK_CONST_METHOD1(getDisplayConnectionType, ui::DisplayConnectionType(PhysicalDisplayId)); - MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(PhysicalDisplayId)); - MOCK_CONST_METHOD1(getDisplayVsyncPeriod, ftl::Expected<nsecs_t, status_t>(PhysicalDisplayId)); - MOCK_METHOD4(setActiveModeWithConstraints, - status_t(PhysicalDisplayId, hal::HWConfigId, - const hal::VsyncPeriodChangeConstraints&, - hal::VsyncPeriodChangeTimeline*)); - MOCK_METHOD2(setBootDisplayMode, status_t(PhysicalDisplayId, hal::HWConfigId)); - MOCK_METHOD1(clearBootDisplayMode, status_t(PhysicalDisplayId)); - MOCK_METHOD1(getPreferredBootDisplayMode, std::optional<hal::HWConfigId>(PhysicalDisplayId)); - MOCK_METHOD0(getBootDisplayModeSupport, bool()); - MOCK_CONST_METHOD0( - getHdrConversionCapabilities, - std::vector<aidl::android::hardware::graphics::common::HdrConversionCapability>()); - MOCK_METHOD2(setHdrConversionStrategy, - status_t(aidl::android::hardware::graphics::common::HdrConversionStrategy, - aidl::android::hardware::graphics::common::Hdr*)); - MOCK_METHOD2(setAutoLowLatencyMode, status_t(PhysicalDisplayId, bool)); - MOCK_METHOD(status_t, getSupportedContentTypes, - (PhysicalDisplayId, std::vector<hal::ContentType>*), (const, override)); - MOCK_METHOD2(setContentType, status_t(PhysicalDisplayId, hal::ContentType)); - MOCK_CONST_METHOD0(getSupportedLayerGenericMetadata, - const std::unordered_map<std::string, bool>&()); - - MOCK_CONST_METHOD1(dump, void(std::string&)); - MOCK_CONST_METHOD1(dumpOverlayProperties, void(std::string&)); - MOCK_CONST_METHOD0(getComposer, android::Hwc2::Composer*()); - - MOCK_METHOD(hal::HWDisplayId, getPrimaryHwcDisplayId, (), (const, override)); - MOCK_METHOD(PhysicalDisplayId, getPrimaryDisplayId, (), (const, override)); - MOCK_METHOD(bool, isHeadless, (), (const, override)); - - MOCK_METHOD(std::optional<PhysicalDisplayId>, toPhysicalDisplayId, (hal::HWDisplayId), - (const, override)); - MOCK_METHOD(std::optional<hal::HWDisplayId>, fromPhysicalDisplayId, (PhysicalDisplayId), - (const, override)); - MOCK_METHOD2(getDisplayDecorationSupport, - status_t(PhysicalDisplayId, - std::optional<aidl::android::hardware::graphics::common:: - DisplayDecorationSupport>* support)); - MOCK_METHOD2(setIdleTimerEnabled, status_t(PhysicalDisplayId, std::chrono::milliseconds)); - MOCK_METHOD(bool, hasDisplayIdleTimerCapability, (PhysicalDisplayId), (const, override)); - MOCK_METHOD(Hwc2::AidlTransform, getPhysicalDisplayOrientation, (PhysicalDisplayId), - (const, override)); - MOCK_METHOD(bool, getValidateSkipped, (HalDisplayId), (const, override)); - MOCK_METHOD(const aidl::android::hardware::graphics::composer3::OverlayProperties&, - getOverlaySupport, (), (const, override)); - MOCK_METHOD(status_t, setRefreshRateChangedCallbackDebugEnabled, (PhysicalDisplayId, bool)); - MOCK_METHOD(status_t, notifyExpectedPresent, (PhysicalDisplayId, TimePoint, Fps)); - MOCK_METHOD(status_t, getRequestedLuts, - (PhysicalDisplayId, - std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*), - (override)); -}; - -} // namespace mock -} // namespace android diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp deleted file mode 100644 index 85b94031c3..0000000000 --- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 deleted file mode 100644 index ed2ffa9df6..0000000000 --- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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 <gmock/gmock.h> - -#include "DisplayHardware/PowerAdvisor.h" - -namespace android { -namespace Hwc2 { -namespace mock { - -class PowerAdvisor : public android::Hwc2::PowerAdvisor { -public: - PowerAdvisor(); - ~PowerAdvisor() override; - - MOCK_METHOD(void, init, (), (override)); - MOCK_METHOD(void, onBootFinished, (), (override)); - MOCK_METHOD(void, setExpensiveRenderingExpected, (DisplayId displayId, bool expected), - (override)); - MOCK_METHOD(bool, isUsingExpensiveRendering, (), (override)); - MOCK_METHOD(void, notifyCpuLoadUp, (), (override)); - MOCK_METHOD(void, notifyDisplayUpdateImminentAndCpuReset, (), (override)); - MOCK_METHOD(bool, usePowerHintSession, (), (override)); - MOCK_METHOD(bool, supportsPowerHintSession, (), (override)); - MOCK_METHOD(bool, supportsGpuReporting, (), (override)); - MOCK_METHOD(void, updateTargetWorkDuration, (Duration targetDuration), (override)); - MOCK_METHOD(void, reportActualWorkDuration, (), (override)); - MOCK_METHOD(void, enablePowerHintSession, (bool enabled), (override)); - MOCK_METHOD(bool, startPowerHintSession, (std::vector<int32_t> && threadIds), (override)); - MOCK_METHOD(void, setGpuStartTime, (DisplayId displayId, TimePoint startTime), (override)); - MOCK_METHOD(void, setGpuFenceTime, - (DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override)); - MOCK_METHOD(void, setHwcValidateTiming, - (DisplayId displayId, TimePoint validateStartTime, TimePoint validateEndTime), - (override)); - MOCK_METHOD(void, setHwcPresentTiming, - (DisplayId displayId, TimePoint presentStartTime, TimePoint presentEndTime), - (override)); - MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override)); - MOCK_METHOD(void, setRequiresRenderEngine, (DisplayId displayId, bool requiresRenderEngine), - (override)); - MOCK_METHOD(void, setExpectedPresentTime, (TimePoint expectedPresentTime), (override)); - MOCK_METHOD(void, setSfPresentTiming, (TimePoint presentFenceTime, TimePoint presentEndTime), - (override)); - MOCK_METHOD(void, setHwcPresentDelayedTime, - (DisplayId displayId, TimePoint earliestFrameStartTime)); - MOCK_METHOD(void, setFrameDelay, (Duration frameDelayDuration), (override)); - MOCK_METHOD(void, setCommitStart, (TimePoint commitStartTime), (override)); - MOCK_METHOD(void, setCompositeEnd, (TimePoint compositeEndTime), (override)); - MOCK_METHOD(void, setDisplays, (std::vector<DisplayId> & displayIds), (override)); - MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (Duration targetDuration), (override)); -}; - -} // namespace mock -} // namespace Hwc2 -} // namespace android diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 1c54469cc0..dbffe80a3a 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <com_android_graphics_libgui_flags.h> #include <compositionengine/impl/HwcBufferCache.h> #include <compositionengine/impl/OutputLayer.h> #include <compositionengine/impl/OutputLayerCompositionState.h> @@ -23,13 +24,14 @@ #include <compositionengine/mock/Output.h> #include <gtest/gtest.h> #include <log/log.h> - #include <renderengine/impl/ExternalTexture.h> #include <renderengine/mock/RenderEngine.h> +#include <ui/FloatRect.h> #include <ui/PixelFormat.h> -#include "MockHWC2.h" -#include "MockHWComposer.h" + #include "RegionMatcher.h" +#include "mock/DisplayHardware/MockHWC2.h" +#include "mock/DisplayHardware/MockHWComposer.h" #include <aidl/android/hardware/graphics/composer3/Composition.h> @@ -270,7 +272,7 @@ struct OutputLayerDisplayFrameTest : public OutputLayerTest { mLayerFEState.geomLayerTransform = ui::Transform{TR_IDENT}; mLayerFEState.geomBufferSize = Rect{0, 0, 1920, 1080}; mLayerFEState.geomBufferUsesDisplayInverseTransform = false; - mLayerFEState.geomCrop = Rect{0, 0, 1920, 1080}; + mLayerFEState.geomCrop = FloatRect{0, 0, 1920, 1080}; mLayerFEState.geomLayerBounds = FloatRect{0.f, 0.f, 1920.f, 1080.f}; mOutputState.layerStackSpace.setContent(Rect{0, 0, 1920, 1080}); @@ -296,20 +298,20 @@ TEST_F(OutputLayerDisplayFrameTest, fullActiveTransparentRegionReturnsEmptyFrame } TEST_F(OutputLayerDisplayFrameTest, cropAffectsDisplayFrame) { - mLayerFEState.geomCrop = Rect{100, 200, 300, 500}; + mLayerFEState.geomCrop = FloatRect{100, 200, 300, 500}; const Rect expected{100, 200, 300, 500}; EXPECT_THAT(calculateOutputDisplayFrame(), expected); } TEST_F(OutputLayerDisplayFrameTest, cropAffectsDisplayFrameRotated) { - mLayerFEState.geomCrop = Rect{100, 200, 300, 500}; + mLayerFEState.geomCrop = FloatRect{100, 200, 300, 500}; mLayerFEState.geomLayerTransform.set(HAL_TRANSFORM_ROT_90, 1920, 1080); const Rect expected{1420, 100, 1720, 300}; EXPECT_THAT(calculateOutputDisplayFrame(), expected); } TEST_F(OutputLayerDisplayFrameTest, emptyGeomCropIsNotUsedToComputeFrame) { - mLayerFEState.geomCrop = Rect{}; + mLayerFEState.geomCrop = FloatRect{}; const Rect expected{0, 0, 1920, 1080}; EXPECT_THAT(calculateOutputDisplayFrame(), expected); } @@ -339,7 +341,7 @@ TEST_F(OutputLayerDisplayFrameTest, shadowExpandsDisplayFrame) { mLayerFEState.geomLayerBounds = FloatRect{100.f, 100.f, 200.f, 200.f}; Rect expected{mLayerFEState.geomLayerBounds}; - expected.inset(-kShadowRadius, -kShadowRadius, -kShadowRadius, -kShadowRadius); + expected.inset(-2 * kShadowRadius, -2 * kShadowRadius, -2 * kShadowRadius, -2 * kShadowRadius); EXPECT_THAT(calculateOutputDisplayFrame(), expected); } @@ -1331,6 +1333,71 @@ TEST_F(OutputLayerWriteStateToHWCTest, setCompositionTypeRefreshRateIndicator) { /*zIsOverridden*/ false, /*isPeekingThrough*/ false); } +TEST_F(OutputLayerWriteStateToHWCTest, setsPictureProfileWhenCommitted) { + if (!com_android_graphics_libgui_flags_apply_picture_profiles()) { + GTEST_SKIP() << "Feature flag disabled, skipping"; + } + mLayerFEState.compositionType = Composition::DEVICE; + mLayerFEState.pictureProfileHandle = PictureProfileHandle(1); + + expectGeometryCommonCalls(); + expectPerFrameCommonCalls(); + expectSetHdrMetadataAndBufferCalls(); + expectSetCompositionTypeCall(Composition::DEVICE); + + EXPECT_CALL(*mHwcLayer, setPictureProfileHandle(PictureProfileHandle(1))); + + mOutputLayer.commitPictureProfileToCompositionState(); + mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); +} + +TEST_F(OutputLayerWriteStateToHWCTest, doesNotSetPictureProfileWhenNotCommitted) { + if (!com_android_graphics_libgui_flags_apply_picture_profiles()) { + GTEST_SKIP() << "Feature flag disabled, skipping"; + } + mLayerFEState.compositionType = Composition::DEVICE; + mLayerFEState.pictureProfileHandle = PictureProfileHandle(1); + + expectGeometryCommonCalls(); + expectPerFrameCommonCalls(); + expectSetHdrMetadataAndBufferCalls(); + expectSetCompositionTypeCall(Composition::DEVICE); + + EXPECT_CALL(*mHwcLayer, setPictureProfileHandle(_)).Times(0); + + mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); +} + +TEST_F(OutputLayerWriteStateToHWCTest, doesNotSetPictureProfileWhenNotCommittedLater) { + if (!com_android_graphics_libgui_flags_apply_picture_profiles()) { + GTEST_SKIP() << "Feature flag disabled, skipping"; + } + mLayerFEState.compositionType = Composition::DEVICE; + mLayerFEState.pictureProfileHandle = PictureProfileHandle(1); + + expectGeometryCommonCalls(); + expectPerFrameCommonCalls(); + expectSetHdrMetadataAndBufferCalls(); + expectSetCompositionTypeCall(Composition::DEVICE); + + EXPECT_CALL(*mHwcLayer, setPictureProfileHandle(PictureProfileHandle(1))); + + mOutputLayer.commitPictureProfileToCompositionState(); + mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + + expectGeometryCommonCalls(); + expectPerFrameCommonCalls(); + expectSetHdrMetadataAndBufferCalls(kExpectedHwcSlot, nullptr, kFence); + + EXPECT_CALL(*mHwcLayer, setPictureProfileHandle(PictureProfileHandle(1))).Times(0); + // No committing of picture profile before writing the state + mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, + /*zIsOverridden*/ false, /*isPeekingThrough*/ false); +} + /* * OutputLayer::uncacheBuffers */ diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index c34168d025..442b603ca0 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -15,6 +15,7 @@ */ #include <android-base/stringprintf.h> +#include <com_android_graphics_libgui_flags.h> #include <com_android_graphics_surfaceflinger_flags.h> #include <compositionengine/LayerFECompositionState.h> #include <compositionengine/impl/Output.h> @@ -34,15 +35,17 @@ #include <ui/Rect.h> #include <ui/Region.h> -#include <cmath> #include <cstdint> #include <variant> +#include <com_android_graphics_surfaceflinger_flags.h> + #include <common/FlagManager.h> #include <common/test/FlagUtils.h> #include "CallOrderStateMachineHelper.h" -#include "MockHWC2.h" #include "RegionMatcher.h" +#include "mock/DisplayHardware/MockHWC2.h" +#include "mock/DisplayHardware/MockHWComposer.h" namespace android::compositionengine { namespace { @@ -143,6 +146,24 @@ struct OutputTest : public testing::Test { public: using impl::Output::injectOutputLayerForTest; virtual void injectOutputLayerForTest(std::unique_ptr<compositionengine::OutputLayer>) = 0; + + virtual ftl::Optional<DisplayId> getDisplayId() const override { return mId; } + + virtual bool hasPictureProcessing() const override { return mHasPictureProcessing; } + virtual int32_t getMaxLayerPictureProfiles() const override { + return mMaxLayerPictureProfiles; + } + + void setDisplayIdForTest(DisplayId value) { mId = value; } + + void setHasPictureProcessingForTest(bool value) { mHasPictureProcessing = value; } + + void setMaxLayerPictureProfilesForTest(int32_t value) { mMaxLayerPictureProfiles = value; } + + private: + ftl::Optional<DisplayId> mId; + bool mHasPictureProcessing; + int32_t mMaxLayerPictureProfiles; }; static std::shared_ptr<Output> createOutput( @@ -158,6 +179,7 @@ struct OutputTest : public testing::Test { mOutput->editState().displaySpace.setBounds( ui::Size(kDefaultDisplaySize.getWidth(), kDefaultDisplaySize.getHeight())); EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine)); + EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer)); } void injectOutputLayer(InjectedLayer& layer) { @@ -170,6 +192,7 @@ struct OutputTest : public testing::Test { static const Rect kDefaultDisplaySize; + StrictMock<::android::mock::HWComposer> mHwComposer; StrictMock<mock::CompositionEngine> mCompositionEngine; StrictMock<renderengine::mock::RenderEngine> mRenderEngine; mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>(); @@ -786,17 +809,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerContentForAllLayers InjectedLayer layer3; uint32_t z = 0; - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180)); + EXPECT_CALL(*layer1.outputLayer, + updateCompositionState(false, false, ui::Transform::ROT_180, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180)); + EXPECT_CALL(*layer2.outputLayer, + updateCompositionState(false, false, ui::Transform::ROT_180, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180)); + EXPECT_CALL(*layer3.outputLayer, + updateCompositionState(false, false, ui::Transform::ROT_180, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); @@ -823,17 +849,17 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerGeometryAndContentF InjectedLayer layer3; uint32_t z = 0; - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); @@ -859,17 +885,17 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, forcesClientCompositionForAllLa InjectedLayer layer3; uint32_t z = 0; - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); @@ -897,11 +923,11 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, peekThroughLayerChangesOrder) { InjectedLayer layer3; InSequence seq; - EXPECT_CALL(*layer0.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer0.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); uint32_t z = 0; EXPECT_CALL(*layer0.outputLayer, @@ -3263,57 +3289,9 @@ TEST_F(OutputPostFramebufferTest, ifEnabledMustFlipThenPresentThenSendPresentCom mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled); } -TEST_F(OutputPostFramebufferTest, releaseFencesAreSentToLayerFE) { - SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::ce_fence_promise, false); - ASSERT_FALSE(FlagManager::getInstance().ce_fence_promise()); - // Simulate getting release fences from each layer, and ensure they are passed to the - // front-end layer interface for each layer correctly. - - mOutput.mState.isEnabled = true; - - // Create three unique fence instances - sp<Fence> layer1Fence = sp<Fence>::make(); - sp<Fence> layer2Fence = sp<Fence>::make(); - sp<Fence> layer3Fence = sp<Fence>::make(); - - Output::FrameFences frameFences; - frameFences.layerFences.emplace(&mLayer1.hwc2Layer, layer1Fence); - frameFences.layerFences.emplace(&mLayer2.hwc2Layer, layer2Fence); - frameFences.layerFences.emplace(&mLayer3.hwc2Layer, layer3Fence); - - EXPECT_CALL(mOutput, presentFrame()).WillOnce(Return(frameFences)); - EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted()); - - // Compare the pointers values of each fence to make sure the correct ones - // are passed. This happens to work with the current implementation, but - // would not survive certain calls like Fence::merge() which would return a - // new instance. - EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed(_, _)) - .WillOnce([&layer1Fence](ftl::SharedFuture<FenceResult> futureFenceResult, - ui::LayerStack) { - EXPECT_EQ(FenceResult(layer1Fence), futureFenceResult.get()); - }); - EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed(_, _)) - .WillOnce([&layer2Fence](ftl::SharedFuture<FenceResult> futureFenceResult, - ui::LayerStack) { - EXPECT_EQ(FenceResult(layer2Fence), futureFenceResult.get()); - }); - EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed(_, _)) - .WillOnce([&layer3Fence](ftl::SharedFuture<FenceResult> futureFenceResult, - ui::LayerStack) { - EXPECT_EQ(FenceResult(layer3Fence), futureFenceResult.get()); - }); - - constexpr bool kFlushEvenWhenDisabled = false; - mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled); -} - TEST_F(OutputPostFramebufferTest, releaseFencesAreSetInLayerFE) { - SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::ce_fence_promise, true); - ASSERT_TRUE(FlagManager::getInstance().ce_fence_promise()); // Simulate getting release fences from each layer, and ensure they are passed to the // front-end layer interface for each layer correctly. - mOutput.mState.isEnabled = true; // Create three unique fence instances @@ -3350,37 +3328,7 @@ TEST_F(OutputPostFramebufferTest, releaseFencesAreSetInLayerFE) { mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled); } -TEST_F(OutputPostFramebufferTest, releaseFencesIncludeClientTargetAcquireFence) { - SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::ce_fence_promise, false); - ASSERT_FALSE(FlagManager::getInstance().ce_fence_promise()); - - mOutput.mState.isEnabled = true; - mOutput.mState.usesClientComposition = true; - - Output::FrameFences frameFences; - frameFences.clientTargetAcquireFence = sp<Fence>::make(); - frameFences.layerFences.emplace(&mLayer1.hwc2Layer, sp<Fence>::make()); - frameFences.layerFences.emplace(&mLayer2.hwc2Layer, sp<Fence>::make()); - frameFences.layerFences.emplace(&mLayer3.hwc2Layer, sp<Fence>::make()); - - EXPECT_CALL(mOutput, presentFrame()).WillOnce(Return(frameFences)); - EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted()); - - // Fence::merge is called, and since none of the fences are actually valid, - // Fence::NO_FENCE is returned and passed to each onLayerDisplayed() call. - // This is the best we can do without creating a real kernel fence object. - EXPECT_CALL(*mLayer1.layerFE, onLayerDisplayed).WillOnce(Return()); - EXPECT_CALL(*mLayer2.layerFE, onLayerDisplayed).WillOnce(Return()); - EXPECT_CALL(*mLayer3.layerFE, onLayerDisplayed).WillOnce(Return()); - - constexpr bool kFlushEvenWhenDisabled = false; - mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled); -} - TEST_F(OutputPostFramebufferTest, setReleaseFencesIncludeClientTargetAcquireFence) { - SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::ce_fence_promise, true); - ASSERT_TRUE(FlagManager::getInstance().ce_fence_promise()); - mOutput.mState.isEnabled = true; mOutput.mState.usesClientComposition = true; @@ -3403,62 +3351,7 @@ TEST_F(OutputPostFramebufferTest, setReleaseFencesIncludeClientTargetAcquireFenc mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled); } -TEST_F(OutputPostFramebufferTest, releasedLayersSentPresentFence) { - SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::ce_fence_promise, false); - ASSERT_FALSE(FlagManager::getInstance().ce_fence_promise()); - - mOutput.mState.isEnabled = true; - mOutput.mState.usesClientComposition = true; - - // This should happen even if there are no (current) output layers. - EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u)); - - // Load up the released layers with some mock instances - sp<StrictMock<mock::LayerFE>> releasedLayer1 = sp<StrictMock<mock::LayerFE>>::make(); - sp<StrictMock<mock::LayerFE>> releasedLayer2 = sp<StrictMock<mock::LayerFE>>::make(); - sp<StrictMock<mock::LayerFE>> releasedLayer3 = sp<StrictMock<mock::LayerFE>>::make(); - Output::ReleasedLayers layers; - layers.push_back(releasedLayer1); - layers.push_back(releasedLayer2); - layers.push_back(releasedLayer3); - mOutput.setReleasedLayers(std::move(layers)); - - // Set up a fake present fence - sp<Fence> presentFence = sp<Fence>::make(); - Output::FrameFences frameFences; - frameFences.presentFence = presentFence; - - EXPECT_CALL(mOutput, presentFrame()).WillOnce(Return(frameFences)); - EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted()); - - // Each released layer should be given the presentFence. - EXPECT_CALL(*releasedLayer1, onLayerDisplayed(_, _)) - .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult, - ui::LayerStack) { - EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get()); - }); - EXPECT_CALL(*releasedLayer2, onLayerDisplayed(_, _)) - .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult, - ui::LayerStack) { - EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get()); - }); - EXPECT_CALL(*releasedLayer3, onLayerDisplayed(_, _)) - .WillOnce([&presentFence](ftl::SharedFuture<FenceResult> futureFenceResult, - ui::LayerStack) { - EXPECT_EQ(FenceResult(presentFence), futureFenceResult.get()); - }); - - constexpr bool kFlushEvenWhenDisabled = false; - mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled); - - // After the call the list of released layers should have been cleared. - EXPECT_TRUE(mOutput.getReleasedLayersForTest().empty()); -} - TEST_F(OutputPostFramebufferTest, setReleasedLayersSentPresentFence) { - SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::ce_fence_promise, true); - ASSERT_TRUE(FlagManager::getInstance().ce_fence_promise()); - mOutput.mState.isEnabled = true; mOutput.mState.usesClientComposition = true; @@ -5066,12 +4959,12 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, noBackgroundBlurWhenOpaque) { uint32_t z = 0; // Layer requesting blur, or below, should request client composition, unless opaque. - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); @@ -5100,17 +4993,17 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests) uint32_t z = 0; // Layer requesting blur, or below, should request client composition. - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); @@ -5140,17 +5033,17 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBlurRegionRequests) { uint32_t z = 0; // Layer requesting blur, or below, should request client composition. - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); @@ -5174,6 +5067,133 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBlurRegionRequests) { mOutput->writeCompositionState(args); } +TEST_F(OutputUpdateAndWriteCompositionStateTest, assignsDisplayProfileBasedOnLayerPriority) { + if (!com_android_graphics_libgui_flags_apply_picture_profiles()) { + GTEST_SKIP() << "Feature flag disabled, skipping"; + } + + mOutput->setDisplayIdForTest(PhysicalDisplayId::fromPort(1)); + // Has only one display-global picture processing pipeline + mOutput->setHasPictureProcessingForTest(true); + mOutput->setMaxLayerPictureProfilesForTest(0); + + InjectedLayer layer1; + injectOutputLayer(layer1); + PictureProfileHandle profileForLayer1(1); + EXPECT_CALL(*layer1.outputLayer, getPictureProfilePriority()).WillRepeatedly(Return(3)); + EXPECT_CALL(*layer1.outputLayer, getPictureProfileHandle()) + .WillRepeatedly(ReturnRef(profileForLayer1)); + + InjectedLayer layer2; + injectOutputLayer(layer2); + PictureProfileHandle profileForLayer2(2); + EXPECT_CALL(*layer2.outputLayer, getPictureProfilePriority()).WillRepeatedly(Return(1)); + EXPECT_CALL(*layer2.outputLayer, getPictureProfileHandle()) + .WillRepeatedly(ReturnRef(profileForLayer2)); + + InjectedLayer layer3; + injectOutputLayer(layer3); + PictureProfileHandle profileForLayer3(3); + EXPECT_CALL(*layer3.outputLayer, getPictureProfilePriority()).WillRepeatedly(Return(2)); + EXPECT_CALL(*layer3.outputLayer, getPictureProfileHandle()) + .WillRepeatedly(ReturnRef(profileForLayer3)); + + // Because StrictMock + EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(_, _, _, _)); + EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(_, _, _, _, _)); + EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(_, _, _, _)); + EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(_, _, _, _, _)); + EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(_, _, _, _)); + EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(_, _, _, _, _)); + + // No layer picture profiles should be committed + EXPECT_CALL(*layer1.outputLayer, commitPictureProfileToCompositionState).Times(0); + EXPECT_CALL(*layer2.outputLayer, commitPictureProfileToCompositionState).Times(0); + EXPECT_CALL(*layer3.outputLayer, commitPictureProfileToCompositionState).Times(0); + + // Sets display picture profile to the highest priority layer's profile + EXPECT_CALL(mHwComposer, setDisplayPictureProfileHandle(_, Eq(profileForLayer2))); + + // Marks only the highest priority layer as committed + EXPECT_CALL(*layer1.layerFE, onPictureProfileCommitted).Times(0); + EXPECT_CALL(*layer2.layerFE, onPictureProfileCommitted); + EXPECT_CALL(*layer3.layerFE, onPictureProfileCommitted).Times(0); + + mOutput->editState().isEnabled = true; + CompositionRefreshArgs args; + args.updatingGeometryThisFrame = false; + args.devOptForceClientComposition = false; + mOutput->updateCompositionState(args); + mOutput->planComposition(); + mOutput->writeCompositionState(args); +} + +TEST_F(OutputUpdateAndWriteCompositionStateTest, assignsLayerProfileBasedOnLayerPriority) { + if (!com_android_graphics_libgui_flags_apply_picture_profiles()) { + GTEST_SKIP() << "Feature flag disabled, skipping"; + } + mOutput->setDisplayIdForTest(PhysicalDisplayId::fromPort(1)); + // Has 2 layer-specific picture processing pipelines + mOutput->setHasPictureProcessingForTest(true); + mOutput->setMaxLayerPictureProfilesForTest(2); + + InjectedLayer layer1; + injectOutputLayer(layer1); + PictureProfileHandle profileForLayer1(1); + EXPECT_CALL(*layer1.outputLayer, getPictureProfilePriority()).WillRepeatedly(Return(3)); + EXPECT_CALL(*layer1.outputLayer, getPictureProfileHandle()) + .WillRepeatedly(ReturnRef(profileForLayer1)); + + InjectedLayer layer2; + injectOutputLayer(layer2); + PictureProfileHandle profileForLayer2(2); + EXPECT_CALL(*layer2.outputLayer, getPictureProfilePriority()).WillRepeatedly(Return(1)); + EXPECT_CALL(*layer2.outputLayer, getPictureProfileHandle()) + .WillRepeatedly(ReturnRef(profileForLayer2)); + + InjectedLayer layer3; + injectOutputLayer(layer3); + PictureProfileHandle profileForLayer3(3); + EXPECT_CALL(*layer3.outputLayer, getPictureProfilePriority()).WillRepeatedly(Return(2)); + EXPECT_CALL(*layer3.outputLayer, getPictureProfileHandle()) + .WillRepeatedly(ReturnRef(profileForLayer3)); + + // Because StrictMock + EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(_, _, _, _)); + EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(_, _, _, _, _)); + EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(_, _, _, _)); + EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(_, _, _, _, _)); + EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(_, _, _, _)); + EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(_, _, _, _, _)); + + // The two highest priority layers should have their picture profiles committed + EXPECT_CALL(*layer1.outputLayer, commitPictureProfileToCompositionState).Times(0); + EXPECT_CALL(*layer2.outputLayer, commitPictureProfileToCompositionState); + EXPECT_CALL(*layer3.outputLayer, commitPictureProfileToCompositionState); + + // Marks only the highest priority layers as committed + EXPECT_CALL(*layer1.layerFE, onPictureProfileCommitted).Times(0); + EXPECT_CALL(*layer2.layerFE, onPictureProfileCommitted); + EXPECT_CALL(*layer3.layerFE, onPictureProfileCommitted); + + // No display picture profile is sent + EXPECT_CALL(mHwComposer, setDisplayPictureProfileHandle).Times(0); + + mOutput->editState().isEnabled = true; + CompositionRefreshArgs args; + args.updatingGeometryThisFrame = false; + args.devOptForceClientComposition = false; + mOutput->updateCompositionState(args); + mOutput->planComposition(); + mOutput->writeCompositionState(args); +} + TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenRequests) { // In split-screen landscape mode, the screen is rotated 90 degrees, with // one layer on the left covering the left side of the output, and one layer diff --git a/services/surfaceflinger/Display/DisplayModeController.cpp b/services/surfaceflinger/Display/DisplayModeController.cpp index f8b6c6e5d5..a086aee847 100644 --- a/services/surfaceflinger/Display/DisplayModeController.cpp +++ b/services/surfaceflinger/Display/DisplayModeController.cpp @@ -28,6 +28,7 @@ #include <ftl/concat.h> #include <ftl/expected.h> #include <log/log.h> +#include <utils/Errors.h> namespace android::display { @@ -177,12 +178,13 @@ void DisplayModeController::clearDesiredMode(PhysicalDisplayId displayId) { } } -bool DisplayModeController::initiateModeChange(PhysicalDisplayId displayId, - DisplayModeRequest&& desiredMode, - const hal::VsyncPeriodChangeConstraints& constraints, - hal::VsyncPeriodChangeTimeline& outTimeline) { +auto DisplayModeController::initiateModeChange( + PhysicalDisplayId displayId, DisplayModeRequest&& desiredMode, + const hal::VsyncPeriodChangeConstraints& constraints, + hal::VsyncPeriodChangeTimeline& outTimeline) -> ModeChangeResult { std::lock_guard lock(mDisplayLock); - const auto& displayPtr = FTL_EXPECT(mDisplays.get(displayId).ok_or(false)).get(); + const auto& displayPtr = + FTL_EXPECT(mDisplays.get(displayId).ok_or(ModeChangeResult::Aborted)).get(); // TODO: b/255635711 - Flow the DisplayModeRequest through the desired/pending/active states. // For now, `desiredMode` and `desiredModeOpt` are one and the same, but the latter is not @@ -201,13 +203,17 @@ bool DisplayModeController::initiateModeChange(PhysicalDisplayId displayId, const auto& mode = *displayPtr->pendingModeOpt->mode.modePtr; - if (mComposerPtr->setActiveModeWithConstraints(displayId, mode.getHwcId(), constraints, - &outTimeline) != OK) { - return false; + const auto error = mComposerPtr->setActiveModeWithConstraints(displayId, mode.getHwcId(), + constraints, &outTimeline); + switch (error) { + case FAILED_TRANSACTION: + return ModeChangeResult::Rejected; + case OK: + SFTRACE_INT(displayPtr->pendingModeFpsTrace.c_str(), mode.getVsyncRate().getIntValue()); + return ModeChangeResult::Changed; + default: + return ModeChangeResult::Aborted; } - - SFTRACE_INT(displayPtr->pendingModeFpsTrace.c_str(), mode.getVsyncRate().getIntValue()); - return true; } void DisplayModeController::finalizeModeChange(PhysicalDisplayId displayId, DisplayModeId modeId, diff --git a/services/surfaceflinger/Display/DisplayModeController.h b/services/surfaceflinger/Display/DisplayModeController.h index 9ec603d5f6..af3e909bcf 100644 --- a/services/surfaceflinger/Display/DisplayModeController.h +++ b/services/surfaceflinger/Display/DisplayModeController.h @@ -70,6 +70,7 @@ public: RefreshRateSelectorPtr selectorPtrFor(PhysicalDisplayId) const EXCLUDES(mDisplayLock); enum class DesiredModeAction { None, InitiateDisplayModeSwitch, InitiateRenderRateSwitch }; + enum class ModeChangeResult { Changed, Rejected, Aborted }; DesiredModeAction setDesiredMode(PhysicalDisplayId, DisplayModeRequest&&) EXCLUDES(mDisplayLock); @@ -86,9 +87,9 @@ public: scheduler::FrameRateMode getActiveMode(PhysicalDisplayId) const EXCLUDES(mDisplayLock); - bool initiateModeChange(PhysicalDisplayId, DisplayModeRequest&&, - const hal::VsyncPeriodChangeConstraints&, - hal::VsyncPeriodChangeTimeline& outTimeline) + ModeChangeResult initiateModeChange(PhysicalDisplayId, DisplayModeRequest&&, + const hal::VsyncPeriodChangeConstraints&, + hal::VsyncPeriodChangeTimeline& outTimeline) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock); void finalizeModeChange(PhysicalDisplayId, DisplayModeId, Fps vsyncRate, Fps renderFps) diff --git a/services/surfaceflinger/Display/VirtualDisplaySnapshot.h b/services/surfaceflinger/Display/VirtualDisplaySnapshot.h new file mode 100644 index 0000000000..c68020ce51 --- /dev/null +++ b/services/surfaceflinger/Display/VirtualDisplaySnapshot.h @@ -0,0 +1,52 @@ +/* + * Copyright 2024 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 <optional> +#include <string> + +#include <ui/DisplayId.h> + +#include "Utils/Dumper.h" + +namespace android::display { + +// Immutable state of a virtual display, captured on creation. +class VirtualDisplaySnapshot { +public: + VirtualDisplaySnapshot(GpuVirtualDisplayId gpuId, std::string uniqueId) + : mIsGpu(true), mUniqueId(std::move(uniqueId)), mVirtualId(gpuId) {} + VirtualDisplaySnapshot(HalVirtualDisplayId halId, std::string uniqueId) + : mIsGpu(false), mUniqueId(std::move(uniqueId)), mVirtualId(halId) {} + + VirtualDisplayId displayId() const { return mVirtualId; } + bool isGpu() const { return mIsGpu; } + + void dump(utils::Dumper& dumper) const { + using namespace std::string_view_literals; + + dumper.dump("isGpu"sv, mIsGpu ? "true"sv : "false"sv); + dumper.dump("uniqueId"sv, mUniqueId); + } + +private: + const bool mIsGpu; + const std::string mUniqueId; + const VirtualDisplayId mVirtualId; +}; + +} // namespace android::display diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 402a3d2e2f..c743ea2ff4 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -201,6 +201,10 @@ bool DisplayDevice::isPoweredOn() const { return mPowerMode != hal::PowerMode::OFF; } +bool DisplayDevice::isRefreshable() const { + return mPowerMode == hal::PowerMode::DOZE || mPowerMode == hal::PowerMode::ON; +} + ui::Dataspace DisplayDevice::getCompositionDataSpace() const { return mCompositionDisplay->getState().dataspace; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 3e3f558cee..af2b48fc07 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -42,7 +42,6 @@ #include "DisplayHardware/DisplayMode.h" #include "DisplayHardware/Hal.h" -#include "DisplayHardware/PowerAdvisor.h" #include "FrontEnd/DisplayInfo.h" #include "Scheduler/RefreshRateSelector.h" #include "ThreadContext.h" @@ -173,6 +172,7 @@ public: hardware::graphics::composer::hal::PowerMode getPowerMode() const; void setPowerMode(hardware::graphics::composer::hal::PowerMode); bool isPoweredOn() const; + bool isRefreshable() const; void tracePowerMode(); // Enables layer caching on this DisplayDevice @@ -285,6 +285,8 @@ struct DisplayDeviceState { bool isProtected = false; // Refer to DisplayDevice::mRequestedRefreshRate, for virtual display only Fps requestedRefreshRate; + int32_t maxLayerPictureProfiles = 0; + bool hasPictureProcessing = false; private: static std::atomic<int32_t> sNextSequenceId; diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index 66237b9d8a..25f6513ffa 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -37,19 +37,14 @@ namespace android { -using hardware::hidl_handle; -using hardware::hidl_vec; -using hardware::Return; - using aidl::android::hardware::graphics::composer3::BnComposerCallback; using aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness; -using aidl::android::hardware::graphics::composer3::Lut; +using aidl::android::hardware::graphics::composer3::CommandResultPayload; +using aidl::android::hardware::graphics::composer3::Luts; using aidl::android::hardware::graphics::composer3::PowerMode; using aidl::android::hardware::graphics::composer3::VirtualDisplay; -using aidl::android::hardware::graphics::composer3::CommandResultPayload; - using AidlColorMode = aidl::android::hardware::graphics::composer3::ColorMode; using AidlContentType = aidl::android::hardware::graphics::composer3::ContentType; using AidlDisplayIdentification = @@ -525,11 +520,15 @@ Error AidlComposer::getColorModes(Display display, std::vector<ColorMode>* outMo Error AidlComposer::getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" const auto status = mAidlComposerClient->getDisplayAttribute(translate<int64_t>(display), translate<int32_t>(config), static_cast<AidlDisplayAttribute>(attribute), outValue); +#pragma clang diagnostic pop + if (!status.isOk()) { ALOGE("getDisplayAttribute failed %s", status.getDescription().c_str()); return static_cast<Error>(status.getServiceSpecificError()); @@ -539,8 +538,13 @@ Error AidlComposer::getDisplayAttribute(Display display, Config config, Error AidlComposer::getDisplayConfigs(Display display, std::vector<Config>* outConfigs) { std::vector<int32_t> configs; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" const auto status = mAidlComposerClient->getDisplayConfigs(translate<int64_t>(display), &configs); +#pragma clang diagnostic pop + if (!status.isOk()) { ALOGE("getDisplayConfigs failed %s", status.getDescription().c_str()); return static_cast<Error>(status.getServiceSpecificError()); @@ -1385,7 +1389,7 @@ V2_4::Error AidlComposer::getDisplayVsyncPeriod(Display display, VsyncPeriodNano return V2_4::Error::NONE; } -V2_4::Error AidlComposer::setActiveConfigWithConstraints( +Error AidlComposer::setActiveConfigWithConstraints( Display display, Config config, const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, VsyncPeriodChangeTimeline* outTimeline) { @@ -1399,10 +1403,10 @@ V2_4::Error AidlComposer::setActiveConfigWithConstraints( &timeline); if (!status.isOk()) { ALOGE("setActiveConfigWithConstraints failed %s", status.getDescription().c_str()); - return static_cast<V2_4::Error>(status.getServiceSpecificError()); + return static_cast<Error>(status.getServiceSpecificError()); } *outTimeline = translate<VsyncPeriodChangeTimeline>(timeline); - return V2_4::Error::NONE; + return Error::NONE; } V2_4::Error AidlComposer::setAutoLowLatencyMode(Display display, bool on) { @@ -1547,7 +1551,8 @@ Error AidlComposer::getClientTargetProperty( return error; } -Error AidlComposer::getRequestedLuts(Display display, std::vector<DisplayLuts::LayerLut>* outLuts) { +Error AidlComposer::getRequestedLuts(Display display, std::vector<Layer>* outLayers, + std::vector<DisplayLuts::LayerLut>* outLuts) { Error error = Error::NONE; mMutex.lock_shared(); if (auto reader = getReader(display)) { @@ -1556,10 +1561,15 @@ Error AidlComposer::getRequestedLuts(Display display, std::vector<DisplayLuts::L error = Error::BAD_DISPLAY; } mMutex.unlock_shared(); + + outLayers->reserve(outLuts->size()); + for (const auto& layerLut : *outLuts) { + outLayers->emplace_back(translate<Layer>(layerLut.layer)); + } return error; } -Error AidlComposer::setLayerLuts(Display display, Layer layer, std::vector<Lut>& luts) { +Error AidlComposer::setLayerLuts(Display display, Layer layer, Luts& luts) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { @@ -1633,6 +1643,41 @@ Error AidlComposer::getPhysicalDisplayOrientation(Display displayId, return Error::NONE; } +Error AidlComposer::getMaxLayerPictureProfiles(Display display, int32_t* outMaxProfiles) { + const auto status = mAidlComposerClient->getMaxLayerPictureProfiles(translate<int64_t>(display), + outMaxProfiles); + if (!status.isOk()) { + ALOGE("getMaxLayerPictureProfiles failed %s", status.getDescription().c_str()); + return static_cast<Error>(status.getServiceSpecificError()); + } + return Error::NONE; +} + +Error AidlComposer::setDisplayPictureProfileId(Display display, PictureProfileId id) { + Error error = Error::NONE; + mMutex.lock_shared(); + if (auto writer = getWriter(display)) { + writer->get().setDisplayPictureProfileId(translate<int64_t>(display), id); + } else { + error = Error::BAD_DISPLAY; + } + mMutex.unlock_shared(); + return error; +} + +Error AidlComposer::setLayerPictureProfileId(Display display, Layer layer, PictureProfileId id) { + Error error = Error::NONE; + mMutex.lock_shared(); + if (auto writer = getWriter(display)) { + writer->get().setLayerPictureProfileId(translate<int64_t>(display), + translate<int64_t>(layer), id); + } else { + error = Error::BAD_DISPLAY; + } + mMutex.unlock_shared(); + return error; +} + ftl::Optional<std::reference_wrapper<ComposerClientWriter>> AidlComposer::getWriter(Display display) REQUIRES_SHARED(mMutex) { return mWriters.get(display); diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h index 246223a668..6b5ebc59a3 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -27,11 +27,6 @@ #include <utility> #include <vector> -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#pragma clang diagnostic ignored "-Wextra" - #include <android/hardware/graphics/composer/2.4/IComposer.h> #include <android/hardware/graphics/composer/2.4/IComposerClient.h> @@ -43,9 +38,6 @@ #include <aidl/android/hardware/graphics/composer3/Composition.h> #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h> -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" - namespace android::Hwc2 { using aidl::android::hardware::graphics::common::DisplayDecorationSupport; @@ -53,6 +45,7 @@ using aidl::android::hardware::graphics::common::HdrConversionCapability; using aidl::android::hardware::graphics::common::HdrConversionStrategy; using aidl::android::hardware::graphics::composer3::ComposerClientReader; using aidl::android::hardware::graphics::composer3::ComposerClientWriter; +using aidl::android::hardware::graphics::composer3::Luts; using aidl::android::hardware::graphics::composer3::OverlayProperties; class AidlIComposerCallbackWrapper; @@ -205,7 +198,7 @@ public: V2_4::Error getDisplayConnectionType(Display display, IComposerClient::DisplayConnectionType* outType) override; V2_4::Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) override; - V2_4::Error setActiveConfigWithConstraints( + Error setActiveConfigWithConstraints( Display display, Config config, const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, VsyncPeriodChangeTimeline* outTimeline) override; @@ -245,12 +238,13 @@ public: Error notifyExpectedPresent(Display, nsecs_t expectedPresentTime, int32_t frameIntervalNs) override; Error getRequestedLuts( - Display display, + Display display, std::vector<Layer>* outLayers, std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>* outLuts) override; - Error setLayerLuts( - Display display, Layer layer, - std::vector<aidl::android::hardware::graphics::composer3::Lut>& luts) override; + Error setLayerLuts(Display display, Layer layer, Luts& luts) override; + Error getMaxLayerPictureProfiles(Display, int32_t* outMaxProfiles) override; + Error setDisplayPictureProfileId(Display, PictureProfileId id) override; + Error setLayerPictureProfileId(Display, Layer, PictureProfileId id) override; private: // Many public functions above simply write a command into the command diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 7db9a94e54..ff292fa350 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -29,11 +29,15 @@ #include <math/mat4.h> #include <ui/DisplayedFrameStats.h> #include <ui/GraphicBuffer.h> +#include <ui/PictureProfileHandle.h> #include <utils/StrongPointer.h> +#include "DisplayHardware/Hal.h" + #include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h> #include <aidl/android/hardware/graphics/common/HdrConversionCapability.h> #include <aidl/android/hardware/graphics/common/HdrConversionStrategy.h> +#include <aidl/android/hardware/graphics/common/Transform.h> #include <aidl/android/hardware/graphics/composer3/Capability.h> #include <aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.h> #include <aidl/android/hardware/graphics/composer3/Color.h> @@ -42,10 +46,8 @@ #include <aidl/android/hardware/graphics/composer3/DisplayConfiguration.h> #include <aidl/android/hardware/graphics/composer3/DisplayLuts.h> #include <aidl/android/hardware/graphics/composer3/IComposerCallback.h> -#include <aidl/android/hardware/graphics/composer3/Lut.h> #include <aidl/android/hardware/graphics/composer3/OverlayProperties.h> -#include <aidl/android/hardware/graphics/common/Transform.h> #include <optional> // TODO(b/129481165): remove the #pragma below and fix conversion issues @@ -73,9 +75,9 @@ using types::V1_2::ColorMode; using types::V1_2::Dataspace; using types::V1_2::PixelFormat; +using hardware::graphics::composer::hal::Error; using V2_1::Config; using V2_1::Display; -using V2_1::Error; using V2_1::Layer; using V2_4::CommandReaderBase; using V2_4::CommandWriterBase; @@ -261,7 +263,7 @@ public: Display display, IComposerClient::DisplayConnectionType* outType) = 0; virtual V2_4::Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) = 0; - virtual V2_4::Error setActiveConfigWithConstraints( + virtual Error setActiveConfigWithConstraints( Display display, Config config, const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, VsyncPeriodChangeTimeline* outTimeline) = 0; @@ -305,9 +307,12 @@ public: virtual Error setRefreshRateChangedCallbackDebugEnabled(Display, bool) = 0; virtual Error notifyExpectedPresent(Display, nsecs_t expectedPresentTime, int32_t frameIntervalNs) = 0; - virtual Error getRequestedLuts(Display display, + virtual Error getRequestedLuts(Display display, std::vector<Layer>* outLayers, std::vector<V3_0::DisplayLuts::LayerLut>* outLuts) = 0; - virtual Error setLayerLuts(Display display, Layer layer, std::vector<V3_0::Lut>& luts) = 0; + virtual Error setLayerLuts(Display display, Layer layer, V3_0::Luts& luts) = 0; + virtual Error getMaxLayerPictureProfiles(Display display, int32_t* outMaxProfiles) = 0; + virtual Error setDisplayPictureProfileId(Display display, PictureProfileId id) = 0; + virtual Error setLayerPictureProfileId(Display display, Layer layer, PictureProfileId id) = 0; }; } // namespace Hwc2 diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h index 224f50e78e..e90b5b70cb 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayMode.h +++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h @@ -31,10 +31,11 @@ #include <common/FlagManager.h> #include <scheduler/Fps.h> -#include "DisplayHardware/Hal.h" +#include "Hal.h" namespace android { +using aidl::android::hardware::graphics::composer3::OutputType; namespace hal = android::hardware::graphics::composer::hal; class DisplayMode; @@ -114,6 +115,11 @@ public: return *this; } + Builder& setHdrOutputType(OutputType type) { + mDisplayMode->mHdrOutputType = type; + return *this; + } + private: float getDefaultDensity() { // Default density is based on TVs: 1080p displays get XHIGH density, lower- @@ -166,6 +172,8 @@ public: // without visual interruptions such as a black screen. int32_t getGroup() const { return mGroup; } + OutputType getHdrOutputType() const { return mHdrOutputType; } + private: explicit DisplayMode(hal::HWConfigId id) : mHwcId(id) {} @@ -179,21 +187,25 @@ private: Dpi mDpi; int32_t mGroup = -1; std::optional<hal::VrrConfig> mVrrConfig; + OutputType mHdrOutputType; }; inline bool equalsExceptDisplayModeId(const DisplayMode& lhs, const DisplayMode& rhs) { return lhs.getHwcId() == rhs.getHwcId() && lhs.getResolution() == rhs.getResolution() && lhs.getVsyncRate().getPeriodNsecs() == rhs.getVsyncRate().getPeriodNsecs() && - lhs.getDpi() == rhs.getDpi() && lhs.getGroup() == rhs.getGroup(); + lhs.getDpi() == rhs.getDpi() && lhs.getGroup() == rhs.getGroup() && + lhs.getVrrConfig() == rhs.getVrrConfig() && + lhs.getHdrOutputType() == rhs.getHdrOutputType(); } inline std::string to_string(const DisplayMode& mode) { return base::StringPrintf("{id=%d, hwcId=%d, resolution=%dx%d, vsyncRate=%s, " - "dpi=%.2fx%.2f, group=%d, vrrConfig=%s}", + "dpi=%.2fx%.2f, group=%d, vrrConfig=%s, supportedHdrTypes=%s}", ftl::to_underlying(mode.getId()), mode.getHwcId(), mode.getWidth(), mode.getHeight(), to_string(mode.getVsyncRate()).c_str(), mode.getDpi().x, mode.getDpi().y, mode.getGroup(), - to_string(mode.getVrrConfig()).c_str()); + to_string(mode.getVrrConfig()).c_str(), + toString(mode.getHdrOutputType()).c_str()); } template <typename... DisplayModePtrs> diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index f1fa9389eb..081f4aa269 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -31,6 +31,9 @@ #include <ui/Fence.h> #include <ui/FloatRect.h> #include <ui/GraphicBuffer.h> +#include <ui/PictureProfileHandle.h> + +#include "DisplayHardware/Hal.h" #include <algorithm> #include <cinttypes> @@ -42,7 +45,8 @@ using aidl::android::hardware::graphics::composer3::Composition; using AidlCapability = aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::DisplayCapability; using aidl::android::hardware::graphics::composer3::DisplayLuts; -using aidl::android::hardware::graphics::composer3::Lut; +using aidl::android::hardware::graphics::composer3::LutProperties; +using aidl::android::hardware::graphics::composer3::Luts; using aidl::android::hardware::graphics::composer3::OverlayProperties; namespace android { @@ -52,6 +56,7 @@ using android::FloatRect; using android::GraphicBuffer; using android::HdrCapabilities; using android::HdrMetadata; +using android::PictureProfileHandle; using android::Rect; using android::Region; using android::sp; @@ -609,17 +614,37 @@ Error Display::getClientTargetProperty( return static_cast<Error>(error); } -Error Display::getRequestedLuts(std::vector<DisplayLuts::LayerLut>* outLayerLuts) { - std::vector<DisplayLuts::LayerLut> tmpLayerLuts; - const auto error = mComposer.getRequestedLuts(mId, &tmpLayerLuts); - for (DisplayLuts::LayerLut& layerLut : tmpLayerLuts) { - if (layerLut.lut.pfd.get() >= 0) { - outLayerLuts->push_back({layerLut.layer, - Lut{ndk::ScopedFileDescriptor(layerLut.lut.pfd.release()), - layerLut.lut.lutProperties}}); +Error Display::getRequestedLuts(LayerLuts* outLuts, + LutFileDescriptorMapper& lutFileDescriptorMapper) { + std::vector<Hwc2::Layer> layerIds; + std::vector<DisplayLuts::LayerLut> tmpLuts; + const auto error = static_cast<Error>(mComposer.getRequestedLuts(mId, &layerIds, &tmpLuts)); + if (error != Error::NONE) { + return error; + } + + uint32_t numElements = layerIds.size(); + outLuts->clear(); + for (uint32_t i = 0; i < numElements; ++i) { + auto layer = getLayerById(layerIds[i]); + if (layer) { + auto& layerLut = tmpLuts[i]; + if (layerLut.luts.pfd.get() > 0 && layerLut.luts.offsets.has_value()) { + const auto& offsets = layerLut.luts.offsets.value(); + std::vector<std::pair<int32_t, LutProperties>> lutOffsetsAndProperties; + lutOffsetsAndProperties.reserve(offsets.size()); + std::transform(offsets.begin(), offsets.end(), layerLut.luts.lutProperties.begin(), + std::back_inserter(lutOffsetsAndProperties), + [](int32_t i, LutProperties j) { return std::make_pair(i, j); }); + outLuts->emplace_or_replace(layer.get(), lutOffsetsAndProperties); + lutFileDescriptorMapper.emplace_or_replace(layer.get(), + ndk::ScopedFileDescriptor( + layerLut.luts.pfd.release())); + } } } - return static_cast<Error>(error); + + return Error::NONE; } Error Display::getDisplayDecorationSupport( @@ -634,6 +659,16 @@ Error Display::setIdleTimerEnabled(std::chrono::milliseconds timeout) { return static_cast<Error>(error); } +Error Display::getMaxLayerPictureProfiles(int32_t* outMaxProfiles) { + const auto error = mComposer.getMaxLayerPictureProfiles(mId, outMaxProfiles); + return static_cast<Error>(error); +} + +Error Display::setPictureProfileHandle(const PictureProfileHandle& handle) { + const auto error = mComposer.setDisplayPictureProfileId(mId, handle.getId()); + return static_cast<Error>(error); +} + // For use by Device void Display::setConnected(bool connected) { @@ -1057,7 +1092,7 @@ Error Layer::setBlockingRegion(const Region& region) { return static_cast<Error>(intError); } -Error Layer::setLuts(std::vector<Lut>& luts) { +Error Layer::setLuts(aidl::android::hardware::graphics::composer3::Luts& luts) { if (CC_UNLIKELY(!mDisplay)) { return Error::BAD_DISPLAY; } @@ -1065,6 +1100,15 @@ Error Layer::setLuts(std::vector<Lut>& luts) { return static_cast<Error>(intError); } +Error Layer::setPictureProfileHandle(const PictureProfileHandle& handle) { + if (CC_UNLIKELY(!mDisplay)) { + return Error::BAD_DISPLAY; + } + const auto intError = + mComposer.setLayerPictureProfileId(mDisplay->getId(), mId, handle.getId()); + return static_cast<Error>(intError); +} + } // namespace impl } // namespace HWC2 } // namespace android diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 8e2aeaf234..6740d8a832 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -20,9 +20,11 @@ #include <android-base/thread_annotations.h> #include <ftl/expected.h> #include <ftl/future.h> +#include <ftl/small_map.h> #include <gui/HdrMetadata.h> #include <math/mat4.h> #include <ui/HdrCapabilities.h> +#include <ui/PictureProfileHandle.h> #include <ui/Region.h> #include <ui/StaticDisplayInfo.h> #include <utils/Log.h> @@ -45,7 +47,7 @@ #include <aidl/android/hardware/graphics/composer3/Color.h> #include <aidl/android/hardware/graphics/composer3/Composition.h> #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h> -#include <aidl/android/hardware/graphics/composer3/Lut.h> +#include <aidl/android/hardware/graphics/composer3/Luts.h> #include <aidl/android/hardware/graphics/composer3/OverlayProperties.h> #include <aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.h> @@ -107,6 +109,14 @@ public: virtual void onLayerDestroyed(hal::HWLayerId layerId) = 0; virtual std::optional<ui::Size> getPhysicalSizeInMm() const = 0; + static const int kLutFileDescriptorMapperSize = 20; + using LutOffsetAndProperties = std::vector< + std::pair<int32_t, aidl::android::hardware::graphics::composer3::LutProperties>>; + using LayerLuts = + ftl::SmallMap<HWC2::Layer*, LutOffsetAndProperties, kLutFileDescriptorMapperSize>; + using LutFileDescriptorMapper = + ftl::SmallMap<HWC2::Layer*, ndk::ScopedFileDescriptor, kLutFileDescriptorMapperSize>; + [[nodiscard]] virtual hal::Error acceptChanges() = 0; [[nodiscard]] virtual base::expected<std::shared_ptr<HWC2::Layer>, hal::Error> createLayer() = 0; @@ -183,14 +193,16 @@ public: aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness* outClientTargetProperty) = 0; [[nodiscard]] virtual hal::Error getRequestedLuts( - std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>* - outLuts) = 0; + LayerLuts* outLuts, LutFileDescriptorMapper& lutFileDescriptorMapper) = 0; [[nodiscard]] virtual hal::Error getDisplayDecorationSupport( std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>* support) = 0; [[nodiscard]] virtual hal::Error setIdleTimerEnabled(std::chrono::milliseconds timeout) = 0; [[nodiscard]] virtual hal::Error getPhysicalDisplayOrientation( Hwc2::AidlTransform* outTransform) const = 0; + [[nodiscard]] virtual hal::Error getMaxLayerPictureProfiles(int32_t* maxProfiles) = 0; + [[nodiscard]] virtual hal::Error setPictureProfileHandle( + const PictureProfileHandle& handle) = 0; }; namespace impl { @@ -268,13 +280,14 @@ public: hal::Error getClientTargetProperty( aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness* outClientTargetProperty) override; - hal::Error getRequestedLuts( - std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>* - outLuts) override; + hal::Error getRequestedLuts(LayerLuts* outLuts, + LutFileDescriptorMapper& lutFileDescriptorMapper) override; hal::Error getDisplayDecorationSupport( std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>* support) override; hal::Error setIdleTimerEnabled(std::chrono::milliseconds timeout) override; + hal::Error getMaxLayerPictureProfiles(int32_t* maxProfiles) override; + hal::Error setPictureProfileHandle(const android::PictureProfileHandle& handle) override; // Other Display methods hal::HWDisplayId getId() const override { return mId; } @@ -369,7 +382,9 @@ public: [[nodiscard]] virtual hal::Error setBrightness(float brightness) = 0; [[nodiscard]] virtual hal::Error setBlockingRegion(const android::Region& region) = 0; [[nodiscard]] virtual hal::Error setLuts( - std::vector<aidl::android::hardware::graphics::composer3::Lut>& luts) = 0; + aidl::android::hardware::graphics::composer3::Luts& luts) = 0; + [[nodiscard]] virtual hal::Error setPictureProfileHandle( + const PictureProfileHandle& handle) = 0; }; namespace impl { @@ -420,8 +435,8 @@ public: // AIDL HAL hal::Error setBrightness(float brightness) override; hal::Error setBlockingRegion(const android::Region& region) override; - hal::Error setLuts( - std::vector<aidl::android::hardware::graphics::composer3::Lut>& luts) override; + hal::Error setLuts(aidl::android::hardware::graphics::composer3::Luts&) override; + hal::Error setPictureProfileHandle(const PictureProfileHandle& handle) override; private: // These are references to data owned by HWComposer, which will outlive @@ -443,6 +458,7 @@ private: android::HdrMetadata mHdrMetadata; android::mat4 mColorMatrix; uint32_t mBufferSlot; + android::PictureProfileHandle profile; }; } // namespace impl diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index d08e261e6c..55ccdefa7a 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -27,6 +27,7 @@ #include "HWComposer.h" +#include <aidl/android/hardware/graphics/composer3/IComposerClient.h> #include <android-base/properties.h> #include <common/trace.h> #include <compositionengine/Output.h> @@ -335,7 +336,8 @@ std::vector<HWComposer::HWCDisplayMode> HWComposer::getModesFromDisplayConfigura .height = config.height, .vsyncPeriod = config.vsyncPeriod, .configGroup = config.configGroup, - .vrrConfig = config.vrrConfig}; + .vrrConfig = config.vrrConfig, + .hdrOutputType = config.hdrOutputType}; const DisplayConfiguration::Dpi estimatedDPI = getEstimatedDotsPerInchFromSize(hwcDisplayId, hwcMode); @@ -379,7 +381,7 @@ std::vector<HWComposer::HWCDisplayMode> HWComposer::getModesFromLegacyDisplayCon const int32_t dpiX = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X); const int32_t dpiY = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y); const DisplayConfiguration::Dpi hwcDpi = - DisplayConfiguration::Dpi{dpiX == -1 ? dpiY : dpiX / 1000.f, + DisplayConfiguration::Dpi{dpiX == -1 ? dpiX : dpiX / 1000.f, dpiY == -1 ? dpiY : dpiY / 1000.f}; const DisplayConfiguration::Dpi estimatedDPI = getEstimatedDotsPerInchFromSize(hwcDisplayId, hwcMode); @@ -587,9 +589,14 @@ status_t HWComposer::getDeviceCompositionChanges( error = hwcDisplay->getClientTargetProperty(&clientTargetProperty); RETURN_IF_HWC_ERROR_FOR("getClientTargetProperty", error, displayId, BAD_INDEX); + DeviceRequestedChanges::LayerLuts layerLuts; + error = hwcDisplay->getRequestedLuts(&layerLuts, mLutFileDescriptorMapper); + RETURN_IF_HWC_ERROR_FOR("getRequestedLuts", error, displayId, BAD_INDEX); + outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests), std::move(layerRequests), - std::move(clientTargetProperty)}); + std::move(clientTargetProperty), + std::move(layerLuts)}); error = hwcDisplay->acceptChanges(); RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX); @@ -728,7 +735,11 @@ status_t HWComposer::setActiveModeWithConstraints( auto error = mDisplayData[displayId].hwcDisplay->setActiveConfigWithConstraints(hwcModeId, constraints, outTimeline); - RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); + if (error == hal::Error::CONFIG_FAILED) { + RETURN_IF_HWC_ERROR_FOR("setActiveConfigWithConstraints", error, displayId, + FAILED_TRANSACTION); + } + RETURN_IF_HWC_ERROR_FOR("setActiveConfigWithConstraints", error, displayId, UNKNOWN_ERROR); return NO_ERROR; } @@ -978,21 +989,6 @@ status_t HWComposer::getDisplayDecorationSupport( return NO_ERROR; } -status_t HWComposer::getRequestedLuts( - PhysicalDisplayId displayId, - std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>* outLuts) { - RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); - const auto error = mDisplayData[displayId].hwcDisplay->getRequestedLuts(outLuts); - if (error == hal::Error::UNSUPPORTED) { - RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); - } - if (error == hal::Error::BAD_PARAMETER) { - RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE); - } - RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); - return NO_ERROR; -} - status_t HWComposer::setAutoLowLatencyMode(PhysicalDisplayId displayId, bool on) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = mDisplayData[displayId].hwcDisplay->setAutoLowLatencyMode(on); @@ -1032,10 +1028,33 @@ status_t HWComposer::setContentType(PhysicalDisplayId displayId, hal::ContentTyp return NO_ERROR; } +int32_t HWComposer::getMaxLayerPictureProfiles(PhysicalDisplayId displayId) { + int32_t maxProfiles = 0; + RETURN_IF_INVALID_DISPLAY(displayId, 0); + const auto error = mDisplayData[displayId].hwcDisplay->getMaxLayerPictureProfiles(&maxProfiles); + RETURN_IF_HWC_ERROR(error, displayId, 0); + return maxProfiles; +} + +status_t HWComposer::setDisplayPictureProfileHandle(PhysicalDisplayId displayId, + const PictureProfileHandle& handle) { + RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); + const auto error = mDisplayData[displayId].hwcDisplay->setPictureProfileHandle(handle); + if (error != hal::Error::UNSUPPORTED) { + RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); + } + return NO_ERROR; +} + const std::unordered_map<std::string, bool>& HWComposer::getSupportedLayerGenericMetadata() const { return mSupportedLayerGenericMetadata; } +ftl::SmallMap<HWC2::Layer*, ndk::ScopedFileDescriptor, 20>& +HWComposer::getLutFileDescriptorMapper() { + return mLutFileDescriptorMapper; +} + void HWComposer::dumpOverlayProperties(std::string& result) const { // dump overlay properties result.append("OverlayProperties:\n"); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index b95c619f75..52662cffbb 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -29,6 +29,7 @@ #include <ftl/future.h> #include <ui/DisplayIdentification.h> #include <ui/FenceTime.h> +#include <ui/PictureProfileHandle.h> // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push @@ -53,6 +54,8 @@ #include <aidl/android/hardware/graphics/composer3/Composition.h> #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h> #include <aidl/android/hardware/graphics/composer3/DisplayLuts.h> +#include <aidl/android/hardware/graphics/composer3/LutProperties.h> +#include <aidl/android/hardware/graphics/composer3/OutputType.h> #include <aidl/android/hardware/graphics/composer3/OverlayProperties.h> namespace android { @@ -64,6 +67,7 @@ class GraphicBuffer; class TestableSurfaceFlinger; struct HWComposerTest; struct CompositionInfo; +class PictureProfileHandle; namespace Hwc2 { class Composer; @@ -90,11 +94,14 @@ public: aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness; using DisplayRequests = hal::DisplayRequest; using LayerRequests = std::unordered_map<HWC2::Layer*, hal::LayerRequest>; + using LutProperties = aidl::android::hardware::graphics::composer3::LutProperties; + using LayerLuts = HWC2::Display::LayerLuts; ChangedTypes changedTypes; DisplayRequests displayRequests; LayerRequests layerRequests; ClientTargetProperty clientTargetProperty; + LayerLuts layerLuts; }; struct HWCDisplayMode { @@ -106,12 +113,14 @@ public: float dpiY = -1.f; int32_t configGroup = -1; std::optional<hal::VrrConfig> vrrConfig; + OutputType hdrOutputType; friend std::ostream& operator<<(std::ostream& os, const HWCDisplayMode& mode) { return os << "id=" << mode.hwcId << " res=" << mode.width << "x" << mode.height << " vsyncPeriod=" << mode.vsyncPeriod << " dpi=" << mode.dpiX << "x" << mode.dpiY << " group=" << mode.configGroup - << " vrrConfig=" << to_string(mode.vrrConfig).c_str(); + << " vrrConfig=" << to_string(mode.vrrConfig).c_str() + << " hdrOutputType=" << toString(mode.hdrOutputType); } }; @@ -292,7 +301,7 @@ public: virtual std::optional<PhysicalDisplayId> toPhysicalDisplayId(hal::HWDisplayId) const = 0; virtual std::optional<hal::HWDisplayId> fromPhysicalDisplayId(PhysicalDisplayId) const = 0; - // Composer 3.0 + // AIDL Composer virtual status_t setBootDisplayMode(PhysicalDisplayId, hal::HWConfigId) = 0; virtual status_t clearBootDisplayMode(PhysicalDisplayId) = 0; virtual std::optional<hal::HWConfigId> getPreferredBootDisplayMode(PhysicalDisplayId) = 0; @@ -311,18 +320,17 @@ public: virtual status_t setRefreshRateChangedCallbackDebugEnabled(PhysicalDisplayId, bool enabled) = 0; virtual status_t notifyExpectedPresent(PhysicalDisplayId, TimePoint expectedPresentTime, Fps frameInterval) = 0; - - // Composer 4.0 - virtual status_t getRequestedLuts( - PhysicalDisplayId, - std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*) = 0; + virtual HWC2::Display::LutFileDescriptorMapper& getLutFileDescriptorMapper() = 0; + virtual int32_t getMaxLayerPictureProfiles(PhysicalDisplayId) = 0; + virtual status_t setDisplayPictureProfileHandle(PhysicalDisplayId, + const PictureProfileHandle& handle) = 0; }; static inline bool operator==(const android::HWComposer::DeviceRequestedChanges& lhs, const android::HWComposer::DeviceRequestedChanges& rhs) { return lhs.changedTypes == rhs.changedTypes && lhs.displayRequests == rhs.displayRequests && lhs.layerRequests == rhs.layerRequests && - lhs.clientTargetProperty == rhs.clientTargetProperty; + lhs.clientTargetProperty == rhs.clientTargetProperty && lhs.layerLuts == rhs.layerLuts; } namespace impl { @@ -479,12 +487,10 @@ public: status_t setRefreshRateChangedCallbackDebugEnabled(PhysicalDisplayId, bool enabled) override; status_t notifyExpectedPresent(PhysicalDisplayId, TimePoint expectedPresentTime, Fps frameInterval) override; - - // Composer 4.0 - status_t getRequestedLuts( - PhysicalDisplayId, - std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*) - override; + HWC2::Display::LutFileDescriptorMapper& getLutFileDescriptorMapper() override; + int32_t getMaxLayerPictureProfiles(PhysicalDisplayId) override; + status_t setDisplayPictureProfileHandle(PhysicalDisplayId, + const android::PictureProfileHandle& profile) override; // for debugging ---------------------------------------------------------- void dump(std::string& out) const override; @@ -571,6 +577,8 @@ private: const size_t mMaxVirtualDisplayDimension; const bool mUpdateDeviceProductInfoOnHotplugReconnect; bool mEnableVrrTimeout; + + HWC2::Display::LutFileDescriptorMapper mLutFileDescriptorMapper; }; } // namespace impl diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h index e3d962237b..568d758922 100644 --- a/services/surfaceflinger/DisplayHardware/Hal.h +++ b/services/surfaceflinger/DisplayHardware/Hal.h @@ -17,16 +17,21 @@ #pragma once #include <android/hardware/graphics/common/1.1/types.h> +#include <android/hardware/graphics/composer/2.1/types.h> #include <android/hardware/graphics/composer/2.4/IComposer.h> #include <android/hardware/graphics/composer/2.4/IComposerClient.h> +#include <android/hardware/graphics/composer/2.4/types.h> #include <aidl/android/hardware/graphics/common/DisplayHotplugEvent.h> #include <aidl/android/hardware/graphics/common/Hdr.h> #include <aidl/android/hardware/graphics/composer3/Composition.h> #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h> #include <aidl/android/hardware/graphics/composer3/DisplayConfiguration.h> +#include <aidl/android/hardware/graphics/composer3/IComposerClient.h> #include <aidl/android/hardware/graphics/composer3/VrrConfig.h> +#include <ftl/enum.h> + #define ERROR_HAS_CHANGES 5 namespace android { @@ -46,7 +51,6 @@ using types::V1_2::ColorMode; using types::V1_2::Dataspace; using types::V1_2::PixelFormat; -using V2_1::Error; using V2_4::IComposer; using V2_4::IComposerCallback; using V2_4::IComposerClient; @@ -78,6 +82,22 @@ using Hdr = aidl::android::hardware::graphics::common::Hdr; using DisplayConfiguration = V3_0::DisplayConfiguration; using VrrConfig = V3_0::VrrConfig; +enum class Error : int32_t { + NONE = static_cast<int32_t>(V2_1::Error::NONE), + BAD_CONFIG = static_cast<int32_t>(V2_1::Error::BAD_CONFIG), + BAD_DISPLAY = static_cast<int32_t>(V2_1::Error::BAD_DISPLAY), + BAD_LAYER = static_cast<int32_t>(V2_1::Error::BAD_LAYER), + BAD_PARAMETER = static_cast<int32_t>(V2_1::Error::BAD_PARAMETER), + NO_RESOURCES = static_cast<int32_t>(V2_1::Error::NO_RESOURCES), + NOT_VALIDATED = static_cast<int32_t>(V2_1::Error::NOT_VALIDATED), + UNSUPPORTED = static_cast<int32_t>(V2_1::Error::UNSUPPORTED), + SEAMLESS_NOT_ALLOWED = static_cast<int32_t>(V2_4::Error::SEAMLESS_NOT_ALLOWED), + SEAMLESS_NOT_POSSIBLE = static_cast<int32_t>(V2_4::Error::SEAMLESS_NOT_POSSIBLE), + CONFIG_FAILED = V3_0::IComposerClient::EX_CONFIG_FAILED, + PICTURE_PROFILE_MAX_EXCEEDED = V3_0::IComposerClient::EX_PICTURE_PROFILE_MAX_EXCEEDED, + ftl_last = PICTURE_PROFILE_MAX_EXCEEDED +}; + } // namespace hardware::graphics::composer::hal inline bool hasChangesError(hardware::graphics::composer::hal::Error error) { @@ -210,7 +230,11 @@ inline std::string to_string(hardware::graphics::composer::hal::V2_4::Error erro } inline std::string to_string(hardware::graphics::composer::hal::Error error) { - return to_string(static_cast<hardware::graphics::composer::hal::V2_4::Error>(error)); + // 5 is reserved for historical reason, during validation 5 means has changes. + if (hasChangesError(error)) { + return "HAS_CHANGES"; + } + return ftl::enum_string(error); } // For utils::Dumper ADL. diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index ee1e07ae7d..5703a2d37c 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -27,6 +27,7 @@ #include <SurfaceFlingerProperties.h> #include <aidl/android/hardware/graphics/common/DisplayHotplugEvent.h> #include <android/binder_manager.h> +#include <android/hardware/graphics/composer/2.1/types.h> #include <common/trace.h> #include <composer-command-buffer/2.2/ComposerCommandBuffer.h> #include <hidl/HidlTransportSupport.h> @@ -47,7 +48,7 @@ using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrig using aidl::android::hardware::graphics::composer3::DimmingStage; using aidl::android::hardware::graphics::composer3::DisplayCapability; using aidl::android::hardware::graphics::composer3::DisplayLuts; -using aidl::android::hardware::graphics::composer3::Lut; +using aidl::android::hardware::graphics::composer3::Luts; using aidl::android::hardware::graphics::composer3::OverlayProperties; namespace android { @@ -173,7 +174,7 @@ private: }; // assume NO_RESOURCES when Status::isOk returns false -constexpr Error kDefaultError = Error::NO_RESOURCES; +constexpr V2_1::Error kDefaultError = V2_1::Error::NO_RESOURCES; constexpr V2_4::Error kDefaultError_2_4 = static_cast<V2_4::Error>(kDefaultError); template <typename T, typename U> @@ -181,7 +182,7 @@ T unwrapRet(Return<T>& ret, const U& default_val) { return (ret.isOk()) ? static_cast<T>(ret) : static_cast<T>(default_val); } -Error unwrapRet(Return<Error>& ret) { +V2_1::Error unwrapRet(Return<V2_1::Error>& ret) { return unwrapRet(ret, kDefaultError); } @@ -235,7 +236,7 @@ HidlComposer::HidlComposer(const std::string& serviceName) }); } else if (sp<V2_3::IComposer> composer_2_3 = V2_3::IComposer::castFrom(mComposer)) { composer_2_3->createClient_2_3([&](const auto& tmpError, const auto& tmpClient) { - if (tmpError == Error::NONE) { + if (tmpError == V2_1::Error::NONE) { mClient = tmpClient; mClient_2_2 = tmpClient; mClient_2_3 = tmpClient; @@ -243,7 +244,7 @@ HidlComposer::HidlComposer(const std::string& serviceName) }); } else { mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) { - if (tmpError != Error::NONE) { + if (tmpError != V2_1::Error::NONE) { return; } @@ -325,14 +326,14 @@ uint32_t HidlComposer::getMaxVirtualDisplayCount() { Error HidlComposer::createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format, Display* outDisplay) { const uint32_t bufferSlotCount = 1; - Error error = kDefaultError; + Error error = static_cast<Error>(kDefaultError); if (mClient_2_2) { mClient_2_2->createVirtualDisplay_2_2(width, height, static_cast<types::V1_1::PixelFormat>(*format), bufferSlotCount, [&](const auto& tmpError, const auto& tmpDisplay, const auto& tmpFormat) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -346,7 +347,7 @@ Error HidlComposer::createVirtualDisplay(uint32_t width, uint32_t height, PixelF bufferSlotCount, [&](const auto& tmpError, const auto& tmpDisplay, const auto& tmpFormat) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -361,7 +362,7 @@ Error HidlComposer::createVirtualDisplay(uint32_t width, uint32_t height, PixelF Error HidlComposer::destroyVirtualDisplay(Display display) { auto ret = mClient->destroyVirtualDisplay(display); - return unwrapRet(ret); + return static_cast<Error>(unwrapRet(ret)); } Error HidlComposer::acceptDisplayChanges(Display display) { @@ -371,10 +372,10 @@ Error HidlComposer::acceptDisplayChanges(Display display) { } Error HidlComposer::createLayer(Display display, Layer* outLayer) { - Error error = kDefaultError; + Error error = static_cast<Error>(kDefaultError); mClient->createLayer(display, kMaxLayerBufferCount, [&](const auto& tmpError, const auto& tmpLayer) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -387,13 +388,13 @@ Error HidlComposer::createLayer(Display display, Layer* outLayer) { Error HidlComposer::destroyLayer(Display display, Layer layer) { auto ret = mClient->destroyLayer(display, layer); - return unwrapRet(ret); + return static_cast<Error>(unwrapRet(ret)); } Error HidlComposer::getActiveConfig(Display display, Config* outConfig) { - Error error = kDefaultError; + Error error = static_cast<Error>(kDefaultError); mClient->getActiveConfig(display, [&](const auto& tmpError, const auto& tmpConfig) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -412,11 +413,11 @@ Error HidlComposer::getChangedCompositionTypes( } Error HidlComposer::getColorModes(Display display, std::vector<ColorMode>* outModes) { - Error error = kDefaultError; + Error error = static_cast<Error>(kDefaultError); if (mClient_2_3) { mClient_2_3->getColorModes_2_3(display, [&](const auto& tmpError, const auto& tmpModes) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -425,7 +426,7 @@ Error HidlComposer::getColorModes(Display display, std::vector<ColorMode>* outMo }); } else if (mClient_2_2) { mClient_2_2->getColorModes_2_2(display, [&](const auto& tmpError, const auto& tmpModes) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -436,7 +437,7 @@ Error HidlComposer::getColorModes(Display display, std::vector<ColorMode>* outMo }); } else { mClient->getColorModes(display, [&](const auto& tmpError, const auto& tmpModes) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -451,7 +452,7 @@ Error HidlComposer::getColorModes(Display display, std::vector<ColorMode>* outMo Error HidlComposer::getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) { - Error error = kDefaultError; + Error error = static_cast<Error>(kDefaultError); if (mClient_2_4) { mClient_2_4->getDisplayAttribute_2_4(display, config, attribute, [&](const auto& tmpError, const auto& tmpValue) { @@ -466,7 +467,7 @@ Error HidlComposer::getDisplayAttribute(Display display, Config config, mClient->getDisplayAttribute(display, config, static_cast<V2_1::IComposerClient::Attribute>(attribute), [&](const auto& tmpError, const auto& tmpValue) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -479,9 +480,9 @@ Error HidlComposer::getDisplayAttribute(Display display, Config config, } Error HidlComposer::getDisplayConfigs(Display display, std::vector<Config>* outConfigs) { - Error error = kDefaultError; + Error error = static_cast<Error>(kDefaultError); mClient->getDisplayConfigs(display, [&](const auto& tmpError, const auto& tmpConfigs) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -499,9 +500,9 @@ Error HidlComposer::getDisplayConfigurations(Display, int32_t /*maxFrameInterval } Error HidlComposer::getDisplayName(Display display, std::string* outName) { - Error error = kDefaultError; + Error error = static_cast<Error>(kDefaultError); mClient->getDisplayName(display, [&](const auto& tmpError, const auto& tmpName) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -520,9 +521,9 @@ Error HidlComposer::getDisplayRequests(Display display, uint32_t* outDisplayRequ } Error HidlComposer::getDozeSupport(Display display, bool* outSupport) { - Error error = kDefaultError; + Error error = static_cast<Error>(kDefaultError); mClient->getDozeSupport(display, [&](const auto& tmpError, const auto& tmpSupport) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -541,14 +542,14 @@ Error HidlComposer::hasDisplayIdleTimerCapability(Display, bool*) { Error HidlComposer::getHdrCapabilities(Display display, std::vector<Hdr>* outHdrTypes, float* outMaxLuminance, float* outMaxAverageLuminance, float* outMinLuminance) { - Error error = kDefaultError; + Error error = static_cast<Error>(kDefaultError); if (mClient_2_3) { mClient_2_3->getHdrCapabilities_2_3(display, [&](const auto& tmpError, const auto& tmpHdrTypes, const auto& tmpMaxLuminance, const auto& tmpMaxAverageLuminance, const auto& tmpMinLuminance) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -564,7 +565,7 @@ Error HidlComposer::getHdrCapabilities(Display display, std::vector<Hdr>* outHdr const auto& tmpMaxLuminance, const auto& tmpMaxAverageLuminance, const auto& tmpMinLuminance) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -606,7 +607,7 @@ Error HidlComposer::presentDisplay(Display display, int* outPresentFence) { Error HidlComposer::setActiveConfig(Display display, Config config) { auto ret = mClient->setActiveConfig(display, config); - return unwrapRet(ret); + return static_cast<Error>(unwrapRet(ret)); } Error HidlComposer::setClientTarget(Display display, uint32_t slot, const sp<GraphicBuffer>& target, @@ -625,7 +626,7 @@ Error HidlComposer::setClientTarget(Display display, uint32_t slot, const sp<Gra } Error HidlComposer::setColorMode(Display display, ColorMode mode, RenderIntent renderIntent) { - hardware::Return<Error> ret(kDefaultError); + hardware::Return<V2_1::Error> ret(kDefaultError); if (mClient_2_3) { ret = mClient_2_3->setColorMode_2_3(display, mode, renderIntent); } else if (mClient_2_2) { @@ -634,7 +635,7 @@ Error HidlComposer::setColorMode(Display display, ColorMode mode, RenderIntent r } else { ret = mClient->setColorMode(display, static_cast<types::V1_0::ColorMode>(mode)); } - return unwrapRet(ret); + return static_cast<Error>(unwrapRet(ret)); } Error HidlComposer::setColorTransform(Display display, const float* matrix) { @@ -654,25 +655,25 @@ Error HidlComposer::setOutputBuffer(Display display, const native_handle_t* buff } Error HidlComposer::setPowerMode(Display display, IComposerClient::PowerMode mode) { - Return<Error> ret(Error::UNSUPPORTED); + Return<V2_1::Error> ret(V2_1::Error::UNSUPPORTED); if (mClient_2_2) { ret = mClient_2_2->setPowerMode_2_2(display, mode); } else if (mode != IComposerClient::PowerMode::ON_SUSPEND) { ret = mClient->setPowerMode(display, static_cast<V2_1::IComposerClient::PowerMode>(mode)); } - return unwrapRet(ret); + return static_cast<Error>(unwrapRet(ret)); } Error HidlComposer::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) { auto ret = mClient->setVsyncEnabled(display, enabled); - return unwrapRet(ret); + return static_cast<Error>(unwrapRet(ret)); } Error HidlComposer::setClientTargetSlotCount(Display display) { const uint32_t bufferSlotCount = BufferQueue::NUM_BUFFER_SLOTS; auto ret = mClient->setClientTargetSlotCount(display, bufferSlotCount); - return unwrapRet(ret); + return static_cast<Error>(unwrapRet(ret)); } Error HidlComposer::validateDisplay(Display display, nsecs_t /*expectedPresentTime*/, @@ -903,7 +904,7 @@ Error HidlComposer::execute() { // set up new input command queue if necessary if (queueChanged) { auto ret = mClient->setInputCommandQueue(*mWriter.getMQDescriptor()); - auto error = unwrapRet(ret); + auto error = static_cast<Error>(unwrapRet(ret)); if (error != Error::NONE) { mWriter.reset(); return error; @@ -915,17 +916,17 @@ Error HidlComposer::execute() { return Error::NONE; } - Error error = kDefaultError; + Error error = static_cast<Error>(kDefaultError); hardware::Return<void> ret; auto hidl_callback = [&](const auto& tmpError, const auto& tmpOutChanged, const auto& tmpOutLength, const auto& tmpOutHandles) { - error = tmpError; + error = static_cast<Error>(tmpError); // set up new output command queue if necessary if (error == Error::NONE && tmpOutChanged) { - error = kDefaultError; + error = static_cast<Error>(kDefaultError); mClient->getOutputCommandQueue([&](const auto& tmpError, const auto& tmpDescriptor) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -1000,11 +1001,11 @@ std::vector<IComposerClient::PerFrameMetadataKey> HidlComposer::getPerFrameMetad return keys; } - Error error = kDefaultError; + Error error = static_cast<Error>(kDefaultError); if (mClient_2_3) { mClient_2_3->getPerFrameMetadataKeys_2_3(display, [&](const auto& tmpError, const auto& tmpKeys) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { ALOGW("getPerFrameMetadataKeys failed " "with %d", @@ -1016,7 +1017,7 @@ std::vector<IComposerClient::PerFrameMetadataKey> HidlComposer::getPerFrameMetad } else { mClient_2_2 ->getPerFrameMetadataKeys(display, [&](const auto& tmpError, const auto& tmpKeys) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { ALOGW("getPerFrameMetadataKeys failed with %d", tmpError); return; @@ -1039,10 +1040,10 @@ Error HidlComposer::getRenderIntents(Display display, ColorMode colorMode, return Error::NONE; } - Error error = kDefaultError; + Error error = static_cast<Error>(kDefaultError); auto getRenderIntentsLambda = [&](const auto& tmpError, const auto& tmpKeys) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -1066,10 +1067,10 @@ Error HidlComposer::getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outM return Error::NONE; } - Error error = kDefaultError; + Error error = static_cast<Error>(kDefaultError); mClient_2_2->getDataspaceSaturationMatrix(static_cast<types::V1_1::Dataspace>(dataspace), [&](const auto& tmpError, const auto& tmpMatrix) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -1087,11 +1088,11 @@ Error HidlComposer::getDisplayIdentificationData(Display display, uint8_t* outPo return Error::UNSUPPORTED; } - Error error = kDefaultError; + Error error = static_cast<Error>(kDefaultError); mClient_2_3->getDisplayIdentificationData(display, [&](const auto& tmpError, const auto& tmpPort, const auto& tmpData) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -1123,13 +1124,13 @@ Error HidlComposer::getDisplayedContentSamplingAttributes(Display display, Pixel if (!mClient_2_3) { return Error::UNSUPPORTED; } - Error error = kDefaultError; + Error error = static_cast<Error>(kDefaultError); mClient_2_3->getDisplayedContentSamplingAttributes(display, [&](const auto tmpError, const auto& tmpFormat, const auto& tmpDataspace, const auto& tmpComponentMask) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error == Error::NONE) { *outFormat = tmpFormat; *outDataspace = tmpDataspace; @@ -1149,8 +1150,9 @@ Error HidlComposer::setDisplayContentSamplingEnabled(Display display, bool enabl auto enable = enabled ? V2_3::IComposerClient::DisplayedContentSampling::ENABLE : V2_3::IComposerClient::DisplayedContentSampling::DISABLE; - return mClient_2_3->setDisplayedContentSamplingEnabled(display, enable, componentMask, - maxFrames); + auto ret = mClient_2_3->setDisplayedContentSamplingEnabled(display, enable, componentMask, + maxFrames); + return static_cast<Error>(unwrapRet(ret)); } Error HidlComposer::getDisplayedContentSample(Display display, uint64_t maxFrames, @@ -1161,12 +1163,12 @@ Error HidlComposer::getDisplayedContentSample(Display display, uint64_t maxFrame if (!mClient_2_3) { return Error::UNSUPPORTED; } - Error error = kDefaultError; + Error error = static_cast<Error>(kDefaultError); mClient_2_3->getDisplayedContentSample(display, maxFrames, timestamp, [&](const auto tmpError, auto tmpNumFrames, const auto& tmpSamples0, const auto& tmpSamples1, const auto& tmpSamples2, const auto& tmpSamples3) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error == Error::NONE) { outStats->numFrames = tmpNumFrames; outStats->component_0_sample = tmpSamples0; @@ -1196,7 +1198,8 @@ Error HidlComposer::setDisplayBrightness(Display display, float brightness, floa if (!mClient_2_3) { return Error::UNSUPPORTED; } - return mClient_2_3->setDisplayBrightness(display, brightness); + auto ret = mClient_2_3->setDisplayBrightness(display, brightness); + return static_cast<Error>(unwrapRet(ret)); } // Composer HAL 2.4 @@ -1273,19 +1276,18 @@ V2_4::Error HidlComposer::getDisplayVsyncPeriod(Display display, VsyncPeriodNano return error; } -V2_4::Error HidlComposer::setActiveConfigWithConstraints( +Error HidlComposer::setActiveConfigWithConstraints( Display display, Config config, const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, VsyncPeriodChangeTimeline* outTimeline) { - using Error = V2_4::Error; if (!mClient_2_4) { return Error::UNSUPPORTED; } - Error error = kDefaultError_2_4; + Error error = static_cast<Error>(kDefaultError_2_4); mClient_2_4->setActiveConfigWithConstraints(display, config, vsyncPeriodChangeConstraints, [&](const auto& tmpError, const auto& tmpTimeline) { - error = tmpError; + error = static_cast<Error>(tmpError); if (error != Error::NONE) { return; } @@ -1410,11 +1412,12 @@ Error HidlComposer::getClientTargetProperty( return Error::NONE; } -Error HidlComposer::getRequestedLuts(Display, std::vector<DisplayLuts::LayerLut>*) { +Error HidlComposer::getRequestedLuts(Display, std::vector<Layer>*, + std::vector<DisplayLuts::LayerLut>*) { return Error::NONE; } -Error HidlComposer::setLayerLuts(Display, Layer, std::vector<Lut>&) { +Error HidlComposer::setLayerLuts(Display, Layer, Luts&) { return Error::NONE; } @@ -1445,6 +1448,18 @@ Error HidlComposer::getPhysicalDisplayOrientation(Display, AidlTransform*) { "OptionalFeature::PhysicalDisplayOrientation is not supported on HIDL"); } +Error HidlComposer::getMaxLayerPictureProfiles(Display, int32_t*) { + return Error::UNSUPPORTED; +} + +Error HidlComposer::setDisplayPictureProfileId(Display, PictureProfileId) { + return Error::UNSUPPORTED; +} + +Error HidlComposer::setLayerPictureProfileId(Display, Layer, PictureProfileId) { + return Error::UNSUPPORTED; +} + void HidlComposer::registerCallback(ComposerCallback& callback) { const bool vsyncSwitchingSupported = isSupported(Hwc2::Composer::OptionalFeature::RefreshRateSwitching); diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h index 701a54bc66..42ba9a957b 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h @@ -60,7 +60,6 @@ using types::V1_2::PixelFormat; using V2_1::Config; using V2_1::Display; -using V2_1::Error; using V2_1::Layer; using V2_4::CommandReaderBase; using V2_4::CommandWriterBase; @@ -308,7 +307,7 @@ public: V2_4::Error getDisplayConnectionType(Display display, IComposerClient::DisplayConnectionType* outType) override; V2_4::Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) override; - V2_4::Error setActiveConfigWithConstraints( + Error setActiveConfigWithConstraints( Display display, Config config, const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints, VsyncPeriodChangeTimeline* outTimeline) override; @@ -352,11 +351,14 @@ public: Error setRefreshRateChangedCallbackDebugEnabled(Display, bool) override; Error notifyExpectedPresent(Display, nsecs_t, int32_t) override; Error getRequestedLuts( - Display, + Display, std::vector<Layer>*, std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*) override; Error setLayerLuts(Display, Layer, - std::vector<aidl::android::hardware::graphics::composer3::Lut>&) override; + aidl::android::hardware::graphics::composer3::Luts&) override; + Error getMaxLayerPictureProfiles(Display, int32_t* outMaxProfiles) override; + Error setDisplayPictureProfileId(Display, PictureProfileId) override; + Error setLayerPictureProfileId(Display, Layer, PictureProfileId) override; private: class CommandWriter : public CommandWriterBase { diff --git a/services/surfaceflinger/EventLog/EventLog.cpp b/services/surfaceflinger/EventLog/EventLog.cpp deleted file mode 100644 index 3b609524e8..0000000000 --- a/services/surfaceflinger/EventLog/EventLog.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2013 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. - */ - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - -#include <stdio.h> -#include <stdlib.h> -#include <log/log.h> - -#include "EventLog.h" - -namespace android { - -ANDROID_SINGLETON_STATIC_INSTANCE(EventLog) - - -EventLog::EventLog() { -} - -void EventLog::doLogFrameDurations(const std::string_view& name, const int32_t* durations, - size_t numDurations) { - EventLog::TagBuffer buffer(LOGTAG_SF_FRAME_DUR); - buffer.startList(1 + numDurations); - buffer.writeString(name); - for (size_t i = 0; i < numDurations; i++) { - buffer.writeInt32(durations[i]); - } - buffer.endList(); - buffer.log(); -} - -void EventLog::logFrameDurations(const std::string_view& name, const int32_t* durations, - size_t numDurations) { - EventLog::getInstance().doLogFrameDurations(name, durations, numDurations); -} - -// --------------------------------------------------------------------------- - -EventLog::TagBuffer::TagBuffer(int32_t tag) - : mPos(0), mTag(tag), mOverflow(false) { -} - -void EventLog::TagBuffer::log() { - if (mOverflow) { - ALOGW("couldn't log to binary event log: overflow."); - } else if (android_bWriteLog(mTag, mStorage, mPos) < 0) { - ALOGE("couldn't log to EventLog: %s", strerror(errno)); - } - // purge the buffer - mPos = 0; - mOverflow = false; -} - -void EventLog::TagBuffer::startList(int8_t count) { - if (mOverflow) return; - const size_t needed = 1 + sizeof(count); - if (mPos + needed > STORAGE_MAX_SIZE) { - mOverflow = true; - return; - } - mStorage[mPos + 0] = EVENT_TYPE_LIST; - mStorage[mPos + 1] = count; - mPos += needed; -} - -void EventLog::TagBuffer::endList() { - if (mOverflow) return; - const size_t needed = 1; - if (mPos + needed > STORAGE_MAX_SIZE) { - mOverflow = true; - return; - } - mStorage[mPos + 0] = '\n'; - mPos += needed; -} - -void EventLog::TagBuffer::writeInt32(int32_t value) { - if (mOverflow) return; - const size_t needed = 1 + sizeof(value); - if (mPos + needed > STORAGE_MAX_SIZE) { - mOverflow = true; - return; - } - mStorage[mPos + 0] = EVENT_TYPE_INT; - memcpy(&mStorage[mPos + 1], &value, sizeof(value)); - mPos += needed; -} - -void EventLog::TagBuffer::writeInt64(int64_t value) { - if (mOverflow) return; - const size_t needed = 1 + sizeof(value); - if (mPos + needed > STORAGE_MAX_SIZE) { - mOverflow = true; - return; - } - mStorage[mPos + 0] = EVENT_TYPE_LONG; - memcpy(&mStorage[mPos + 1], &value, sizeof(value)); - mPos += needed; -} - -void EventLog::TagBuffer::writeString(const std::string_view& value) { - if (mOverflow) return; - const size_t stringLen = value.length(); - const size_t needed = 1 + sizeof(int32_t) + stringLen; - if (mPos + needed > STORAGE_MAX_SIZE) { - mOverflow = true; - return; - } - mStorage[mPos + 0] = EVENT_TYPE_STRING; - memcpy(&mStorage[mPos + 1], &stringLen, sizeof(int32_t)); - memcpy(&mStorage[mPos + 5], value.data(), stringLen); - mPos += needed; -} - -} // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/EventLog/EventLog.h b/services/surfaceflinger/EventLog/EventLog.h deleted file mode 100644 index ee3587ef8a..0000000000 --- a/services/surfaceflinger/EventLog/EventLog.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2013 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 <utils/Errors.h> -#include <utils/Singleton.h> - -#include <cstdint> -#include <string_view> - -namespace android { - -class EventLog : public Singleton<EventLog> { - -public: - static void logFrameDurations(const std::string_view& name, const int32_t* durations, - size_t numDurations); - -protected: - EventLog(); - -private: - /* - * EventLogBuffer is a helper class to construct an in-memory event log - * tag. In this version the buffer is not dynamic, so write operation can - * fail if there is not enough space in the temporary buffer. - * Once constructed, the buffer can be logger by calling the log() - * method. - */ - - class TagBuffer { - enum { STORAGE_MAX_SIZE = 128 }; - int32_t mPos; - int32_t mTag; - bool mOverflow; - char mStorage[STORAGE_MAX_SIZE]; - public: - explicit TagBuffer(int32_t tag); - - void startList(int8_t count); - void endList(); - - void writeInt32(int32_t); - void writeInt64(int64_t); - void writeString(const std::string_view&); - - void log(); - }; - - friend class Singleton<EventLog>; - EventLog(const EventLog&); - EventLog& operator =(const EventLog&); - - enum { LOGTAG_SF_FRAME_DUR = 60100 }; - void doLogFrameDurations(const std::string_view& name, const int32_t* durations, - size_t numDurations); -}; - -} // namespace android diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 47b811b721..86d7388f5b 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -29,6 +29,7 @@ #include <cinttypes> #include <numeric> #include <unordered_set> +#include <vector> #include "../Jank/JankTracker.h" @@ -378,6 +379,11 @@ void SurfaceFrame::setAcquireFenceTime(nsecs_t acquireFenceTime) { } } +void SurfaceFrame::setDesiredPresentTime(nsecs_t desiredPresentTime) { + std::scoped_lock lock(mMutex); + mActuals.desiredPresentTime = desiredPresentTime; +} + void SurfaceFrame::setDropTime(nsecs_t dropTime) { std::scoped_lock lock(mMutex); mDropTime = dropTime; @@ -997,6 +1003,11 @@ void FrameTimeline::setSfPresent(nsecs_t sfPresentTime, finalizeCurrentDisplayFrame(); } +const std::vector<std::shared_ptr<frametimeline::SurfaceFrame>>& FrameTimeline::getPresentFrames() + const { + return mPresentFrames; +} + void FrameTimeline::onCommitNotComposited() { SFTRACE_CALL(); std::scoped_lock lock(mMutex); @@ -1456,6 +1467,30 @@ float FrameTimeline::computeFps(const std::unordered_set<int32_t>& layerIds) { static_cast<float>(totalPresentToPresentWalls); } +void FrameTimeline::generateFrameStats(int32_t layer, size_t count, FrameStats* outStats) const { + std::scoped_lock lock(mMutex); + + // TODO: Include FPS calculation here + for (auto displayFrame : mDisplayFrames) { + if (!count--) { + break; + } + + if (displayFrame->getActuals().presentTime <= 0) { + continue; + } + + for (const auto& surfaceFrame : displayFrame->getSurfaceFrames()) { + if (surfaceFrame->getLayerId() == layer) { + outStats->actualPresentTimesNano.push_back(surfaceFrame->getActuals().presentTime); + outStats->desiredPresentTimesNano.push_back( + surfaceFrame->getActuals().desiredPresentTime); + outStats->frameReadyTimesNano.push_back(surfaceFrame->getActuals().endTime); + } + } + } +} + std::optional<size_t> FrameTimeline::getFirstSignalFenceIndex() const { for (size_t i = 0; i < mPendingPresentFences.size(); i++) { const auto& [fence, _] = mPendingPresentFences[i]; @@ -1492,6 +1527,7 @@ void FrameTimeline::flushPendingPresentFences() { mPendingPresentFences.erase(mPendingPresentFences.begin()); } + mPresentFrames.clear(); for (size_t i = 0; i < mPendingPresentFences.size(); i++) { const auto& pendingPresentFence = mPendingPresentFences[i]; nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID; @@ -1504,6 +1540,13 @@ void FrameTimeline::flushPendingPresentFences() { auto& displayFrame = pendingPresentFence.second; displayFrame->onPresent(signalTime, mPreviousActualPresentTime); + + // Surface frames have been jank classified and can be provided to caller + // to detect if buffer stuffing is occurring. + for (const auto& frame : displayFrame->getSurfaceFrames()) { + mPresentFrames.push_back(frame); + } + mPreviousPredictionPresentTime = displayFrame->trace(mSurfaceFlingerPid, monoBootOffset, mPreviousPredictionPresentTime, mFilterFramesBeforeTraceStarts); diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index cffb61ee10..a47bd573de 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -85,16 +85,20 @@ enum class FrameStartMetadata : int8_t { */ struct TimelineItem { TimelineItem(const nsecs_t startTime = 0, const nsecs_t endTime = 0, - const nsecs_t presentTime = 0) - : startTime(startTime), endTime(endTime), presentTime(presentTime) {} + const nsecs_t presentTime = 0, const nsecs_t desiredPresentTime = 0) + : startTime(startTime), + endTime(endTime), + presentTime(presentTime), + desiredPresentTime(desiredPresentTime) {} nsecs_t startTime; nsecs_t endTime; nsecs_t presentTime; + nsecs_t desiredPresentTime; bool operator==(const TimelineItem& other) const { return startTime == other.startTime && endTime == other.endTime && - presentTime == other.presentTime; + presentTime == other.presentTime && desiredPresentTime != other.desiredPresentTime; } bool operator!=(const TimelineItem& other) const { return !(*this == other); } @@ -183,6 +187,7 @@ public: void setActualStartTime(nsecs_t actualStartTime); void setActualQueueTime(nsecs_t actualQueueTime); void setAcquireFenceTime(nsecs_t acquireFenceTime); + void setDesiredPresentTime(nsecs_t desiredPresentTime); void setDropTime(nsecs_t dropTime); void setPresentState(PresentState presentState, nsecs_t lastLatchTime = 0); void setRenderRate(Fps renderRate); @@ -323,6 +328,11 @@ public: virtual void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence, const std::shared_ptr<FenceTime>& gpuFence) = 0; + // Provides surface frames that have already been jank classified in the most recent + // flush of pending present fences. This allows buffer stuffing detection from SF. + virtual const std::vector<std::shared_ptr<frametimeline::SurfaceFrame>>& getPresentFrames() + const = 0; + // Tells FrameTimeline that a frame was committed but not composited. This is used to flush // all the associated surface frames. virtual void onCommitNotComposited() = 0; @@ -341,6 +351,9 @@ public: // containing at least one layer ID. virtual float computeFps(const std::unordered_set<int32_t>& layerIds) = 0; + // Supports the legacy FrameStats interface + virtual void generateFrameStats(int32_t layer, size_t count, FrameStats* outStats) const = 0; + // Restores the max number of display frames to default. Called by SF backdoor. virtual void reset() = 0; }; @@ -497,10 +510,13 @@ public: void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate, Fps renderRate) override; void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence, const std::shared_ptr<FenceTime>& gpuFence = FenceTime::NO_FENCE) override; + const std::vector<std::shared_ptr<frametimeline::SurfaceFrame>>& getPresentFrames() + const override; void onCommitNotComposited() override; void parseArgs(const Vector<String16>& args, std::string& result) override; void setMaxDisplayFrames(uint32_t size) override; float computeFps(const std::unordered_set<int32_t>& layerIds) override; + void generateFrameStats(int32_t layer, size_t count, FrameStats* outStats) const override; void reset() override; // Sets up the perfetto tracing backend and data source. @@ -543,6 +559,9 @@ private: // display frame, this is a good starting size for the vector so that we can avoid the // internal vector resizing that happens with push_back. static constexpr uint32_t kNumSurfaceFramesInitial = 10; + // Presented surface frames that have been jank classified and can + // indicate of potential buffer stuffing. + std::vector<std::shared_ptr<frametimeline::SurfaceFrame>> mPresentFrames; }; } // namespace impl diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp index ca8cdc3c0a..93d0313e53 100644 --- a/services/surfaceflinger/FrameTracker.cpp +++ b/services/surfaceflinger/FrameTracker.cpp @@ -26,16 +26,10 @@ #include <ui/FrameStats.h> #include "FrameTracker.h" -#include "EventLog/EventLog.h" namespace android { -FrameTracker::FrameTracker() : - mOffset(0), - mNumFences(0), - mDisplayPeriod(0) { - resetFrameCountersLocked(); -} +FrameTracker::FrameTracker() : mOffset(0), mNumFences(0), mDisplayPeriod(0) {} void FrameTracker::setDesiredPresentTime(nsecs_t presentTime) { Mutex::Autolock lock(mMutex); @@ -73,9 +67,6 @@ void FrameTracker::setDisplayRefreshPeriod(nsecs_t displayPeriod) { void FrameTracker::advanceFrame() { Mutex::Autolock lock(mMutex); - // Update the statistic to include the frame we just finished. - updateStatsLocked(mOffset); - // Advance to the next frame. mOffset = (mOffset+1) % NUM_FRAME_RECORDS; mFrameRecords[mOffset].desiredPresentTime = INT64_MAX; @@ -138,19 +129,12 @@ void FrameTracker::getStats(FrameStats* outStats) const { } } -void FrameTracker::logAndResetStats(const std::string_view& name) { - Mutex::Autolock lock(mMutex); - logStatsLocked(name); - resetFrameCountersLocked(); -} - void FrameTracker::processFencesLocked() const { FrameRecord* records = const_cast<FrameRecord*>(mFrameRecords); int& numFences = const_cast<int&>(mNumFences); for (int i = 1; i < NUM_FRAME_RECORDS && numFences > 0; i++) { - size_t idx = (mOffset+NUM_FRAME_RECORDS-i) % NUM_FRAME_RECORDS; - bool updated = false; + size_t idx = (mOffset + NUM_FRAME_RECORDS - i) % NUM_FRAME_RECORDS; const std::shared_ptr<FenceTime>& rfence = records[idx].frameReadyFence; if (rfence != nullptr) { @@ -158,7 +142,6 @@ void FrameTracker::processFencesLocked() const { if (records[idx].frameReadyTime < INT64_MAX) { records[idx].frameReadyFence = nullptr; numFences--; - updated = true; } } @@ -169,58 +152,7 @@ void FrameTracker::processFencesLocked() const { if (records[idx].actualPresentTime < INT64_MAX) { records[idx].actualPresentFence = nullptr; numFences--; - updated = true; - } - } - - if (updated) { - updateStatsLocked(idx); - } - } -} - -void FrameTracker::updateStatsLocked(size_t newFrameIdx) const { - int* numFrames = const_cast<int*>(mNumFrames); - - if (mDisplayPeriod > 0 && isFrameValidLocked(newFrameIdx)) { - size_t prevFrameIdx = (newFrameIdx+NUM_FRAME_RECORDS-1) % - NUM_FRAME_RECORDS; - - if (isFrameValidLocked(prevFrameIdx)) { - nsecs_t newPresentTime = - mFrameRecords[newFrameIdx].actualPresentTime; - nsecs_t prevPresentTime = - mFrameRecords[prevFrameIdx].actualPresentTime; - - nsecs_t duration = newPresentTime - prevPresentTime; - int numPeriods = int((duration + mDisplayPeriod/2) / - mDisplayPeriod); - - for (int i = 0; i < NUM_FRAME_BUCKETS-1; i++) { - int nextBucket = 1 << (i+1); - if (numPeriods < nextBucket) { - numFrames[i]++; - return; - } } - - // The last duration bucket is a catch-all. - numFrames[NUM_FRAME_BUCKETS-1]++; - } - } -} - -void FrameTracker::resetFrameCountersLocked() { - for (int i = 0; i < NUM_FRAME_BUCKETS; i++) { - mNumFrames[i] = 0; - } -} - -void FrameTracker::logStatsLocked(const std::string_view& name) const { - for (int i = 0; i < NUM_FRAME_BUCKETS; i++) { - if (mNumFrames[i] > 0) { - EventLog::logFrameDurations(name, mNumFrames, NUM_FRAME_BUCKETS); - return; } } } diff --git a/services/surfaceflinger/FrameTracker.h b/services/surfaceflinger/FrameTracker.h index bc412aee2f..fd6fadc6dd 100644 --- a/services/surfaceflinger/FrameTracker.h +++ b/services/surfaceflinger/FrameTracker.h @@ -41,8 +41,6 @@ public: // frame time history. enum { NUM_FRAME_RECORDS = 128 }; - enum { NUM_FRAME_BUCKETS = 7 }; - FrameTracker(); // setDesiredPresentTime sets the time at which the current frame @@ -142,13 +140,6 @@ private: // doesn't grow with NUM_FRAME_RECORDS. int mNumFences; - // mNumFrames keeps a count of the number of frames with a duration in a - // particular range of vsync periods. Element n of the array stores the - // number of frames with duration in the half-inclusive range - // [2^n, 2^(n+1)). The last element of the array contains the count for - // all frames with duration greater than 2^(NUM_FRAME_BUCKETS-1). - int32_t mNumFrames[NUM_FRAME_BUCKETS]; - // mDisplayPeriod is the display refresh period of the display for which // this FrameTracker is gathering information. nsecs_t mDisplayPeriod; diff --git a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h index 0788d1abce..07a5724852 100644 --- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h +++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h @@ -61,6 +61,7 @@ struct LayerCreationArgs { ui::LayerStack layerStackToMirror = ui::INVALID_LAYER_STACK; uint32_t parentId = UNASSIGNED_LAYER_ID; uint32_t layerIdToMirror = UNASSIGNED_LAYER_ID; + std::atomic<int32_t>* pendingBuffers = 0; }; } // namespace android::surfaceflinger diff --git a/services/surfaceflinger/FrontEnd/LayerHandle.cpp b/services/surfaceflinger/FrontEnd/LayerHandle.cpp index 75e4e3ae11..ffd51a40bb 100644 --- a/services/surfaceflinger/FrontEnd/LayerHandle.cpp +++ b/services/surfaceflinger/FrontEnd/LayerHandle.cpp @@ -28,7 +28,7 @@ LayerHandle::LayerHandle(const sp<android::SurfaceFlinger>& flinger, LayerHandle::~LayerHandle() { if (mFlinger) { - mFlinger->onHandleDestroyed(this, mLayer, mLayerId); + mFlinger->onHandleDestroyed(mLayer, mLayerId); } } diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp index d709530990..da536b6660 100644 --- a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp +++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp @@ -166,7 +166,8 @@ void LayerHierarchy::dump(std::ostream& out, const std::string& prefix, } out << "(Mirroring) "; } - out << *mLayer; + + out << *mLayer << " pid=" << mLayer->ownerPid.val() << " uid=" << mLayer->ownerUid.val(); } for (size_t i = 0; i < mChildren.size(); i++) { diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index e5f6b7bcd1..58f6b96e57 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -250,6 +250,7 @@ std::string LayerSnapshot::getIsVisibleReason() const { if (drawShadows()) reason << " shadowSettings.length=" << shadowSettings.length; if (backgroundBlurRadius > 0) reason << " backgroundBlurRadius=" << backgroundBlurRadius; if (blurRegions.size() > 0) reason << " blurRegions.size()=" << blurRegions.size(); + if (contentDirty) reason << " contentDirty"; return reason.str(); } @@ -359,8 +360,9 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate uint32_t displayRotationFlags) { clientChanges = requested.what; changes = requested.changes; - contentDirty = requested.what & layer_state_t::CONTENT_DIRTY; - hasReadyFrame = requested.autoRefresh; + autoRefresh = requested.autoRefresh; + contentDirty = requested.what & layer_state_t::CONTENT_DIRTY || autoRefresh; + hasReadyFrame = autoRefresh; sidebandStreamHasFrame = requested.hasSidebandStreamFrame(); updateSurfaceDamage(requested, requested.hasReadyFrame(), forceFullDamage, surfaceDamage); @@ -411,6 +413,13 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate if (forceUpdate || requested.what & layer_state_t::eCropChanged) { geomCrop = requested.crop; } + if (forceUpdate || requested.what & layer_state_t::ePictureProfileHandleChanged) { + pictureProfileHandle = requested.pictureProfileHandle; + } + if (forceUpdate || requested.what & layer_state_t::eAppContentPriorityChanged) { + // TODO(b/337330263): Also consider the system-determined priority of the app + pictureProfilePriority = requested.appContentPriority; + } if (forceUpdate || requested.what & layer_state_t::eDefaultFrameRateCompatibilityChanged) { const auto compatibility = @@ -513,6 +522,10 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate isOpaque = contentOpaque && !roundedCorner.hasRoundedCorners() && color.a == 1.f; blendMode = getBlendMode(requested); } + + if (forceUpdate || requested.what & layer_state_t::eLutsChanged) { + luts = requested.luts; + } } } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index 398e64a4f1..b8df3ed748 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -72,11 +72,12 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { bool premultipliedAlpha; ui::Transform parentTransform; Rect bufferSize; - Rect croppedBufferSize; + FloatRect croppedBufferSize; std::shared_ptr<renderengine::ExternalTexture> externalTexture; gui::LayerMetadata layerMetadata; gui::LayerMetadata relativeLayerMetadata; bool hasReadyFrame; // used in post composition to check if there is another frame ready + bool autoRefresh; ui::Transform localTransformInverse; gui::WindowInfo inputInfo; ui::Transform localTransform; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index ee605b7a3e..4d9a9ca06e 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -116,7 +116,7 @@ ui::Transform getInputTransform(const LayerSnapshot& snapshot) { * that's already included. */ std::pair<FloatRect, bool> getInputBounds(const LayerSnapshot& snapshot, bool fillParentBounds) { - FloatRect inputBounds = snapshot.croppedBufferSize.toFloatRect(); + FloatRect inputBounds = snapshot.croppedBufferSize; if (snapshot.hasBufferOrSidebandStream() && snapshot.croppedBufferSize.isValid() && snapshot.localTransform.getType() != ui::Transform::IDENTITY) { inputBounds = snapshot.localTransform.transform(inputBounds); @@ -220,7 +220,7 @@ void handleDropInputMode(LayerSnapshot& snapshot, const LayerSnapshot& parentSna } // Check if the parent has cropped the buffer - Rect bufferSize = snapshot.croppedBufferSize; + FloatRect bufferSize = snapshot.croppedBufferSize; if (!bufferSize.isValid()) { snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED; return; @@ -261,20 +261,25 @@ void updateVisibility(LayerSnapshot& snapshot, bool visible) { } snapshot.isVisible = visible; - // TODO(b/238781169) we are ignoring this compat for now, since we will have - // to remove any optimization based on visibility. - - // For compatibility reasons we let layers which can receive input - // receive input before they have actually submitted a buffer. Because - // of this we use canReceiveInput instead of isVisible to check the - // policy-visibility, ignoring the buffer state. However for layers with - // hasInputInfo()==false we can use the real visibility state. - // We are just using these layers for occlusion detection in - // InputDispatcher, and obviously if they aren't visible they can't occlude - // anything. - const bool visibleForInput = - snapshot.hasInputInfo() ? snapshot.canReceiveInput() : snapshot.isVisible; - snapshot.inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visibleForInput); + if (FlagManager::getInstance().skip_invisible_windows_in_input()) { + snapshot.inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visible); + } else { + // TODO(b/238781169) we are ignoring this compat for now, since we will have + // to remove any optimization based on visibility. + + // For compatibility reasons we let layers which can receive input + // receive input before they have actually submitted a buffer. Because + // of this we use canReceiveInput instead of isVisible to check the + // policy-visibility, ignoring the buffer state. However for layers with + // hasInputInfo()==false we can use the real visibility state. + // We are just using these layers for occlusion detection in + // InputDispatcher, and obviously if they aren't visible they can't occlude + // anything. + const bool visibleForInput = + snapshot.hasInputInfo() ? snapshot.canReceiveInput() : snapshot.isVisible; + snapshot.inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, + !visibleForInput); + } LLOGV(snapshot.sequence, "updating visibility %s %s", visible ? "true" : "false", snapshot.getDebugString().c_str()); } @@ -314,8 +319,8 @@ void updateMetadataAndGameMode(LayerSnapshot& snapshot, const RequestedLayerStat void clearChanges(LayerSnapshot& snapshot) { snapshot.changes.clear(); snapshot.clientChanges = 0; - snapshot.contentDirty = false; - snapshot.hasReadyFrame = false; + snapshot.contentDirty = snapshot.autoRefresh; + snapshot.hasReadyFrame = snapshot.autoRefresh; snapshot.sidebandStreamHasFrame = false; snapshot.surfaceDamage.clear(); } @@ -724,10 +729,12 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a if (args.displayChanges) snapshot.changes |= RequestedLayerState::Changes::Geometry; snapshot.reachablilty = LayerSnapshot::Reachablilty::Reachable; snapshot.clientChanges |= (parentSnapshot.clientChanges & layer_state_t::AFFECTS_CHILDREN); + // mark the content as dirty if the parent state changes can dirty the child's content (for + // example alpha) + snapshot.contentDirty |= (snapshot.clientChanges & layer_state_t::CONTENT_DIRTY) != 0; snapshot.isHiddenByPolicyFromParent = parentSnapshot.isHiddenByPolicyFromParent || parentSnapshot.invalidTransform || requested.isHiddenByPolicy() || (args.excludeLayerIds.find(path.id) != args.excludeLayerIds.end()); - const bool forceUpdate = args.forceUpdate == ForceUpdateFlags::ALL || snapshot.clientChanges & layer_state_t::eReparent || snapshot.changes.any(RequestedLayerState::Changes::Visibility | @@ -970,7 +977,7 @@ void LayerSnapshotBuilder::updateRoundedCorner(LayerSnapshot& snapshot, parentRoundedCorner.radius.y *= t.getScaleY(); } - FloatRect layerCropRect = snapshot.croppedBufferSize.toFloatRect(); + FloatRect layerCropRect = snapshot.croppedBufferSize; const vec2 radius(requested.cornerRadius, requested.cornerRadius); RoundedCornerState layerSettings(layerCropRect, radius); const bool layerSettingsValid = layerSettings.hasRoundedCorners() && !layerCropRect.isEmpty(); @@ -1061,7 +1068,7 @@ void LayerSnapshotBuilder::updateLayerBounds(LayerSnapshot& snapshot, requested.externalTexture ? snapshot.bufferSize.toFloatRect() : parentBounds; snapshot.geomLayerCrop = parentBounds; if (!requested.crop.isEmpty()) { - snapshot.geomLayerCrop = snapshot.geomLayerCrop.intersect(requested.crop.toFloatRect()); + snapshot.geomLayerCrop = snapshot.geomLayerCrop.intersect(requested.crop); } snapshot.geomLayerBounds = snapshot.geomLayerBounds.intersect(snapshot.geomLayerCrop); snapshot.transformedBounds = snapshot.geomLayerTransform.transform(snapshot.geomLayerBounds); @@ -1072,10 +1079,10 @@ void LayerSnapshotBuilder::updateLayerBounds(LayerSnapshot& snapshot, snapshot.geomLayerTransform.transform(geomLayerBoundsWithoutTransparentRegion); snapshot.parentTransform = parentSnapshot.geomLayerTransform; - // Subtract the transparent region and snap to the bounds - const Rect bounds = - RequestedLayerState::reduce(snapshot.croppedBufferSize, requested.transparentRegion); if (requested.potentialCursor) { + // Subtract the transparent region and snap to the bounds + const Rect bounds = RequestedLayerState::reduce(Rect(snapshot.croppedBufferSize), + requested.transparentRegion); snapshot.cursorFrame = snapshot.geomLayerTransform.transform(bounds); } } @@ -1192,7 +1199,8 @@ void LayerSnapshotBuilder::updateInput(LayerSnapshot& snapshot, snapshot.inputInfo.inputConfig |= InputConfig::TRUSTED_OVERLAY; } - snapshot.inputInfo.contentSize = snapshot.croppedBufferSize.getSize(); + snapshot.inputInfo.contentSize = {snapshot.croppedBufferSize.getHeight(), + snapshot.croppedBufferSize.getWidth()}; // If the layer is a clone, we need to crop the input region to cloned root to prevent // touches from going outside the cloned area. @@ -1257,6 +1265,10 @@ void LayerSnapshotBuilder::forEachInputSnapshot(const ConstVisitor& visitor) con for (int i = mNumInterestingSnapshots - 1; i >= 0; i--) { LayerSnapshot& snapshot = *mSnapshots[(size_t)i]; if (!snapshot.hasInputInfo()) continue; + if (FlagManager::getInstance().skip_invisible_windows_in_input() && + snapshot.inputInfo.inputConfig.test(gui::WindowInfo::InputConfig::NOT_VISIBLE)) { + continue; + } visitor(snapshot); } } diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index 5734ccf38f..ee9302b937 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -56,7 +56,8 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) ownerUid(args.ownerUid), ownerPid(args.ownerPid), parentId(args.parentId), - layerIdToMirror(args.layerIdToMirror) { + layerIdToMirror(args.layerIdToMirror), + pendingBuffers(args.pendingBuffers) { layerId = static_cast<int32_t>(args.sequence); changes |= RequestedLayerState::Changes::Created; metadata.merge(args.metadata); @@ -96,7 +97,7 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) LLOGV(layerId, "Created %s flags=%d", getDebugString().c_str(), flags); color.a = 1.0f; - crop.makeInvalid(); + crop = {0, 0, -1, -1}; z = 0; layerStack = ui::DEFAULT_LAYER_STACK; transformToDisplayInverse = false; @@ -162,7 +163,7 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta uint64_t clientChanges = what | layer_state_t::diff(clientState); layer_state_t::merge(clientState); what = clientChanges; - LLOGV(layerId, "requested=%" PRIu64 "flags=%" PRIu64, clientState.what, clientChanges); + LLOGV(layerId, "requested=%" PRIu64 " flags=%" PRIu64 " ", clientState.what, clientChanges); if (clientState.what & layer_state_t::eFlagsChanged) { if ((oldFlags ^ flags) & @@ -473,10 +474,10 @@ Rect RequestedLayerState::getBufferSize(uint32_t displayRotationFlags) const { return Rect(0, 0, static_cast<int32_t>(bufWidth), static_cast<int32_t>(bufHeight)); } -Rect RequestedLayerState::getCroppedBufferSize(const Rect& bufferSize) const { - Rect size = bufferSize; +FloatRect RequestedLayerState::getCroppedBufferSize(const Rect& bufferSize) const { + FloatRect size = bufferSize.toFloatRect(); if (!crop.isEmpty() && size.isValid()) { - size.intersect(crop, &size); + size = size.intersect(crop); } else if (!crop.isEmpty()) { size = crop; } @@ -632,7 +633,7 @@ bool RequestedLayerState::isSimpleBufferUpdate(const layer_state_t& s) const { layer_state_t::eEdgeExtensionChanged | layer_state_t::eBufferCropChanged | layer_state_t::eDestinationFrameChanged | layer_state_t::eDimmingEnabledChanged | layer_state_t::eExtendedRangeBrightnessChanged | - layer_state_t::eDesiredHdrHeadroomChanged | + layer_state_t::eDesiredHdrHeadroomChanged | layer_state_t::eLutsChanged | (FlagManager::getInstance().latch_unsignaled_with_auto_refresh_changed() ? layer_state_t::eFlagsChanged : 0); diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h index 1d96dff336..7ddd7baf1e 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h @@ -79,7 +79,7 @@ struct RequestedLayerState : layer_state_t { bool isHiddenByPolicy() const; half4 getColor() const; Rect getBufferSize(uint32_t displayRotationFlags) const; - Rect getCroppedBufferSize(const Rect& bufferSize) const; + FloatRect getCroppedBufferSize(const Rect& bufferSize) const; Rect getBufferCrop() const; std::string getDebugString() const; std::string getDebugStringShort() const; @@ -131,6 +131,7 @@ struct RequestedLayerState : layer_state_t { uint64_t barrierFrameNumber = 0; uint32_t barrierProducerId = 0; std::string debugName; + std::atomic<int32_t>* pendingBuffers = 0; // book keeping states bool handleAlive = true; diff --git a/services/surfaceflinger/FrontEnd/readme.md b/services/surfaceflinger/FrontEnd/readme.md index e5f51a5773..6258f7e530 100644 --- a/services/surfaceflinger/FrontEnd/readme.md +++ b/services/surfaceflinger/FrontEnd/readme.md @@ -17,6 +17,29 @@ maintain policies at different levels without needing to understand the entire h This allows control to be delegated to different parts of the system - such as SystemServer, SysUI and Apps. +### Layer Drawing Order +Layers are drawn based on an inorder traversal, treating relative parents as +direct parents. Negative z-values place layers below their parent, while +non-negative values place them above. Layers with the same z-value are drawn +in creation order (newer on top). However, relying on creation order for +z-ordering is discouraged; use unique z-values whenever possible for better +control. + +Traversal pseudo code: +``` +fn traverseBottomToTop(root): + for each child node including relative children, + sorted by z then layer id, with z less than 0: + traverseBottomToTop(childNode) + + visit(root) + + for each child node including relative children, + sorted by z then layer id, with z greater than + or equal to 0: + traverseBottomToTop(childNode) +``` + ### Layer Lifecycle Layer is created by a client. The client receives a strong binder reference to the layer handle, which will keep the layer alive as long as the client holds the reference. The diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index dcb0812b67..195461f47e 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -138,7 +138,7 @@ Layer::Layer(const surfaceflinger::LayerCreationArgs& args) args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))) { ALOGV("Creating Layer %s", getDebugName()); - mDrawingState.crop.makeInvalid(); + mDrawingState.crop = {0, 0, -1, -1}; mDrawingState.sequence = 0; mDrawingState.transform.set(0, 0); mDrawingState.frameNumber = 0; @@ -154,7 +154,7 @@ Layer::Layer(const surfaceflinger::LayerCreationArgs& args) mDrawingState.metadata = args.metadata; mDrawingState.frameTimelineInfo = {}; mDrawingState.postTime = -1; - mFrameTracker.setDisplayRefreshPeriod( + mDeprecatedFrameTracker.setDisplayRefreshPeriod( args.flinger->mScheduler->getPacesetterVsyncPeriod().ns()); mOwnerUid = args.ownerUid; @@ -183,9 +183,16 @@ Layer::~Layer() { mFlinger->mTimeStats->onDestroy(layerId); mFlinger->mFrameTracer->onDestroy(layerId); - mFrameTracker.logAndResetStats(mName); mFlinger->onLayerDestroyed(this); + const auto currentTime = std::chrono::steady_clock::now(); + if (mBufferInfo.mTimeSinceDataspaceUpdate > std::chrono::steady_clock::time_point::min()) { + mFlinger->mLayerEvents.emplace_back(mOwnerUid, getSequence(), mBufferInfo.mDataspace, + std::chrono::duration_cast<std::chrono::milliseconds>( + currentTime - + mBufferInfo.mTimeSinceDataspaceUpdate)); + } + if (mDrawingState.sidebandStream != nullptr) { mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount(); } @@ -316,7 +323,7 @@ bool Layer::computeTrustedPresentationState(const FloatRect& bounds, const Float Rect Layer::getCroppedBufferSize(const State& s) const { Rect size = getBufferSize(s); - Rect crop = getCrop(s); + Rect crop = Rect(getCrop(s)); if (!crop.isEmpty() && size.isValid()) { size.intersect(crop, &size); } else if (!crop.isEmpty()) { @@ -373,7 +380,7 @@ void Layer::setTransactionFlags(uint32_t mask) { mTransactionFlags |= mask; } -bool Layer::setCrop(const Rect& crop) { +bool Layer::setCrop(const FloatRect& crop) { if (mDrawingState.crop == crop) return false; mDrawingState.sequence++; mDrawingState.crop = crop; @@ -465,6 +472,9 @@ std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForTransac getSequence(), mName, mTransactionName, /*isBuffer*/ false, gameMode); + // Buffer hasn't yet been latched, so use mDrawingState + surfaceFrame->setDesiredPresentTime(mDrawingState.desiredPresentTime); + surfaceFrame->setActualStartTime(info.startTimeNanos); // For Transactions, the post time is considered to be both queue and acquire fence time. surfaceFrame->setActualQueueTime(postTime); @@ -483,6 +493,8 @@ std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForBuffer( mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid, getSequence(), mName, debugName, /*isBuffer*/ true, gameMode); + // Buffer hasn't yet been latched, so use mDrawingState + surfaceFrame->setDesiredPresentTime(mDrawingState.desiredPresentTime); surfaceFrame->setActualStartTime(info.startTimeNanos); // For buffers, acquire fence time will set during latch. surfaceFrame->setActualQueueTime(queueTime); @@ -507,6 +519,8 @@ void Layer::setFrameTimelineVsyncForSkippedFrames(const FrameTimelineInfo& info, mOwnerPid, mOwnerUid, getSequence(), mName, debugName, /*isBuffer*/ false, gameMode); + // Buffer hasn't yet been latched, so use mDrawingState + surfaceFrame->setDesiredPresentTime(mDrawingState.desiredPresentTime); surfaceFrame->setActualStartTime(skippedFrameTimelineInfo.skippedFrameStartTimeNanos); // For Transactions, the post time is considered to be both queue and acquire fence time. surfaceFrame->setActualQueueTime(postTime); @@ -598,19 +612,42 @@ void Layer::miniDump(std::string& result, const frontend::LayerSnapshot& snapsho } void Layer::dumpFrameStats(std::string& result) const { - mFrameTracker.dumpStats(result); -} + if (FlagManager::getInstance().deprecate_frame_tracker()) { + FrameStats fs = FrameStats(); + getFrameStats(&fs); + for (auto desired = fs.desiredPresentTimesNano.begin(), + actual = fs.actualPresentTimesNano.begin(), + ready = fs.frameReadyTimesNano.begin(); + desired != fs.desiredPresentTimesNano.end() && + actual != fs.actualPresentTimesNano.end() && ready != fs.frameReadyTimesNano.end(); + ++desired, ++actual, ++ready) { + result.append(std::format("{}\t{}\t{}\n", *desired, *actual, *ready)); + } -void Layer::clearFrameStats() { - mFrameTracker.clearStats(); + result.push_back('\n'); + } else { + mDeprecatedFrameTracker.dumpStats(result); + } } -void Layer::logFrameStats() { - mFrameTracker.logAndResetStats(mName); +void Layer::clearFrameStats() { + if (FlagManager::getInstance().deprecate_frame_tracker()) { + mFrameStatsHistorySize = 0; + } else { + mDeprecatedFrameTracker.clearStats(); + } } void Layer::getFrameStats(FrameStats* outStats) const { - mFrameTracker.getStats(outStats); + if (FlagManager::getInstance().deprecate_frame_tracker()) { + if (auto ftl = getTimeline()) { + float fps = ftl->get().computeFps({getSequence()}); + ftl->get().generateFrameStats(getSequence(), mFrameStatsHistorySize, outStats); + outStats->refreshPeriodNano = Fps::fromValue(fps).getPeriodNsecs(); + } + } else { + mDeprecatedFrameTracker.getStats(outStats); + } } void Layer::onDisconnect() { @@ -686,8 +723,20 @@ void Layer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& l listener->onReleaseBuffer(callbackId, fence, currentMaxAcquiredBufferCount); } - if (mBufferReleaseChannel) { - mBufferReleaseChannel->writeReleaseFence(callbackId, fence, currentMaxAcquiredBufferCount); + if (!mBufferReleaseChannel) { + return; + } + + status_t status = mBufferReleaseChannel->writeReleaseFence(callbackId, fence, + currentMaxAcquiredBufferCount); + if (status != OK) { + int error = -status; + // callReleaseBufferCallback is called during Layer's destructor. In this case, it's + // expected to receive connection errors. + if (error != EPIPE && error != ECONNRESET) { + ALOGD("[%s] writeReleaseFence failed. error %d (%s)", getDebugName(), error, + strerror(error)); + } } } @@ -756,54 +805,6 @@ void Layer::prepareReleaseCallbacks(ftl::Future<FenceResult> futureFenceResult, } } -void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult, - ui::LayerStack layerStack, - std::function<FenceResult(FenceResult)>&& continuation) { - sp<CallbackHandle> ch = findCallbackHandle(); - - if (!FlagManager::getInstance().screenshot_fence_preservation() && continuation) { - futureFenceResult = ftl::Future(futureFenceResult).then(std::move(continuation)).share(); - } - - if (ch != nullptr) { - ch->previousReleaseCallbackId = mPreviousReleaseCallbackId; - ch->previousSharedReleaseFences.emplace_back(std::move(futureFenceResult)); - ch->name = mName; - } else if (FlagManager::getInstance().screenshot_fence_preservation()) { - // If we didn't get a release callback yet, e.g. some scenarios when capturing screenshots - // asynchronously, then make sure we don't drop the fence. - mPreviousReleaseFenceAndContinuations.emplace_back(std::move(futureFenceResult), - std::move(continuation)); - std::vector<FenceAndContinuation> mergedFences; - sp<Fence> prevFence = nullptr; - // For a layer that's frequently screenshotted, try to merge fences to make sure we don't - // grow unbounded. - for (const auto& futureAndContinuation : mPreviousReleaseFenceAndContinuations) { - auto result = futureAndContinuation.future.wait_for(0s); - if (result != std::future_status::ready) { - mergedFences.emplace_back(futureAndContinuation); - continue; - } - - mergeFence(getDebugName(), - futureAndContinuation.chain().get().value_or(Fence::NO_FENCE), prevFence); - } - if (prevFence != nullptr) { - mergedFences.emplace_back(ftl::yield(FenceResult(std::move(prevFence))).share()); - } - - mPreviousReleaseFenceAndContinuations.swap(mergedFences); - } - - if (mBufferInfo.mBuffer) { - mPreviouslyPresentedLayerStacks.push_back(layerStack); - } - - if (mDrawingState.frameNumber > 0) { - mDrawingState.previousFrameNumber = mDrawingState.frameNumber; - } -} - void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) { for (const auto& handle : mDrawingState.callbackHandles) { handle->bufferReleaseChannel = mBufferReleaseChannel; @@ -1116,22 +1117,13 @@ bool Layer::setTransactionCompletedListeners(const std::vector<sp<CallbackHandle handle->acquireTimeOrFence = mCallbackHandleAcquireTimeOrFence; handle->frameNumber = mDrawingState.frameNumber; handle->previousFrameNumber = mDrawingState.previousFrameNumber; - if (FlagManager::getInstance().ce_fence_promise() && - mPreviousReleaseBufferEndpoint == handle->listener) { + if (mPreviousReleaseBufferEndpoint == handle->listener) { // Add fence from previous screenshot now so that it can be dispatched to the // client. for (auto& [_, future] : mAdditionalPreviousReleaseFences) { handle->previousReleaseFences.emplace_back(std::move(future)); } mAdditionalPreviousReleaseFences.clear(); - } else if (FlagManager::getInstance().screenshot_fence_preservation() && - mPreviousReleaseBufferEndpoint == handle->listener) { - // Add fences from previous screenshots now so that they can be dispatched to the - // client. - for (const auto& futureAndContinution : mPreviousReleaseFenceAndContinuations) { - handle->previousSharedReleaseFences.emplace_back(futureAndContinution.chain()); - } - mPreviousReleaseFenceAndContinuations.clear(); } // Store so latched time and release fence can be set mDrawingState.callbackHandles.push_back(handle); @@ -1323,8 +1315,17 @@ void Layer::gatherBufferInfo() { } } } - if (lastDataspace != mBufferInfo.mDataspace) { + if (lastDataspace != mBufferInfo.mDataspace || + mBufferInfo.mTimeSinceDataspaceUpdate == std::chrono::steady_clock::time_point::min()) { mFlinger->mHdrLayerInfoChanged = true; + const auto currentTime = std::chrono::steady_clock::now(); + if (mBufferInfo.mTimeSinceDataspaceUpdate > std::chrono::steady_clock::time_point::min()) { + mFlinger->mLayerEvents + .emplace_back(mOwnerUid, getSequence(), lastDataspace, + std::chrono::duration_cast<std::chrono::milliseconds>( + currentTime - mBufferInfo.mTimeSinceDataspaceUpdate)); + } + mBufferInfo.mTimeSinceDataspaceUpdate = currentTime; } if (mBufferInfo.mDesiredHdrSdrRatio != mDrawingState.desiredHdrSdrRatio) { mBufferInfo.mDesiredHdrSdrRatio = mDrawingState.desiredHdrSdrRatio; @@ -1347,7 +1348,7 @@ Rect Layer::computeBufferCrop(const State& s) { } void Layer::decrementPendingBufferCount() { - int32_t pendingBuffers = --mPendingBufferTransactions; + int32_t pendingBuffers = --mPendingBuffers; tracePendingBufferCount(pendingBuffers); } @@ -1381,9 +1382,9 @@ void Layer::onCompositionPresented(const DisplayDevice* display, handle->compositorTiming = compositorTiming; } - // Update mFrameTracker. + // Update mDeprecatedFrameTracker. nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime; - mFrameTracker.setDesiredPresentTime(desiredPresentTime); + mDeprecatedFrameTracker.setDesiredPresentTime(desiredPresentTime); const int32_t layerId = getSequence(); mFlinger->mTimeStats->setDesiredTime(layerId, mCurrentFrameNumber, desiredPresentTime); @@ -1403,15 +1404,15 @@ void Layer::onCompositionPresented(const DisplayDevice* display, } } + // The SurfaceFrame's AcquireFence is the same as this. std::shared_ptr<FenceTime> frameReadyFence = mBufferInfo.mFenceTime; if (frameReadyFence->isValid()) { - mFrameTracker.setFrameReadyFence(std::move(frameReadyFence)); + mDeprecatedFrameTracker.setFrameReadyFence(std::move(frameReadyFence)); } else { // There was no fence for this frame, so assume that it was ready // to be presented at the desired present time. - mFrameTracker.setFrameReadyTime(desiredPresentTime); + mDeprecatedFrameTracker.setFrameReadyTime(desiredPresentTime); } - if (display) { const auto activeMode = display->refreshRateSelector().getActiveMode(); const Fps refreshRate = activeMode.fps; @@ -1426,7 +1427,7 @@ void Layer::onCompositionPresented(const DisplayDevice* display, mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber, presentFence, FrameTracer::FrameEvent::PRESENT_FENCE); - mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence)); + mDeprecatedFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence)); } else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId()); displayId && mFlinger->getHwComposer().isConnected(*displayId)) { // The HWC doesn't support present fences, so use the present timestamp instead. @@ -1447,11 +1448,12 @@ void Layer::onCompositionPresented(const DisplayDevice* display, mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber, actualPresentTime, FrameTracer::FrameEvent::PRESENT_FENCE); - mFrameTracker.setActualPresentTime(actualPresentTime); + mDeprecatedFrameTracker.setActualPresentTime(actualPresentTime); } } - mFrameTracker.advanceFrame(); + mFrameStatsHistorySize++; + mDeprecatedFrameTracker.advanceFrame(); mBufferInfo.mFrameLatencyNeeded = false; } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 9bc557e917..c234a75693 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -18,6 +18,7 @@ #include <android/gui/DropInputMode.h> #include <android/gui/ISurfaceComposerClient.h> +#include <com_android_graphics_surfaceflinger_flags.h> #include <ftl/small_map.h> #include <gui/BufferQueue.h> #include <gui/LayerState.h> @@ -44,6 +45,7 @@ #include <scheduler/Seamlessness.h> #include <cstdint> +#include <functional> #include <optional> #include <vector> @@ -95,7 +97,7 @@ public: struct State { int32_t sequence; // changes when visible regions can change // Crop is expressed in layer space coordinate. - Rect crop; + FloatRect crop; LayerMetadata metadata; ui::Dataspace dataspace; @@ -172,7 +174,7 @@ public: // be delayed until the resize completes. // Buffer space - bool setCrop(const Rect& crop); + bool setCrop(const FloatRect& crop); bool setTransform(uint32_t /*transform*/); bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/); @@ -198,7 +200,7 @@ public: Region getVisibleRegion(const DisplayDevice*) const; void updateLastLatchTime(nsecs_t latchtime); - Rect getCrop(const Layer::State& s) const { return s.crop; } + Rect getCrop(const Layer::State& s) const { return Rect(s.crop); } // from graphics API static ui::Dataspace translateDataspace(ui::Dataspace dataspace); @@ -242,6 +244,8 @@ public: sp<Fence> mFence; uint32_t mTransform{0}; ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN}; + std::chrono::steady_clock::time_point mTimeSinceDataspaceUpdate = + std::chrono::steady_clock::time_point::min(); Rect mCrop; PixelFormat mPixelFormat{PIXEL_FORMAT_NONE}; bool mTransformToDisplayInverse{false}; @@ -257,8 +261,6 @@ public: bool fenceHasSignaled() const; void onPreComposition(nsecs_t refreshStartTime); - void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack layerStack, - std::function<FenceResult(FenceResult)>&& continuation = nullptr); // Tracks mLastClientCompositionFence and gets the callback handle for this layer. sp<CallbackHandle> findCallbackHandle(); @@ -369,7 +371,7 @@ public: // See mPendingBufferTransactions void decrementPendingBufferCount(); - std::atomic<int32_t>* getPendingBufferCounter() { return &mPendingBufferTransactions; } + std::atomic<int32_t>* getPendingBufferCounter() { return &mPendingBuffers; } std::string getPendingBufferCounterName() { return mBlastTransactionName; } void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, const sp<GraphicBuffer>& buffer, uint64_t framenumber, @@ -387,20 +389,6 @@ public: // from the layer. std::vector<ui::LayerStack> mPreviouslyPresentedLayerStacks; - struct FenceAndContinuation { - ftl::SharedFuture<FenceResult> future; - std::function<FenceResult(FenceResult)> continuation; - - ftl::SharedFuture<FenceResult> chain() const { - if (continuation) { - return ftl::Future(future).then(continuation).share(); - } else { - return future; - } - } - }; - std::vector<FenceAndContinuation> mPreviousReleaseFenceAndContinuations; - // Release fences for buffers that have not yet received a release // callback. A release callback may not be given when capturing // screenshots asynchronously. There may be no buffer update for the @@ -447,8 +435,12 @@ protected: uint32_t mTransactionFlags{0}; + // Leverages FrameTimeline to generate FrameStats. Since FrameTimeline already has the data, + // statistical history needs to only be tracked by count of frames. + // TODO: Deprecate the '--latency-clear' and get rid of this. + std::atomic<uint16_t> mFrameStatsHistorySize; // Timestamp history for UIAutomation. Thread safe. - FrameTracker mFrameTracker; + FrameTracker mDeprecatedFrameTracker; // main thread sp<NativeHandle> mSidebandStream; @@ -562,7 +554,7 @@ private: // - If the integer increases, a buffer arrived at the server. // - If the integer decreases in latchBuffer, that buffer was latched // - If the integer decreases in setBuffer, a buffer was dropped - std::atomic<int32_t> mPendingBufferTransactions{0}; + std::atomic<int32_t> mPendingBuffers{0}; // Contains requested position and matrix updates. This will be applied if the client does // not specify a destination frame. @@ -570,6 +562,9 @@ private: std::vector<std::pair<frontend::LayerHierarchy::TraversalPath, sp<LayerFE>>> mLayerFEs; bool mHandleAlive = false; + std::optional<std::reference_wrapper<frametimeline::FrameTimeline>> getTimeline() const { + return *mFlinger->mFrameTimeline; + } }; std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate); diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp index b05f0eecc4..fea7671af2 100644 --- a/services/surfaceflinger/LayerFE.cpp +++ b/services/surfaceflinger/LayerFE.cpp @@ -26,9 +26,7 @@ #include "LayerFE.h" #include "SurfaceFlinger.h" -#include "common/FlagManager.h" #include "ui/FenceResult.h" -#include "ui/LayerStack.h" namespace android { @@ -84,8 +82,7 @@ LayerFE::~LayerFE() { // Ensures that no promise is left unfulfilled before the LayerFE is destroyed. // An unfulfilled promise could occur when a screenshot is attempted, but the // render area is invalid and there is no memory for the capture result. - if (FlagManager::getInstance().ce_fence_promise() && - mReleaseFencePromiseStatus == ReleaseFencePromiseStatus::INITIALIZED) { + if (mReleaseFencePromiseStatus == ReleaseFencePromiseStatus::INITIALIZED) { setReleaseFence(Fence::NO_FENCE); } } @@ -176,6 +173,7 @@ std::optional<compositionengine::LayerFE::LayerSettings> LayerFE::prepareClientC layerSettings.edgeExtensionEffect = mSnapshot->edgeExtensionEffect; // Record the name of the layer for debugging further down the stack. layerSettings.name = mSnapshot->name; + layerSettings.luts = mSnapshot->luts; if (hasEffect() && !hasBufferOrSidebandStream()) { prepareEffectsClientComposition(layerSettings, targetSettings); @@ -344,13 +342,15 @@ void LayerFE::prepareShadowClientComposition(LayerFE::LayerSettings& caster, caster.shadow = state; } -void LayerFE::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult, - ui::LayerStack layerStack) { - mCompositionResult.releaseFences.emplace_back(std::move(futureFenceResult), layerStack); +void LayerFE::onPictureProfileCommitted() { + mCompositionResult.wasPictureProfileCommitted = true; + mCompositionResult.pictureProfileHandle = mSnapshot->pictureProfileHandle; } -CompositionResult&& LayerFE::stealCompositionResult() { - return std::move(mCompositionResult); +CompositionResult LayerFE::stealCompositionResult() { + CompositionResult result; + std::swap(mCompositionResult, result); + return result; } const char* LayerFE::getDebugName() const { diff --git a/services/surfaceflinger/LayerFE.h b/services/surfaceflinger/LayerFE.h index 658f949640..9483aebafa 100644 --- a/services/surfaceflinger/LayerFE.h +++ b/services/surfaceflinger/LayerFE.h @@ -18,19 +18,24 @@ #include <android/gui/CachingHint.h> #include <gui/LayerMetadata.h> +#include <ui/LayerStack.h> +#include <ui/PictureProfileHandle.h> + #include "FrontEnd/LayerSnapshot.h" #include "compositionengine/LayerFE.h" #include "compositionengine/LayerFECompositionState.h" #include "renderengine/LayerSettings.h" -#include "ui/LayerStack.h" #include <ftl/future.h> namespace android { struct CompositionResult { - std::vector<std::pair<ftl::SharedFuture<FenceResult>, ui::LayerStack>> releaseFences; sp<Fence> lastClientCompositionFence = nullptr; + bool wasPictureProfileCommitted = false; + // TODO(b/337330263): Why does LayerFE coming from SF have a null composition state? + // It would be better not to duplicate this information + PictureProfileHandle pictureProfileHandle = PictureProfileHandle::NONE; }; class LayerFE : public virtual RefBase, public virtual compositionengine::LayerFE { @@ -41,7 +46,6 @@ public: // compositionengine::LayerFE overrides const compositionengine::LayerFECompositionState* getCompositionState() const override; bool onPreComposition(bool updatingOutputGeometryThisFrame) override; - void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack) override; const char* getDebugName() const override; int32_t getSequence() const override; bool hasRoundedCorners() const override; @@ -50,10 +54,11 @@ public: const gui::LayerMetadata* getRelativeMetadata() const override; std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition( compositionengine::LayerFE::ClientCompositionTargetSettings&) const; - CompositionResult&& stealCompositionResult(); + CompositionResult stealCompositionResult(); ftl::Future<FenceResult> createReleaseFenceFuture() override; void setReleaseFence(const FenceResult& releaseFence) override; LayerFE::ReleaseFencePromiseStatus getReleaseFencePromiseStatus() override; + void onPictureProfileCommitted() override; std::unique_ptr<surfaceflinger::frontend::LayerSnapshot> mSnapshot; diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp index 5eea45b436..44cd3194bc 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -106,6 +106,13 @@ void LayerProtoHelper::readFromProto(const perfetto::protos::RectProto& proto, R outRect.right = proto.right(); } +void LayerProtoHelper::readFromProto(const perfetto::protos::RectProto& proto, FloatRect& outRect) { + outRect.left = proto.left(); + outRect.top = proto.top(); + outRect.bottom = proto.bottom(); + outRect.right = proto.right(); +} + void LayerProtoHelper::writeToProto( const FloatRect& rect, std::function<perfetto::protos::FloatRectProto*()> getFloatRectProto) { @@ -180,10 +187,6 @@ void LayerProtoHelper::writeToProto( void LayerProtoHelper::writeToProto( const WindowInfo& inputInfo, std::function<perfetto::protos::InputWindowInfoProto*()> getInputWindowInfoProto) { - if (inputInfo.token == nullptr) { - return; - } - perfetto::protos::InputWindowInfoProto* proto = getInputWindowInfoProto(); proto->set_layout_params_flags(inputInfo.layoutParamsFlags.get()); proto->set_input_config(inputInfo.inputConfig.get()); @@ -427,7 +430,7 @@ void LayerProtoHelper::writeSnapshotToProto(perfetto::protos::LayerProto* layerI layerInfo->mutable_color_transform()); } - LayerProtoHelper::writeToProto(snapshot.croppedBufferSize.toFloatRect(), + LayerProtoHelper::writeToProto(snapshot.croppedBufferSize, [&]() { return layerInfo->mutable_source_bounds(); }); LayerProtoHelper::writeToProto(snapshot.transformedBounds, [&]() { return layerInfo->mutable_screen_bounds(); }); @@ -455,7 +458,7 @@ void LayerProtoHelper::writeSnapshotToProto(perfetto::protos::LayerProto* layerI return layerInfo->mutable_requested_position(); }); - LayerProtoHelper::writeToProto(requestedState.crop, + LayerProtoHelper::writeToProto(Rect(requestedState.crop), [&]() { return layerInfo->mutable_crop(); }); layerInfo->set_is_opaque(snapshot.contentOpaque); diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h index 41ea68420f..3ca553a903 100644 --- a/services/surfaceflinger/LayerProtoHelper.h +++ b/services/surfaceflinger/LayerProtoHelper.h @@ -44,6 +44,7 @@ public: std::function<perfetto::protos::RectProto*()> getRectProto); static void writeToProto(const Rect& rect, perfetto::protos::RectProto* rectProto); static void readFromProto(const perfetto::protos::RectProto& proto, Rect& outRect); + static void readFromProto(const perfetto::protos::RectProto& proto, FloatRect& outRect); static void writeToProto(const FloatRect& rect, std::function<perfetto::protos::FloatRectProto*()> getFloatRectProto); static void writeToProto(const Region& region, diff --git a/services/surfaceflinger/PowerAdvisor/Android.bp b/services/surfaceflinger/PowerAdvisor/Android.bp new file mode 100644 index 0000000000..4efbcb9510 --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/Android.bp @@ -0,0 +1,47 @@ +/* + * Copyright 2024 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. + */ + +// ADPF uses FMQ which can't build to CPP backend, and is thus not +// compatible with the rest of SF aidl for this reason + +aidl_interface { + name: "android.adpf.sessionmanager_aidl", + srcs: [ + "aidl/android/adpf/*.aidl", + ], + local_include_dir: "aidl", + unstable: true, + backend: { + java: { + sdk_version: "module_current", + enabled: true, + }, + cpp: { + enabled: false, + }, + ndk: { + enabled: true, + }, + }, +} + +cc_defaults { + name: "poweradvisor_deps", + shared_libs: [ + "libpowermanager", + "android.adpf.sessionmanager_aidl-ndk", + ], +} diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp index 334c104faf..c7d0b2c9ef 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -//#define LOG_NDEBUG 0 +// #define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_GRAPHICS @@ -24,6 +24,7 @@ #include <unistd.h> #include <cinttypes> #include <cstdint> +#include <functional> #include <optional> #include <android-base/properties.h> @@ -33,45 +34,29 @@ #include <binder/IServiceManager.h> -#include "../SurfaceFlingerProperties.h" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#include <powermanager/PowerHalController.h> +#include <powermanager/PowerHintSessionWrapper.h> +#pragma clang diagnostic pop +#include <common/FlagManager.h> #include "PowerAdvisor.h" -#include "SurfaceFlinger.h" -namespace android { -namespace Hwc2 { +namespace hal = aidl::android::hardware::power; -PowerAdvisor::~PowerAdvisor() = default; - -namespace impl { - -using aidl::android::hardware::power::Boost; -using aidl::android::hardware::power::ChannelConfig; -using aidl::android::hardware::power::Mode; -using aidl::android::hardware::power::SessionHint; -using aidl::android::hardware::power::SessionTag; -using aidl::android::hardware::power::WorkDuration; -using aidl::android::hardware::power::WorkDurationFixedV1; +namespace android::adpf::impl { -using aidl::android::hardware::common::fmq::MQDescriptor; using aidl::android::hardware::common::fmq::SynchronizedReadWrite; -using aidl::android::hardware::power::ChannelMessage; using android::hardware::EventFlag; -using ChannelMessageContents = ChannelMessage::ChannelMessageContents; -using MsgQueue = android::AidlMessageQueue<ChannelMessage, SynchronizedReadWrite>; +using ChannelMessageContents = hal::ChannelMessage::ChannelMessageContents; +using MsgQueue = android::AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>; using FlagQueue = android::AidlMessageQueue<int8_t, SynchronizedReadWrite>; PowerAdvisor::~PowerAdvisor() = default; namespace { -std::chrono::milliseconds getUpdateTimeout() { - // Default to a timeout of 80ms if nothing else is specified - static std::chrono::milliseconds timeout = - std::chrono::milliseconds(sysprop::display_update_imminent_timeout_ms(80)); - return timeout; -} - void traceExpensiveRendering(bool enabled) { if (enabled) { SFTRACE_ASYNC_BEGIN("ExpensiveRendering", 0); @@ -82,28 +67,30 @@ void traceExpensiveRendering(bool enabled) { } // namespace -PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger) - : mPowerHal(std::make_unique<power::PowerHalController>()), mFlinger(flinger) { - if (getUpdateTimeout() > 0ms) { - mScreenUpdateTimer.emplace("UpdateImminentTimer", getUpdateTimeout(), +PowerAdvisor::PowerAdvisor(std::function<void()>&& sfDisableExpensiveFn, + std::chrono::milliseconds timeout) + : mPowerHal(std::make_unique<power::PowerHalController>()) { + if (timeout > 0ms) { + mScreenUpdateTimer.emplace("UpdateImminentTimer", timeout, /* resetCallback */ nullptr, /* timeoutCallback */ - [this] { + [this, disableExpensiveFn = std::move(sfDisableExpensiveFn), + timeout] { while (true) { auto timeSinceLastUpdate = std::chrono::nanoseconds( systemTime() - mLastScreenUpdatedTime.load()); - if (timeSinceLastUpdate >= getUpdateTimeout()) { + if (timeSinceLastUpdate >= timeout) { break; } // We may try to disable expensive rendering and allow // for sending DISPLAY_UPDATE_IMMINENT hints too early if // we idled very shortly after updating the screen, so // make sure we wait enough time. - std::this_thread::sleep_for(getUpdateTimeout() - + std::this_thread::sleep_for(timeout - timeSinceLastUpdate); } mSendUpdateImminent.store(true); - mFlinger.disableExpensiveRendering(); + disableExpensiveFn(); }); } } @@ -132,7 +119,7 @@ void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expec const bool expectsExpensiveRendering = !mExpensiveDisplays.empty(); if (mNotifiedExpensiveRendering != expectsExpensiveRendering) { - auto ret = getPowerHal().setMode(Mode::EXPENSIVE_RENDERING, expectsExpensiveRendering); + auto ret = getPowerHal().setMode(hal::Mode::EXPENSIVE_RENDERING, expectsExpensiveRendering); if (!ret.isOk()) { if (ret.isUnsupported()) { mHasExpensiveRendering = false; @@ -151,7 +138,7 @@ void PowerAdvisor::notifyCpuLoadUp() { if (!mBootFinished.load()) { return; } - sendHintSessionHint(SessionHint::CPU_LOAD_UP); + sendHintSessionHint(hal::SessionHint::CPU_LOAD_UP); } void PowerAdvisor::notifyDisplayUpdateImminentAndCpuReset() { @@ -163,12 +150,12 @@ void PowerAdvisor::notifyDisplayUpdateImminentAndCpuReset() { if (mSendUpdateImminent.exchange(false)) { ALOGV("AIDL notifyDisplayUpdateImminentAndCpuReset"); - sendHintSessionHint(SessionHint::CPU_LOAD_RESET); + sendHintSessionHint(hal::SessionHint::CPU_LOAD_RESET); if (!mHasDisplayUpdateImminent) { ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it"); } else { - auto ret = getPowerHal().setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0); + auto ret = getPowerHal().setBoost(hal::Boost::DISPLAY_UPDATE_IMMINENT, 0); if (ret.isUnsupported()) { mHasDisplayUpdateImminent = false; } @@ -205,7 +192,7 @@ bool PowerAdvisor::shouldCreateSessionWithConfig() { FlagManager::getInstance().adpf_use_fmq_channel(); } -void PowerAdvisor::sendHintSessionHint(SessionHint hint) { +void PowerAdvisor::sendHintSessionHint(hal::SessionHint hint) { if (!mBootFinished || !usePowerHintSession()) { ALOGV("Power hint session is not enabled, skip sending session hint"); return; @@ -236,11 +223,12 @@ bool PowerAdvisor::ensurePowerHintSessionRunning() { static_cast<int32_t>(getuid()), mHintSessionThreadIds, mTargetDuration.ns(), - SessionTag::SURFACEFLINGER, + hal::SessionTag::SURFACEFLINGER, &mSessionConfig); if (ret.isOk()) { mHintSession = ret.value(); - if (FlagManager::getInstance().adpf_use_fmq_channel_fixed()) { + if (FlagManager::getInstance().adpf_use_fmq_channel_fixed() && + FlagManager::getInstance().adpf_fmq_sf()) { setUpFmq(); } } @@ -325,7 +313,7 @@ void PowerAdvisor::reportActualWorkDuration() { return; } SFTRACE_CALL(); - std::optional<WorkDuration> actualDuration = estimateWorkDuration(); + std::optional<hal::WorkDuration> actualDuration = estimateWorkDuration(); if (!actualDuration.has_value() || actualDuration->durationNanos < 0) { ALOGV("Failed to send actual work duration, skipping"); return; @@ -376,7 +364,7 @@ void PowerAdvisor::reportActualWorkDuration() { mHintSessionQueue.clear(); } -template <ChannelMessage::ChannelMessageContents::Tag T, class In> +template <hal::ChannelMessage::ChannelMessageContents::Tag T, class In> bool PowerAdvisor::writeHintSessionMessage(In* contents, size_t count) { if (!mMsgQueue) { ALOGV("Skip using FMQ with message tag %hhd as it's not supported", T); @@ -394,13 +382,13 @@ bool PowerAdvisor::writeHintSessionMessage(In* contents, size_t count) { } for (size_t i = 0; i < count; ++i) { if constexpr (T == ChannelMessageContents::Tag::workDuration) { - const WorkDuration& duration = contents[i]; - new (tx.getSlot(i)) ChannelMessage{ + const hal::WorkDuration& duration = contents[i]; + new (tx.getSlot(i)) hal::ChannelMessage{ .sessionID = static_cast<int32_t>(mSessionConfig.id), .timeStampNanos = (i == count - 1) ? ::android::uptimeNanos() : duration.timeStampNanos, .data = ChannelMessageContents::make<ChannelMessageContents::Tag::workDuration, - WorkDurationFixedV1>({ + hal::WorkDurationFixedV1>({ .durationNanos = duration.durationNanos, .workPeriodStartTimestampNanos = duration.workPeriodStartTimestampNanos, .cpuDurationNanos = duration.cpuDurationNanos, @@ -408,7 +396,7 @@ bool PowerAdvisor::writeHintSessionMessage(In* contents, size_t count) { }), }; } else { - new (tx.getSlot(i)) ChannelMessage{ + new (tx.getSlot(i)) hal::ChannelMessage{ .sessionID = static_cast<int32_t>(mSessionConfig.id), .timeStampNanos = ::android::uptimeNanos(), .data = ChannelMessageContents::make<T, In>(std::move(contents[i])), @@ -571,7 +559,7 @@ std::vector<DisplayId> PowerAdvisor::getOrderedDisplayIds( return sortedDisplays; } -std::optional<WorkDuration> PowerAdvisor::estimateWorkDuration() { +std::optional<hal::WorkDuration> PowerAdvisor::estimateWorkDuration() { if (!mExpectedPresentTimes.isFull() || !mCommitStartTimes.isFull()) { return std::nullopt; } @@ -656,7 +644,7 @@ std::optional<WorkDuration> PowerAdvisor::estimateWorkDuration() { Duration combinedDuration = combineTimingEstimates(totalDuration, flingerDuration); Duration cpuDuration = combineTimingEstimates(totalDurationWithoutGpu, flingerDuration); - WorkDuration duration{ + hal::WorkDuration duration{ .timeStampNanos = TimePoint::now().ns(), .durationNanos = combinedDuration.ns(), .workPeriodStartTimestampNanos = mCommitStartTimes[0].ns(), @@ -759,6 +747,4 @@ power::PowerHalController& PowerAdvisor::getPowerHal() { return *mPowerHal; } -} // namespace impl -} // namespace Hwc2 -} // namespace android +} // namespace android::adpf::impl diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h index 1076b2b79b..458b46d500 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h +++ b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h @@ -17,7 +17,7 @@ #pragma once #include <atomic> -#include <chrono> +#include <future> #include <unordered_map> #include <unordered_set> @@ -30,10 +30,8 @@ #pragma clang diagnostic ignored "-Wconversion" #include <aidl/android/hardware/power/IPower.h> #include <fmq/AidlMessageQueue.h> -#include <powermanager/PowerHalController.h> #pragma clang diagnostic pop -#include <compositionengine/impl/OutputCompositionState.h> #include <scheduler/Time.h> #include <ui/DisplayIdentification.h> #include "../Scheduler/OneShotTimer.h" @@ -42,13 +40,16 @@ using namespace std::chrono_literals; namespace android { -class SurfaceFlinger; +namespace power { +class PowerHalController; +class PowerHintSessionWrapper; +} // namespace power -namespace Hwc2 { +namespace adpf { class PowerAdvisor { public: - virtual ~PowerAdvisor(); + virtual ~PowerAdvisor() = default; // Initializes resources that cannot be initialized on construction virtual void init() = 0; @@ -113,9 +114,9 @@ namespace impl { // PowerAdvisor is a wrapper around IPower HAL which takes into account the // full state of the system when sending out power hints to things like the GPU. -class PowerAdvisor final : public Hwc2::PowerAdvisor { +class PowerAdvisor final : public adpf::PowerAdvisor { public: - PowerAdvisor(SurfaceFlinger& flinger); + PowerAdvisor(std::function<void()>&& function, std::chrono::milliseconds timeout); ~PowerAdvisor() override; void init() override; @@ -159,7 +160,6 @@ private: std::unordered_set<DisplayId> mExpensiveDisplays; bool mNotifiedExpensiveRendering = false; - SurfaceFlinger& mFlinger; std::atomic_bool mSendUpdateImminent = true; std::atomic<nsecs_t> mLastScreenUpdatedTime = 0; std::optional<scheduler::OneShotTimer> mScreenUpdateTimer; @@ -326,5 +326,5 @@ private: }; } // namespace impl -} // namespace Hwc2 +} // namespace adpf } // namespace android diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.cpp b/services/surfaceflinger/PowerAdvisor/aidl/android/adpf/ISessionManager.aidl index 2323ebb4aa..c1a6a9e63c 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.cpp +++ b/services/surfaceflinger/PowerAdvisor/aidl/android/adpf/ISessionManager.aidl @@ -1,5 +1,5 @@ /* - * Copyright 2022 The Android Open Source Project + * Copyright 2024 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. @@ -14,11 +14,13 @@ * limitations under the License. */ -#include "mock/DisplayHardware/MockIPower.h" +package android.adpf; -namespace android::Hwc2::mock { - -// Explicit default instantiation is recommended. -MockIPower::MockIPower() = default; - -} // namespace android::Hwc2::mock +/** + * Private service for SessionManager to use. Ideally this will + * eventually take the role of HintManagerService. + */ +interface ISessionManager { + oneway void associateSessionToLayers(in int sessionId, in int ownerUid, in IBinder[] layers); + oneway void trackedSessionsDied(in int[] sessionId); +} diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 06c2f26a6d..21d3396ebe 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -353,22 +353,13 @@ void RegionSamplingThread::captureSample() { sampledBounds.getSize(), ui::Dataspace::V0_SRGB, displayWeak, RenderArea::Options::CAPTURE_SECURE_LAYERS); - FenceResult fenceResult; - if (FlagManager::getInstance().single_hop_screenshot() && - FlagManager::getInstance().ce_fence_promise() && mFlinger.mRenderEngine->isThreaded()) { - std::vector<sp<LayerFE>> layerFEs; - auto displayState = mFlinger.getSnapshotsFromMainThread(renderAreaBuilder, - getLayerSnapshotsFn, layerFEs); - fenceResult = mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling, - kGrayscale, kIsProtected, kAttachGainmap, nullptr, - displayState, layerFEs) - .get(); - } else { - fenceResult = mFlinger.captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn, - buffer, kRegionSampling, kGrayscale, - kIsProtected, kAttachGainmap, nullptr) - .get(); - } + std::vector<std::pair<Layer*, sp<LayerFE>>> layers; + auto displayState = + mFlinger.getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layers); + FenceResult fenceResult = + mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling, kGrayscale, + kIsProtected, kAttachGainmap, nullptr, displayState, layers) + .get(); if (fenceResult.ok()) { fenceResult.value()->waitForever(LOG_TAG); } diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 218c56ef3d..c6d7160818 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -43,11 +43,10 @@ #include <utils/Errors.h> #include <common/FlagManager.h> +#include <scheduler/FrameRateMode.h> #include <scheduler/VsyncConfig.h> -#include "DisplayHardware/DisplayMode.h" #include "FrameTimeline.h" #include "VSyncDispatch.h" -#include "VSyncTracker.h" #include "EventThread.h" @@ -104,6 +103,10 @@ std::string toString(const DisplayEventReceiver::Event& event) { to_string(event.header.displayId).c_str(), event.hdcpLevelsChange.connectedLevel, event.hdcpLevelsChange.maxLevel); + case DisplayEventReceiver::DISPLAY_EVENT_MODE_REJECTION: + return StringPrintf("ModeRejected{displayId=%s, modeId=%u}", + to_string(event.header.displayId).c_str(), + event.modeRejection.modeId); default: return "Event{}"; } @@ -188,6 +191,18 @@ DisplayEventReceiver::Event makeHdcpLevelsChange(PhysicalDisplayId displayId, }; } +DisplayEventReceiver::Event makeModeRejection(PhysicalDisplayId displayId, DisplayModeId modeId) { + return DisplayEventReceiver::Event{ + .header = + DisplayEventReceiver::Event::Header{ + .type = DisplayEventReceiver::DISPLAY_EVENT_MODE_REJECTION, + .displayId = displayId, + .timestamp = systemTime(), + }, + .modeRejection.modeId = ftl::to_underlying(modeId), + }; +} + } // namespace EventThreadConnection::EventThreadConnection(EventThread* eventThread, uid_t callingUid, @@ -420,14 +435,24 @@ void EventThread::enableSyntheticVsync(bool enable) { mCondition.notify_all(); } +void EventThread::omitVsyncDispatching(bool omitted) { + std::lock_guard<std::mutex> lock(mMutex); + if (!mVSyncState || mVSyncState->omitted == omitted) { + return; + } + + mVSyncState->omitted = omitted; + mCondition.notify_all(); +} + void EventThread::onVsync(nsecs_t vsyncTime, nsecs_t wakeupTime, nsecs_t readyTime) { std::lock_guard<std::mutex> lock(mMutex); mLastVsyncCallbackTime = TimePoint::fromNs(vsyncTime); LOG_FATAL_IF(!mVSyncState); mVsyncTracer = (mVsyncTracer + 1) % 2; - mPendingEvents.push_back(makeVSync(mVSyncState->displayId, wakeupTime, ++mVSyncState->count, - vsyncTime, readyTime)); + mPendingEvents.push_back(makeVSync(mVsyncSchedule->getPhysicalDisplayId(), wakeupTime, + ++mVSyncState->count, vsyncTime, readyTime)); mCondition.notify_all(); } @@ -472,6 +497,21 @@ void EventThread::onHdcpLevelsChanged(PhysicalDisplayId displayId, int32_t conne mCondition.notify_all(); } +void EventThread::onModeRejected(PhysicalDisplayId displayId, DisplayModeId modeId) { + std::lock_guard<std::mutex> lock(mMutex); + + mPendingEvents.push_back(makeModeRejection(displayId, modeId)); + mCondition.notify_all(); +} + +// Merge lists of buffer stuffed Uids +void EventThread::addBufferStuffedUids(BufferStuffingMap bufferStuffedUids) { + std::lock_guard<std::mutex> lock(mMutex); + for (auto& [uid, count] : bufferStuffedUids) { + mBufferStuffedUids.emplace_or_replace(uid, count); + } +} + void EventThread::threadMain(std::unique_lock<std::mutex>& lock) { DisplayEventConsumers consumers; @@ -486,9 +526,9 @@ void EventThread::threadMain(std::unique_lock<std::mutex>& lock) { if (event->header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG) { if (event->hotplug.connectionError == 0) { if (event->hotplug.connected && !mVSyncState) { - mVSyncState.emplace(event->header.displayId); - } else if (!event->hotplug.connected && mVSyncState && - mVSyncState->displayId == event->header.displayId) { + mVSyncState.emplace(); + } else if (!event->hotplug.connected && + mVsyncSchedule->getPhysicalDisplayId() == event->header.displayId) { mVSyncState.reset(); } } else { @@ -521,7 +561,17 @@ void EventThread::threadMain(std::unique_lock<std::mutex>& lock) { } if (mVSyncState && vsyncRequested) { - mState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync; + const bool vsyncOmitted = + FlagManager::getInstance().no_vsyncs_on_screen_off() && mVSyncState->omitted; + if (vsyncOmitted) { + mState = State::Idle; + SFTRACE_INT("VsyncPendingScreenOn", 1); + } else { + mState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync; + if (FlagManager::getInstance().no_vsyncs_on_screen_off()) { + SFTRACE_INT("VsyncPendingScreenOn", 0); + } + } } else { ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected"); mState = State::Idle; @@ -559,7 +609,7 @@ void EventThread::threadMain(std::unique_lock<std::mutex>& lock) { const auto now = systemTime(SYSTEM_TIME_MONOTONIC); const auto deadlineTimestamp = now + timeout.count(); const auto expectedVSyncTime = deadlineTimestamp + timeout.count(); - mPendingEvents.push_back(makeVSync(mVSyncState->displayId, now, + mPendingEvents.push_back(makeVSync(mVsyncSchedule->getPhysicalDisplayId(), now, ++mVSyncState->count, expectedVSyncTime, deadlineTimestamp)); } @@ -701,6 +751,10 @@ void EventThread::generateFrameTimeline(VsyncEventData& outVsyncEventData, nsecs void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, const DisplayEventConsumers& consumers) { + // List of Uids that have been sent vsync data with queued buffer count. + // Used to keep track of which Uids can be removed from the map of + // buffer stuffed clients. + ftl::SmallVector<uid_t, 10> uidsPostedQueuedBuffers; for (const auto& consumer : consumers) { DisplayEventReceiver::Event copy = event; if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { @@ -710,6 +764,13 @@ void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, event.vsync.vsyncData.preferredExpectedPresentationTime(), event.vsync.vsyncData.preferredDeadlineTimestamp()); } + auto it = mBufferStuffedUids.find(consumer->mOwnerUid); + if (it != mBufferStuffedUids.end()) { + copy.vsync.vsyncData.numberQueuedBuffers = it->second; + uidsPostedQueuedBuffers.emplace_back(consumer->mOwnerUid); + } else { + copy.vsync.vsyncData.numberQueuedBuffers = 0; + } switch (consumer->postEvent(copy)) { case NO_ERROR: break; @@ -725,6 +786,12 @@ void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, removeDisplayEventConnectionLocked(consumer); } } + // The clients that have already received the queued buffer count + // can be removed from the buffer stuffed Uid list to avoid + // being sent duplicate messages. + for (auto uid : uidsPostedQueuedBuffers) { + mBufferStuffedUids.erase(uid); + } if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC && FlagManager::getInstance().vrr_config()) { mLastCommittedVsyncTime = @@ -739,7 +806,7 @@ void EventThread::dump(std::string& result) const { StringAppendF(&result, "%s: state=%s VSyncState=", mThreadName, toCString(mState)); if (mVSyncState) { StringAppendF(&result, "{displayId=%s, count=%u%s}\n", - to_string(mVSyncState->displayId).c_str(), mVSyncState->count, + to_string(mVsyncSchedule->getPhysicalDisplayId()).c_str(), mVSyncState->count, mVSyncState->synthetic ? ", synthetic" : ""); } else { StringAppendF(&result, "none\n"); diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index bbe4f9d899..18bf41643c 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -21,6 +21,7 @@ #include <gui/DisplayEventReceiver.h> #include <private/gui/BitTube.h> #include <sys/types.h> +#include <ui/DisplayId.h> #include <utils/Errors.h> #include <scheduler/FrameRateMode.h> @@ -55,6 +56,7 @@ using gui::VsyncEventData; // --------------------------------------------------------------------------- using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; +using BufferStuffingMap = ftl::SmallMap<uid_t, uint32_t, 10>; enum class VSyncRequest { None = -2, @@ -106,6 +108,8 @@ public: // Feed clients with fake VSYNC, e.g. while the display is off. virtual void enableSyntheticVsync(bool) = 0; + virtual void omitVsyncDispatching(bool) = 0; + virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0; virtual void onHotplugConnectionError(int32_t connectionError) = 0; @@ -113,6 +117,9 @@ public: // called when SF changes the active mode and apps needs to be notified about the change virtual void onModeChanged(const scheduler::FrameRateMode&) = 0; + // called when SF rejects the mode change request + virtual void onModeRejected(PhysicalDisplayId displayId, DisplayModeId modeId) = 0; + // called when SF updates the Frame Rate Override list virtual void onFrameRateOverridesChanged(PhysicalDisplayId displayId, std::vector<FrameRateOverride> overrides) = 0; @@ -134,6 +141,10 @@ public: virtual void onHdcpLevelsChanged(PhysicalDisplayId displayId, int32_t connectedLevel, int32_t maxLevel) = 0; + + // An elevated number of queued buffers in the server is detected. This propagates a + // flag to Choreographer indicating that buffer stuffing recovery should begin. + virtual void addBufferStuffedUids(BufferStuffingMap bufferStuffedUids); }; struct IEventThreadCallback { @@ -165,12 +176,16 @@ public: void enableSyntheticVsync(bool) override; + void omitVsyncDispatching(bool) override; + void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override; void onHotplugConnectionError(int32_t connectionError) override; void onModeChanged(const scheduler::FrameRateMode&) override; + void onModeRejected(PhysicalDisplayId displayId, DisplayModeId modeId) override; + void onFrameRateOverridesChanged(PhysicalDisplayId displayId, std::vector<FrameRateOverride> overrides) override; @@ -184,6 +199,8 @@ public: void onHdcpLevelsChanged(PhysicalDisplayId displayId, int32_t connectedLevel, int32_t maxLevel) override; + void addBufferStuffedUids(BufferStuffingMap bufferStuffedUids) override; + private: friend EventThreadTest; @@ -224,6 +241,10 @@ private: scheduler::VSyncCallbackRegistration mVsyncRegistration GUARDED_BY(mMutex); frametimeline::TokenManager* const mTokenManager; + // All consumers that need to recover from buffer stuffing and the number + // of their queued buffers. + BufferStuffingMap mBufferStuffedUids GUARDED_BY(mMutex); + IEventThreadCallback& mCallback; std::thread mThread; @@ -235,15 +256,14 @@ private: // VSYNC state of connected display. struct VSyncState { - explicit VSyncState(PhysicalDisplayId displayId) : displayId(displayId) {} - - const PhysicalDisplayId displayId; - // Number of VSYNC events since display was connected. uint32_t count = 0; // True if VSYNC should be faked, e.g. when display is off. bool synthetic = false; + + // True if VSYNC should not be delivered to apps. Used when the display is off. + bool omitted = false; }; // TODO(b/74619554): Create per-display threads waiting on respective VSYNC signals, diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 64b85c080e..630beb03a3 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -280,6 +280,9 @@ void LayerHistory::partitionLayers(nsecs_t now, bool isVrrDevice) { case Layer::FrameRateCompatibility::Exact: return LayerVoteType::ExplicitExact; case Layer::FrameRateCompatibility::Gte: + if (frameRate.isNoVote()) { + return LayerVoteType::NoVote; + } if (isVrrDevice) { return LayerVoteType::ExplicitGte; } else { @@ -308,6 +311,15 @@ void LayerHistory::partitionLayers(nsecs_t now, bool isVrrDevice) { const auto setFrameRateVoteType = info->isVisible() ? voteType : LayerVoteType::NoVote; + const bool hasSetFrameRateOpinion = + frameRate.isValuelessType() || frameRate.vote.rate.isValid(); + const bool hasCategoryOpinion = + frameRate.category != FrameRateCategory::NoPreference && + frameRate.category != FrameRateCategory::Default; + const bool hasFrameRateOpinionAboveGameDefault = + hasSetFrameRateOpinion || hasCategoryOpinion; + const bool hasFrameRateOpinionArr = frameRate.isValid() && !frameRate.isNoVote(); + if (gameModeFrameRateOverride.isValid()) { info->setLayerVote({gameFrameRateOverrideVoteType, gameModeFrameRateOverride}); SFTRACE_FORMAT_INSTANT("GameModeFrameRateOverride"); @@ -315,7 +327,8 @@ void LayerHistory::partitionLayers(nsecs_t now, bool isVrrDevice) { trace(*info, gameFrameRateOverrideVoteType, gameModeFrameRateOverride.getIntValue()); } - } else if (frameRate.isValid() && frameRate.isVoteValidForMrr(isVrrDevice)) { + } else if (hasFrameRateOpinionAboveGameDefault && + frameRate.isVoteValidForMrr(isVrrDevice)) { info->setLayerVote({setFrameRateVoteType, isValuelessVote ? 0_Hz : frameRate.vote.rate, frameRate.vote.seamlessness, frameRate.category}); @@ -331,8 +344,18 @@ void LayerHistory::partitionLayers(nsecs_t now, bool isVrrDevice) { trace(*info, gameFrameRateOverrideVoteType, gameDefaultFrameRateOverride.getIntValue()); } + } else if (hasFrameRateOpinionArr && frameRate.isVoteValidForMrr(isVrrDevice)) { + // This allows NoPreference votes on ARR devices after considering the + // gameDefaultFrameRateOverride (above). + info->setLayerVote({setFrameRateVoteType, + isValuelessVote ? 0_Hz : frameRate.vote.rate, + frameRate.vote.seamlessness, frameRate.category}); + if (CC_UNLIKELY(mTraceEnabled)) { + trace(*info, gameFrameRateOverrideVoteType, + frameRate.vote.rate.getIntValue()); + } } else { - if (frameRate.isValid() && !frameRate.isVoteValidForMrr(isVrrDevice)) { + if (hasFrameRateOpinionArr && !frameRate.isVoteValidForMrr(isVrrDevice)) { SFTRACE_FORMAT_INSTANT("Reset layer to ignore explicit vote on MRR %s: %s " "%s %s", info->getName().c_str(), diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index ff1926e03f..6e2b943509 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -504,7 +504,7 @@ FrameRateCompatibility LayerInfo::FrameRate::convertCompatibility(int8_t compati return FrameRateCompatibility::Exact; case ANATIVEWINDOW_FRAME_RATE_MIN: return FrameRateCompatibility::Min; - case ANATIVEWINDOW_FRAME_RATE_GTE: + case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_GTE: return FrameRateCompatibility::Gte; case ANATIVEWINDOW_FRAME_RATE_NO_VOTE: return FrameRateCompatibility::NoVote; @@ -562,7 +562,10 @@ LayerInfo::FrameRateSelectionStrategy LayerInfo::convertFrameRateSelectionStrate } bool LayerInfo::FrameRate::isNoVote() const { - return vote.type == FrameRateCompatibility::NoVote; + // A desired frame rate greater than or equal to 0 is treated as NoVote. + bool isNoVoteGte = FlagManager::getInstance().arr_setframerate_gte_enum() && + vote.type == FrameRateCompatibility::Gte && !vote.rate.isValid(); + return vote.type == FrameRateCompatibility::NoVote || isNoVoteGte; } bool LayerInfo::FrameRate::isValuelessType() const { @@ -577,7 +580,12 @@ bool LayerInfo::FrameRate::isValuelessType() const { case FrameRateCompatibility::Default: case FrameRateCompatibility::ExactOrMultiple: case FrameRateCompatibility::Exact: + return false; case FrameRateCompatibility::Gte: + if (isNoVote()) { + // Special case: GTE 0 is same as NoVote. + return true; + } return false; } } diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index ab9014e418..97f1f8ff31 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -489,6 +489,20 @@ auto RefreshRateSelector::getRankedFrameRates(const std::vector<LayerRequirement return mGetRankedFrameRatesCache->result; } +using LayerRequirementPtrs = std::vector<const RefreshRateSelector::LayerRequirement*>; +using PerUidLayerRequirements = std::unordered_map<uid_t, LayerRequirementPtrs>; + +PerUidLayerRequirements groupLayersByUid( + const std::vector<RefreshRateSelector::LayerRequirement>& layers) { + PerUidLayerRequirements layersByUid; + for (const auto& layer : layers) { + const auto it = layersByUid.emplace(layer.ownerUid, LayerRequirementPtrs()).first; + auto& layersWithSameUid = it->second; + layersWithSameUid.push_back(&layer); + } + return layersByUid; +} + auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequirement>& layers, GlobalSignals signals, Fps pacesetterFps) const -> RankedFrameRates { @@ -525,6 +539,43 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi return {ranking, GlobalSignals{.powerOnImminent = true}}; } + // A method for UI Toolkit to send the touch signal via "HighHint" category vote, + // which will touch boost when there are no ExplicitDefault layer votes on the app. + // At most one app can have the "HighHint" touch boost vote at a time. + // This accounts for cases such as games that use `setFrameRate` + // with Default compatibility to limit the frame rate and disabling touch boost. + bool isAppTouchBoost = false; + const auto layersByUid = groupLayersByUid(layers); + for (const auto& [uid, layersWithSameUid] : layersByUid) { + bool hasHighHint = false; + bool hasExplicitDefault = false; + for (const auto& layer : layersWithSameUid) { + switch (layer->vote) { + case LayerVoteType::ExplicitDefault: + hasExplicitDefault = true; + break; + case LayerVoteType::ExplicitCategory: + if (layer->frameRateCategory == FrameRateCategory::HighHint) { + hasHighHint = true; + } + break; + default: + // No action + break; + } + if (hasHighHint && hasExplicitDefault) { + break; + } + } + + if (hasHighHint && !hasExplicitDefault) { + // Focused app has touch signal (HighHint) and no frame rate ExplicitDefault votes + // (which prevents touch boost due to games use case). + isAppTouchBoost = true; + break; + } + } + int noVoteLayers = 0; // Layers that prefer the same mode ("no-op"). int noPreferenceLayers = 0; @@ -535,7 +586,6 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi int explicitExact = 0; int explicitGteLayers = 0; int explicitCategoryVoteLayers = 0; - int interactiveLayers = 0; int seamedFocusedLayers = 0; int categorySmoothSwitchOnlyLayers = 0; @@ -563,11 +613,9 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi explicitGteLayers++; break; case LayerVoteType::ExplicitCategory: - if (layer.frameRateCategory == FrameRateCategory::HighHint) { - // HighHint does not count as an explicit signal from an app. It may be - // be a touch signal. - interactiveLayers++; - } else { + // HighHint does not count as an explicit signal from an app. It is a touch signal + // sent from UI Toolkit. + if (layer.frameRateCategory != FrameRateCategory::HighHint) { explicitCategoryVoteLayers++; } if (layer.frameRateCategory == FrameRateCategory::NoPreference) { @@ -877,14 +925,11 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi return explicitCategoryVoteLayers + noVoteLayers + explicitGteLayers != layers.size(); }; - // A method for UI Toolkit to send the touch signal via "HighHint" category vote, - // which will touch boost when there are no ExplicitDefault layer votes. This is an - // incomplete solution but accounts for cases such as games that use `setFrameRate` with default + // This accounts for cases such as games that use `setFrameRate` with Default // compatibility to limit the frame rate, which should not have touch boost. - const bool hasInteraction = signals.touch || interactiveLayers > 0; - - if (hasInteraction && explicitDefaultVoteLayers == 0 && isTouchBoostForExplicitExact() && - isTouchBoostForCategory()) { + const bool isLateGlobalTouchBoost = signals.touch && explicitDefaultVoteLayers == 0; + const bool isLateTouchBoost = isLateGlobalTouchBoost || isAppTouchBoost; + if (isLateTouchBoost && isTouchBoostForExplicitExact() && isTouchBoostForCategory()) { const auto touchRefreshRates = rankFrameRates(anchorGroup, RefreshRateOrder::Descending); using fps_approx_ops::operator<; @@ -912,40 +957,6 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi return {ranking, kNoSignals}; } -using LayerRequirementPtrs = std::vector<const RefreshRateSelector::LayerRequirement*>; -using PerUidLayerRequirements = std::unordered_map<uid_t, LayerRequirementPtrs>; - -PerUidLayerRequirements groupLayersByUid( - const std::vector<RefreshRateSelector::LayerRequirement>& layers) { - PerUidLayerRequirements layersByUid; - for (const auto& layer : layers) { - const auto it = layersByUid.emplace(layer.ownerUid, LayerRequirementPtrs()).first; - auto& layersWithSameUid = it->second; - layersWithSameUid.push_back(&layer); - } - - // Remove uids that can't have a frame rate override - for (auto it = layersByUid.begin(); it != layersByUid.end();) { - const auto& layersWithSameUid = it->second; - bool skipUid = false; - for (const auto& layer : layersWithSameUid) { - using LayerVoteType = RefreshRateSelector::LayerVoteType; - - if (layer->vote == LayerVoteType::Max || layer->vote == LayerVoteType::Heuristic) { - skipUid = true; - break; - } - } - if (skipUid) { - it = layersByUid.erase(it); - } else { - ++it; - } - } - - return layersByUid; -} - auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequirement>& layers, Fps displayRefreshRate, GlobalSignals globalSignals) const @@ -990,6 +1001,7 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequireme bool hasExplicitExactOrMultiple = false; bool hasExplicitDefault = false; bool hasHighHint = false; + bool hasSkipOverrideLayer = false; for (const auto& layer : layersWithSameUid) { switch (layer->vote) { case LayerVoteType::ExplicitExactOrMultiple: @@ -1003,15 +1015,25 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vector<LayerRequireme hasHighHint = true; } break; + case LayerVoteType::Max: + case LayerVoteType::Heuristic: + hasSkipOverrideLayer = true; + break; default: // No action break; } - if (hasExplicitExactOrMultiple && hasExplicitDefault && hasHighHint) { + if (hasExplicitExactOrMultiple && hasExplicitDefault && hasHighHint && + hasSkipOverrideLayer) { break; } } + if (hasSkipOverrideLayer) { + ALOGV("%s: Skipping due to vote(s): uid=%d", __func__, uid); + continue; + } + // Layers with ExplicitExactOrMultiple expect touch boost if (globalSignals.touch && hasExplicitExactOrMultiple) { continue; @@ -1510,6 +1532,9 @@ void RefreshRateSelector::constructAvailableRefreshRates() { mPrimaryFrameRates = filterRefreshRates(policy->primaryRanges, "primary"); mAppRequestFrameRates = filterRefreshRates(policy->appRequestRanges, "app request"); + mAllFrameRates = filterRefreshRates(FpsRanges(getSupportedFrameRateRangeLocked(), + getSupportedFrameRateRangeLocked()), + "full frame rates"); } bool RefreshRateSelector::isVrrDevice() const { @@ -1535,6 +1560,27 @@ Fps RefreshRateSelector::findClosestKnownFrameRate(Fps frameRate) const { return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound); } +std::vector<float> RefreshRateSelector::getSupportedFrameRates() const { + std::scoped_lock lock(mLock); + // TODO(b/356986687) Remove the limit once we have the anchor list implementation. + const size_t frameRatesSize = std::min<size_t>(11, mAllFrameRates.size()); + std::vector<float> supportedFrameRates; + supportedFrameRates.reserve(frameRatesSize); + std::transform(mAllFrameRates.rbegin(), + mAllFrameRates.rbegin() + static_cast<int>(frameRatesSize), + std::back_inserter(supportedFrameRates), + [](FrameRateMode mode) { return mode.fps.getValue(); }); + return supportedFrameRates; +} + +FpsRange RefreshRateSelector::getSupportedFrameRateRangeLocked() const { + using fps_approx_ops::operator<; + if (mMaxRefreshRateModeIt->second->getPeakFps() < kMinSupportedFrameRate) { + return {mMaxRefreshRateModeIt->second->getPeakFps(), kMinSupportedFrameRate}; + } + return {kMinSupportedFrameRate, mMaxRefreshRateModeIt->second->getPeakFps()}; +} + auto RefreshRateSelector::getIdleTimerAction() const -> KernelIdleTimerAction { std::lock_guard lock(mLock); @@ -1638,9 +1684,9 @@ std::chrono::milliseconds RefreshRateSelector::getIdleTimerTimeout() { FpsRange RefreshRateSelector::getFrameRateCategoryRange(FrameRateCategory category) { switch (category) { case FrameRateCategory::High: - return FpsRange{90_Hz, 120_Hz}; + return FpsRange{kFrameRateCategoryRateHigh, 120_Hz}; case FrameRateCategory::Normal: - return FpsRange{60_Hz, 120_Hz}; + return FpsRange{kFrameRateCategoryRateNormal, 120_Hz}; case FrameRateCategory::Low: return FpsRange{48_Hz, 120_Hz}; case FrameRateCategory::HighHint: diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h index a398c01a8f..8e173b11c8 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h @@ -52,6 +52,12 @@ public: // The lowest Render Frame Rate that will ever be selected static constexpr Fps kMinSupportedFrameRate = 20_Hz; + // Start range for FrameRateCategory Normal and High. + static constexpr Fps kFrameRateCategoryRateHigh = 90_Hz; + static constexpr Fps kFrameRateCategoryRateNormal = 60_Hz; + static constexpr std::pair<Fps, Fps> kFrameRateCategoryRates = {kFrameRateCategoryRateNormal, + kFrameRateCategoryRateHigh}; + class Policy { static constexpr int kAllowGroupSwitchingDefault = false; @@ -433,6 +439,10 @@ public: bool isVrrDevice() const; + std::pair<Fps, Fps> getFrameRateCategoryRates() const { return kFrameRateCategoryRates; } + + std::vector<float> getSupportedFrameRates() const EXCLUDES(mLock); + private: friend struct TestableRefreshRateSelector; @@ -543,6 +553,7 @@ private: // Display modes that satisfy the Policy's ranges, filtered and sorted by refresh rate. std::vector<FrameRateMode> mPrimaryFrameRates GUARDED_BY(mLock); std::vector<FrameRateMode> mAppRequestFrameRates GUARDED_BY(mLock); + std::vector<FrameRateMode> mAllFrameRates GUARDED_BY(mLock); // Caches whether the device is VRR-compatible based on the active display mode. std::atomic_bool mIsVrrDevice = false; @@ -587,6 +598,9 @@ private: // Used to detect (lack of) frame activity. ftl::Optional<scheduler::OneShotTimer> mIdleTimer; std::atomic<bool> mIdleTimerStarted = false; + + // Returns the range of supported frame rates. + FpsRange getSupportedFrameRateRangeLocked() const REQUIRES(mLock); }; } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index ee811eb9a8..4da76f6ecc 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -203,12 +203,16 @@ void Scheduler::run() { void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, TimePoint expectedVsyncTime) { + const auto debugPresentDelay = mDebugPresentDelay.load(); + mDebugPresentDelay.store(std::nullopt); + const FrameTargeter::BeginFrameArgs beginFrameArgs = {.frameBeginTime = SchedulerClock::now(), .vsyncId = vsyncId, .expectedVsyncTime = expectedVsyncTime, .sfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration, - .hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration}; + .hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration, + .debugPresentTimeDelay = debugPresentDelay}; ftl::NonNull<const Display*> pacesetterPtr = pacesetterPtrLocked(); pacesetterPtr->targeterPtr->beginFrame(beginFrameArgs, *pacesetterPtr->schedulePtr); @@ -405,6 +409,14 @@ void Scheduler::enableSyntheticVsync(bool enable) { eventThreadFor(Cycle::Render).enableSyntheticVsync(enable); } +void Scheduler::omitVsyncDispatching(bool omitted) { + eventThreadFor(Cycle::Render).omitVsyncDispatching(omitted); + // Note: If we don't couple Cycle::LastComposite event thread, there is a black screen + // after boot. This is most likely sysui or system_server dependency on sf instance + // Choreographer + eventThreadFor(Cycle::LastComposite).omitVsyncDispatching(omitted); +} + void Scheduler::onFrameRateOverridesChanged() { const auto [pacesetterId, supportsFrameRateOverrideByContent] = [this] { std::scoped_lock lock(mDisplayLock); @@ -428,7 +440,8 @@ void Scheduler::onHdcpLevelsChanged(Cycle cycle, PhysicalDisplayId displayId, #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-value" // b/369277774 -bool Scheduler::onDisplayModeChanged(PhysicalDisplayId displayId, const FrameRateMode& mode) { +bool Scheduler::onDisplayModeChanged(PhysicalDisplayId displayId, const FrameRateMode& mode, + bool clearContentRequirements) { const bool isPacesetter = FTL_FAKE_GUARD(kMainThreadContext, (std::scoped_lock(mDisplayLock), displayId == mPacesetterDisplayId)); @@ -437,9 +450,11 @@ bool Scheduler::onDisplayModeChanged(PhysicalDisplayId displayId, const FrameRat std::lock_guard<std::mutex> lock(mPolicyLock); mPolicy.emittedModeOpt = mode; - // Invalidate content based refresh rate selection so it could be calculated - // again for the new refresh rate. - mPolicy.contentRequirements.clear(); + if (clearContentRequirements) { + // Invalidate content based refresh rate selection so it could be calculated + // again for the new refresh rate. + mPolicy.contentRequirements.clear(); + } } if (hasEventThreads()) { @@ -450,6 +465,12 @@ bool Scheduler::onDisplayModeChanged(PhysicalDisplayId displayId, const FrameRat } #pragma clang diagnostic pop +void Scheduler::onDisplayModeRejected(PhysicalDisplayId displayId, DisplayModeId modeId) { + if (hasEventThreads()) { + eventThreadFor(Cycle::Render).onModeRejected(displayId, modeId); + } +} + void Scheduler::emitModeChangeIfNeeded() { if (!mPolicy.modeOpt || !mPolicy.emittedModeOpt) { ALOGW("No mode change to emit"); @@ -940,6 +961,11 @@ bool Scheduler::updateFrameRateOverridesLocked(GlobalSignals consideredSignals, return mFrameRateOverrideMappings.updateFrameRateOverridesByContent(frameRateOverrides); } +void Scheduler::addBufferStuffedUids(BufferStuffingMap bufferStuffedUids) { + if (!mRenderEventThread) return; + mRenderEventThread->addBufferStuffedUids(std::move(bufferStuffedUids)); +} + void Scheduler::promotePacesetterDisplay(PhysicalDisplayId pacesetterId, PromotionParams params) { std::shared_ptr<VsyncSchedule> pacesetterVsyncSchedule; { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index c88b563805..a2cdd460ca 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -36,13 +36,14 @@ #include <ftl/non_null.h> #include <ftl/optional.h> #include <scheduler/Features.h> +#include <scheduler/FrameRateMode.h> #include <scheduler/FrameTargeter.h> #include <scheduler/Time.h> #include <scheduler/VsyncConfig.h> #include <ui/DisplayId.h> #include <ui/DisplayMap.h> -#include "Display/DisplayModeRequest.h" +#include "DisplayHardware/DisplayMode.h" #include "EventThread.h" #include "FrameRateOverrideMappings.h" #include "ISchedulerCallback.h" @@ -151,9 +152,13 @@ public: void dispatchHotplugError(int32_t errorCode); // Returns true if the PhysicalDisplayId is the pacesetter. - bool onDisplayModeChanged(PhysicalDisplayId, const FrameRateMode&) EXCLUDES(mPolicyLock); + bool onDisplayModeChanged(PhysicalDisplayId, const FrameRateMode&, + bool clearContentRequirements) EXCLUDES(mPolicyLock); + + void onDisplayModeRejected(PhysicalDisplayId, DisplayModeId); void enableSyntheticVsync(bool = true) REQUIRES(kMainThreadContext); + void omitVsyncDispatching(bool) REQUIRES(kMainThreadContext); void onHdcpLevelsChanged(Cycle, PhysicalDisplayId, int32_t, int32_t); @@ -204,6 +209,7 @@ public: ftl::FakeGuard guard(kMainThreadContext); resyncToHardwareVsyncLocked(id, allowToEnable, modePtr); } + void resync() override EXCLUDES(mDisplayLock); void forceNextResync() { mLastResyncTime = 0; } // Passes a vsync sample to VsyncController. Returns true if @@ -332,6 +338,12 @@ public: mPacesetterFrameDurationFractionToSkip = frameDurationFraction; } + // Propagates a flag to the EventThread indicating that buffer stuffing + // recovery should begin. + void addBufferStuffedUids(BufferStuffingMap bufferStuffedUids); + + void setDebugPresentDelay(TimePoint delay) { mDebugPresentDelay = delay; } + private: friend class TestableScheduler; @@ -459,7 +471,6 @@ private: bool throttleVsync(TimePoint, uid_t) override; // Get frame interval Period getVsyncPeriod(uid_t) override EXCLUDES(mDisplayLock); - void resync() override EXCLUDES(mDisplayLock); void onExpectedPresentTimePosted(TimePoint expectedPresentTime) override EXCLUDES(mDisplayLock); std::unique_ptr<EventThread> mRenderEventThread; @@ -597,6 +608,8 @@ private: FrameRateOverrideMappings mFrameRateOverrideMappings; SmallAreaDetectionAllowMappings mSmallAreaDetectionAllowMappings; + + std::atomic<std::optional<TimePoint>> mDebugPresentDelay; }; } // namespace scheduler diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index 6e36f02463..ff360b754c 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -458,7 +458,8 @@ void VSyncPredictor::setDisplayModePtr(ftl::NonNull<DisplayModePtr> modePtr) { Duration VSyncPredictor::ensureMinFrameDurationIsKept(TimePoint expectedPresentTime, TimePoint lastConfirmedPresentTime) { - SFTRACE_CALL(); + SFTRACE_FORMAT("%s mNumVsyncsForFrame=%d mPastExpectedPresentTimes.size()=%zu", __func__, + mNumVsyncsForFrame, mPastExpectedPresentTimes.size()); if (mNumVsyncsForFrame <= 1) { return 0ns; @@ -470,12 +471,8 @@ Duration VSyncPredictor::ensureMinFrameDurationIsKept(TimePoint expectedPresentT auto prev = lastConfirmedPresentTime.ns(); for (auto& current : mPastExpectedPresentTimes) { - if (CC_UNLIKELY(mTraceOn)) { - SFTRACE_FORMAT_INSTANT("current %.2f past last signaled fence", - static_cast<float>(current.ns() - - lastConfirmedPresentTime.ns()) / - 1e6f); - } + SFTRACE_FORMAT_INSTANT("current %.2f past last signaled fence", + static_cast<float>(current.ns() - prev) / 1e6f); const auto minPeriodViolation = current.ns() - prev + threshold < minFramePeriod.ns(); if (minPeriodViolation) { @@ -522,11 +519,9 @@ void VSyncPredictor::onFrameBegin(TimePoint expectedPresentTime, FrameTime lastS const auto front = mPastExpectedPresentTimes.front().ns(); const bool frontIsBeforeConfirmed = front < lastConfirmedPresentTime.ns() + threshold; if (frontIsBeforeConfirmed) { - if (CC_UNLIKELY(mTraceOn)) { - SFTRACE_FORMAT_INSTANT("Discarding old vsync - %.2f before last signaled fence", - static_cast<float>(lastConfirmedPresentTime.ns() - front) / - 1e6f); - } + SFTRACE_FORMAT_INSTANT("Discarding old vsync - %.2f before last signaled fence", + static_cast<float>(lastConfirmedPresentTime.ns() - front) / + 1e6f); mPastExpectedPresentTimes.pop_front(); } else { break; diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.h b/services/surfaceflinger/Scheduler/VsyncSchedule.h index 881d6789b2..e63cbb2c82 100644 --- a/services/surfaceflinger/Scheduler/VsyncSchedule.h +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.h @@ -112,6 +112,8 @@ public: bool getPendingHardwareVsyncState() const REQUIRES(kMainThreadContext); + PhysicalDisplayId getPhysicalDisplayId() const { return mId; } + protected: using ControllerPtr = std::unique_ptr<VsyncController>; diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h index 2185bb07ec..813d4dedff 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h @@ -53,6 +53,8 @@ public: TimePoint expectedPresentTime() const { return mExpectedPresentTime; } + std::optional<TimePoint> debugPresentDelay() const { return mDebugPresentTimeDelay; } + std::optional<TimePoint> earliestPresentTime() const { return mEarliestPresentTime; } // Equivalent to `expectedSignaledPresentFence` unless running N VSYNCs ahead. @@ -84,6 +86,7 @@ protected: TimePoint mFrameBeginTime; TimePoint mExpectedPresentTime; std::optional<TimePoint> mEarliestPresentTime; + std::optional<TimePoint> mDebugPresentTimeDelay; TracedOrdinal<bool> mFramePending; TracedOrdinal<bool> mFrameMissed; @@ -135,6 +138,7 @@ public: TimePoint expectedVsyncTime; Duration sfWorkDuration; Duration hwcMinWorkDuration; + std::optional<TimePoint> debugPresentTimeDelay; // used to introduce jank for testing }; void beginFrame(const BeginFrameArgs&, const IVsyncSource&); diff --git a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp index 3ee1e541c3..50199492cb 100644 --- a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp +++ b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp @@ -31,6 +31,7 @@ FrameTarget::FrameTarget(const std::string& displayLabel) std::pair<bool /* wouldBackpressure */, FrameTarget::PresentFence> FrameTarget::expectedSignaledPresentFence(Period vsyncPeriod, Period minFramePeriod) const { + SFTRACE_CALL(); if (!FlagManager::getInstance().allow_n_vsyncs_in_targeter()) { const size_t i = static_cast<size_t>(targetsVsyncsAhead<2>(minFramePeriod)); return {true, mPresentFencesLegacy[i]}; @@ -40,17 +41,28 @@ FrameTarget::expectedSignaledPresentFence(Period vsyncPeriod, Period minFramePer auto expectedPresentTime = mExpectedPresentTime; for (size_t i = mPresentFences.size(); i != 0; --i) { const auto& fence = mPresentFences[i - 1]; + SFTRACE_FORMAT_INSTANT("fence at idx: %zu expectedPresentTime in %.2f", i - 1, + ticks<std::milli, float>(fence.expectedPresentTime - + TimePoint::now())); if (fence.expectedPresentTime + minFramePeriod < expectedPresentTime - vsyncPeriod / 2) { + SFTRACE_FORMAT_INSTANT("would not backpressure"); wouldBackpressure = false; } if (fence.expectedPresentTime <= mFrameBeginTime) { + SFTRACE_FORMAT_INSTANT("fence at idx: %zu is %.2f before frame begin " + "(wouldBackpressure=%s)", + i - 1, + ticks<std::milli, float>(mFrameBeginTime - + fence.expectedPresentTime), + wouldBackpressure ? "true" : "false"); return {wouldBackpressure, fence}; } expectedPresentTime = fence.expectedPresentTime; } + SFTRACE_FORMAT_INSTANT("No fence found"); return {wouldBackpressure, PresentFence{}}; } @@ -86,6 +98,7 @@ void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& v IsFencePendingFuncPtr isFencePendingFuncPtr) { mVsyncId = args.vsyncId; mFrameBeginTime = args.frameBeginTime; + mDebugPresentTimeDelay = args.debugPresentTimeDelay; // The `expectedVsyncTime`, which was predicted when this frame was scheduled, is normally in // the future relative to `frameBeginTime`, but may not be for delayed frames. Adjust @@ -153,6 +166,12 @@ void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& v if (pastPresentTime < 0) return false; mLastSignaledFrameTime = {.signalTime = TimePoint::fromNs(pastPresentTime), .expectedPresentTime = fence.expectedPresentTime}; + SFTRACE_FORMAT_INSTANT("LastSignaledFrameTime expectedPresentTime %.2f ago, signalTime " + "%.2f ago", + ticks<std::milli, float>(mLastSignaledFrameTime.expectedPresentTime - + TimePoint::now()), + ticks<std::milli, float>(mLastSignaledFrameTime.signalTime - + TimePoint::now())); const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2; return lastScheduledPresentTime.ns() < pastPresentTime - frameMissedSlop; }(); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 326bf57f0a..05db927402 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -64,11 +64,13 @@ #include <ftl/concat.h> #include <ftl/fake_guard.h> #include <ftl/future.h> +#include <ftl/small_map.h> #include <ftl/unit.h> #include <gui/AidlUtil.h> #include <gui/BufferQueue.h> #include <gui/DebugEGLImageTracker.h> #include <gui/IProducerListener.h> +#include <gui/JankInfo.h> #include <gui/LayerMetadata.h> #include <gui/LayerState.h> #include <gui/Surface.h> @@ -83,6 +85,7 @@ #include <renderengine/RenderEngine.h> #include <renderengine/impl/ExternalTexture.h> #include <scheduler/FrameTargeter.h> +#include <statslog_surfaceflinger.h> #include <sys/types.h> #include <ui/ColorSpace.h> #include <ui/DebugUtils.h> @@ -91,6 +94,7 @@ #include <ui/DisplayStatInfo.h> #include <ui/DisplayState.h> #include <ui/DynamicDisplayInfo.h> +#include <ui/FrameRateCategoryRate.h> #include <ui/GraphicBufferAllocator.h> #include <ui/HdrRenderTypeUtils.h> #include <ui/LayerStack.h> @@ -122,6 +126,7 @@ #include <gui/SchedulingPolicy.h> #include <gui/SyncScreenCaptureListener.h> #include <ui/DisplayIdentification.h> +#include "ActivePictureUpdater.h" #include "BackgroundExecutor.h" #include "Client.h" #include "ClientCache.h" @@ -131,7 +136,6 @@ #include "DisplayHardware/FramebufferSurface.h" #include "DisplayHardware/HWComposer.h" #include "DisplayHardware/Hal.h" -#include "DisplayHardware/PowerAdvisor.h" #include "DisplayHardware/VirtualDisplaySurface.h" #include "DisplayRenderArea.h" #include "Effects/Daltonizer.h" @@ -151,6 +155,7 @@ #include "LayerVector.h" #include "MutexUtils.h" #include "NativeWindowSurface.h" +#include "PowerAdvisor/PowerAdvisor.h" #include "RegionSamplingThread.h" #include "RenderAreaBuilder.h" #include "Scheduler/EventThread.h" @@ -167,6 +172,7 @@ #include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h> #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h> +#include <aidl/android/hardware/graphics/composer3/OutputType.h> #include <aidl/android/hardware/graphics/composer3/RenderIntent.h> #undef NO_THREAD_SAFETY_ANALYSIS @@ -368,6 +374,7 @@ const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER" const String16 sRotateSurfaceFlinger("android.permission.ROTATE_SURFACE_FLINGER"); const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER"); const String16 sControlDisplayBrightness("android.permission.CONTROL_DISPLAY_BRIGHTNESS"); +const String16 sObservePictureProfiles("android.permission.OBSERVE_PICTURE_PROFILES"); const String16 sDump("android.permission.DUMP"); const String16 sCaptureBlackoutContent("android.permission.CAPTURE_BLACKOUT_CONTENT"); const String16 sInternalSystemWindow("android.permission.INTERNAL_SYSTEM_WINDOW"); @@ -424,7 +431,11 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)), mInternalDisplayDensity( getDensityFromProperty("ro.sf.lcd_density", !mEmulatedDisplayDensity)), - mPowerAdvisor(std::make_unique<Hwc2::impl::PowerAdvisor>(*this)), + mPowerAdvisor(std::make_unique< + adpf::impl::PowerAdvisor>([this] { disableExpensiveRendering(); }, + std::chrono::milliseconds( + sysprop::display_update_imminent_timeout_ms( + 80)))), mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make()), mSkipPowerOnForQuiescent(base::GetBoolProperty("ro.boot.quiescent"s, false)) { ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str()); @@ -639,11 +650,12 @@ void SurfaceFlinger::enableHalVirtualDisplays(bool enable) { } } -VirtualDisplayId SurfaceFlinger::acquireVirtualDisplay(ui::Size resolution, - ui::PixelFormat format) { +VirtualDisplayId SurfaceFlinger::acquireVirtualDisplay(ui::Size resolution, ui::PixelFormat format, + const std::string& uniqueId) { if (auto& generator = mVirtualDisplayIdGenerators.hal) { if (const auto id = generator->generateId()) { if (getHwComposer().allocateVirtualDisplay(*id, resolution, &format)) { + acquireVirtualDisplaySnapshot(*id, uniqueId); return *id; } @@ -657,6 +669,7 @@ VirtualDisplayId SurfaceFlinger::acquireVirtualDisplay(ui::Size resolution, const auto id = mVirtualDisplayIdGenerators.gpu.generateId(); LOG_ALWAYS_FATAL_IF(!id, "Failed to generate ID for GPU virtual display"); + acquireVirtualDisplaySnapshot(*id, uniqueId); return *id; } @@ -664,6 +677,7 @@ void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) { if (const auto id = HalVirtualDisplayId::tryCast(displayId)) { if (auto& generator = mVirtualDisplayIdGenerators.hal) { generator->releaseId(*id); + releaseVirtualDisplaySnapshot(*id); } return; } @@ -671,6 +685,14 @@ void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) { const auto id = GpuVirtualDisplayId::tryCast(displayId); LOG_ALWAYS_FATAL_IF(!id); mVirtualDisplayIdGenerators.gpu.releaseId(*id); + releaseVirtualDisplaySnapshot(*id); +} + +void SurfaceFlinger::releaseVirtualDisplaySnapshot(VirtualDisplayId displayId) { + std::lock_guard lock(mVirtualDisplaysMutex); + if (!mVirtualDisplays.erase(displayId)) { + ALOGW("%s: Virtual display snapshot was not removed", __func__); + } } std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const { @@ -787,6 +809,12 @@ void SurfaceFlinger::bootFinished() { })); } +bool shouldUseGraphiteIfCompiledAndSupported() { + return FlagManager::getInstance().graphite_renderengine() || + (FlagManager::getInstance().graphite_renderengine_preview_rollout() && + base::GetBoolProperty(PROPERTY_DEBUG_RENDERENGINE_GRAPHITE_PREVIEW_OPTIN, false)); +} + void chooseRenderEngineType(renderengine::RenderEngineCreationArgs::Builder& builder) { char prop[PROPERTY_VALUE_MAX]; property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, ""); @@ -815,14 +843,13 @@ void chooseRenderEngineType(renderengine::RenderEngineCreationArgs::Builder& bui // is used by layertracegenerator (which also needs SurfaceFlinger.cpp). :) #if COM_ANDROID_GRAPHICS_SURFACEFLINGER_FLAGS_GRAPHITE_RENDERENGINE || \ COM_ANDROID_GRAPHICS_SURFACEFLINGER_FLAGS_FORCE_COMPILE_GRAPHITE_RENDERENGINE - const bool useGraphite = FlagManager::getInstance().graphite_renderengine() && + const bool useGraphite = shouldUseGraphiteIfCompiledAndSupported() && renderengine::RenderEngine::canSupport(kVulkan); #else const bool useGraphite = false; - if (FlagManager::getInstance().graphite_renderengine()) { - ALOGE("RenderEngine's Graphite Skia backend was requested with the " - "debug.renderengine.graphite system property, but it is not compiled in this " - "build! Falling back to Ganesh backend selection logic."); + if (shouldUseGraphiteIfCompiledAndSupported()) { + ALOGE("RenderEngine's Graphite Skia backend was requested, but it is not compiled in " + "this build! Falling back to Ganesh backend selection logic."); } #endif const bool useVulkan = useGraphite || @@ -850,6 +877,9 @@ renderengine::RenderEngine::BlurAlgorithm chooseBlurAlgorithm(bool supportsBlur) } else if (algorithm == "kawase2") { return renderengine::RenderEngine::BlurAlgorithm::KAWASE_DUAL_FILTER; } else { + if (FlagManager::getInstance().window_blur_kawase2()) { + return renderengine::RenderEngine::BlurAlgorithm::KAWASE_DUAL_FILTER; + } return renderengine::RenderEngine::BlurAlgorithm::KAWASE; } } @@ -946,16 +976,20 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { })); })); - mLayerTracing.setTakeLayersSnapshotProtoFunction([&](uint32_t traceFlags) { - auto snapshot = perfetto::protos::LayersSnapshotProto{}; - mScheduler - ->schedule([&]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(kMainThreadContext) { - snapshot = takeLayersSnapshotProto(traceFlags, TimePoint::now(), - mLastCommittedVsyncId, true); - }) - .wait(); - return snapshot; - }); + mLayerTracing.setTakeLayersSnapshotProtoFunction( + [&](uint32_t traceFlags, + const LayerTracing::OnLayersSnapshotCallback& onLayersSnapshot) { + // Do not wait the future to avoid deadlocks + // between main and Perfetto threads (b/313130597) + static_cast<void>(mScheduler->schedule( + [&, traceFlags, onLayersSnapshot]() FTL_FAKE_GUARD(mStateLock) + FTL_FAKE_GUARD(kMainThreadContext) { + auto snapshot = + takeLayersSnapshotProto(traceFlags, TimePoint::now(), + mLastCommittedVsyncId, true); + onLayersSnapshot(std::move(snapshot)); + })); + }); // Commit secondary display(s). processDisplayChangesLocked(); @@ -1004,7 +1038,8 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { config.cacheUltraHDR = base::GetBoolProperty("ro.surface_flinger.prime_shader_cache.ultrahdr"s, false); config.cacheEdgeExtension = - base::GetBoolProperty("debug.sf.edge_extension_shader"s, true); + base::GetBoolProperty("debug.sf.prime_shader_cache.edge_extension_shader"s, + true); return getRenderEngine().primeCache(config); }); @@ -1211,6 +1246,13 @@ void SurfaceFlinger::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*& info const auto mode = display->refreshRateSelector().getActiveMode(); info->activeDisplayModeId = ftl::to_underlying(mode.modePtr->getId()); info->renderFrameRate = mode.fps.getValue(); + info->hasArrSupport = mode.modePtr->getVrrConfig() && FlagManager::getInstance().vrr_config(); + + const auto [normal, high] = display->refreshRateSelector().getFrameRateCategoryRates(); + ui::FrameRateCategoryRate frameRateCategoryRate(normal.getValue(), high.getValue()); + info->frameRateCategoryRate = frameRateCategoryRate; + + info->supportedRefreshRates = display->refreshRateSelector().getSupportedFrameRates(); info->activeColorMode = display->getCompositionDisplay()->getState().colorMode; info->hdrCapabilities = filterOut4k30(display->getHdrCapabilities()); @@ -1342,7 +1384,8 @@ void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode) { mScheduler->updatePhaseConfiguration(displayId, mode.fps); if (emitEvent) { - mScheduler->onDisplayModeChanged(displayId, mode); + mScheduler->onDisplayModeChanged(displayId, mode, + /*clearContentRequirements*/ false); } break; case DesiredModeAction::None: @@ -1401,8 +1444,6 @@ status_t SurfaceFlinger::setActiveModeFromBackdoor(const sp<display::DisplayToke return future.get(); } -// TODO: b/241285876 - Restore thread safety analysis once mStateLock below is unconditional. -[[clang::no_thread_safety_analysis]] void SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) { SFTRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str()); @@ -1418,8 +1459,6 @@ void SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) { if (const auto oldResolution = mDisplayModeController.getActiveMode(displayId).modePtr->getResolution(); oldResolution != activeMode.modePtr->getResolution()) { - ConditionalLock lock(mStateLock, !FlagManager::getInstance().connected_display()); - auto& state = mCurrentState.displays.editValueFor(getPhysicalDisplayTokenLocked(displayId)); // We need to generate new sequenceId in order to recreate the display (and this // way the framebuffer). @@ -1437,7 +1476,7 @@ void SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) { mScheduler->updatePhaseConfiguration(displayId, activeMode.fps); if (pendingModeOpt->emitEvent) { - mScheduler->onDisplayModeChanged(displayId, activeMode); + mScheduler->onDisplayModeChanged(displayId, activeMode, /*clearContentRequirements*/ true); } } @@ -1508,8 +1547,15 @@ void SurfaceFlinger::initiateDisplayModeChanges() { constraints.seamlessRequired = false; hal::VsyncPeriodChangeTimeline outTimeline; - if (!mDisplayModeController.initiateModeChange(displayId, std::move(*desiredModeOpt), - constraints, outTimeline)) { + const auto error = + mDisplayModeController.initiateModeChange(displayId, std::move(*desiredModeOpt), + constraints, outTimeline); + if (error != display::DisplayModeController::ModeChangeResult::Changed) { + dropModeRequest(displayId); + if (FlagManager::getInstance().display_config_error_hal() && + error == display::DisplayModeController::ModeChangeResult::Rejected) { + mScheduler->onDisplayModeRejected(displayId, desiredModeId); + } continue; } @@ -1650,6 +1696,25 @@ status_t SurfaceFlinger::getOverlaySupport(gui::OverlayProperties* outProperties outProperties->combinations.emplace_back(outCombination); } outProperties->supportMixedColorSpaces = aidlProperties.supportMixedColorSpaces; + if (aidlProperties.lutProperties) { + std::vector<gui::LutProperties> outLutProperties; + for (auto properties : *aidlProperties.lutProperties) { + if (!properties) { + gui::LutProperties currentProperties; + currentProperties.dimension = + static_cast<gui::LutProperties::Dimension>(properties->dimension); + currentProperties.size = properties->size; + currentProperties.samplingKeys.reserve(properties->samplingKeys.size()); + std::transform(properties->samplingKeys.cbegin(), properties->samplingKeys.cend(), + std::back_inserter(currentProperties.samplingKeys), + [](const auto& val) { + return static_cast<gui::LutProperties::SamplingKey>(val); + }); + outLutProperties.push_back(std::move(currentProperties)); + } + } + outProperties->lutProperties.emplace(outLutProperties.begin(), outLutProperties.end()); + } return NO_ERROR; } @@ -1804,6 +1869,24 @@ void SurfaceFlinger::setGameContentType(const sp<IBinder>& displayToken, bool on })); } +status_t SurfaceFlinger::getMaxLayerPictureProfiles(const sp<IBinder>& displayToken, + int32_t* outMaxProfiles) { + const char* const whence = __func__; + auto future = mScheduler->schedule([=, this]() FTL_FAKE_GUARD(mStateLock) { + const ssize_t index = mCurrentState.displays.indexOfKey(displayToken); + if (index < 0) { + ALOGE("%s: Invalid display token %p", whence, displayToken.get()); + return 0; + } + const DisplayDeviceState& state = mCurrentState.displays.valueAt(index); + return state.maxLayerPictureProfiles > 0 ? state.maxLayerPictureProfiles + : state.hasPictureProcessing ? 1 + : 0; + }); + *outMaxProfiles = future.get(); + return NO_ERROR; +} + status_t SurfaceFlinger::overrideHdrTypes(const sp<IBinder>& displayToken, const std::vector<ui::Hdr>& hdrTypes) { Mutex::Autolock lock(mStateLock); @@ -2214,12 +2297,23 @@ void SurfaceFlinger::onComposerHalHotplugEvent(hal::HWDisplayId hwcDisplayId, return; } - if (FlagManager::getInstance().hotplug2()) { - // TODO(b/311403559): use enum type instead of int + if (event < DisplayHotplugEvent::ERROR_LINK_UNSTABLE) { + // This needs to be kept in sync with DisplayHotplugEvent to prevent passing new errors. const auto errorCode = static_cast<int32_t>(event); - ALOGD("%s: Hotplug error %d for hwcDisplayId %" PRIu64, __func__, errorCode, hwcDisplayId); - mScheduler->dispatchHotplugError(errorCode); + ALOGW("%s: Unknown hotplug error %d for hwcDisplayId %" PRIu64, __func__, errorCode, + hwcDisplayId); + return; } + + if (event == DisplayHotplugEvent::ERROR_LINK_UNSTABLE && + !FlagManager::getInstance().display_config_error_hal()) { + return; + } + + // TODO(b/311403559): use enum type instead of int + const auto errorCode = static_cast<int32_t>(event); + ALOGD("%s: Hotplug error %d for hwcDisplayId %" PRIu64, __func__, errorCode, hwcDisplayId); + mScheduler->dispatchHotplugError(errorCode); } void SurfaceFlinger::onComposerHalVsyncPeriodTimingChanged( @@ -2501,17 +2595,13 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, frontend::LayerSnapshot* snapshot = mLayerSnapshotBuilder.getSnapshot(it->second->sequence); gui::GameMode gameMode = (snapshot) ? snapshot->gameMode : gui::GameMode::Unsupported; mLayersWithQueuedFrames.emplace(it->second, gameMode); - mLayersIdsWithQueuedFrames.emplace(it->second->sequence); } updateLayerHistory(latchTime); mLayerSnapshotBuilder.forEachSnapshot([&](const frontend::LayerSnapshot& snapshot) { - // update output dirty region if we have a queued buffer that is visible or a snapshot - // recently became invisible - // TODO(b/360050020) investigate if we need to update dirty region when layer color changes - if ((snapshot.isVisible && - (mLayersIdsWithQueuedFrames.find(snapshot.path.id) != - mLayersIdsWithQueuedFrames.end())) || + // update output's dirty region if a snapshot is visible and its + // content is dirty or if a snapshot recently became invisible + if ((snapshot.isVisible && snapshot.contentDirty) || (!snapshot.isVisible && snapshot.changes.test(Changes::Visibility))) { Region visibleReg; visibleReg.set(snapshot.transformedBoundsWithoutTransparentRegion); @@ -2565,7 +2655,7 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId, } { - ConditionalLock lock(mStateLock, FlagManager::getInstance().connected_display()); + Mutex::Autolock lock(mStateLock); for (const auto [displayId, _] : frameTargets) { if (mDisplayModeController.isModeSetPending(displayId)) { @@ -2668,13 +2758,6 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId, mScheduler->chooseRefreshRateForContent(&mLayerHierarchyBuilder.getHierarchy(), updateAttachedChoreographer); - if (FlagManager::getInstance().connected_display()) { - initiateDisplayModeChanges(); - } - } - - if (!FlagManager::getInstance().connected_display()) { - ftl::FakeGuard guard(mStateLock); initiateDisplayModeChanges(); } @@ -2737,16 +2820,6 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( compositionengine::Feature::kSnapshotLayerMetadata); refreshArgs.bufferIdsToUncache = std::move(mBufferIdsToUncache); - - if (!FlagManager::getInstance().ce_fence_promise()) { - refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size()); - for (auto& [layer, _] : mLayersWithQueuedFrames) { - if (const auto& layerFE = layer->getCompositionEngineLayerFE( - {static_cast<uint32_t>(layer->sequence)})) - refreshArgs.layersWithQueuedFrames.push_back(layerFE); - } - } - refreshArgs.outputColorSetting = mDisplayColorSetting; refreshArgs.forceOutputColorMode = mForceColorMode; @@ -2810,51 +2883,38 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( layer->onPreComposition(refreshArgs.refreshStartTime); } - if (FlagManager::getInstance().ce_fence_promise()) { - for (auto& [layer, layerFE] : layers) { - attachReleaseFenceFutureToLayer(layer, layerFE, - layerFE->mSnapshot->outputFilter.layerStack); - } - - refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size()); - for (auto& [layer, _] : mLayersWithQueuedFrames) { - if (const auto& layerFE = layer->getCompositionEngineLayerFE( - {static_cast<uint32_t>(layer->sequence)})) { - refreshArgs.layersWithQueuedFrames.push_back(layerFE); - // Some layers are not displayed and do not yet have a future release fence - if (layerFE->getReleaseFencePromiseStatus() == - LayerFE::ReleaseFencePromiseStatus::UNINITIALIZED || - layerFE->getReleaseFencePromiseStatus() == - LayerFE::ReleaseFencePromiseStatus::FULFILLED) { - // layerStack is invalid because layer is not on a display - attachReleaseFenceFutureToLayer(layer.get(), layerFE.get(), - ui::INVALID_LAYER_STACK); - } + for (auto& [layer, layerFE] : layers) { + attachReleaseFenceFutureToLayer(layer, layerFE, + layerFE->mSnapshot->outputFilter.layerStack); + } + + refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size()); + for (auto& [layer, _] : mLayersWithQueuedFrames) { + if (const auto& layerFE = + layer->getCompositionEngineLayerFE({static_cast<uint32_t>(layer->sequence)})) { + refreshArgs.layersWithQueuedFrames.push_back(layerFE); + // Some layers are not displayed and do not yet have a future release fence + if (layerFE->getReleaseFencePromiseStatus() == + LayerFE::ReleaseFencePromiseStatus::UNINITIALIZED || + layerFE->getReleaseFencePromiseStatus() == + LayerFE::ReleaseFencePromiseStatus::FULFILLED) { + // layerStack is invalid because layer is not on a display + attachReleaseFenceFutureToLayer(layer.get(), layerFE.get(), + ui::INVALID_LAYER_STACK); } } + } - mCompositionEngine->present(refreshArgs); - moveSnapshotsFromCompositionArgs(refreshArgs, layers); + mCompositionEngine->present(refreshArgs); + moveSnapshotsFromCompositionArgs(refreshArgs, layers); - for (auto& [layer, layerFE] : layers) { - CompositionResult compositionResult{layerFE->stealCompositionResult()}; - if (compositionResult.lastClientCompositionFence) { - layer->setWasClientComposed(compositionResult.lastClientCompositionFence); - } + for (auto& [layer, layerFE] : layers) { + CompositionResult compositionResult{layerFE->stealCompositionResult()}; + if (compositionResult.lastClientCompositionFence) { + layer->setWasClientComposed(compositionResult.lastClientCompositionFence); } - - } else { - mCompositionEngine->present(refreshArgs); - moveSnapshotsFromCompositionArgs(refreshArgs, layers); - - for (auto [layer, layerFE] : layers) { - CompositionResult compositionResult{layerFE->stealCompositionResult()}; - for (auto& [releaseFence, layerStack] : compositionResult.releaseFences) { - layer->onLayerDisplayed(std::move(releaseFence), layerStack); - } - if (compositionResult.lastClientCompositionFence) { - layer->setWasClientComposed(compositionResult.lastClientCompositionFence); - } + if (com_android_graphics_libgui_flags_apply_picture_profiles()) { + mActivePictureUpdater.onLayerComposed(*layer, *layerFE, compositionResult); } } @@ -2927,7 +2987,6 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( mScheduler->modulateVsync({}, &VsyncModulator::onDisplayRefresh, hasGpuUseOrReuse); mLayersWithQueuedFrames.clear(); - mLayersIdsWithQueuedFrames.clear(); doActiveLayersTracingIfNeeded(true, mVisibleRegionsDirty, pacesetterTarget.frameBeginTime(), vsyncId); @@ -3067,12 +3126,40 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, const TimePoint presentTime = TimePoint::now(); + // The Uids of layer owners that are in buffer stuffing mode, and their elevated + // buffer counts. Messages to start recovery are sent exclusively to these Uids. + BufferStuffingMap bufferStuffedUids; + // Set presentation information before calling Layer::releasePendingBuffer, such that jank // information from previous' frame classification is already available when sending jank info // to clients, so they get jank classification as early as possible. mFrameTimeline->setSfPresent(presentTime.ns(), pacesetterPresentFenceTime, pacesetterGpuCompositionDoneFenceTime); + // Find and register any layers that are in buffer stuffing mode + const auto& presentFrames = mFrameTimeline->getPresentFrames(); + + for (const auto& frame : presentFrames) { + const auto& layer = mLayerLifecycleManager.getLayerFromId(frame->getLayerId()); + if (!layer) continue; + uint32_t numberQueuedBuffers = layer->pendingBuffers ? layer->pendingBuffers->load() : 0; + int32_t jankType = frame->getJankType().value_or(JankType::None); + if (jankType & JankType::BufferStuffing && + layer->flags & layer_state_t::eRecoverableFromBufferStuffing) { + auto [it, wasEmplaced] = + bufferStuffedUids.try_emplace(layer->ownerUid.val(), numberQueuedBuffers); + // Update with maximum number of queued buffers, allows clients drawing + // multiple windows to account for the most severely stuffed window + if (!wasEmplaced && it->second < numberQueuedBuffers) { + it->second = numberQueuedBuffers; + } + } + } + + if (!bufferStuffedUids.empty()) { + mScheduler->addBufferStuffedUids(std::move(bufferStuffedUids)); + } + // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might // be sampled a little later than when we started doing work for this frame, // but that should be okay since CompositorTiming has snapping logic. @@ -3109,13 +3196,8 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, auto optDisplay = layerStackToDisplay.get(layerStack); if (optDisplay && !optDisplay->get()->isVirtual()) { auto fence = getHwComposer().getPresentFence(optDisplay->get()->getPhysicalId()); - if (FlagManager::getInstance().ce_fence_promise()) { - layer->prepareReleaseCallbacks(ftl::yield<FenceResult>(fence), - ui::INVALID_LAYER_STACK); - } else { - layer->onLayerDisplayed(ftl::yield<FenceResult>(fence).share(), - ui::INVALID_LAYER_STACK); - } + layer->prepareReleaseCallbacks(ftl::yield<FenceResult>(fence), + ui::INVALID_LAYER_STACK); } } layer->releasePendingBuffer(presentTime.ns()); @@ -3129,9 +3211,23 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, layer->releasePendingBuffer(presentTime.ns()); } + for (const auto& layerEvent : mLayerEvents) { + auto result = + stats::stats_write(stats::SURFACE_CONTROL_EVENT, + static_cast<int32_t>(layerEvent.uid), + static_cast<int64_t>(layerEvent.timeSinceLastEvent.count()), + static_cast<int32_t>(layerEvent.dataspace)); + if (result < 0) { + ALOGW("Failed to report layer event with error: %d", result); + } + } + mLayerEvents.clear(); + std::vector<std::pair<std::shared_ptr<compositionengine::Display>, sp<HdrLayerInfoReporter>>> hdrInfoListeners; - bool haveNewListeners = false; + bool haveNewHdrInfoListeners = false; + sp<gui::IActivePictureListener> activePictureListener; + bool haveNewActivePictureListener = false; { Mutex::Autolock lock(mStateLock); if (mFpsReporter) { @@ -3141,6 +3237,7 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, if (mTunnelModeEnabledReporter) { mTunnelModeEnabledReporter->updateTunnelModeStatus(); } + hdrInfoListeners.reserve(mHdrLayerInfoListeners.size()); for (const auto& [displayId, reporter] : mHdrLayerInfoListeners) { if (reporter && reporter->hasListeners()) { @@ -3149,11 +3246,15 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, } } } - haveNewListeners = mAddingHDRLayerInfoListener; // grab this with state lock + haveNewHdrInfoListeners = mAddingHDRLayerInfoListener; // grab this with state lock mAddingHDRLayerInfoListener = false; + + activePictureListener = mActivePictureListener; + haveNewActivePictureListener = mHaveNewActivePictureListener; + mHaveNewActivePictureListener = false; } - if (haveNewListeners || mHdrLayerInfoChanged) { + if (haveNewHdrInfoListeners || mHdrLayerInfoChanged) { for (auto& [compositionDisplay, listener] : hdrInfoListeners) { HdrLayerInfoReporter::HdrLayerInfo info; int32_t maxArea = 0; @@ -3171,7 +3272,15 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, snapshot.desiredHdrSdrRatio < 1.f ? std::numeric_limits<float>::infinity() : snapshot.desiredHdrSdrRatio; - info.mergeDesiredRatio(desiredHdrSdrRatio); + + float desiredRatio = desiredHdrSdrRatio; + if (FlagManager::getInstance().begone_bright_hlg() && + desiredHdrSdrRatio == + std::numeric_limits<float>::infinity()) { + desiredRatio = getIdealizedMaxHeadroom(snapshot.dataspace); + } + + info.mergeDesiredRatio(desiredRatio); info.numberOfHdrLayers++; const auto displayFrame = outputLayer->getState().displayFrame; const int32_t area = @@ -3203,9 +3312,19 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, listener->dispatchHdrLayerInfo(info); } } - mHdrLayerInfoChanged = false; + if (com_android_graphics_libgui_flags_apply_picture_profiles()) { + // Track, update and notify changes to active pictures - layers that are undergoing picture + // processing + if (mActivePictureUpdater.updateAndHasChanged() || haveNewActivePictureListener) { + if (activePictureListener) { + activePictureListener->onActivePicturesChanged( + mActivePictureUpdater.getActivePictures()); + } + } + } + mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */); mTransactionCallbackInvoker.clearCompletedTransactions(); @@ -3264,8 +3383,6 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, // getTotalSize returns the total number of buffers that were allocated by SurfaceFlinger SFTRACE_INT64("Total Buffer Size", GraphicBufferAllocator::get().getTotalSize()); } - - logFrameStats(presentTime); } void SurfaceFlinger::commitTransactions() { @@ -3402,6 +3519,9 @@ std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes( DisplayModes newModes; for (const auto& hwcMode : hwcModes) { const auto id = nextModeId++; + OutputType hdrOutputType = FlagManager::getInstance().connected_display_hdr() + ? hwcMode.hdrOutputType + : OutputType::INVALID; newModes.try_emplace(id, DisplayMode::Builder(hwcMode.hwcId) .setId(id) @@ -3412,6 +3532,7 @@ std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes( .setDpiX(hwcMode.dpiX) .setDpiY(hwcMode.dpiY) .setGroup(hwcMode.configGroup) + .setHdrOutputType(hdrOutputType) .build()); } @@ -3453,10 +3574,8 @@ bool SurfaceFlinger::configureLocked() { processHotplugConnect(displayId, hwcDisplayId, std::move(*info), displayString.c_str()); if (!activeModeIdOpt) { - if (FlagManager::getInstance().hotplug2()) { - mScheduler->dispatchHotplugError( - static_cast<int32_t>(DisplayHotplugEvent::ERROR_UNKNOWN)); - } + mScheduler->dispatchHotplugError( + static_cast<int32_t>(DisplayHotplugEvent::ERROR_UNKNOWN)); getHwComposer().disconnectDisplay(displayId); continue; } @@ -3547,7 +3666,9 @@ std::optional<DisplayModeId> SurfaceFlinger::processHotplugConnect(PhysicalDispl } state.isProtected = true; state.displayName = std::move(info.name); - + state.maxLayerPictureProfiles = getHwComposer().getMaxLayerPictureProfiles(displayId); + state.hasPictureProcessing = + getHwComposer().hasDisplayCapability(displayId, DisplayCapability::PICTURE_PROCESSING); mCurrentState.displays.add(token, state); ALOGI("Connecting %s", displayString); return activeModeId; @@ -3655,6 +3776,26 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( return display; } +void SurfaceFlinger::incRefreshableDisplays() { + if (FlagManager::getInstance().no_vsyncs_on_screen_off()) { + mRefreshableDisplays++; + if (mRefreshableDisplays == 1) { + ftl::FakeGuard guard(kMainThreadContext); + mScheduler->omitVsyncDispatching(false); + } + } +} + +void SurfaceFlinger::decRefreshableDisplays() { + if (FlagManager::getInstance().no_vsyncs_on_screen_off()) { + mRefreshableDisplays--; + if (mRefreshableDisplays == 0) { + ftl::FakeGuard guard(kMainThreadContext); + mScheduler->omitVsyncDispatching(true); + } + } +} + void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState& state) { ui::Size resolution(0, 0); @@ -3682,12 +3823,14 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, if (const auto& physical = state.physical) { builder.setId(physical->id); } else { - builder.setId(acquireVirtualDisplay(resolution, pixelFormat)); + builder.setId(acquireVirtualDisplay(resolution, pixelFormat, state.uniqueId)); } builder.setPixels(resolution); builder.setIsSecure(state.isSecure); builder.setIsProtected(state.isProtected); + builder.setHasPictureProcessing(state.hasPictureProcessing); + builder.setMaxLayerPictureProfiles(state.maxLayerPictureProfiles); builder.setPowerAdvisor(mPowerAdvisor.get()); builder.setName(state.displayName); auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); @@ -3746,6 +3889,10 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, display->adjustRefreshRate(mScheduler->getPacesetterRefreshRate()); } + if (display->isRefreshable()) { + incRefreshableDisplays(); + } + mDisplays.try_emplace(displayToken, std::move(display)); // For an external display, loadDisplayModes already attempted to select the same mode @@ -3780,6 +3927,10 @@ void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) { } else { mScheduler->unregisterDisplay(display->getPhysicalId(), mActiveDisplayId); } + + if (display->isRefreshable()) { + decRefreshableDisplays(); + } } mDisplays.erase(displayToken); @@ -3814,6 +3965,10 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, if (display->isVirtual()) { releaseVirtualDisplay(display->getVirtualId()); } + + if (display->isRefreshable()) { + decRefreshableDisplays(); + } } mDisplays.erase(displayToken); @@ -3978,7 +4133,8 @@ void SurfaceFlinger::updateInputFlinger(VsyncId vsyncId, TimePoint frameTime) { inputWindowCommands = std::move(mInputWindowCommands), inputFlinger = mInputFlinger, this, - visibleWindowsChanged, vsyncId, frameTime]() { + visibleWindowsChanged, vsyncId, + frameTime]() mutable { SFTRACE_NAME("BackgroundExecutor::updateInputFlinger"); if (updateWindowInfo) { mWindowInfosListenerInvoker @@ -4389,6 +4545,7 @@ void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule sche SFTRACE_INT("mTransactionFlags", transactionFlags); if (const bool scheduled = transactionFlags & mask; !scheduled) { + mScheduler->resync(); scheduleCommit(frameHint); } else if (frameHint == FrameHint::kActive) { // Even if the next frame is already scheduled, we should reset the idle timer @@ -4698,6 +4855,7 @@ status_t SurfaceFlinger::setTransactionState( for (auto& state : states) { resolvedStates.emplace_back(std::move(state)); auto& resolvedState = resolvedStates.back(); + resolvedState.layerId = LayerHandle::getLayerId(resolvedState.state.surface); if (resolvedState.state.hasBufferChanges() && resolvedState.state.hasValidBuffer() && resolvedState.state.surface) { sp<Layer> layer = LayerHandle::getLayer(resolvedState.state.surface); @@ -4709,9 +4867,8 @@ status_t SurfaceFlinger::setTransactionState( if (resolvedState.externalTexture) { resolvedState.state.bufferData->buffer = resolvedState.externalTexture->getBuffer(); } - mBufferCountTracker.increment(resolvedState.state.surface->localBinder()); + mBufferCountTracker.increment(resolvedState.layerId); } - resolvedState.layerId = LayerHandle::getLayerId(resolvedState.state.surface); if (resolvedState.state.what & layer_state_t::eReparent) { resolvedState.parentId = getLayerIdFromSurfaceControl(resolvedState.state.parentSurfaceControlForChild); @@ -5130,7 +5287,7 @@ status_t SurfaceFlinger::mirrorDisplay(DisplayId displayId, const LayerCreationA outResult.layerId = rootMirrorLayer->sequence; outResult.layerName = String16(rootMirrorLayer->getDebugName()); addClientLayer(mirrorArgs, outResult.handle, rootMirrorLayer /* layer */, - nullptr /* parent */, nullptr /* outTransformHint */); + nullptr /* parent */, nullptr /* outTransformHint */); } setTransactionFlags(eTransactionFlushNeeded); @@ -5156,8 +5313,9 @@ status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, gui::CreateSurface std::atomic<int32_t>* pendingBufferCounter = layer->getPendingBufferCounter(); if (pendingBufferCounter) { std::string counterName = layer->getPendingBufferCounterName(); - mBufferCountTracker.add(outResult.handle->localBinder(), counterName, + mBufferCountTracker.add(LayerHandle::getLayerId(outResult.handle), counterName, pendingBufferCounter); + args.pendingBuffers = pendingBufferCounter; } } break; default: @@ -5234,7 +5392,7 @@ status_t SurfaceFlinger::checkLayerLeaks() { return NO_ERROR; } -void SurfaceFlinger::onHandleDestroyed(BBinder* handle, sp<Layer>& layer, uint32_t layerId) { +void SurfaceFlinger::onHandleDestroyed(sp<Layer>& layer, uint32_t layerId) { { // Used to remove stalled transactions which uses an internal lock. ftl::FakeGuard guard(kMainThreadContext); @@ -5247,7 +5405,7 @@ void SurfaceFlinger::onHandleDestroyed(BBinder* handle, sp<Layer>& layer, uint32 Mutex::Autolock stateLock(mStateLock); layer->onHandleDestroyed(); - mBufferCountTracker.remove(handle); + mBufferCountTracker.remove(layerId); layer.clear(); setTransactionFlags(eTransactionFlushNeeded | eTransactionNeeded); } @@ -5322,7 +5480,15 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: activeDisplay->isPoweredOn(), "Trying to change power mode on inactive display without powering off active display"); + const bool couldRefresh = display->isRefreshable(); display->setPowerMode(mode); + const bool canRefresh = display->isRefreshable(); + + if (couldRefresh && !canRefresh) { + decRefreshableDisplays(); + } else if (!couldRefresh && canRefresh) { + incRefreshableDisplays(); + } const auto activeMode = display->refreshRateSelector().getActiveMode().modePtr; if (currentMode == hal::PowerMode::OFF) { @@ -5656,6 +5822,14 @@ void SurfaceFlinger::dumpDisplays(std::string& result) const { utils::Dumper::Section section(dumper, ftl::Concat("Virtual Display ", displayId.value).str()); display->dump(dumper); + + if (const auto virtualIdOpt = VirtualDisplayId::tryCast(displayId)) { + std::lock_guard lock(mVirtualDisplaysMutex); + const auto virtualSnapshotIt = mVirtualDisplays.find(virtualIdOpt.value()); + if (virtualSnapshotIt != mVirtualDisplays.end()) { + virtualSnapshotIt->second.dump(dumper); + } + } } } } @@ -5748,7 +5922,7 @@ void SurfaceFlinger::dumpHdrInfo(std::string& result) const { void SurfaceFlinger::dumpFrontEnd(std::string& result) { std::ostringstream out; - out << "\nComposition list\n"; + out << "\nComposition list (bottom to top)\n"; ui::LayerStack lastPrintedLayerStackHeader = ui::INVALID_LAYER_STACK; for (const auto& snapshot : mLayerSnapshotBuilder.getSnapshots()) { if (lastPrintedLayerStackHeader != snapshot->outputFilter.layerStack) { @@ -5776,7 +5950,7 @@ void SurfaceFlinger::dumpFrontEnd(std::string& result) { void SurfaceFlinger::dumpVisibleFrontEnd(std::string& result) { std::ostringstream out; - out << "\nComposition list\n"; + out << "\nComposition list (bottom to top)\n"; ui::LayerStack lastPrintedLayerStackHeader = ui::INVALID_LAYER_STACK; mLayerSnapshotBuilder.forEachVisibleSnapshot( [&](std::unique_ptr<frontend::LayerSnapshot>& snapshot) { @@ -6187,7 +6361,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } // Numbers from 1000 to 1045 are currently used for backdoors. The code // in onTransact verifies that the user is root, and has access to use SF. - if (code >= 1000 && code <= 1045) { + if (code >= 1000 && code <= 1046) { ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code); return OK; } @@ -6720,6 +6894,15 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } return err; } + // Introduce jank to HWC + case 1046: { + int32_t jankDelayMs = 0; + if (data.readInt32(&jankDelayMs) != NO_ERROR) { + return BAD_VALUE; + } + mScheduler->setDebugPresentDelay(TimePoint::fromNs(ms2ns(jankDelayMs))); + return NO_ERROR; + } } } return err; @@ -7163,9 +7346,10 @@ void SurfaceFlinger::attachReleaseFenceFutureToLayer(Layer* layer, LayerFE* laye // typically a layer with DRM contents, or have the GRALLOC_USAGE_PROTECTED set on the buffer. // A protected layer has no implication on whether it's secure, which is explicitly set by // application to avoid being screenshot or drawn via unsecure display. -bool SurfaceFlinger::layersHasProtectedLayer(const std::vector<sp<LayerFE>>& layers) const { +bool SurfaceFlinger::layersHasProtectedLayer( + const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const { bool protectedLayerFound = false; - for (auto& layerFE : layers) { + for (auto& [_, layerFE] : layers) { protectedLayerFound |= (layerFE->mSnapshot->isVisible && layerFE->mSnapshot->hasProtectedContent); if (protectedLayerFound) { @@ -7181,15 +7365,21 @@ bool SurfaceFlinger::layersHasProtectedLayer(const std::vector<sp<LayerFE>>& lay // risk of deadlocks. std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getSnapshotsFromMainThread( RenderAreaBuilderVariant& renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, - std::vector<sp<LayerFE>>& layerFEs) { + std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) { return mScheduler - ->schedule([=, this, &renderAreaBuilder, &layerFEs]() REQUIRES(kMainThreadContext) { + ->schedule([=, this, &renderAreaBuilder, &layers]() REQUIRES(kMainThreadContext) { SFTRACE_NAME("getSnapshotsFromMainThread"); - auto layers = getLayerSnapshotsFn(); - for (auto& [layer, layerFE] : layers) { - attachReleaseFenceFutureToLayer(layer, layerFE.get(), ui::INVALID_LAYER_STACK); + layers = getLayerSnapshotsFn(); + // Non-threaded RenderEngine eventually returns to the main thread a 2nd time + // to complete the screenshot. Release fences should only be added during the 2nd + // hop to main thread in order to avoid potential deadlocks from waiting for the + // the future fence to fire. + if (mRenderEngine->isThreaded()) { + for (auto& [layer, layerFE] : layers) { + attachReleaseFenceFutureToLayer(layer, layerFE.get(), + ui::INVALID_LAYER_STACK); + } } - layerFEs = extractLayerFEs(layers); return getDisplayStateFromRenderAreaBuilder(renderAreaBuilder); }) .get(); @@ -7210,80 +7400,41 @@ void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuil return; } - if (FlagManager::getInstance().single_hop_screenshot() && - FlagManager::getInstance().ce_fence_promise() && mRenderEngine->isThreaded()) { - std::vector<sp<LayerFE>> layerFEs; - auto displayState = - getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layerFEs); - - const bool supportsProtected = getRenderEngine().supportsProtectedContent(); - bool hasProtectedLayer = false; - if (allowProtected && supportsProtected) { - hasProtectedLayer = layersHasProtectedLayer(layerFEs); - } - const bool isProtected = hasProtectedLayer && allowProtected && supportsProtected; - const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER | - GRALLOC_USAGE_HW_TEXTURE | - (isProtected ? GRALLOC_USAGE_PROTECTED - : GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); - sp<GraphicBuffer> buffer = - getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(), - static_cast<android_pixel_format>(reqPixelFormat), - 1 /* layerCount */, usage, "screenshot"); - - const status_t bufferStatus = buffer->initCheck(); - if (bufferStatus != OK) { - // Animations may end up being really janky, but don't crash here. - // Otherwise an irreponsible process may cause an SF crash by allocating - // too much. - ALOGE("%s: Buffer failed to allocate: %d", __func__, bufferStatus); - invokeScreenCaptureError(bufferStatus, captureListener); - return; - } - const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared< - renderengine::impl::ExternalTexture>(buffer, getRenderEngine(), - renderengine::impl::ExternalTexture::Usage:: - WRITEABLE); - auto futureFence = captureScreenshot(renderAreaBuilder, texture, false /* regionSampling */, - grayscale, isProtected, attachGainmap, captureListener, - displayState, layerFEs); - futureFence.get(); - - } else { - const bool supportsProtected = getRenderEngine().supportsProtectedContent(); - bool hasProtectedLayer = false; - if (allowProtected && supportsProtected) { - auto layers = mScheduler->schedule([=]() { return getLayerSnapshotsFn(); }).get(); - hasProtectedLayer = layersHasProtectedLayer(extractLayerFEs(layers)); - } - const bool isProtected = hasProtectedLayer && allowProtected && supportsProtected; - const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER | - GRALLOC_USAGE_HW_TEXTURE | - (isProtected ? GRALLOC_USAGE_PROTECTED - : GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); - sp<GraphicBuffer> buffer = - getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(), - static_cast<android_pixel_format>(reqPixelFormat), - 1 /* layerCount */, usage, "screenshot"); - - const status_t bufferStatus = buffer->initCheck(); - if (bufferStatus != OK) { - // Animations may end up being really janky, but don't crash here. - // Otherwise an irreponsible process may cause an SF crash by allocating - // too much. - ALOGE("%s: Buffer failed to allocate: %d", __func__, bufferStatus); - invokeScreenCaptureError(bufferStatus, captureListener); - return; - } - const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared< - renderengine::impl::ExternalTexture>(buffer, getRenderEngine(), - renderengine::impl::ExternalTexture::Usage:: - WRITEABLE); - auto futureFence = captureScreenshotLegacy(renderAreaBuilder, getLayerSnapshotsFn, texture, - false /* regionSampling */, grayscale, - isProtected, attachGainmap, captureListener); - futureFence.get(); + std::vector<std::pair<Layer*, sp<LayerFE>>> layers; + auto displayState = getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layers); + + const bool supportsProtected = getRenderEngine().supportsProtectedContent(); + bool hasProtectedLayer = false; + if (allowProtected && supportsProtected) { + hasProtectedLayer = layersHasProtectedLayer(layers); + } + const bool isProtected = hasProtectedLayer && allowProtected && supportsProtected; + const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER | + GRALLOC_USAGE_HW_TEXTURE | + (isProtected ? GRALLOC_USAGE_PROTECTED + : GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); + sp<GraphicBuffer> buffer = + getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(), + static_cast<android_pixel_format>(reqPixelFormat), + 1 /* layerCount */, usage, "screenshot"); + + const status_t bufferStatus = buffer->initCheck(); + if (bufferStatus != OK) { + // Animations may end up being really janky, but don't crash here. + // Otherwise an irreponsible process may cause an SF crash by allocating + // too much. + ALOGE("%s: Buffer failed to allocate: %d", __func__, bufferStatus); + invokeScreenCaptureError(bufferStatus, captureListener); + return; } + const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared< + renderengine::impl::ExternalTexture>(buffer, getRenderEngine(), + renderengine::impl::ExternalTexture::Usage:: + WRITEABLE); + auto futureFence = + captureScreenshot(renderAreaBuilder, texture, false /* regionSampling */, grayscale, + isProtected, attachGainmap, captureListener, displayState, layers); + futureFence.get(); } std::optional<SurfaceFlinger::OutputCompositionState> @@ -7322,22 +7473,13 @@ SurfaceFlinger::getDisplayStateFromRenderAreaBuilder(RenderAreaBuilderVariant& r return std::nullopt; } -std::vector<sp<LayerFE>> SurfaceFlinger::extractLayerFEs( - const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const { - std::vector<sp<LayerFE>> layerFEs; - layerFEs.reserve(layers.size()); - for (const auto& [_, layerFE] : layers) { - layerFEs.push_back(layerFE); - } - return layerFEs; -} - ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( const RenderAreaBuilderVariant& renderAreaBuilder, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, bool grayscale, bool isProtected, bool attachGainmap, const sp<IScreenCaptureListener>& captureListener, - std::optional<OutputCompositionState>& displayState, std::vector<sp<LayerFE>>& layerFEs) { + std::optional<OutputCompositionState>& displayState, + std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) { SFTRACE_CALL(); ScreenCaptureResults captureResults; @@ -7356,11 +7498,9 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( float displayBrightnessNits = displayState.value().displayBrightnessNits; float sdrWhitePointNits = displayState.value().sdrWhitePointNits; - // Empty vector needed to pass into renderScreenImpl for legacy path - std::vector<std::pair<Layer*, sp<android::LayerFE>>> layers; ftl::SharedFuture<FenceResult> renderFuture = renderScreenImpl(renderArea.get(), buffer, regionSampling, grayscale, isProtected, - attachGainmap, captureResults, displayState, layers, layerFEs); + captureResults, displayState, layers); if (captureResults.capturedHdrLayers && attachGainmap && FlagManager::getInstance().true_hdr_screenshots()) { @@ -7395,8 +7535,7 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( ScreenCaptureResults unusedResults; ftl::SharedFuture<FenceResult> hdrRenderFuture = renderScreenImpl(renderArea.get(), hdrTexture, regionSampling, grayscale, - isProtected, attachGainmap, unusedResults, displayState, - layers, layerFEs); + isProtected, unusedResults, displayState, layers); renderFuture = ftl::Future(std::move(renderFuture)) @@ -7442,77 +7581,14 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( return renderFuture; } -ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshotLegacy( - RenderAreaBuilderVariant renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, - const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, - bool grayscale, bool isProtected, bool attachGainmap, - const sp<IScreenCaptureListener>& captureListener) { - SFTRACE_CALL(); - - auto takeScreenshotFn = [=, this, renderAreaBuilder = std::move(renderAreaBuilder)]() REQUIRES( - kMainThreadContext) mutable -> ftl::SharedFuture<FenceResult> { - auto layers = getLayerSnapshotsFn(); - if (FlagManager::getInstance().ce_fence_promise()) { - for (auto& [layer, layerFE] : layers) { - attachReleaseFenceFutureToLayer(layer, layerFE.get(), ui::INVALID_LAYER_STACK); - } - } - auto displayState = getDisplayStateFromRenderAreaBuilder(renderAreaBuilder); - - ScreenCaptureResults captureResults; - std::unique_ptr<const RenderArea> renderArea = - std::visit([](auto&& arg) -> std::unique_ptr<RenderArea> { return arg.build(); }, - renderAreaBuilder); - - if (!renderArea) { - ALOGW("Skipping screen capture because of invalid render area."); - if (captureListener) { - captureResults.fenceResult = base::unexpected(NO_MEMORY); - captureListener->onScreenCaptureCompleted(captureResults); - } - return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share(); - } - - auto layerFEs = extractLayerFEs(layers); - ftl::SharedFuture<FenceResult> renderFuture = - renderScreenImpl(renderArea.get(), buffer, regionSampling, grayscale, isProtected, - attachGainmap, captureResults, displayState, layers, layerFEs); - - if (captureListener) { - // Defer blocking on renderFuture back to the Binder thread. - return ftl::Future(std::move(renderFuture)) - .then([captureListener, captureResults = std::move(captureResults)]( - FenceResult fenceResult) mutable -> FenceResult { - captureResults.fenceResult = std::move(fenceResult); - captureListener->onScreenCaptureCompleted(captureResults); - return base::unexpected(NO_ERROR); - }) - .share(); - } - return renderFuture; - }; - - // TODO(b/294936197): Run takeScreenshotsFn() in a binder thread to reduce the number - // of calls on the main thread. - auto future = - mScheduler->schedule(FTL_FAKE_GUARD(kMainThreadContext, std::move(takeScreenshotFn))); - - // Flatten nested futures. - auto chain = ftl::Future(std::move(future)).then([](ftl::SharedFuture<FenceResult> future) { - return future; - }); - - return chain.share(); -} - ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( const RenderArea* renderArea, const std::shared_ptr<renderengine::ExternalTexture>& buffer, - bool regionSampling, bool grayscale, bool isProtected, bool attachGainmap, - ScreenCaptureResults& captureResults, std::optional<OutputCompositionState>& displayState, - std::vector<std::pair<Layer*, sp<LayerFE>>>& layers, std::vector<sp<LayerFE>>& layerFEs) { + bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults& captureResults, + std::optional<OutputCompositionState>& displayState, + std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) { SFTRACE_CALL(); - for (auto& layerFE : layerFEs) { + for (auto& [_, layerFE] : layers) { frontend::LayerSnapshot* snapshot = layerFE->mSnapshot.get(); captureResults.capturedSecureLayers |= (snapshot->isVisible && snapshot->isSecure); captureResults.capturedHdrLayers |= isHdrLayer(*snapshot); @@ -7571,29 +7647,32 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( captureResults.buffer = capturedBuffer->getBuffer(); ui::LayerStack layerStack{ui::DEFAULT_LAYER_STACK}; - if (!layerFEs.empty()) { - const sp<LayerFE>& layerFE = layerFEs.back(); + if (!layers.empty()) { + const sp<LayerFE>& layerFE = layers.back().second; layerStack = layerFE->getCompositionState()->outputFilter.layerStack; } - auto copyLayerFEs = [&layerFEs]() { - std::vector<sp<compositionengine::LayerFE>> ceLayerFEs; - ceLayerFEs.reserve(layerFEs.size()); - for (const auto& layerFE : layerFEs) { - ceLayerFEs.push_back(layerFE); - } - return ceLayerFEs; - }; - auto present = [this, buffer = capturedBuffer, dataspace = captureResults.capturedDataspace, sdrWhitePointNits, displayBrightnessNits, grayscale, isProtected, - layerFEs = copyLayerFEs(), layerStack, regionSampling, + layers = std::move(layers), layerStack, regionSampling, renderArea = std::move(renderArea), renderIntent, enableLocalTonemapping]() -> FenceResult { std::unique_ptr<compositionengine::CompositionEngine> compositionEngine = mFactory.createCompositionEngine(); compositionEngine->setRenderEngine(mRenderEngine.get()); + std::vector<sp<compositionengine::LayerFE>> layerFEs; + layerFEs.reserve(layers.size()); + for (auto& [layer, layerFE] : layers) { + // Release fences were not yet added for non-threaded render engine. To avoid + // deadlocks between main thread and binder threads waiting for the future fence + // result, fences should be added to layers in the same hop onto the main thread. + if (!mRenderEngine->isThreaded()) { + attachReleaseFenceFutureToLayer(layer, layerFE.get(), ui::INVALID_LAYER_STACK); + } + layerFEs.push_back(layerFE); + } + compositionengine::Output::ColorProfile colorProfile{.dataspace = dataspace, .renderIntent = renderIntent}; @@ -7651,36 +7730,9 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( // // TODO(b/196334700) Once we use RenderEngineThreaded everywhere we can always defer the call // to CompositionEngine::present. - ftl::SharedFuture<FenceResult> presentFuture; - if (FlagManager::getInstance().single_hop_screenshot() && - FlagManager::getInstance().ce_fence_promise() && mRenderEngine->isThreaded()) { - presentFuture = ftl::yield(present()).share(); - } else { - presentFuture = mRenderEngine->isThreaded() ? ftl::defer(std::move(present)).share() - : ftl::yield(present()).share(); - } - - if (!FlagManager::getInstance().ce_fence_promise()) { - for (auto& [layer, layerFE] : layers) { - layer->onLayerDisplayed(presentFuture, ui::INVALID_LAYER_STACK, - [layerFE = std::move(layerFE)](FenceResult) { - if (FlagManager::getInstance() - .screenshot_fence_preservation()) { - const auto compositionResult = - layerFE->stealCompositionResult(); - const auto& fences = compositionResult.releaseFences; - // CompositionEngine may choose to cull layers that - // aren't visible, so pass a non-fence. - return fences.empty() ? Fence::NO_FENCE - : fences.back().first.get(); - } else { - return layerFE->stealCompositionResult() - .releaseFences.back() - .first.get(); - } - }); - } - } + ftl::SharedFuture<FenceResult> presentFuture = mRenderEngine->isThreaded() + ? ftl::yield(present()).share() + : mScheduler->schedule(std::move(present)).share(); return presentFuture; } @@ -7744,7 +7796,8 @@ status_t SurfaceFlinger::applyRefreshRateSelectorPolicy( ALOGV("Setting desired display mode specs: %s", currentPolicy.toString().c_str()); if (const bool isPacesetter = - mScheduler->onDisplayModeChanged(displayId, selector.getActiveMode())) { + mScheduler->onDisplayModeChanged(displayId, selector.getActiveMode(), + /*clearContentRequirements*/ true)) { mDisplayModeController.updateKernelIdleTimer(displayId); } @@ -8133,6 +8186,14 @@ void SurfaceFlinger::updateHdcpLevels(hal::HWDisplayId hwcDisplayId, int32_t con })); } +void SurfaceFlinger::setActivePictureListener(const sp<gui::IActivePictureListener>& listener) { + if (com_android_graphics_libgui_flags_apply_picture_profiles()) { + Mutex::Autolock lock(mStateLock); + mActivePictureListener = listener; + mHaveNewActivePictureListener = listener != nullptr; + } +} + std::shared_ptr<renderengine::ExternalTexture> SurfaceFlinger::getExternalTextureFromBufferData( BufferData& bufferData, const char* layerName, uint64_t transactionId) { if (bufferData.buffer && @@ -8631,6 +8692,15 @@ void SurfaceComposerAIDL::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo& outInfo->activeDisplayModeId = info.activeDisplayModeId; outInfo->renderFrameRate = info.renderFrameRate; + outInfo->hasArrSupport = info.hasArrSupport; + gui::FrameRateCategoryRate& frameRateCategoryRate = outInfo->frameRateCategoryRate; + frameRateCategoryRate.normal = info.frameRateCategoryRate.getNormal(); + frameRateCategoryRate.high = info.frameRateCategoryRate.getHigh(); + outInfo->supportedRefreshRates.clear(); + outInfo->supportedRefreshRates.reserve(info.supportedRefreshRates.size()); + for (float supportedRefreshRate : info.supportedRefreshRates) { + outInfo->supportedRefreshRates.push_back(supportedRefreshRate); + } outInfo->supportedColorModes.clear(); outInfo->supportedColorModes.reserve(info.supportedColorModes.size()); @@ -8786,6 +8856,16 @@ binder::Status SurfaceComposerAIDL::setGameContentType(const sp<IBinder>& displa return binder::Status::ok(); } +binder::Status SurfaceComposerAIDL::getMaxLayerPictureProfiles(const sp<IBinder>& display, + int32_t* outMaxProfiles) { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } + mFlinger->getMaxLayerPictureProfiles(display, outMaxProfiles); + return binder::Status::ok(); +} + binder::Status SurfaceComposerAIDL::captureDisplay( const DisplayCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) { mFlinger->captureDisplay(args, captureListener); @@ -9064,6 +9144,15 @@ binder::Status SurfaceComposerAIDL::removeHdrLayerInfoListener( return binderStatusFromStatusT(status); } +binder::Status SurfaceComposerAIDL::setActivePictureListener( + const sp<gui::IActivePictureListener>& listener) { + status_t status = checkObservePictureProfilesPermission(); + if (status == OK) { + mFlinger->setActivePictureListener(listener); + } + return binderStatusFromStatusT(status); +} + binder::Status SurfaceComposerAIDL::notifyPowerBoost(int boostId) { status_t status = checkAccessPermission(); if (status == OK) { @@ -9134,26 +9223,46 @@ binder::Status SurfaceComposerAIDL::setGameDefaultFrameRateOverride(int32_t uid, } binder::Status SurfaceComposerAIDL::enableRefreshRateOverlay(bool active) { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } mFlinger->sfdo_enableRefreshRateOverlay(active); return binder::Status::ok(); } binder::Status SurfaceComposerAIDL::setDebugFlash(int delay) { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } mFlinger->sfdo_setDebugFlash(delay); return binder::Status::ok(); } binder::Status SurfaceComposerAIDL::scheduleComposite() { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } mFlinger->sfdo_scheduleComposite(); return binder::Status::ok(); } binder::Status SurfaceComposerAIDL::scheduleCommit() { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } mFlinger->sfdo_scheduleCommit(); return binder::Status::ok(); } binder::Status SurfaceComposerAIDL::forceClientComposition(bool enabled) { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } mFlinger->sfdo_forceClientComposition(enabled); return binder::Status::ok(); } @@ -9319,6 +9428,17 @@ status_t SurfaceComposerAIDL::checkReadFrameBufferPermission() { return OK; } +status_t SurfaceComposerAIDL::checkObservePictureProfilesPermission() { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if (!PermissionCache::checkPermission(sObservePictureProfiles, pid, uid)) { + ALOGE("Permission Denial: can't manage picture profiles pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + return OK; +} + void SurfaceFlinger::forceFutureUpdate(int delayInMs) { static_cast<void>(mScheduler->scheduleDelayed([&]() { scheduleRepaint(); }, ms2ns(delayInMs))); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 24194b18ac..cdd83f2149 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -24,9 +24,11 @@ #include <android-base/stringprintf.h> #include <android-base/strings.h> #include <android-base/thread_annotations.h> +#include <android/gui/ActivePicture.h> #include <android/gui/BnSurfaceComposer.h> #include <android/gui/DisplayStatInfo.h> #include <android/gui/DisplayState.h> +#include <android/gui/IActivePictureListener.h> #include <android/gui/IJankListener.h> #include <android/gui/ISurfaceComposerClient.h> #include <common/trace.h> @@ -57,6 +59,7 @@ #include <utils/threads.h> #include <compositionengine/OutputColorSetting.h> +#include <compositionengine/impl/OutputCompositionState.h> #include <scheduler/Fps.h> #include <scheduler/PresentLatencyTracker.h> #include <scheduler/Time.h> @@ -66,11 +69,13 @@ #include <ui/FenceResult.h> #include <common/FlagManager.h> +#include "ActivePictureUpdater.h" +#include "BackgroundExecutor.h" #include "Display/DisplayModeController.h" #include "Display/PhysicalDisplay.h" +#include "Display/VirtualDisplaySnapshot.h" #include "DisplayDevice.h" #include "DisplayHardware/HWC2.h" -#include "DisplayHardware/PowerAdvisor.h" #include "DisplayIdGenerator.h" #include "Effects/Daltonizer.h" #include "FrontEnd/DisplayInfo.h" @@ -81,6 +86,7 @@ #include "FrontEnd/TransactionHandler.h" #include "LayerVector.h" #include "MutexUtils.h" +#include "PowerAdvisor/PowerAdvisor.h" #include "Scheduler/ISchedulerCallback.h" #include "Scheduler/RefreshRateSelector.h" #include "Scheduler/Scheduler.h" @@ -92,6 +98,7 @@ #include "TransactionState.h" #include "Utils/OnceFuture.h" +#include <algorithm> #include <atomic> #include <cstdint> #include <functional> @@ -296,7 +303,7 @@ public: // Called when all clients have released all their references to // this layer. The layer may still be kept alive by its parents but // the client can no longer modify this layer directly. - void onHandleDestroyed(BBinder* handle, sp<Layer>& layer, uint32_t layerId); + void onHandleDestroyed(sp<Layer>& layer, uint32_t layerId); TransactionCallbackInvoker& getTransactionCallbackInvoker() { return mTransactionCallbackInvoker; @@ -433,32 +440,32 @@ private: // This is done to avoid lock contention with the main thread. class BufferCountTracker { public: - void increment(BBinder* layerHandle) { + void increment(uint32_t layerId) { std::lock_guard<std::mutex> lock(mLock); - auto it = mCounterByLayerHandle.find(layerHandle); - if (it != mCounterByLayerHandle.end()) { + auto it = mCounterByLayerId.find(layerId); + if (it != mCounterByLayerId.end()) { auto [name, pendingBuffers] = it->second; int32_t count = ++(*pendingBuffers); SFTRACE_INT(name.c_str(), count); } else { - ALOGW("Handle not found! %p", layerHandle); + ALOGW("Layer ID not found! %d", layerId); } } - void add(BBinder* layerHandle, const std::string& name, std::atomic<int32_t>* counter) { + void add(uint32_t layerId, const std::string& name, std::atomic<int32_t>* counter) { std::lock_guard<std::mutex> lock(mLock); - mCounterByLayerHandle[layerHandle] = std::make_pair(name, counter); + mCounterByLayerId[layerId] = std::make_pair(name, counter); } - void remove(BBinder* layerHandle) { + void remove(uint32_t layerId) { std::lock_guard<std::mutex> lock(mLock); - mCounterByLayerHandle.erase(layerHandle); + mCounterByLayerId.erase(layerId); } private: std::mutex mLock; - std::unordered_map<BBinder*, std::pair<std::string, std::atomic<int32_t>*>> - mCounterByLayerHandle GUARDED_BY(mLock); + std::unordered_map<uint32_t, std::pair<std::string, std::atomic<int32_t>*>> + mCounterByLayerId GUARDED_BY(mLock); }; enum class BootStage { @@ -590,6 +597,7 @@ private: status_t getHdrOutputConversionSupport(bool* outSupport) const; void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on); void setGameContentType(const sp<IBinder>& displayToken, bool on); + status_t getMaxLayerPictureProfiles(const sp<IBinder>& displayToken, int32_t* outMaxProfiles); void setPowerMode(const sp<IBinder>& displayToken, int mode); status_t overrideHdrTypes(const sp<IBinder>& displayToken, const std::vector<ui::Hdr>& hdrTypes); @@ -659,6 +667,8 @@ private: void updateHdcpLevels(hal::HWDisplayId hwcDisplayId, int32_t connectedLevel, int32_t maxLevel); + void setActivePictureListener(const sp<gui::IActivePictureListener>& listener); + // IBinder::DeathRecipient overrides: void binderDied(const wp<IBinder>& who) override; @@ -854,13 +864,14 @@ private: void attachReleaseFenceFutureToLayer(Layer* layer, LayerFE* layerFE, ui::LayerStack layerStack); // Checks if a protected layer exists in a list of layers. - bool layersHasProtectedLayer(const std::vector<sp<LayerFE>>& layers) const; + bool layersHasProtectedLayer(const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const; using OutputCompositionState = compositionengine::impl::OutputCompositionState; std::optional<OutputCompositionState> getSnapshotsFromMainThread( RenderAreaBuilderVariant& renderAreaBuilder, - GetLayerSnapshotsFunction getLayerSnapshotsFn, std::vector<sp<LayerFE>>& layerFEs); + GetLayerSnapshotsFunction getLayerSnapshotsFn, + std::vector<std::pair<Layer*, sp<LayerFE>>>& layers); void captureScreenCommon(RenderAreaBuilderVariant, GetLayerSnapshotsFunction, ui::Size bufferSize, ui::PixelFormat, bool allowProtected, @@ -869,32 +880,19 @@ private: std::optional<OutputCompositionState> getDisplayStateFromRenderAreaBuilder( RenderAreaBuilderVariant& renderAreaBuilder) REQUIRES(kMainThreadContext); - // Legacy layer raw pointer is not safe to access outside the main thread. - // Creates a new vector consisting only of LayerFEs, which can be safely - // accessed outside the main thread. - std::vector<sp<LayerFE>> extractLayerFEs( - const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const; - ftl::SharedFuture<FenceResult> captureScreenshot( const RenderAreaBuilderVariant& renderAreaBuilder, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, bool grayscale, bool isProtected, bool attachGainmap, const sp<IScreenCaptureListener>& captureListener, std::optional<OutputCompositionState>& displayState, - std::vector<sp<LayerFE>>& layerFEs); - - ftl::SharedFuture<FenceResult> captureScreenshotLegacy( - RenderAreaBuilderVariant, GetLayerSnapshotsFunction, - const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling, - bool grayscale, bool isProtected, bool attachGainmap, - const sp<IScreenCaptureListener>&); + std::vector<std::pair<Layer*, sp<LayerFE>>>& layers); ftl::SharedFuture<FenceResult> renderScreenImpl( const RenderArea*, const std::shared_ptr<renderengine::ExternalTexture>&, - bool regionSampling, bool grayscale, bool isProtected, bool attachGainmap, - ScreenCaptureResults&, std::optional<OutputCompositionState>& displayState, - std::vector<std::pair<Layer*, sp<LayerFE>>>& layers, - std::vector<sp<LayerFE>>& layerFEs); + bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults&, + std::optional<OutputCompositionState>& displayState, + std::vector<std::pair<Layer*, sp<LayerFE>>>& layers); void readPersistentProperties(); @@ -1081,8 +1079,20 @@ private: void enableHalVirtualDisplays(bool); // Virtual display lifecycle for ID generation and HAL allocation. - VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat) REQUIRES(mStateLock); + VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat, const std::string& uniqueId) + REQUIRES(mStateLock); + template <typename ID> + void acquireVirtualDisplaySnapshot(ID displayId, const std::string& uniqueId) { + std::lock_guard lock(mVirtualDisplaysMutex); + const bool emplace_success = + mVirtualDisplays.try_emplace(displayId, displayId, uniqueId).second; + if (!emplace_success) { + ALOGW("%s: Virtual display snapshot with the same ID already exists", __func__); + } + } + void releaseVirtualDisplay(VirtualDisplayId); + void releaseVirtualDisplaySnapshot(VirtualDisplayId displayId); // Returns a display other than `mActiveDisplayId` that can be activated, if any. sp<DisplayDevice> getActivatableDisplay() const REQUIRES(mStateLock, kMainThreadContext); @@ -1224,6 +1234,14 @@ private: bool mHdrLayerInfoChanged = false; + struct LayerEvent { + uid_t uid; + int32_t layerId; + ui::Dataspace dataspace; + std::chrono::milliseconds timeSinceLastEvent; + }; + std::vector<LayerEvent> mLayerEvents; + // Used to ensure we omit a callback when HDR layer info listener is newly added but the // scene hasn't changed bool mAddingHDRLayerInfoListener = false; @@ -1248,7 +1266,6 @@ private: // latched. std::unordered_set<std::pair<sp<Layer>, gui::GameMode>, LayerIntHash> mLayersWithQueuedFrames; std::unordered_set<sp<Layer>, SpHash<Layer>> mLayersWithBuffersRemoved; - std::unordered_set<uint32_t> mLayersIdsWithQueuedFrames; // Sorted list of layers that were composed during previous frame. This is used to // avoid an expensive traversal of the layer hierarchy when there are no @@ -1276,6 +1293,10 @@ private: display::PhysicalDisplays mPhysicalDisplays GUARDED_BY(mStateLock); + mutable std::mutex mVirtualDisplaysMutex; + ftl::SmallMap<VirtualDisplayId, const display::VirtualDisplaySnapshot, 2> mVirtualDisplays + GUARDED_BY(mVirtualDisplaysMutex); + // The inner or outer display for foldables, while unfolded or folded, respectively. std::atomic<PhysicalDisplayId> mActiveDisplayId; @@ -1368,7 +1389,7 @@ private: sp<os::IInputFlinger> mInputFlinger; InputWindowCommands mInputWindowCommands; - std::unique_ptr<Hwc2::PowerAdvisor> mPowerAdvisor; + std::unique_ptr<adpf::PowerAdvisor> mPowerAdvisor; void enableRefreshRateOverlay(bool enable) REQUIRES(mStateLock, kMainThreadContext); @@ -1377,11 +1398,17 @@ private: // Flag used to set override desired display mode from backdoor bool mDebugDisplayModeSetByBackdoor = false; + // Tracks the number of maximum queued buffers by layer owner Uid. + using BufferStuffingMap = ftl::SmallMap<uid_t, uint32_t, 10>; BufferCountTracker mBufferCountTracker; std::unordered_map<DisplayId, sp<HdrLayerInfoReporter>> mHdrLayerInfoListeners GUARDED_BY(mStateLock); + sp<gui::IActivePictureListener> mActivePictureListener GUARDED_BY(mStateLock); + bool mHaveNewActivePictureListener GUARDED_BY(mStateLock); + ActivePictureUpdater mActivePictureUpdater GUARDED_BY(kMainThreadContext); + std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint; // Must only be accessed on the main thread. @@ -1418,6 +1445,11 @@ private: // Whether a display should be turned on when initialized bool mSkipPowerOnForQuiescent; + // used for omitting vsync callbacks to apps when the display is not updatable + int mRefreshableDisplays GUARDED_BY(mStateLock) = 0; + void incRefreshableDisplays() REQUIRES(mStateLock); + void decRefreshableDisplays() REQUIRES(mStateLock); + frontend::LayerLifecycleManager mLayerLifecycleManager GUARDED_BY(kMainThreadContext); frontend::LayerHierarchyBuilder mLayerHierarchyBuilder GUARDED_BY(kMainThreadContext); frontend::LayerSnapshotBuilder mLayerSnapshotBuilder GUARDED_BY(kMainThreadContext); @@ -1522,6 +1554,8 @@ public: binder::Status getHdrOutputConversionSupport(bool* outSupport) override; binder::Status setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override; binder::Status setGameContentType(const sp<IBinder>& display, bool on) override; + binder::Status getMaxLayerPictureProfiles(const sp<IBinder>& display, + int32_t* outMaxProfiles) override; binder::Status captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&) override; binder::Status captureDisplayById(int64_t, const CaptureArgs&, @@ -1610,12 +1644,15 @@ public: binder::Status flushJankData(int32_t layerId) override; binder::Status removeJankListener(int32_t layerId, const sp<gui::IJankListener>& listener, int64_t afterVsync) override; + binder::Status setActivePictureListener(const sp<gui::IActivePictureListener>& listener); + binder::Status clearActivePictureListener(); private: static const constexpr bool kUsePermissionCache = true; status_t checkAccessPermission(bool usePermissionCache = kUsePermissionCache); status_t checkControlDisplayBrightnessPermission(); status_t checkReadFrameBufferPermission(); + status_t checkObservePictureProfilesPermission(); static void getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo& info, gui::DynamicDisplayInfo*& outInfo); diff --git a/services/surfaceflinger/Tracing/LayerDataSource.cpp b/services/surfaceflinger/Tracing/LayerDataSource.cpp index ed1e2ec89c..cc0063cd2a 100644 --- a/services/surfaceflinger/Tracing/LayerDataSource.cpp +++ b/services/surfaceflinger/Tracing/LayerDataSource.cpp @@ -82,10 +82,13 @@ void LayerDataSource::OnFlush(const LayerDataSource::FlushArgs& args) { } } -void LayerDataSource::OnStop(const LayerDataSource::StopArgs&) { +void LayerDataSource::OnStop(const LayerDataSource::StopArgs& args) { ALOGD("Received OnStop event (mode = 0x%02x, flags = 0x%02x)", mMode, mFlags); if (auto* p = mLayerTracing.load()) { - p->onStop(mMode); + // In dump mode we need to defer the stop (through HandleStopAsynchronously()) till + // the layers snapshot has been captured and written to perfetto. We must avoid writing + // to perfetto within the OnStop callback to prevent deadlocks (b/313130597). + p->onStop(mMode, mFlags, args.HandleStopAsynchronously()); } } diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp index d40b888504..d78f9bbbae 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.cpp +++ b/services/surfaceflinger/Tracing/LayerTracing.cpp @@ -32,7 +32,7 @@ namespace android { LayerTracing::LayerTracing() { - mTakeLayersSnapshotProto = [](uint32_t) { return perfetto::protos::LayersSnapshotProto{}; }; + mTakeLayersSnapshotProto = [](uint32_t, const OnLayersSnapshotCallback&) {}; LayerDataSource::Initialize(*this); } @@ -45,7 +45,7 @@ LayerTracing::~LayerTracing() { } void LayerTracing::setTakeLayersSnapshotProtoFunction( - const std::function<perfetto::protos::LayersSnapshotProto(uint32_t)>& callback) { + const std::function<void(uint32_t, const OnLayersSnapshotCallback&)>& callback) { mTakeLayersSnapshotProto = callback; } @@ -62,7 +62,10 @@ void LayerTracing::onStart(Mode mode, uint32_t flags) { // It might take a while before a layers change occurs and a "spontaneous" snapshot is // taken. Let's manually take a snapshot, so that the trace's first entry will contain // the current layers state. - addProtoSnapshotToOstream(mTakeLayersSnapshotProto(flags), Mode::MODE_ACTIVE); + auto onLayersSnapshot = [this](perfetto::protos::LayersSnapshotProto&& snapshot) { + addProtoSnapshotToOstream(std::move(snapshot), Mode::MODE_ACTIVE); + }; + mTakeLayersSnapshotProto(flags, onLayersSnapshot); ALOGD("Started active tracing (traced initial snapshot)"); break; } @@ -89,9 +92,7 @@ void LayerTracing::onStart(Mode mode, uint32_t flags) { break; } case Mode::MODE_DUMP: { - auto snapshot = mTakeLayersSnapshotProto(flags); - addProtoSnapshotToOstream(std::move(snapshot), Mode::MODE_DUMP); - ALOGD("Started dump tracing (dumped single snapshot)"); + ALOGD("Started dump tracing"); break; } default: { @@ -125,10 +126,27 @@ void LayerTracing::onFlush(Mode mode, uint32_t flags, bool isBugreport) { ALOGD("Flushed generated tracing"); } -void LayerTracing::onStop(Mode mode) { - if (mode == Mode::MODE_ACTIVE) { - mIsActiveTracingStarted.store(false); - ALOGD("Stopped active tracing"); +void LayerTracing::onStop(Mode mode, uint32_t flags, std::function<void()>&& deferredStopDone) { + switch (mode) { + case Mode::MODE_ACTIVE: { + mIsActiveTracingStarted.store(false); + deferredStopDone(); + ALOGD("Stopped active tracing"); + break; + } + case Mode::MODE_DUMP: { + auto onLayersSnapshot = [this, deferredStopDone = std::move(deferredStopDone)]( + perfetto::protos::LayersSnapshotProto&& snapshot) { + addProtoSnapshotToOstream(std::move(snapshot), Mode::MODE_DUMP); + deferredStopDone(); + ALOGD("Stopped dump tracing (written single snapshot)"); + }; + mTakeLayersSnapshotProto(flags, onLayersSnapshot); + break; + } + default: { + deferredStopDone(); + } } } diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h index 2895ba7026..e99fe4c7f1 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.h +++ b/services/surfaceflinger/Tracing/LayerTracing.h @@ -87,6 +87,7 @@ EOF class LayerTracing { public: using Mode = perfetto::protos::pbzero::SurfaceFlingerLayersConfig::Mode; + using OnLayersSnapshotCallback = std::function<void(perfetto::protos::LayersSnapshotProto&&)>; enum Flag : uint32_t { TRACE_INPUT = 1 << 1, @@ -102,7 +103,7 @@ public: LayerTracing(std::ostream&); ~LayerTracing(); void setTakeLayersSnapshotProtoFunction( - const std::function<perfetto::protos::LayersSnapshotProto(uint32_t)>&); + const std::function<void(uint32_t, const OnLayersSnapshotCallback&)>&); void setTransactionTracing(TransactionTracing&); // Start event from perfetto data source @@ -110,7 +111,7 @@ public: // Flush event from perfetto data source void onFlush(Mode mode, uint32_t flags, bool isBugreport); // Stop event from perfetto data source - void onStop(Mode mode); + void onStop(Mode mode, uint32_t flags, std::function<void()>&& deferredStopDone); void addProtoSnapshotToOstream(perfetto::protos::LayersSnapshotProto&& snapshot, Mode mode); bool isActiveTracingStarted() const; @@ -123,7 +124,7 @@ private: void writeSnapshotToPerfetto(const perfetto::protos::LayersSnapshotProto& snapshot, Mode mode); bool checkAndUpdateLastVsyncIdWrittenToPerfetto(Mode mode, std::int64_t vsyncId); - std::function<perfetto::protos::LayersSnapshotProto(uint32_t)> mTakeLayersSnapshotProto; + std::function<void(uint32_t, const OnLayersSnapshotCallback&)> mTakeLayersSnapshotProto; TransactionTracing* mTransactionTracing; std::atomic<bool> mIsActiveTracingStarted{false}; diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index b1895989ec..f39a4d2af4 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -147,7 +147,7 @@ perfetto::protos::LayerState TransactionProtoParser::toProto( proto.set_transform_to_display_inverse(layer.transformToDisplayInverse); } if (layer.what & layer_state_t::eCropChanged) { - LayerProtoHelper::writeToProto(layer.crop, proto.mutable_crop()); + LayerProtoHelper::writeToProto(Rect(layer.crop), proto.mutable_crop()); } if (layer.what & layer_state_t::eBufferChanged) { perfetto::protos::LayerState_BufferData* bufferProto = proto.mutable_buffer_data(); diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp index c6856aea75..b22ec66819 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.cpp +++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp @@ -28,7 +28,6 @@ #include "Utils/FenceUtils.h" #include <binder/IInterface.h> -#include <common/FlagManager.h> #include <common/trace.h> #include <utils/RefBase.h> @@ -127,14 +126,8 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp<CallbackHandle>& if (surfaceControl) { sp<Fence> prevFence = nullptr; - if (FlagManager::getInstance().ce_fence_promise()) { - for (auto& future : handle->previousReleaseFences) { - mergeFence(handle->name.c_str(), future.get().value_or(Fence::NO_FENCE), prevFence); - } - } else { - for (const auto& future : handle->previousSharedReleaseFences) { - mergeFence(handle->name.c_str(), future.get().value_or(Fence::NO_FENCE), prevFence); - } + for (auto& future : handle->previousReleaseFences) { + mergeFence(handle->name.c_str(), future.get().value_or(Fence::NO_FENCE), prevFence); } handle->previousReleaseFence = prevFence; @@ -151,7 +144,7 @@ status_t TransactionCallbackInvoker::addCallbackHandle(const sp<CallbackHandle>& eventStats, handle->previousReleaseCallbackId); if (handle->bufferReleaseChannel && handle->previousReleaseCallbackId != ReleaseCallbackId::INVALID_ID) { - mBufferReleases.emplace_back(handle->bufferReleaseChannel, + mBufferReleases.emplace_back(handle->name, handle->bufferReleaseChannel, handle->previousReleaseCallbackId, handle->previousReleaseFence, handle->currentMaxAcquiredBufferCount); @@ -166,8 +159,13 @@ void TransactionCallbackInvoker::addPresentFence(sp<Fence> presentFence) { void TransactionCallbackInvoker::sendCallbacks(bool onCommitOnly) { for (const auto& bufferRelease : mBufferReleases) { - bufferRelease.channel->writeReleaseFence(bufferRelease.callbackId, bufferRelease.fence, - bufferRelease.currentMaxAcquiredBufferCount); + status_t status = bufferRelease.channel + ->writeReleaseFence(bufferRelease.callbackId, bufferRelease.fence, + bufferRelease.currentMaxAcquiredBufferCount); + if (status != OK) { + ALOGE("[%s] writeReleaseFence failed. error %d (%s)", bufferRelease.layerName.c_str(), + -status, strerror(-status)); + } } mBufferReleases.clear(); diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index 14a7487156..178ddbbe79 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -43,7 +43,6 @@ public: std::string name; sp<Fence> previousReleaseFence; std::vector<ftl::Future<FenceResult>> previousReleaseFences; - std::vector<ftl::SharedFuture<FenceResult>> previousSharedReleaseFences; std::variant<nsecs_t, sp<Fence>> acquireTimeOrFence = -1; nsecs_t latchTime = -1; std::optional<uint32_t> transformHint = std::nullopt; @@ -84,6 +83,7 @@ private: mCompletedTransactions; struct BufferRelease { + std::string layerName; std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> channel; ReleaseCallbackId callbackId; sp<Fence> fence; diff --git a/services/surfaceflinger/common/Android.bp b/services/surfaceflinger/common/Android.bp index f9c99bf2d2..8786f6e592 100644 --- a/services/surfaceflinger/common/Android.bp +++ b/services/surfaceflinger/common/Android.bp @@ -38,6 +38,7 @@ cc_library_static { ], static_libs: [ "libsurfaceflingerflags", + "aconfig_hardware_flags_c_lib", "android.os.flags-aconfig-cc", "android.server.display.flags-aconfig-cc", "libguiflags_no_apex", @@ -51,6 +52,7 @@ cc_library_static { ], static_libs: [ "libsurfaceflingerflags_test", + "aconfig_hardware_flags_c_lib", "android.os.flags-aconfig-cc-test", "android.server.display.flags-aconfig-cc", "libguiflags_no_apex", @@ -67,6 +69,7 @@ cc_defaults { static_libs: [ "libsurfaceflinger_common", "libsurfaceflingerflags", + "aconfig_hardware_flags_c_lib", "android.os.flags-aconfig-cc", "android.server.display.flags-aconfig-cc", "libguiflags_no_apex", @@ -83,6 +86,7 @@ cc_defaults { static_libs: [ "libsurfaceflinger_common_test", "libsurfaceflingerflags_test", + "aconfig_hardware_flags_c_lib", "android.os.flags-aconfig-cc-test", "android.server.display.flags-aconfig-cc", "libguiflags_no_apex", diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp index 12d6138675..5e78426c77 100644 --- a/services/surfaceflinger/common/FlagManager.cpp +++ b/services/surfaceflinger/common/FlagManager.cpp @@ -27,6 +27,7 @@ #include <cinttypes> #include <android_os.h> +#include <android_hardware_flags.h> #include <com_android_graphics_libgui_flags.h> #include <com_android_graphics_surfaceflinger_flags.h> #include <com_android_server_display_feature_flags.h> @@ -89,9 +90,9 @@ void FlagManager::setUnitTestMode() { mBootCompleted = true; } -void FlagManager::dumpFlag(std::string& result, bool readonly, const char* name, +void FlagManager::dumpFlag(std::string& result, bool aconfig, const char* name, std::function<bool()> getter) const { - if (readonly || mBootCompleted) { + if (aconfig || mBootCompleted) { base::StringAppendF(&result, "%s: %s\n", name, getter() ? "true" : "false"); } else { base::StringAppendF(&result, "%s: in progress (still booting)\n", name); @@ -99,67 +100,75 @@ void FlagManager::dumpFlag(std::string& result, bool readonly, const char* name, } void FlagManager::dump(std::string& result) const { -#define DUMP_FLAG_INTERVAL(name, readonly) \ - dumpFlag(result, (readonly), #name, std::bind(&FlagManager::name, this)) -#define DUMP_SERVER_FLAG(name) DUMP_FLAG_INTERVAL(name, false) -#define DUMP_READ_ONLY_FLAG(name) DUMP_FLAG_INTERVAL(name, true) +#define DUMP_FLAG_INTERNAL(name, aconfig) \ + dumpFlag(result, (aconfig), #name, std::bind(&FlagManager::name, this)) +#define DUMP_LEGACY_SERVER_FLAG(name) DUMP_FLAG_INTERNAL(name, false) +#define DUMP_ACONFIG_FLAG(name) DUMP_FLAG_INTERNAL(name, true) base::StringAppendF(&result, "FlagManager values: \n"); /// Legacy server flags /// - DUMP_SERVER_FLAG(use_adpf_cpu_hint); - DUMP_SERVER_FLAG(use_skia_tracing); + DUMP_LEGACY_SERVER_FLAG(use_adpf_cpu_hint); + DUMP_LEGACY_SERVER_FLAG(use_skia_tracing); - /// Trunk stable server flags /// - DUMP_SERVER_FLAG(refresh_rate_overlay_on_external_display); - DUMP_SERVER_FLAG(adpf_gpu_sf); - DUMP_SERVER_FLAG(adpf_use_fmq_channel); + /// Trunk stable server (R/W) flags /// + DUMP_ACONFIG_FLAG(refresh_rate_overlay_on_external_display); + DUMP_ACONFIG_FLAG(adpf_gpu_sf); + DUMP_ACONFIG_FLAG(adpf_native_session_manager); + DUMP_ACONFIG_FLAG(adpf_use_fmq_channel); + DUMP_ACONFIG_FLAG(graphite_renderengine_preview_rollout); /// Trunk stable readonly flags /// - DUMP_READ_ONLY_FLAG(connected_display); - DUMP_READ_ONLY_FLAG(enable_small_area_detection); - DUMP_READ_ONLY_FLAG(frame_rate_category_mrr); - DUMP_READ_ONLY_FLAG(misc1); - DUMP_READ_ONLY_FLAG(vrr_config); - DUMP_READ_ONLY_FLAG(hotplug2); - DUMP_READ_ONLY_FLAG(hdcp_level_hal); - DUMP_READ_ONLY_FLAG(multithreaded_present); - DUMP_READ_ONLY_FLAG(add_sf_skipped_frames_to_trace); - DUMP_READ_ONLY_FLAG(use_known_refresh_rate_for_fps_consistency); - DUMP_READ_ONLY_FLAG(cache_when_source_crop_layer_only_moved); - DUMP_READ_ONLY_FLAG(enable_fro_dependent_features); - DUMP_READ_ONLY_FLAG(display_protected); - DUMP_READ_ONLY_FLAG(fp16_client_target); - DUMP_READ_ONLY_FLAG(game_default_frame_rate); - DUMP_READ_ONLY_FLAG(enable_layer_command_batching); - DUMP_READ_ONLY_FLAG(screenshot_fence_preservation); - DUMP_READ_ONLY_FLAG(vulkan_renderengine); - DUMP_READ_ONLY_FLAG(renderable_buffer_usage); - DUMP_READ_ONLY_FLAG(vrr_bugfix_24q4); - DUMP_READ_ONLY_FLAG(vrr_bugfix_dropped_frame); - DUMP_READ_ONLY_FLAG(restore_blur_step); - DUMP_READ_ONLY_FLAG(dont_skip_on_early_ro); - DUMP_READ_ONLY_FLAG(protected_if_client); - DUMP_READ_ONLY_FLAG(ce_fence_promise); - DUMP_READ_ONLY_FLAG(idle_screen_refresh_rate_timeout); - DUMP_READ_ONLY_FLAG(graphite_renderengine); - DUMP_READ_ONLY_FLAG(filter_frames_before_trace_starts); - DUMP_READ_ONLY_FLAG(latch_unsignaled_with_auto_refresh_changed); - DUMP_READ_ONLY_FLAG(deprecate_vsync_sf); - DUMP_READ_ONLY_FLAG(allow_n_vsyncs_in_targeter); - DUMP_READ_ONLY_FLAG(detached_mirror); - DUMP_READ_ONLY_FLAG(commit_not_composited); - DUMP_READ_ONLY_FLAG(correct_dpi_with_display_size); - DUMP_READ_ONLY_FLAG(local_tonemap_screenshots); - DUMP_READ_ONLY_FLAG(override_trusted_overlay); - DUMP_READ_ONLY_FLAG(flush_buffer_slots_to_uncache); - DUMP_READ_ONLY_FLAG(force_compile_graphite_renderengine); - DUMP_READ_ONLY_FLAG(single_hop_screenshot); - DUMP_READ_ONLY_FLAG(trace_frame_rate_override); - DUMP_READ_ONLY_FLAG(true_hdr_screenshots); - -#undef DUMP_READ_ONLY_FLAG -#undef DUMP_SERVER_FLAG + DUMP_ACONFIG_FLAG(adpf_fmq_sf); + DUMP_ACONFIG_FLAG(arr_setframerate_gte_enum); + DUMP_ACONFIG_FLAG(connected_display); + DUMP_ACONFIG_FLAG(enable_small_area_detection); + DUMP_ACONFIG_FLAG(stable_edid_ids); + DUMP_ACONFIG_FLAG(frame_rate_category_mrr); + DUMP_ACONFIG_FLAG(misc1); + DUMP_ACONFIG_FLAG(vrr_config); + DUMP_ACONFIG_FLAG(hdcp_level_hal); + DUMP_ACONFIG_FLAG(multithreaded_present); + DUMP_ACONFIG_FLAG(add_sf_skipped_frames_to_trace); + DUMP_ACONFIG_FLAG(use_known_refresh_rate_for_fps_consistency); + DUMP_ACONFIG_FLAG(cache_when_source_crop_layer_only_moved); + DUMP_ACONFIG_FLAG(enable_fro_dependent_features); + DUMP_ACONFIG_FLAG(display_protected); + DUMP_ACONFIG_FLAG(fp16_client_target); + DUMP_ACONFIG_FLAG(game_default_frame_rate); + DUMP_ACONFIG_FLAG(enable_layer_command_batching); + DUMP_ACONFIG_FLAG(vulkan_renderengine); + DUMP_ACONFIG_FLAG(renderable_buffer_usage); + DUMP_ACONFIG_FLAG(vrr_bugfix_24q4); + DUMP_ACONFIG_FLAG(vrr_bugfix_dropped_frame); + DUMP_ACONFIG_FLAG(restore_blur_step); + DUMP_ACONFIG_FLAG(dont_skip_on_early_ro); + DUMP_ACONFIG_FLAG(no_vsyncs_on_screen_off); + DUMP_ACONFIG_FLAG(protected_if_client); + DUMP_ACONFIG_FLAG(idle_screen_refresh_rate_timeout); + DUMP_ACONFIG_FLAG(graphite_renderengine); + DUMP_ACONFIG_FLAG(filter_frames_before_trace_starts); + DUMP_ACONFIG_FLAG(latch_unsignaled_with_auto_refresh_changed); + DUMP_ACONFIG_FLAG(deprecate_vsync_sf); + DUMP_ACONFIG_FLAG(allow_n_vsyncs_in_targeter); + DUMP_ACONFIG_FLAG(detached_mirror); + DUMP_ACONFIG_FLAG(commit_not_composited); + DUMP_ACONFIG_FLAG(correct_dpi_with_display_size); + DUMP_ACONFIG_FLAG(local_tonemap_screenshots); + DUMP_ACONFIG_FLAG(override_trusted_overlay); + DUMP_ACONFIG_FLAG(flush_buffer_slots_to_uncache); + DUMP_ACONFIG_FLAG(force_compile_graphite_renderengine); + DUMP_ACONFIG_FLAG(trace_frame_rate_override); + DUMP_ACONFIG_FLAG(true_hdr_screenshots); + DUMP_ACONFIG_FLAG(display_config_error_hal); + DUMP_ACONFIG_FLAG(connected_display_hdr); + DUMP_ACONFIG_FLAG(deprecate_frame_tracker); + DUMP_ACONFIG_FLAG(skip_invisible_windows_in_input); + DUMP_ACONFIG_FLAG(begone_bright_hlg); + DUMP_ACONFIG_FLAG(window_blur_kawase2); + +#undef DUMP_ACONFIG_FLAG +#undef DUMP_LEGACY_SERVER_FLAG #undef DUMP_FLAG_INTERVAL } @@ -184,35 +193,24 @@ bool FlagManager::getServerConfigurableFlag(const char* experimentFlagName) cons return getServerConfigurableFlag(serverFlagName); \ } -#define FLAG_MANAGER_FLAG_INTERNAL(name, syspropOverride, checkForBootCompleted, owner) \ - bool FlagManager::name() const { \ - if (checkForBootCompleted) { \ - LOG_ALWAYS_FATAL_IF(!mBootCompleted, \ - "Can't read %s before boot completed as it is server writable", \ - __func__); \ - } \ - static const std::optional<bool> debugOverride = getBoolProperty(syspropOverride); \ - static const bool value = getFlagValue([] { return owner ::name(); }, debugOverride); \ - if (mUnitTestMode) { \ - /* \ - * When testing, we don't want to rely on the cached `value` or the debugOverride. \ - */ \ - return owner ::name(); \ - } \ - return value; \ +#define FLAG_MANAGER_ACONFIG_INTERNAL(name, syspropOverride, owner) \ + bool FlagManager::name() const { \ + static const std::optional<bool> debugOverride = getBoolProperty(syspropOverride); \ + static const bool value = getFlagValue([] { return owner ::name(); }, debugOverride); \ + if (mUnitTestMode) { \ + /* \ + * When testing, we don't want to rely on the cached `value` or the debugOverride. \ + */ \ + return owner ::name(); \ + } \ + return value; \ } -#define FLAG_MANAGER_SERVER_FLAG(name, syspropOverride) \ - FLAG_MANAGER_FLAG_INTERNAL(name, syspropOverride, true, flags) +#define FLAG_MANAGER_ACONFIG_FLAG(name, syspropOverride) \ + FLAG_MANAGER_ACONFIG_INTERNAL(name, syspropOverride, flags) -#define FLAG_MANAGER_READ_ONLY_FLAG(name, syspropOverride) \ - FLAG_MANAGER_FLAG_INTERNAL(name, syspropOverride, false, flags) - -#define FLAG_MANAGER_SERVER_FLAG_IMPORTED(name, syspropOverride, owner) \ - FLAG_MANAGER_FLAG_INTERNAL(name, syspropOverride, true, owner) - -#define FLAG_MANAGER_READ_ONLY_FLAG_IMPORTED(name, syspropOverride, owner) \ - FLAG_MANAGER_FLAG_INTERNAL(name, syspropOverride, false, owner) +#define FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(name, syspropOverride, owner) \ + FLAG_MANAGER_ACONFIG_INTERNAL(name, syspropOverride, owner) /// Legacy server flags /// FLAG_MANAGER_LEGACY_SERVER_FLAG(test_flag, "", "") @@ -222,59 +220,68 @@ FLAG_MANAGER_LEGACY_SERVER_FLAG(use_skia_tracing, PROPERTY_SKIA_ATRACE_ENABLED, "SkiaTracingFeature__use_skia_tracing") /// Trunk stable readonly flags /// -FLAG_MANAGER_READ_ONLY_FLAG(connected_display, "") -FLAG_MANAGER_READ_ONLY_FLAG(enable_small_area_detection, "") -FLAG_MANAGER_READ_ONLY_FLAG(frame_rate_category_mrr, "debug.sf.frame_rate_category_mrr") -FLAG_MANAGER_READ_ONLY_FLAG(misc1, "") -FLAG_MANAGER_READ_ONLY_FLAG(vrr_config, "debug.sf.enable_vrr_config") -FLAG_MANAGER_READ_ONLY_FLAG(hotplug2, "") -FLAG_MANAGER_READ_ONLY_FLAG(hdcp_level_hal, "") -FLAG_MANAGER_READ_ONLY_FLAG(multithreaded_present, "debug.sf.multithreaded_present") -FLAG_MANAGER_READ_ONLY_FLAG(add_sf_skipped_frames_to_trace, "") -FLAG_MANAGER_READ_ONLY_FLAG(use_known_refresh_rate_for_fps_consistency, "") -FLAG_MANAGER_READ_ONLY_FLAG(cache_when_source_crop_layer_only_moved, - "debug.sf.cache_source_crop_only_moved") -FLAG_MANAGER_READ_ONLY_FLAG(enable_fro_dependent_features, "") -FLAG_MANAGER_READ_ONLY_FLAG(display_protected, "") -FLAG_MANAGER_READ_ONLY_FLAG(fp16_client_target, "debug.sf.fp16_client_target") -FLAG_MANAGER_READ_ONLY_FLAG(game_default_frame_rate, "") -FLAG_MANAGER_READ_ONLY_FLAG(enable_layer_command_batching, "debug.sf.enable_layer_command_batching") -FLAG_MANAGER_READ_ONLY_FLAG(screenshot_fence_preservation, "debug.sf.screenshot_fence_preservation") -FLAG_MANAGER_READ_ONLY_FLAG(vulkan_renderengine, "debug.renderengine.vulkan") -FLAG_MANAGER_READ_ONLY_FLAG(renderable_buffer_usage, "") -FLAG_MANAGER_READ_ONLY_FLAG(restore_blur_step, "debug.renderengine.restore_blur_step") -FLAG_MANAGER_READ_ONLY_FLAG(dont_skip_on_early_ro, "") -FLAG_MANAGER_READ_ONLY_FLAG(protected_if_client, "") -FLAG_MANAGER_READ_ONLY_FLAG(vrr_bugfix_24q4, ""); -FLAG_MANAGER_READ_ONLY_FLAG(vrr_bugfix_dropped_frame, "") -FLAG_MANAGER_READ_ONLY_FLAG(ce_fence_promise, ""); -FLAG_MANAGER_READ_ONLY_FLAG(graphite_renderengine, "debug.renderengine.graphite") -FLAG_MANAGER_READ_ONLY_FLAG(filter_frames_before_trace_starts, "") -FLAG_MANAGER_READ_ONLY_FLAG(latch_unsignaled_with_auto_refresh_changed, ""); -FLAG_MANAGER_READ_ONLY_FLAG(deprecate_vsync_sf, ""); -FLAG_MANAGER_READ_ONLY_FLAG(allow_n_vsyncs_in_targeter, ""); -FLAG_MANAGER_READ_ONLY_FLAG(detached_mirror, ""); -FLAG_MANAGER_READ_ONLY_FLAG(commit_not_composited, ""); -FLAG_MANAGER_READ_ONLY_FLAG(correct_dpi_with_display_size, ""); -FLAG_MANAGER_READ_ONLY_FLAG(local_tonemap_screenshots, "debug.sf.local_tonemap_screenshots"); -FLAG_MANAGER_READ_ONLY_FLAG(override_trusted_overlay, ""); -FLAG_MANAGER_READ_ONLY_FLAG(flush_buffer_slots_to_uncache, ""); -FLAG_MANAGER_READ_ONLY_FLAG(force_compile_graphite_renderengine, ""); -FLAG_MANAGER_READ_ONLY_FLAG(single_hop_screenshot, ""); -FLAG_MANAGER_READ_ONLY_FLAG(true_hdr_screenshots, "debug.sf.true_hdr_screenshots"); - -/// Trunk stable server flags /// -FLAG_MANAGER_SERVER_FLAG(refresh_rate_overlay_on_external_display, "") -FLAG_MANAGER_SERVER_FLAG(adpf_gpu_sf, "") - -/// Trunk stable server flags from outside SurfaceFlinger /// -FLAG_MANAGER_SERVER_FLAG_IMPORTED(adpf_use_fmq_channel, "", android::os) +FLAG_MANAGER_ACONFIG_FLAG(adpf_fmq_sf, "") +FLAG_MANAGER_ACONFIG_FLAG(arr_setframerate_gte_enum, "debug.sf.arr_setframerate_gte_enum") +FLAG_MANAGER_ACONFIG_FLAG(connected_display, "") +FLAG_MANAGER_ACONFIG_FLAG(enable_small_area_detection, "") +FLAG_MANAGER_ACONFIG_FLAG(stable_edid_ids, "debug.sf.stable_edid_ids") +FLAG_MANAGER_ACONFIG_FLAG(frame_rate_category_mrr, "debug.sf.frame_rate_category_mrr") +FLAG_MANAGER_ACONFIG_FLAG(misc1, "") +FLAG_MANAGER_ACONFIG_FLAG(vrr_config, "debug.sf.enable_vrr_config") +FLAG_MANAGER_ACONFIG_FLAG(hdcp_level_hal, "") +FLAG_MANAGER_ACONFIG_FLAG(multithreaded_present, "debug.sf.multithreaded_present") +FLAG_MANAGER_ACONFIG_FLAG(add_sf_skipped_frames_to_trace, "") +FLAG_MANAGER_ACONFIG_FLAG(use_known_refresh_rate_for_fps_consistency, "") +FLAG_MANAGER_ACONFIG_FLAG(cache_when_source_crop_layer_only_moved, + "debug.sf.cache_source_crop_only_moved") +FLAG_MANAGER_ACONFIG_FLAG(enable_fro_dependent_features, "") +FLAG_MANAGER_ACONFIG_FLAG(display_protected, "") +FLAG_MANAGER_ACONFIG_FLAG(fp16_client_target, "debug.sf.fp16_client_target") +FLAG_MANAGER_ACONFIG_FLAG(game_default_frame_rate, "") +FLAG_MANAGER_ACONFIG_FLAG(enable_layer_command_batching, "debug.sf.enable_layer_command_batching") +FLAG_MANAGER_ACONFIG_FLAG(vulkan_renderengine, "debug.renderengine.vulkan") +FLAG_MANAGER_ACONFIG_FLAG(renderable_buffer_usage, "") +FLAG_MANAGER_ACONFIG_FLAG(restore_blur_step, "debug.renderengine.restore_blur_step") +FLAG_MANAGER_ACONFIG_FLAG(dont_skip_on_early_ro, "") +FLAG_MANAGER_ACONFIG_FLAG(no_vsyncs_on_screen_off, "debug.sf.no_vsyncs_on_screen_off") +FLAG_MANAGER_ACONFIG_FLAG(protected_if_client, "") +FLAG_MANAGER_ACONFIG_FLAG(vrr_bugfix_24q4, ""); +FLAG_MANAGER_ACONFIG_FLAG(vrr_bugfix_dropped_frame, "") +FLAG_MANAGER_ACONFIG_FLAG(graphite_renderengine, "debug.renderengine.graphite") +FLAG_MANAGER_ACONFIG_FLAG(filter_frames_before_trace_starts, "") +FLAG_MANAGER_ACONFIG_FLAG(latch_unsignaled_with_auto_refresh_changed, ""); +FLAG_MANAGER_ACONFIG_FLAG(deprecate_vsync_sf, ""); +FLAG_MANAGER_ACONFIG_FLAG(allow_n_vsyncs_in_targeter, ""); +FLAG_MANAGER_ACONFIG_FLAG(detached_mirror, ""); +FLAG_MANAGER_ACONFIG_FLAG(commit_not_composited, ""); +FLAG_MANAGER_ACONFIG_FLAG(correct_dpi_with_display_size, ""); +FLAG_MANAGER_ACONFIG_FLAG(local_tonemap_screenshots, "debug.sf.local_tonemap_screenshots"); +FLAG_MANAGER_ACONFIG_FLAG(override_trusted_overlay, ""); +FLAG_MANAGER_ACONFIG_FLAG(flush_buffer_slots_to_uncache, ""); +FLAG_MANAGER_ACONFIG_FLAG(force_compile_graphite_renderengine, ""); +FLAG_MANAGER_ACONFIG_FLAG(true_hdr_screenshots, "debug.sf.true_hdr_screenshots"); +FLAG_MANAGER_ACONFIG_FLAG(display_config_error_hal, ""); +FLAG_MANAGER_ACONFIG_FLAG(connected_display_hdr, "debug.sf.connected_display_hdr"); +FLAG_MANAGER_ACONFIG_FLAG(deprecate_frame_tracker, ""); +FLAG_MANAGER_ACONFIG_FLAG(skip_invisible_windows_in_input, ""); +FLAG_MANAGER_ACONFIG_FLAG(begone_bright_hlg, "debug.sf.begone_bright_hlg"); +FLAG_MANAGER_ACONFIG_FLAG(window_blur_kawase2, ""); + +/// Trunk stable server (R/W) flags /// +FLAG_MANAGER_ACONFIG_FLAG(refresh_rate_overlay_on_external_display, "") +FLAG_MANAGER_ACONFIG_FLAG(adpf_gpu_sf, "") +FLAG_MANAGER_ACONFIG_FLAG(adpf_native_session_manager, ""); +FLAG_MANAGER_ACONFIG_FLAG(graphite_renderengine_preview_rollout, ""); + +/// Trunk stable server (R/W) flags from outside SurfaceFlinger /// +FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(adpf_use_fmq_channel, "", android::os) /// Trunk stable readonly flags from outside SurfaceFlinger /// -FLAG_MANAGER_READ_ONLY_FLAG_IMPORTED(idle_screen_refresh_rate_timeout, "", - com::android::server::display::feature::flags) -FLAG_MANAGER_READ_ONLY_FLAG_IMPORTED(adpf_use_fmq_channel_fixed, "", android::os) -FLAG_MANAGER_READ_ONLY_FLAG_IMPORTED(trace_frame_rate_override, "", - com::android::graphics::libgui::flags); - +FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(idle_screen_refresh_rate_timeout, "", + com::android::server::display::feature::flags) +FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(adpf_use_fmq_channel_fixed, "", android::os) +FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(trace_frame_rate_override, "", + com::android::graphics::libgui::flags); +FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(luts_api, "", + android::hardware::flags); } // namespace android diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h index a1be19421b..d8887f538f 100644 --- a/services/surfaceflinger/common/include/common/FlagManager.h +++ b/services/surfaceflinger/common/include/common/FlagManager.h @@ -47,19 +47,23 @@ public: bool use_adpf_cpu_hint() const; bool use_skia_tracing() const; - /// Trunk stable server flags /// + /// Trunk stable server (R/W) flags /// bool refresh_rate_overlay_on_external_display() const; bool adpf_gpu_sf() const; bool adpf_use_fmq_channel() const; + bool adpf_native_session_manager() const; bool adpf_use_fmq_channel_fixed() const; + bool graphite_renderengine_preview_rollout() const; /// Trunk stable readonly flags /// + bool arr_setframerate_gte_enum() const; + bool adpf_fmq_sf() const; bool connected_display() const; bool frame_rate_category_mrr() const; bool enable_small_area_detection() const; + bool stable_edid_ids() const; bool misc1() const; bool vrr_config() const; - bool hotplug2() const; bool hdcp_level_hal() const; bool multithreaded_present() const; bool add_sf_skipped_frames_to_trace() const; @@ -70,15 +74,14 @@ public: bool fp16_client_target() const; bool game_default_frame_rate() const; bool enable_layer_command_batching() const; - bool screenshot_fence_preservation() const; bool vulkan_renderengine() const; bool vrr_bugfix_24q4() const; bool vrr_bugfix_dropped_frame() const; bool renderable_buffer_usage() const; bool restore_blur_step() const; bool dont_skip_on_early_ro() const; + bool no_vsyncs_on_screen_off() const; bool protected_if_client() const; - bool ce_fence_promise() const; bool idle_screen_refresh_rate_timeout() const; bool graphite_renderengine() const; bool filter_frames_before_trace_starts() const; @@ -92,9 +95,15 @@ public: bool override_trusted_overlay() const; bool flush_buffer_slots_to_uncache() const; bool force_compile_graphite_renderengine() const; - bool single_hop_screenshot() const; bool trace_frame_rate_override() const; bool true_hdr_screenshots() const; + bool display_config_error_hal() const; + bool connected_display_hdr() const; + bool deprecate_frame_tracker() const; + bool skip_invisible_windows_in_input() const; + bool begone_bright_hlg() const; + bool luts_api() const; + bool window_blur_kawase2() const; protected: // overridden for unit tests diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp index ae502cf4b4..1de6b4aed9 100644 --- a/services/surfaceflinger/fuzzer/Android.bp +++ b/services/surfaceflinger/fuzzer/Android.bp @@ -28,16 +28,18 @@ package { cc_defaults { name: "surfaceflinger_fuzz_defaults", static_libs: [ - "libc++fs", "libsurfaceflinger_common", ], srcs: [ + ":libsurfaceflinger_backend_mock_sources", + ":libsurfaceflinger_mock_sources", ":libsurfaceflinger_sources", ], defaults: [ "libsurfaceflinger_defaults", ], header_libs: [ + "libsurfaceflinger_backend_mock_headers", "libsurfaceflinger_headers", ], cflags: [ diff --git a/services/surfaceflinger/EventLog/EventLogTags.logtags b/services/surfaceflinger/surfaceflinger.logtags index 76154cb53a..6dbe0dd35c 100644 --- a/services/surfaceflinger/EventLog/EventLogTags.logtags +++ b/services/surfaceflinger/surfaceflinger.logtags @@ -35,7 +35,6 @@ # 60100 - 60199 reserved for surfaceflinger -60100 sf_frame_dur (window|3),(dur0|1),(dur1|1),(dur2|1),(dur3|1),(dur4|1),(dur5|1),(dur6|1) 60110 sf_stop_bootanim (time|2|3) # NOTE - the range 1000000-2000000 is reserved for partners and others who diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig index 102e2b643c..bdd826d084 100644 --- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig @@ -4,6 +4,14 @@ package: "com.android.graphics.surfaceflinger.flags" container: "system" flag { + name: "adpf_fmq_sf" + namespace: "game" + description: "Guards use of the ADPF FMQ system specifically for SurfaceFlinger" + bug: "315894228" + is_fixed_read_only: true +} # adpf_fmq_sf + +flag { name: "adpf_gpu_sf" namespace: "game" description: "Guards use of the sending ADPF GPU duration hint and load hints from SurfaceFlinger to Power HAL" @@ -11,6 +19,47 @@ flag { } # adpf_gpu_sf flag { + name: "adpf_native_session_manager" + namespace: "game" + description: "Controls ADPF SessionManager being enabled in SF" + bug: "367803904" +} # adpf_sessionmanager + +flag { + name: "arr_setframerate_api" + namespace: "core_graphics" + description: "New SDK Surface#setFrameRate API and Surface.FrameRateParams for Android 16" + bug: "356987016" + is_fixed_read_only: true + is_exported: true +} # arr_setframerate_api + +flag { + name: "arr_setframerate_gte_enum" + namespace: "core_graphics" + description: "Exposes GTE (greater than or equal to) enum for Android 16" + bug: "380949716" + is_fixed_read_only: true +} # arr_setframerate_gte_enum + +flag { + name: "arr_surfacecontrol_setframerate_api" + namespace: "core_graphics" + description: "New SDK SurfaceControl.Transaction#setFrameRate API for Android 16" + bug: "356987016" + is_fixed_read_only: true + is_exported: true +} # arr_surfacecontrol_setframerate_api + +flag { + name: "begone_bright_hlg" + namespace: "core_graphics" + description: "Caps HLG brightness relative to SDR" + bug: "362510107" + is_fixed_read_only: true +} # begone_bright_hlg + +flag { name: "ce_fence_promise" namespace: "window_surfaces" description: "Moves logic for buffer release fences into LayerFE" @@ -33,6 +82,14 @@ flag { } # commit_not_composited flag { + name: "connected_display_hdr" + namespace: "core_graphics" + description: "enable connected display hdr capability" + bug: "374182788" + is_fixed_read_only: true +} # connected_display_hdr + +flag { name: "correct_dpi_with_display_size" namespace: "core_graphics" description: "indicate whether missing or likely incorrect dpi should be corrected using the display size." @@ -44,6 +101,17 @@ flag { } # correct_dpi_with_display_size flag { + name: "deprecate_frame_tracker" + namespace: "core_graphics" + description: "Deprecate using FrameTracker to accumulate and provide FrameStats" + bug: "241394120" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} # deprecate_frame_tracker + +flag { name: "deprecate_vsync_sf" namespace: "core_graphics" description: "Depracate eVsyncSourceSurfaceFlinger and use vsync_app everywhere" @@ -66,6 +134,14 @@ flag { } # detached_mirror flag { + name: "display_config_error_hal" + namespace: "core_graphics" + description: "Report HAL display configuration errors like modeset failure or link training failure" + bug: "374184110" + is_fixed_read_only: true +} # display_config_error_hal + +flag { name: "filter_frames_before_trace_starts" namespace: "core_graphics" description: "Do not trace FrameTimeline events for frames started before the trace started" @@ -107,6 +183,13 @@ flag { } # frame_rate_category_mrr flag { + name: "graphite_renderengine_preview_rollout" + namespace: "core_graphics" + description: "R/W flag to enable Skia's Graphite Vulkan backend in RenderEngine, IF it is already compiled with force_compile_graphite_renderengine, AND the debug.renderengine.graphite_preview_optin sysprop is set to true." + bug: "293371537" +} # graphite_renderengine_preview_rollout + +flag { name: "latch_unsignaled_with_auto_refresh_changed" namespace: "core_graphics" description: "Ignore eAutoRefreshChanged with latch unsignaled" @@ -126,6 +209,14 @@ flag { } # local_tonemap_screenshots flag { + name: "no_vsyncs_on_screen_off" + namespace: "core_graphics" + description: "Stop vsync / Choreographer callbacks to apps when the screen is off" + bug: "331636736" + is_fixed_read_only: true +} # no_vsyncs_on_screen_off + +flag { name: "single_hop_screenshot" namespace: "window_surfaces" description: "Only access SF main thread once during a screenshot" @@ -137,6 +228,25 @@ flag { } # single_hop_screenshot flag { + name: "skip_invisible_windows_in_input" + namespace: "window_surfaces" + description: "Only send visible windows to input list" + bug: "305254099" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } + } # skip_invisible_windows_in_input + +flag { + name: "stable_edid_ids" + namespace: "core_graphics" + description: "Guard use of the new stable EDID-based display IDs system." + bug: "352320847" + is_fixed_read_only: true +} # stable_edid_ids + +flag { name: "true_hdr_screenshots" namespace: "core_graphics" description: "Enables screenshotting display content in HDR, sans tone mapping" @@ -185,4 +295,11 @@ flag { } } # vrr_bugfix_dropped_frame +flag { + name: "window_blur_kawase2" + namespace: "core_graphics" + description: "Flag for using Kawase2 algorithm for window blur" + bug: "353826438" +} # window_blur_kawase2 + # IMPORTANT - please keep alphabetize to reduce merge conflicts diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index e6fed63d96..7b6e4bff6a 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -341,9 +341,9 @@ TEST_F(CredentialsTest, TransactionPermissionTest) { WindowInfosListenerUtils windowInfosListenerUtils; std::string name = "Test Layer"; sp<IBinder> token = sp<BBinder>::make(); - WindowInfo windowInfo; - windowInfo.name = name; - windowInfo.token = token; + auto windowInfo = sp<gui::WindowInfoHandle>::make(); + windowInfo->editInfo()->name = name; + windowInfo->editInfo()->token = token; sp<SurfaceControl> surfaceControl = mComposerClient->createSurface(String8(name.c_str()), 100, 100, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState); @@ -370,7 +370,8 @@ TEST_F(CredentialsTest, TransactionPermissionTest) { UIDFaker f(AID_SYSTEM); auto windowIsPresentAndNotTrusted = [&](const std::vector<WindowInfo>& windowInfos) { auto foundWindowInfo = - WindowInfosListenerUtils::findMatchingWindowInfo(windowInfo, windowInfos); + WindowInfosListenerUtils::findMatchingWindowInfo(*windowInfo->getInfo(), + windowInfos); if (!foundWindowInfo) { return false; } @@ -386,7 +387,8 @@ TEST_F(CredentialsTest, TransactionPermissionTest) { Transaction().setTrustedOverlay(surfaceControl, true).apply(/*synchronous=*/true); auto windowIsPresentAndTrusted = [&](const std::vector<WindowInfo>& windowInfos) { auto foundWindowInfo = - WindowInfosListenerUtils::findMatchingWindowInfo(windowInfo, windowInfos); + WindowInfosListenerUtils::findMatchingWindowInfo(*windowInfo->getInfo(), + windowInfos); if (!foundWindowInfo) { return false; } diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp index 56cf13d7fe..65add63165 100644 --- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp +++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp @@ -19,6 +19,7 @@ #pragma clang diagnostic ignored "-Wconversion" #include <common/FlagManager.h> +#include <gui/IConsumerListener.h> #include <ui/DisplayState.h> #include "LayerTransactionTest.h" @@ -45,11 +46,17 @@ protected: SurfaceComposerClient::getDisplayState(mMainDisplay, &mMainDisplayState); SurfaceComposerClient::getActiveDisplayMode(mMainDisplay, &mMainDisplayMode); - sp<IGraphicBufferConsumer> consumer; - BufferQueue::createBufferQueue(&mProducer, &consumer); - consumer->setConsumerName(String8("Virtual disp consumer")); - consumer->setDefaultBufferSize(mMainDisplayMode.resolution.getWidth(), - mMainDisplayMode.resolution.getHeight()); + BufferQueue::createBufferQueue(&mProducer, &mConsumer); + mConsumer->setConsumerName(String8("Virtual disp consumer (MultiDisplayLayerBounds)")); + mConsumer->setDefaultBufferSize(mMainDisplayMode.resolution.getWidth(), + mMainDisplayMode.resolution.getHeight()); + + class StubConsumerListener : public BnConsumerListener { + virtual void onFrameAvailable(const BufferItem&) override {} + virtual void onBuffersReleased() override {} + virtual void onSidebandStreamChanged() override {} + }; + mConsumer->consumerConnect(sp<StubConsumerListener>::make(), true); } virtual void TearDown() { @@ -92,6 +99,7 @@ protected: sp<IBinder> mMainDisplay; PhysicalDisplayId mMainDisplayId; sp<IBinder> mVirtualDisplay; + sp<IGraphicBufferConsumer> mConsumer; sp<IGraphicBufferProducer> mProducer; sp<SurfaceControl> mColorLayer; Color mExpectedColor = {63, 63, 195, 255}; diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h index 67a524799d..c95c875746 100644 --- a/services/surfaceflinger/tests/TransactionTestHarnesses.h +++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h @@ -17,7 +17,6 @@ #define ANDROID_TRANSACTION_TEST_HARNESSES #include <com_android_graphics_libgui_flags.h> -#include <common/FlagManager.h> #include <ui/DisplayState.h> #include "LayerTransactionTest.h" @@ -59,7 +58,7 @@ public: GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_SW_READ_OFTEN); sp<BufferListener> listener = sp<BufferListener>::make(this); itemConsumer->setFrameAvailableListener(listener); - itemConsumer->setName(String8("Virtual disp consumer")); + itemConsumer->setName(String8("Virtual disp consumer (TransactionTest)")); itemConsumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight()); #else sp<IGraphicBufferProducer> producer; @@ -67,7 +66,7 @@ public: sp<BufferItemConsumer> itemConsumer; BufferQueue::createBufferQueue(&producer, &consumer); - consumer->setConsumerName(String8("Virtual disp consumer")); + consumer->setConsumerName(String8("Virtual disp consumer (TransactionTest)")); consumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight()); itemConsumer = sp<BufferItemConsumer>::make(consumer, @@ -96,12 +95,8 @@ public: #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) t.setDisplayProjection(vDisplay, displayState.orientation, Rect(displayState.layerStackSpaceRect), Rect(resolution)); - if (FlagManager::getInstance().ce_fence_promise()) { - t.setDisplayLayerStack(vDisplay, layerStack); - t.setLayerStack(mirrorSc, layerStack); - } else { - t.setDisplayLayerStack(vDisplay, ui::DEFAULT_LAYER_STACK); - } + t.setDisplayLayerStack(vDisplay, layerStack); + t.setLayerStack(mirrorSc, layerStack); t.apply(); SurfaceComposerClient::Transaction().apply(true); @@ -121,10 +116,8 @@ public: // CompositionEngine::present may attempt to be called on the same // display multiple times. The layerStack is set to invalid here so // that the display is ignored if that scenario occurs. - if (FlagManager::getInstance().ce_fence_promise()) { - t.setLayerStack(mirrorSc, ui::INVALID_LAYER_STACK); - t.apply(true); - } + t.setLayerStack(mirrorSc, ui::INVALID_LAYER_STACK); + t.apply(true); SurfaceComposerClient::destroyVirtualDisplay(vDisplay); return sc; } diff --git a/services/surfaceflinger/tests/VirtualDisplay_test.cpp b/services/surfaceflinger/tests/VirtualDisplay_test.cpp index d69378cec2..1108c7fe56 100644 --- a/services/surfaceflinger/tests/VirtualDisplay_test.cpp +++ b/services/surfaceflinger/tests/VirtualDisplay_test.cpp @@ -29,14 +29,14 @@ protected: void SetUp() override { #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) mGLConsumer = sp<GLConsumer>::make(GLConsumer::TEXTURE_EXTERNAL, true, false, false); - mGLConsumer->setName(String8("Virtual disp consumer")); + mGLConsumer->setName(String8("Virtual disp consumer (VirtualDisplayTest)")); mGLConsumer->setDefaultBufferSize(100, 100); mProducer = mGLConsumer->getSurface()->getIGraphicBufferProducer(); #else sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&mProducer, &consumer); - consumer->setConsumerName(String8("Virtual disp consumer")); + consumer->setConsumerName(String8("Virtual disp consumer (VirtualDisplayTest)")); consumer->setDefaultBufferSize(100, 100); mGLConsumer = sp<GLConsumer>::make(consumer, GLConsumer::TEXTURE_EXTERNAL, true, false); diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp index ad9a674456..2dd0dd9bd3 100644 --- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp +++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp @@ -50,9 +50,9 @@ protected: TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) { std::string name = "Test Layer"; sp<IBinder> token = sp<BBinder>::make(); - WindowInfo windowInfo; - windowInfo.name = name; - windowInfo.token = token; + auto windowInfo = sp<gui::WindowInfoHandle>::make(); + windowInfo->editInfo()->name = name; + windowInfo->editInfo()->token = token; sp<SurfaceControl> surfaceControl = mClient->createSurface(String8(name.c_str()), 100, 100, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState); @@ -65,14 +65,14 @@ TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) { .apply(); auto windowPresent = [&](const std::vector<WindowInfo>& windowInfos) { - return findMatchingWindowInfo(windowInfo, windowInfos); + return findMatchingWindowInfo(*windowInfo->getInfo(), windowInfos); }; ASSERT_TRUE(waitForWindowInfosPredicate(windowPresent)); Transaction().reparent(surfaceControl, nullptr).apply(); auto windowNotPresent = [&](const std::vector<WindowInfo>& windowInfos) { - return !findMatchingWindowInfo(windowInfo, windowInfos); + return !findMatchingWindowInfo(*windowInfo->getInfo(), windowInfos); }; ASSERT_TRUE(waitForWindowInfosPredicate(windowNotPresent)); } @@ -80,9 +80,9 @@ TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) { TEST_F(WindowInfosListenerTest, WindowInfoChanged) { std::string name = "Test Layer"; sp<IBinder> token = sp<BBinder>::make(); - WindowInfo windowInfo; - windowInfo.name = name; - windowInfo.token = token; + auto windowInfo = sp<gui::WindowInfoHandle>::make(); + windowInfo->editInfo()->name = name; + windowInfo->editInfo()->token = token; sp<SurfaceControl> surfaceControl = mClient->createSurface(String8(name.c_str()), 100, 100, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState); @@ -96,7 +96,7 @@ TEST_F(WindowInfosListenerTest, WindowInfoChanged) { .apply(); auto windowIsPresentAndTouchableRegionEmpty = [&](const std::vector<WindowInfo>& windowInfos) { - auto foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos); + auto foundWindowInfo = findMatchingWindowInfo(*windowInfo->getInfo(), windowInfos); if (!foundWindowInfo) { return false; } @@ -104,19 +104,19 @@ TEST_F(WindowInfosListenerTest, WindowInfoChanged) { }; ASSERT_TRUE(waitForWindowInfosPredicate(windowIsPresentAndTouchableRegionEmpty)); - windowInfo.addTouchableRegion({0, 0, 50, 50}); + windowInfo->editInfo()->addTouchableRegion({0, 0, 50, 50}); Transaction().setInputWindowInfo(surfaceControl, windowInfo).apply(); auto windowIsPresentAndTouchableRegionMatches = [&](const std::vector<WindowInfo>& windowInfos) { - auto foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos); + auto foundWindowInfo = findMatchingWindowInfo(*windowInfo->getInfo(), windowInfos); if (!foundWindowInfo) { return false; } auto touchableRegion = foundWindowInfo->transform.transform(foundWindowInfo->touchableRegion); - return touchableRegion.hasSameRects(windowInfo.touchableRegion); + return touchableRegion.hasSameRects(windowInfo->getInfo()->touchableRegion); }; ASSERT_TRUE(waitForWindowInfosPredicate(windowIsPresentAndTouchableRegionMatches)); } diff --git a/services/surfaceflinger/tests/benchmarks/Android.bp b/services/surfaceflinger/tests/benchmarks/Android.bp index 1c47be343e..22fca08ccf 100644 --- a/services/surfaceflinger/tests/benchmarks/Android.bp +++ b/services/surfaceflinger/tests/benchmarks/Android.bp @@ -22,7 +22,6 @@ cc_benchmark { static_libs: [ "libgmock", "libgtest", - "libc++fs", ], header_libs: [ "libsurfaceflinger_mocks_headers", diff --git a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h index ae380ad459..97946205ba 100644 --- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h +++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h @@ -182,7 +182,7 @@ public: mLifecycleManager.applyTransactions(setZTransaction(id, z)); } - void setCrop(uint32_t id, const Rect& crop) { + void setCrop(uint32_t id, const FloatRect& crop) { std::vector<TransactionState> transactions; transactions.emplace_back(); transactions.back().states.push_back({}); @@ -193,6 +193,8 @@ public: mLifecycleManager.applyTransactions(transactions); } + void setCrop(uint32_t id, const Rect& crop) { setCrop(id, crop.toFloatRect()); } + void setFlags(uint32_t id, uint32_t mask, uint32_t flags) { std::vector<TransactionState> transactions; transactions.emplace_back(); @@ -216,6 +218,17 @@ public: mLifecycleManager.applyTransactions(transactions); } + void setAutoRefresh(uint32_t id, bool autoRefresh) { + std::vector<TransactionState> transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + + transactions.back().states.front().state.what = layer_state_t::eAutoRefreshChanged; + transactions.back().states.front().layerId = id; + transactions.back().states.front().state.autoRefresh = autoRefresh; + mLifecycleManager.applyTransactions(transactions); + } + void hideLayer(uint32_t id) { setFlags(id, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden); } diff --git a/services/surfaceflinger/tests/tracing/Android.bp b/services/surfaceflinger/tests/tracing/Android.bp index bce1406e9c..6eb7f4a220 100644 --- a/services/surfaceflinger/tests/tracing/Android.bp +++ b/services/surfaceflinger/tests/tracing/Android.bp @@ -35,9 +35,6 @@ cc_test { ":libsurfaceflinger_mock_sources", "TransactionTraceTestSuite.cpp", ], - static_libs: [ - "libc++fs", - ], header_libs: [ "libsurfaceflinger_mocks_headers", ], diff --git a/services/surfaceflinger/tests/unittests/ActivePictureUpdaterTest.cpp b/services/surfaceflinger/tests/unittests/ActivePictureUpdaterTest.cpp new file mode 100644 index 0000000000..b926d2f4da --- /dev/null +++ b/services/surfaceflinger/tests/unittests/ActivePictureUpdaterTest.cpp @@ -0,0 +1,336 @@ +/* + * Copyright 2024 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 <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <android/gui/ActivePicture.h> +#include <android/gui/IActivePictureListener.h> +#include <compositionengine/mock/CompositionEngine.h> +#include <mock/DisplayHardware/MockComposer.h> +#include <mock/MockLayer.h> +#include <renderengine/mock/RenderEngine.h> + +#include "ActivePictureUpdater.h" +#include "LayerFE.h" +#include "TestableSurfaceFlinger.h" + +namespace android { + +using android::compositionengine::LayerFECompositionState; +using android::gui::ActivePicture; +using android::gui::IActivePictureListener; +using android::mock::MockLayer; +using surfaceflinger::frontend::LayerSnapshot; +using testing::_; +using testing::NiceMock; +using testing::Return; + +class TestableLayerFE : public LayerFE { +public: + TestableLayerFE() : LayerFE("TestableLayerFE"), snapshot(*(new LayerSnapshot)) { + mSnapshot = std::unique_ptr<LayerSnapshot>(&snapshot); + } + + LayerSnapshot& snapshot; +}; + +class ActivePictureUpdaterTest : public testing::Test { +protected: + SurfaceFlinger* flinger() { + if (!mFlingerSetup) { + mFlinger.setupMockScheduler(); + mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>()); + mFlinger.setupRenderEngine(std::make_unique<renderengine::mock::RenderEngine>()); + mFlingerSetup = true; + } + return mFlinger.flinger(); + } + +private: + TestableSurfaceFlinger mFlinger; + bool mFlingerSetup = false; +}; + +// Hack to workaround initializer lists not working for parcelables because parcelables inherit from +// Parcelable, which has a virtual destructor. +auto UnorderedElementsAre(std::initializer_list<std::tuple<int32_t, int32_t, int64_t>> tuples) { + std::vector<ActivePicture> activePictures; + for (auto tuple : tuples) { + ActivePicture ap; + ap.layerId = std::get<0>(tuple); + ap.ownerUid = std::get<1>(tuple); + ap.pictureProfileId = std::get<2>(tuple); + activePictures.push_back(ap); + } + return testing::UnorderedElementsAreArray(activePictures); +} + +// Parcelables don't define this for matchers, which is unfortunate +void PrintTo(const ActivePicture& activePicture, std::ostream* os) { + *os << activePicture.toString(); +} + +TEST_F(ActivePictureUpdaterTest, notCalledWithNoProfile) { + sp<NiceMock<MockLayer>> layer = sp<NiceMock<MockLayer>>::make(flinger(), 100); + TestableLayerFE layerFE; + EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + ActivePictureUpdater updater; + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle::NONE; + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_FALSE(updater.updateAndHasChanged()); + } +} + +TEST_F(ActivePictureUpdaterTest, calledWhenLayerStartsUsingProfile) { + sp<NiceMock<MockLayer>> layer = sp<NiceMock<MockLayer>>::make(flinger(), 100); + TestableLayerFE layerFE; + EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + ActivePictureUpdater updater; + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle::NONE; + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_FALSE(updater.updateAndHasChanged()); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); + } +} + +TEST_F(ActivePictureUpdaterTest, notCalledWhenLayerContinuesUsingProfile) { + sp<NiceMock<MockLayer>> layer = sp<NiceMock<MockLayer>>::make(flinger(), 100); + TestableLayerFE layerFE; + EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + ActivePictureUpdater updater; + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_FALSE(updater.updateAndHasChanged()); + } +} + +TEST_F(ActivePictureUpdaterTest, calledWhenLayerStopsUsingProfile) { + sp<NiceMock<MockLayer>> layer = sp<NiceMock<MockLayer>>::make(flinger(), 100); + TestableLayerFE layerFE; + EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + ActivePictureUpdater updater; + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle::NONE; + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({})); + } +} + +TEST_F(ActivePictureUpdaterTest, calledWhenLayerChangesProfile) { + sp<NiceMock<MockLayer>> layer = sp<NiceMock<MockLayer>>::make(flinger(), 100); + TestableLayerFE layerFE; + EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + ActivePictureUpdater updater; + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE.onPictureProfileCommitted(); + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 2}})); + } +} + +TEST_F(ActivePictureUpdaterTest, notCalledWhenUncommittedLayerChangesProfile) { + sp<NiceMock<MockLayer>> layer1 = sp<NiceMock<MockLayer>>::make(flinger(), 100); + TestableLayerFE layerFE1; + EXPECT_CALL(*layer1, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + sp<NiceMock<MockLayer>> layer2 = sp<NiceMock<MockLayer>>::make(flinger(), 200); + TestableLayerFE layerFE2; + EXPECT_CALL(*layer2, getOwnerUid()).WillRepeatedly(Return(uid_t(20))); + + ActivePictureUpdater updater; + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); + updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); + } + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); + updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + ASSERT_FALSE(updater.updateAndHasChanged()); + } +} + +TEST_F(ActivePictureUpdaterTest, calledWhenDifferentLayerUsesSameProfile) { + sp<NiceMock<MockLayer>> layer1 = sp<NiceMock<MockLayer>>::make(flinger(), 100); + TestableLayerFE layerFE1; + EXPECT_CALL(*layer1, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + sp<NiceMock<MockLayer>> layer2 = sp<NiceMock<MockLayer>>::make(flinger(), 200); + TestableLayerFE layerFE2; + EXPECT_CALL(*layer2, getOwnerUid()).WillRepeatedly(Return(uid_t(20))); + + ActivePictureUpdater updater; + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE2.onPictureProfileCommitted(); + updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), + UnorderedElementsAre({{100, 10, 1}, {200, 20, 2}})); + } + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE1.onPictureProfileCommitted(); + updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE2.onPictureProfileCommitted(); + updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), + UnorderedElementsAre({{100, 10, 2}, {200, 20, 1}})); + } +} + +TEST_F(ActivePictureUpdaterTest, calledWhenSameUidUsesSameProfile) { + sp<NiceMock<MockLayer>> layer1 = sp<NiceMock<MockLayer>>::make(flinger(), 100); + TestableLayerFE layerFE1; + EXPECT_CALL(*layer1, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + sp<NiceMock<MockLayer>> layer2 = sp<NiceMock<MockLayer>>::make(flinger(), 200); + TestableLayerFE layerFE2; + EXPECT_CALL(*layer2, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + ActivePictureUpdater updater; + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE2.onPictureProfileCommitted(); + updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), + UnorderedElementsAre({{100, 10, 1}, {200, 10, 2}})); + } + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE1.onPictureProfileCommitted(); + updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE2.onPictureProfileCommitted(); + updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), + UnorderedElementsAre({{100, 10, 2}, {200, 10, 1}})); + } +} + +TEST_F(ActivePictureUpdaterTest, calledWhenNewLayerUsesSameProfile) { + sp<NiceMock<MockLayer>> layer1 = sp<NiceMock<MockLayer>>::make(flinger(), 100); + TestableLayerFE layerFE1; + EXPECT_CALL(*layer1, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + ActivePictureUpdater updater; + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); + } + + sp<NiceMock<MockLayer>> layer2 = sp<NiceMock<MockLayer>>::make(flinger(), 200); + TestableLayerFE layerFE2; + EXPECT_CALL(*layer2, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE2.onPictureProfileCommitted(); + updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), + UnorderedElementsAre({{100, 10, 1}, {200, 10, 1}})); + } +} + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index f1bd87ccd1..6af51435c3 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -22,15 +22,44 @@ package { default_team: "trendy_team_android_core_graphics_stack", } +// This is a step towards pulling out the "backend" sources to clean up the +// dependency graph between CompositionEngine and SurfaceFlinger. +// MockNativeWindow doesn't strictly belong here, but this works for now so +// that CompositionEngine tests can use these mocks. filegroup { - name: "libsurfaceflinger_mock_sources", + name: "libsurfaceflinger_backend_mock_sources", srcs: [ - "mock/DisplayHardware/MockPowerHalController.cpp", + ":poweradvisor_mock_sources", "mock/DisplayHardware/MockComposer.cpp", "mock/DisplayHardware/MockHWC2.cpp", - "mock/DisplayHardware/MockIPower.cpp", - "mock/DisplayHardware/MockPowerHintSessionWrapper.cpp", - "mock/DisplayHardware/MockPowerAdvisor.cpp", + "mock/DisplayHardware/MockHWComposer.cpp", + "mock/system/window/MockNativeWindow.cpp", + ], +} + +cc_library_headers { + name: "libsurfaceflinger_backend_mock_headers", + export_include_dirs: ["."], + static_libs: [ + "libgmock", + "libgtest", + ], + export_static_lib_headers: [ + "libgmock", + "libgtest", + ], +} + +filegroup { + name: "poweradvisor_mock_sources", + srcs: [ + "mock/PowerAdvisor/*.cpp", + ], +} + +filegroup { + name: "libsurfaceflinger_mock_sources", + srcs: [ "mock/MockEventThread.cpp", "mock/MockFrameTimeline.cpp", "mock/MockFrameTracer.cpp", @@ -39,7 +68,6 @@ filegroup { "mock/MockVsyncController.cpp", "mock/MockVSyncDispatch.cpp", "mock/MockVSyncTracker.cpp", - "mock/system/window/MockNativeWindow.cpp", ], } @@ -57,84 +85,12 @@ cc_test { "surfaceflinger_defaults", ], test_suites: ["device-tests"], - static_libs: ["libc++fs"], header_libs: ["surfaceflinger_tests_common_headers"], srcs: [ + ":libsurfaceflinger_backend_mock_sources", ":libsurfaceflinger_mock_sources", ":libsurfaceflinger_sources", - "libsurfaceflinger_unittest_main.cpp", - "ActiveDisplayRotationFlagsTest.cpp", - "BackgroundExecutorTest.cpp", - "CommitTest.cpp", - "CompositionTest.cpp", - "DaltonizerTest.cpp", - "DisplayIdGeneratorTest.cpp", - "DisplayTransactionTest.cpp", - "DisplayDevice_GetBestColorModeTest.cpp", - "DisplayDevice_SetDisplayBrightnessTest.cpp", - "DisplayDevice_SetProjectionTest.cpp", - "DisplayModeControllerTest.cpp", - "EventThreadTest.cpp", - "FlagManagerTest.cpp", - "FpsReporterTest.cpp", - "FpsTest.cpp", - "FramebufferSurfaceTest.cpp", - "FrameRateOverrideMappingsTest.cpp", - "FrameTimelineTest.cpp", - "HWComposerTest.cpp", - "JankTrackerTest.cpp", - "OneShotTimerTest.cpp", - "LayerHistoryIntegrationTest.cpp", - "LayerInfoTest.cpp", - "LayerMetadataTest.cpp", - "LayerHierarchyTest.cpp", - "LayerLifecycleManagerTest.cpp", - "LayerSnapshotTest.cpp", - "LayerTestUtils.cpp", - "MessageQueueTest.cpp", - "PowerAdvisorTest.cpp", - "SmallAreaDetectionAllowMappingsTest.cpp", - "SurfaceFlinger_ColorMatrixTest.cpp", - "SurfaceFlinger_CreateDisplayTest.cpp", - "SurfaceFlinger_DestroyDisplayTest.cpp", - "SurfaceFlinger_DisplayModeSwitching.cpp", - "SurfaceFlinger_DisplayTransactionCommitTest.cpp", - "SurfaceFlinger_ExcludeDolbyVisionTest.cpp", - "SurfaceFlinger_FoldableTest.cpp", - "SurfaceFlinger_GetDisplayNativePrimariesTest.cpp", - "SurfaceFlinger_GetDisplayStatsTest.cpp", - "SurfaceFlinger_HdrOutputControlTest.cpp", - "SurfaceFlinger_HotplugTest.cpp", - "SurfaceFlinger_InitializeDisplaysTest.cpp", - "SurfaceFlinger_NotifyExpectedPresentTest.cpp", - "SurfaceFlinger_NotifyPowerBoostTest.cpp", - "SurfaceFlinger_PowerHintTest.cpp", - "SurfaceFlinger_SetDisplayStateTest.cpp", - "SurfaceFlinger_SetPowerModeInternalTest.cpp", - "SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp", - "SchedulerTest.cpp", - "RefreshRateSelectorTest.cpp", - "RefreshRateStatsTest.cpp", - "RegionSamplingTest.cpp", - "TestableScheduler.cpp", - "TimeStatsTest.cpp", - "FrameTracerTest.cpp", - "TransactionApplicationTest.cpp", - "TransactionFrameTracerTest.cpp", - "TransactionProtoParserTest.cpp", - "TransactionSurfaceFrameTest.cpp", - "TransactionTraceWriterTest.cpp", - "TransactionTracingTest.cpp", - "TunnelModeEnabledReporterTest.cpp", - "VSyncCallbackRegistrationTest.cpp", - "VSyncDispatchTimerQueueTest.cpp", - "VSyncDispatchRealtimeTest.cpp", - "VsyncModulatorTest.cpp", - "VSyncPredictorTest.cpp", - "VSyncReactorTest.cpp", - "VsyncConfigurationTest.cpp", - "VsyncScheduleTest.cpp", - "WindowInfosListenerInvokerTest.cpp", + "*.cpp", ], } @@ -199,6 +155,7 @@ cc_defaults { "libpowermanager", "libprocessgroup", "libprotobuf-cpp-lite", + "libstatslog_surfaceflinger", "libSurfaceFlingerProp", "libsync", "libui", diff --git a/services/surfaceflinger/tests/unittests/BackgroundExecutorTest.cpp b/services/surfaceflinger/tests/unittests/BackgroundExecutorTest.cpp index 5413bae55c..72d1351eb4 100644 --- a/services/surfaceflinger/tests/unittests/BackgroundExecutorTest.cpp +++ b/services/surfaceflinger/tests/unittests/BackgroundExecutorTest.cpp @@ -1,3 +1,19 @@ +/* + * Copyright 2024 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 <gtest/gtest.h> #include <condition_variable> diff --git a/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h b/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h index d4c801f050..b517ff02ad 100644 --- a/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h +++ b/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h @@ -22,8 +22,8 @@ #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" -#include "mock/DisplayHardware/MockPowerAdvisor.h" #include "mock/MockTimeStats.h" +#include "mock/PowerAdvisor/MockPowerAdvisor.h" #include "mock/system/window/MockNativeWindow.h" namespace android { @@ -33,11 +33,11 @@ struct CommitAndCompositeTest : testing::Test { void SetUp() override { mFlinger.setupMockScheduler({.displayId = DEFAULT_DISPLAY_ID}); mComposer = new Hwc2::mock::Composer(); - mPowerAdvisor = new Hwc2::mock::PowerAdvisor(); + mPowerAdvisor = new adpf::mock::PowerAdvisor(); mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine)); mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats)); mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer)); - mFlinger.setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor>(mPowerAdvisor)); + mFlinger.setupPowerAdvisor(std::unique_ptr<adpf::PowerAdvisor>(mPowerAdvisor)); constexpr bool kIsPrimary = true; FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, hal::DisplayType::PHYSICAL, kIsPrimary) @@ -79,7 +79,7 @@ struct CommitAndCompositeTest : testing::Test { sp<compositionengine::mock::DisplaySurface>::make(); sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make(); mock::TimeStats* mTimeStats = new mock::TimeStats(); - Hwc2::mock::PowerAdvisor* mPowerAdvisor = nullptr; + adpf::mock::PowerAdvisor* mPowerAdvisor = nullptr; Hwc2::mock::Composer* mComposer = nullptr; }; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 23d3c168bd..860ad2e013 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -40,10 +40,10 @@ #include "Layer.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" -#include "mock/DisplayHardware/MockPowerAdvisor.h" #include "mock/MockEventThread.h" #include "mock/MockTimeStats.h" #include "mock/MockVsyncController.h" +#include "mock/PowerAdvisor/MockPowerAdvisor.h" #include "mock/system/window/MockNativeWindow.h" namespace android { @@ -110,9 +110,9 @@ public: mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats)); mComposer = new Hwc2::mock::Composer(); - mPowerAdvisor = new Hwc2::mock::PowerAdvisor(); + mPowerAdvisor = new adpf::mock::PowerAdvisor(); mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer)); - mFlinger.setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor>(mPowerAdvisor)); + mFlinger.setupPowerAdvisor(std::unique_ptr<adpf::PowerAdvisor>(mPowerAdvisor)); mFlinger.mutableMaxRenderTargetSize() = 16384; } @@ -158,7 +158,7 @@ public: Hwc2::mock::Composer* mComposer = nullptr; renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine(); mock::TimeStats* mTimeStats = new mock::TimeStats(); - Hwc2::mock::PowerAdvisor* mPowerAdvisor = nullptr; + adpf::mock::PowerAdvisor* mPowerAdvisor = nullptr; sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE; @@ -467,7 +467,7 @@ struct BaseLayerProperties { LayerProperties::FORMAT, LayerProperties::USAGE | GraphicBuffer::USAGE_HW_TEXTURE); - layer.crop = Rect(0, 0, LayerProperties::HEIGHT, LayerProperties::WIDTH); + layer.crop = FloatRect(0, 0, LayerProperties::HEIGHT, LayerProperties::WIDTH); layer.externalTexture = buffer; layer.bufferData->acquireFence = Fence::NO_FENCE; layer.dataspace = ui::Dataspace::UNKNOWN; @@ -664,7 +664,8 @@ struct SidebandLayerProperties : public BaseLayerProperties<SidebandLayerPropert NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM), false); layer.sidebandStream = stream; - layer.crop = Rect(0, 0, SidebandLayerProperties::HEIGHT, SidebandLayerProperties::WIDTH); + layer.crop = + FloatRect(0, 0, SidebandLayerProperties::HEIGHT, SidebandLayerProperties::WIDTH); } static void setupHwcSetSourceCropBufferCallExpectations(CompositionTest* test) { @@ -828,7 +829,7 @@ struct EffectLayerVariant : public BaseLayerVariant<LayerProperties> { return frontend::RequestedLayerState(args); }); - layer.crop = Rect(0, 0, LayerProperties::HEIGHT, LayerProperties::WIDTH); + layer.crop = FloatRect(0, 0, LayerProperties::HEIGHT, LayerProperties::WIDTH); return layer; } diff --git a/services/surfaceflinger/tests/unittests/DisplayModeControllerTest.cpp b/services/surfaceflinger/tests/unittests/DisplayModeControllerTest.cpp index d971150d42..29a1fab5ff 100644 --- a/services/surfaceflinger/tests/unittests/DisplayModeControllerTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayModeControllerTest.cpp @@ -20,6 +20,7 @@ #include "Display/DisplayModeController.h" #include "Display/DisplaySnapshot.h" #include "DisplayHardware/HWComposer.h" +#include "DisplayHardware/Hal.h" #include "DisplayIdentificationTestHelpers.h" #include "FpsOps.h" #include "mock/DisplayHardware/MockComposer.h" @@ -103,7 +104,7 @@ protected: EXPECT_CALL(*mComposerHal, setActiveConfigWithConstraints(kHwcDisplayId, hwcModeId, constraints, _)) - .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(hal::V2_4::Error::NONE))); + .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(hal::Error::NONE))); return constraints; } @@ -183,7 +184,8 @@ TEST_F(DisplayModeControllerTest, initiateModeChange) REQUIRES(kMainThreadContex hal::VsyncPeriodChangeTimeline timeline; const auto constraints = expectModeSet(modeRequest, timeline); - EXPECT_TRUE(mDmc.initiateModeChange(mDisplayId, std::move(modeRequest), constraints, timeline)); + EXPECT_EQ(DisplayModeController::ModeChangeResult::Changed, + mDmc.initiateModeChange(mDisplayId, std::move(modeRequest), constraints, timeline)); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDmc.getPendingMode(mDisplayId)); mDmc.clearDesiredMode(mDisplayId); @@ -210,7 +212,8 @@ TEST_F(DisplayModeControllerTest, initiateDisplayModeSwitch) FTL_FAKE_GUARD(kMai hal::VsyncPeriodChangeTimeline timeline; auto constraints = expectModeSet(modeRequest, timeline); - EXPECT_TRUE(mDmc.initiateModeChange(mDisplayId, std::move(modeRequest), constraints, timeline)); + EXPECT_EQ(DisplayModeController::ModeChangeResult::Changed, + mDmc.initiateModeChange(mDisplayId, std::move(modeRequest), constraints, timeline)); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode90, mDmc.getPendingMode(mDisplayId)); // No action since a mode switch has already been initiated. @@ -223,7 +226,8 @@ TEST_F(DisplayModeControllerTest, initiateDisplayModeSwitch) FTL_FAKE_GUARD(kMai constexpr bool kSubsequent = true; constraints = expectModeSet(modeRequest, timeline, kSubsequent); - EXPECT_TRUE(mDmc.initiateModeChange(mDisplayId, std::move(modeRequest), constraints, timeline)); + EXPECT_EQ(DisplayModeController::ModeChangeResult::Changed, + mDmc.initiateModeChange(mDisplayId, std::move(modeRequest), constraints, timeline)); EXPECT_DISPLAY_MODE_REQUEST(kDesiredMode120, mDmc.getPendingMode(mDisplayId)); mDmc.clearDesiredMode(mDisplayId); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index db3c0a1d69..fa976c8091 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -47,10 +47,10 @@ #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" #include "mock/DisplayHardware/MockDisplayMode.h" -#include "mock/DisplayHardware/MockPowerAdvisor.h" #include "mock/MockEventThread.h" #include "mock/MockNativeWindowSurface.h" #include "mock/MockVsyncController.h" +#include "mock/PowerAdvisor/MockPowerAdvisor.h" #include "mock/system/window/MockNativeWindow.h" namespace android { @@ -118,7 +118,7 @@ public: sp<GraphicBuffer> mBuffer = sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN); - Hwc2::mock::PowerAdvisor mPowerAdvisor; + adpf::mock::PowerAdvisor mPowerAdvisor; FakeDisplayInjector mFakeDisplayInjector{mFlinger, mPowerAdvisor, mNativeWindow}; diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 625d2e68d8..268a6c416d 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -23,6 +23,7 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> +#include <gui/DisplayEventReceiver.h> #include <log/log.h> #include <scheduler/VsyncConfig.h> #include <utils/Errors.h> @@ -111,6 +112,8 @@ protected: void expectOnExpectedPresentTimePosted(nsecs_t expectedPresentTime); void expectUidFrameRateMappingEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, std::vector<FrameRateOverride>); + void expectQueuedBufferCountReceivedByConnection( + ConnectionEventRecorder& connectionEventRecorder, uint32_t expectedBufferCount); void onVSyncEvent(nsecs_t timestamp, nsecs_t expectedPresentationTime, nsecs_t deadlineTimestamp) { @@ -144,6 +147,7 @@ protected: sp<MockEventThreadConnection> mConnection; sp<MockEventThreadConnection> mThrottledConnection; std::unique_ptr<frametimeline::impl::TokenManager> mTokenManager; + std::vector<ConnectionEventRecorder*> mBufferStuffedConnectionRecorders; std::chrono::nanoseconds mVsyncPeriod; @@ -376,6 +380,14 @@ void EventThreadTest::expectUidFrameRateMappingEventReceivedByConnection( EXPECT_EQ(expectedDisplayId, event.header.displayId); } +void EventThreadTest::expectQueuedBufferCountReceivedByConnection( + ConnectionEventRecorder& connectionEventRecorder, uint32_t expectedBufferCount) { + auto args = connectionEventRecorder.waitForCall(); + ASSERT_TRUE(args.has_value()); + const auto& event = std::get<0>(args.value()); + EXPECT_EQ(expectedBufferCount, event.vsync.vsyncData.numberQueuedBuffers); +} + namespace { using namespace testing; @@ -868,6 +880,63 @@ TEST_F(EventThreadTest, postHcpLevelsChanged) { EXPECT_EQ(HDCP_V2, event.hdcpLevelsChange.maxLevel); } +TEST_F(EventThreadTest, connectionReceivesBufferStuffing) { + setupEventThread(); + + // Create a connection that will experience buffer stuffing. + ConnectionEventRecorder stuffedConnectionEventRecorder{0}; + sp<MockEventThreadConnection> stuffedConnection = + createConnection(stuffedConnectionEventRecorder, + gui::ISurfaceComposer::EventRegistration::modeChanged | + gui::ISurfaceComposer::EventRegistration::frameRateOverride, + 111); + + // Add a connection and buffer count to the list of stuffed Uids that will receive + // data in the next vsync event. + BufferStuffingMap bufferStuffedUids; + bufferStuffedUids.try_emplace(stuffedConnection->mOwnerUid, 3); + mThread->addBufferStuffedUids(bufferStuffedUids); + mBufferStuffedConnectionRecorders.emplace_back(&stuffedConnectionEventRecorder); + + // Signal that we want the next vsync event to be posted to two connections. + mThread->requestNextVsync(mConnection); + mThread->requestNextVsync(stuffedConnection); + onVSyncEvent(123, 456, 789); + + // Vsync event data contains number of queued buffers. + expectQueuedBufferCountReceivedByConnection(mConnectionEventCallRecorder, 0); + expectQueuedBufferCountReceivedByConnection(stuffedConnectionEventRecorder, 3); +} + +TEST_F(EventThreadTest, connectionsWithSameUidReceiveBufferStuffing) { + setupEventThread(); + + // Create a connection with the same Uid as another connection. + ConnectionEventRecorder secondConnectionEventRecorder{0}; + sp<MockEventThreadConnection> secondConnection = + createConnection(secondConnectionEventRecorder, + gui::ISurfaceComposer::EventRegistration::modeChanged | + gui::ISurfaceComposer::EventRegistration::frameRateOverride, + mConnectionUid); + + // Add connection Uid and buffer count to the list of stuffed Uids that will receive + // data in the next vsync event. + BufferStuffingMap bufferStuffedUids; + bufferStuffedUids.try_emplace(mConnectionUid, 3); + mThread->addBufferStuffedUids(bufferStuffedUids); + mBufferStuffedConnectionRecorders.emplace_back(&mConnectionEventCallRecorder); + mBufferStuffedConnectionRecorders.emplace_back(&secondConnectionEventRecorder); + + // Signal that we want the next vsync event to be posted to two connections. + mThread->requestNextVsync(mConnection); + mThread->requestNextVsync(secondConnection); + onVSyncEvent(123, 456, 789); + + // Vsync event data contains number of queued buffers. + expectQueuedBufferCountReceivedByConnection(mConnectionEventCallRecorder, 3); + expectQueuedBufferCountReceivedByConnection(secondConnectionEventRecorder, 3); +} + } // namespace } // namespace android diff --git a/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h b/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h index 6e4bf2b06e..744c53637a 100644 --- a/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h +++ b/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h @@ -19,14 +19,14 @@ #include <gmock/gmock.h> #include "TestableSurfaceFlinger.h" -#include "mock/DisplayHardware/MockPowerAdvisor.h" +#include "mock/PowerAdvisor/MockPowerAdvisor.h" #include "mock/system/window/MockNativeWindow.h" namespace android { using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector; +using android::adpf::mock::PowerAdvisor; using android::hardware::graphics::composer::hal::HWDisplayId; -using android::Hwc2::mock::PowerAdvisor; struct FakeDisplayInjectorArgs { PhysicalDisplayId displayId = PhysicalDisplayId::fromPort(255u); @@ -36,7 +36,7 @@ struct FakeDisplayInjectorArgs { class FakeDisplayInjector { public: - FakeDisplayInjector(TestableSurfaceFlinger& flinger, Hwc2::mock::PowerAdvisor& powerAdvisor, + FakeDisplayInjector(TestableSurfaceFlinger& flinger, PowerAdvisor& powerAdvisor, sp<mock::NativeWindow> nativeWindow) : mFlinger(flinger), mPowerAdvisor(powerAdvisor), mNativeWindow(nativeWindow) {} @@ -89,7 +89,7 @@ public: } TestableSurfaceFlinger& mFlinger; - Hwc2::mock::PowerAdvisor& mPowerAdvisor; + PowerAdvisor& mPowerAdvisor; sp<mock::NativeWindow> mNativeWindow; }; diff --git a/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp b/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp index 51b5f40a52..a5b347a43c 100644 --- a/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp +++ b/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp @@ -85,12 +85,6 @@ TEST_F(FlagManagerTest, legacyReturnsValue) { EXPECT_EQ(false, mFlagManager.test_flag()); } -TEST_F(FlagManagerTest, crashesIfQueriedBeforeBoot) { - mFlagManager.markBootIncomplete(); - EXPECT_DEATH(FlagManager::getInstance() - .refresh_rate_overlay_on_external_display(), ""); -} - TEST_F(FlagManagerTest, returnsOverrideTrue) { mFlagManager.markBootCompleted(); diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp index e0753a3cfb..ba2d3e28ad 100644 --- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -69,7 +69,7 @@ using ::testing::SetArgPointee; using ::testing::StrictMock; struct HWComposerTest : testing::Test { - using HalError = hardware::graphics::composer::V2_1::Error; + using HalError = hal::Error; Hwc2::mock::Composer* const mHal = new StrictMock<Hwc2::mock::Composer>(); impl::HWComposer mHwc{std::unique_ptr<Hwc2::Composer>(mHal)}; @@ -384,6 +384,7 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_ON) { const ui::Size size = info->preferredDetailedTimingDescriptor->physicalSizeInMm; const float expectedDpiX = (kWidth * kMmPerInch / size.width); const float expectedDpiY = (kHeight * kMmPerInch / size.height); + const OutputType hdrOutputType = OutputType::SYSTEM; const hal::VrrConfig vrrConfig = hal::VrrConfig{.minFrameIntervalNs = static_cast<Fps>(120_Hz).getPeriodNsecs(), .notifyExpectedPresentConfig = hal::VrrConfig:: @@ -394,7 +395,8 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_ON) { .height = kHeight, .configGroup = kConfigGroup, .vsyncPeriod = kVsyncPeriod, - .vrrConfig = vrrConfig}; + .vrrConfig = vrrConfig, + .hdrOutputType = hdrOutputType}; EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _, _)) .WillOnce(DoAll(SetArgPointee<2>(std::vector<hal::DisplayConfiguration>{ @@ -410,6 +412,7 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_ON) { EXPECT_EQ(modes.front().configGroup, kConfigGroup); EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod); EXPECT_EQ(modes.front().vrrConfig, vrrConfig); + EXPECT_EQ(modes.front().hdrOutputType, hdrOutputType); if (!FlagManager::getInstance().correct_dpi_with_display_size()) { EXPECT_EQ(modes.front().dpiX, -1); EXPECT_EQ(modes.front().dpiY, -1); @@ -435,6 +438,7 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations_VRR_ON) { EXPECT_EQ(modes.front().configGroup, kConfigGroup); EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod); EXPECT_EQ(modes.front().vrrConfig, vrrConfig); + EXPECT_EQ(modes.front().hdrOutputType, hdrOutputType); EXPECT_EQ(modes.front().dpiX, kDpi); EXPECT_EQ(modes.front().dpiY, kDpi); diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp index de37b6342c..53a9062a5a 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp @@ -584,7 +584,7 @@ TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitGte_vrr) { auto layer = createLegacyAndFrontedEndLayer(1); showLayer(1); - setFrameRate(1, (33_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_GTE, + setFrameRate(1, (33_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_GTE, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); setFrameRateCategory(1, 0); @@ -623,7 +623,7 @@ TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitGte_nonVrr) { auto layer = createLegacyAndFrontedEndLayer(1); showLayer(1); - setFrameRate(1, (33_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_GTE, + setFrameRate(1, (33_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_GTE, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); setFrameRateCategory(1, 0); @@ -654,6 +654,72 @@ TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitGte_nonVrr) { EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); } +TEST_F(LayerHistoryIntegrationTest, oneLayerGteNoVote_arr) { + SET_FLAG_FOR_TEST(flags::arr_setframerate_gte_enum, true); + // Set the test to be on a vrr mode. + SET_FLAG_FOR_TEST(flags::vrr_config, true); + mSelector->setActiveMode(kVrrModeId, HI_FPS); + + auto layer = createLegacyAndFrontedEndLayer(1); + showLayer(1); + setFrameRate(1, (0_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_GTE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + + nsecs_t time = systemTime(); + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + setBufferWithPresentTime(layer, time); + time += HI_FPS_PERIOD; + } + + // Layer is active but GTE with 0 should be considered NoVote, thus nothing from summarize. + ASSERT_EQ(0u, summarizeLayerHistory(time).size()); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + + // layer became inactive. + setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + ASSERT_EQ(0u, summarizeLayerHistory(time).size()); + EXPECT_EQ(0u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); +} + +TEST_F(LayerHistoryIntegrationTest, oneLayerGteNoVote_mrr) { + SET_FLAG_FOR_TEST(flags::arr_setframerate_gte_enum, true); + // True by default on MRR devices as well, but the device is not set to VRR mode. + SET_FLAG_FOR_TEST(flags::vrr_config, true); + + auto layer = createLegacyAndFrontedEndLayer(1); + showLayer(1); + setFrameRate(1, (0_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_GTE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + setFrameRateCategory(1, 0); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + + nsecs_t time = systemTime(); + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + setBufferWithPresentTime(layer, time); + time += HI_FPS_PERIOD; + } + + // Layer is active but GTE with 0 should be considered NoVote, thus nothing from summarize. + ASSERT_EQ(0u, summarizeLayerHistory(time).size()); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + + // layer became inactive. + setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + ASSERT_EQ(0u, summarizeLayerHistory(time).size()); + EXPECT_EQ(0u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); +} + TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitVoteWithCategory_vrrFeatureOff) { SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false); @@ -715,6 +781,204 @@ TEST_F(LayerHistoryIntegrationTest, oneLayerCategoryNoPreference) { EXPECT_EQ(0, frequentLayerCount(time)); } +// Tests MRR NoPreference-only vote, no game default override. Expects vote reset. +TEST_F(LayerHistoryIntegrationTest, oneLayerCategoryNoPreference_mrr) { + SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false); + SET_FLAG_FOR_TEST(flags::game_default_frame_rate, true); + SET_FLAG_FOR_TEST(flags::vrr_config, true); + + const LayerHistory::LayerVoteType defaultVote = LayerHistory::LayerVoteType::Min; + + auto layer = createLegacyAndFrontedEndLayer(1); + setDefaultLayerVote(layer.get(), defaultVote); + showLayer(1); + setFrameRate(1, (0_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + setFrameRateCategory(1, ANATIVEWINDOW_FRAME_RATE_CATEGORY_NO_PREFERENCE); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + + nsecs_t time = systemTime(); + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + setBufferWithPresentTime(layer, time); + time += HI_FPS_PERIOD; + } + + EXPECT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + EXPECT_EQ(defaultVote, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); +} + +// Tests VRR NoPreference-only vote, no game default override. Expects NoPreference, *not* vote +// reset. +TEST_F(LayerHistoryIntegrationTest, oneLayerCategoryNoPreference_vrr) { + SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false); + SET_FLAG_FOR_TEST(flags::game_default_frame_rate, true); + SET_FLAG_FOR_TEST(flags::vrr_config, true); + mSelector->setActiveMode(kVrrModeId, HI_FPS); + + const LayerHistory::LayerVoteType defaultVote = LayerHistory::LayerVoteType::Min; + + auto layer = createLegacyAndFrontedEndLayer(1); + setDefaultLayerVote(layer.get(), defaultVote); + showLayer(1); + setFrameRate(1, (0_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + setFrameRateCategory(1, ANATIVEWINDOW_FRAME_RATE_CATEGORY_NO_PREFERENCE); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + + nsecs_t time = systemTime(); + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + setBufferWithPresentTime(layer, time); + time += HI_FPS_PERIOD; + } + + EXPECT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::NoPreference, summarizeLayerHistory(time)[0].frameRateCategory); +} + +TEST_F(LayerHistoryIntegrationTest, oneLayerCategoryNoPreferenceWithGameDefault_vrr) { + SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false); + SET_FLAG_FOR_TEST(flags::game_default_frame_rate, true); + SET_FLAG_FOR_TEST(flags::vrr_config, true); + mSelector->setActiveMode(kVrrModeId, HI_FPS); + + const Fps gameDefaultFrameRate = Fps::fromValue(30.0f); + const uid_t uid = 456; + + history().updateGameDefaultFrameRateOverride( + FrameRateOverride({uid, gameDefaultFrameRate.getValue()})); + + auto layer = createLegacyAndFrontedEndLayerWithUid(1, gui::Uid(uid)); + showLayer(1); + setFrameRate(1, (0_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + setFrameRateCategory(1, ANATIVEWINDOW_FRAME_RATE_CATEGORY_NO_PREFERENCE); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + + nsecs_t time = systemTime(); + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + setBufferWithPresentTime(layer, time); + time += HI_FPS_PERIOD; + } + + EXPECT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(gameDefaultFrameRate, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); +} + +TEST_F(LayerHistoryIntegrationTest, oneLayerCategoryNoPreferenceWithGameDefault_mrr) { + SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false); + SET_FLAG_FOR_TEST(flags::game_default_frame_rate, true); + SET_FLAG_FOR_TEST(flags::vrr_config, true); + + const Fps gameDefaultFrameRate = Fps::fromValue(30.0f); + const uid_t uid = 456; + + history().updateGameDefaultFrameRateOverride( + FrameRateOverride({uid, gameDefaultFrameRate.getValue()})); + + auto layer = createLegacyAndFrontedEndLayerWithUid(1, gui::Uid(uid)); + showLayer(1); + setFrameRate(1, (0_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + setFrameRateCategory(1, ANATIVEWINDOW_FRAME_RATE_CATEGORY_NO_PREFERENCE); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + + nsecs_t time = systemTime(); + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + setBufferWithPresentTime(layer, time); + time += HI_FPS_PERIOD; + } + + EXPECT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(gameDefaultFrameRate, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); +} + +TEST_F(LayerHistoryIntegrationTest, oneLayerNoVoteWithGameDefault_vrr) { + SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false); + SET_FLAG_FOR_TEST(flags::game_default_frame_rate, true); + SET_FLAG_FOR_TEST(flags::vrr_config, true); + mSelector->setActiveMode(kVrrModeId, HI_FPS); + + const Fps gameDefaultFrameRate = Fps::fromValue(30.0f); + const uid_t uid = 456; + + history().updateGameDefaultFrameRateOverride( + FrameRateOverride({uid, gameDefaultFrameRate.getValue()})); + + auto layer = createLegacyAndFrontedEndLayerWithUid(1, gui::Uid(uid)); + showLayer(1); + setFrameRate(1, (0_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_NO_VOTE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + + nsecs_t time = systemTime(); + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + setBufferWithPresentTime(layer, time); + time += HI_FPS_PERIOD; + } + + // Expect NoVote to be skipped in summarize. + EXPECT_EQ(0u, summarizeLayerHistory(time).size()); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); +} + +TEST_F(LayerHistoryIntegrationTest, oneLayerNoVoteWithGameDefault_mrr) { + SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false); + SET_FLAG_FOR_TEST(flags::game_default_frame_rate, true); + SET_FLAG_FOR_TEST(flags::vrr_config, true); + + const Fps gameDefaultFrameRate = Fps::fromValue(30.0f); + const uid_t uid = 456; + + history().updateGameDefaultFrameRateOverride( + FrameRateOverride({uid, gameDefaultFrameRate.getValue()})); + + auto layer = createLegacyAndFrontedEndLayerWithUid(1, gui::Uid(uid)); + showLayer(1); + setFrameRate(1, (0_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_NO_VOTE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + + nsecs_t time = systemTime(); + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + setBufferWithPresentTime(layer, time); + time += HI_FPS_PERIOD; + } + + // Expect NoVote to be skipped in summarize. + EXPECT_EQ(0u, summarizeLayerHistory(time).size()); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); +} + TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitVoteWithCategory) { SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, true); diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 75d2fa3c7f..8c53eef01a 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -28,7 +28,6 @@ #include "ui/GraphicTypes.h" #include <com_android_graphics_libgui_flags.h> -#include <com_android_graphics_surfaceflinger_flags.h> #define UPDATE_AND_VERIFY(BUILDER, ...) \ ({ \ @@ -162,12 +161,12 @@ TEST_F(LayerSnapshotTest, croppedByParent) { info.info.logicalHeight = 100; info.info.logicalWidth = 200; mFrontEndDisplayInfos.emplace_or_replace(ui::LayerStack::fromValue(1), info); - Rect layerCrop(0, 0, 10, 20); + FloatRect layerCrop(0, 0, 10, 20); setCrop(11, layerCrop); EXPECT_TRUE(mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Geometry)); UPDATE_AND_VERIFY_WITH_DISPLAY_CHANGES(mSnapshotBuilder, STARTING_ZORDER); EXPECT_EQ(getSnapshot(11)->geomCrop, layerCrop); - EXPECT_EQ(getSnapshot(111)->geomLayerBounds, layerCrop.toFloatRect()); + EXPECT_EQ(getSnapshot(111)->geomLayerBounds, layerCrop); float maxHeight = static_cast<float>(info.info.logicalHeight * 10); float maxWidth = static_cast<float>(info.info.logicalWidth * 10); @@ -1551,6 +1550,9 @@ TEST_F(LayerSnapshotTest, propagateDropInputMode) { } TEST_F(LayerSnapshotTest, NonVisibleLayerWithInput) { + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags:: + skip_invisible_windows_in_input, + false); LayerHierarchyTestBase::createRootLayer(3); setColor(3, {-1._hf, -1._hf, -1._hf}); UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); @@ -1576,6 +1578,39 @@ TEST_F(LayerSnapshotTest, NonVisibleLayerWithInput) { EXPECT_TRUE(foundInputLayer); } +TEST_F(LayerSnapshotTest, NonVisibleLayerWithInputShouldNotBeIncluded) { + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags:: + skip_invisible_windows_in_input, + true); + LayerHierarchyTestBase::createRootLayer(3); + setColor(3, {-1._hf, -1._hf, -1._hf}); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + + std::vector<TransactionState> transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged; + transactions.back().states.front().layerId = 3; + transactions.back().states.front().state.windowInfoHandle = sp<gui::WindowInfoHandle>::make(); + auto inputInfo = transactions.back().states.front().state.windowInfoHandle->editInfo(); + inputInfo->token = sp<BBinder>::make(); + hideLayer(3); + mLifecycleManager.applyTransactions(transactions); + + update(mSnapshotBuilder); + + bool foundInputLayer = false; + mSnapshotBuilder.forEachInputSnapshot([&](const frontend::LayerSnapshot& snapshot) { + if (snapshot.uniqueSequence == 3) { + EXPECT_TRUE( + snapshot.inputInfo.inputConfig.test(gui::WindowInfo::InputConfig::NOT_VISIBLE)); + EXPECT_FALSE(snapshot.isVisible); + foundInputLayer = true; + } + }); + EXPECT_FALSE(foundInputLayer); +} + TEST_F(LayerSnapshotTest, ForEachSnapshotsWithPredicate) { std::vector<uint32_t> visitedUniqueSequences; mSnapshotBuilder.forEachSnapshot( @@ -1935,4 +1970,95 @@ TEST_F(LayerSnapshotTest, shouldUpdateInputWhenNoInputInfo) { EXPECT_FALSE(getSnapshot(2)->hasInputInfo()); } +// content dirty test +TEST_F(LayerSnapshotTest, contentDirtyWhenParentAlphaChanges) { + setAlpha(1, 0.5); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_TRUE(getSnapshot(1)->contentDirty); + EXPECT_TRUE(getSnapshot(11)->contentDirty); + EXPECT_TRUE(getSnapshot(111)->contentDirty); + + // subsequent updates clear the dirty bit + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_FALSE(getSnapshot(1)->contentDirty); + EXPECT_FALSE(getSnapshot(11)->contentDirty); + EXPECT_FALSE(getSnapshot(111)->contentDirty); +} + +TEST_F(LayerSnapshotTest, contentDirtyWhenAutoRefresh) { + setAutoRefresh(1, true); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_TRUE(getSnapshot(1)->contentDirty); + + // subsequent updates don't clear the dirty bit + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_TRUE(getSnapshot(1)->contentDirty); + + // second update after removing auto refresh will clear content dirty + setAutoRefresh(1, false); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_FALSE(getSnapshot(1)->contentDirty); +} + +TEST_F(LayerSnapshotTest, contentDirtyWhenColorChanges) { + setColor(1, {1, 2, 3}); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_TRUE(getSnapshot(1)->contentDirty); + + // subsequent updates clear the dirty bit + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_FALSE(getSnapshot(1)->contentDirty); +} + +TEST_F(LayerSnapshotTest, contentDirtyWhenParentGeometryChanges) { + setPosition(1, 2, 3); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_TRUE(getSnapshot(1)->contentDirty); + + // subsequent updates clear the dirty bit + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_FALSE(getSnapshot(1)->contentDirty); +} +TEST_F(LayerSnapshotTest, shouldUpdatePictureProfileHandle) { + if (!com_android_graphics_libgui_flags_apply_picture_profiles()) { + GTEST_SKIP() << "Flag disabled, skipping test"; + } + std::vector<TransactionState> transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + transactions.back().states.front().layerId = 1; + transactions.back().states.front().state.layerId = 1; + transactions.back().states.front().state.what = layer_state_t::ePictureProfileHandleChanged; + transactions.back().states.front().state.pictureProfileHandle = PictureProfileHandle(3); + + mLifecycleManager.applyTransactions(transactions); + EXPECT_EQ(mLifecycleManager.getGlobalChanges(), RequestedLayerState::Changes::Content); + + update(mSnapshotBuilder); + + EXPECT_EQ(getSnapshot(1)->clientChanges, layer_state_t::ePictureProfileHandleChanged); + EXPECT_EQ(getSnapshot(1)->pictureProfileHandle, PictureProfileHandle(3)); +} + +TEST_F(LayerSnapshotTest, shouldUpdatePictureProfilePriorityFromAppContentPriority) { + if (!com_android_graphics_libgui_flags_apply_picture_profiles()) { + GTEST_SKIP() << "Flag disabled, skipping test"; + } + std::vector<TransactionState> transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + transactions.back().states.front().layerId = 1; + transactions.back().states.front().state.layerId = 1; + transactions.back().states.front().state.what = layer_state_t::eAppContentPriorityChanged; + transactions.back().states.front().state.appContentPriority = 3; + + mLifecycleManager.applyTransactions(transactions); + EXPECT_EQ(mLifecycleManager.getGlobalChanges(), RequestedLayerState::Changes::Content); + + update(mSnapshotBuilder); + + EXPECT_EQ(getSnapshot(1)->pictureProfilePriority, 3); +} + } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp index 71f9f88ba7..908637ae76 100644 --- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp @@ -159,9 +159,9 @@ TEST_F(MessageQueueTest, commitTwiceWithCallback) { constexpr VsyncId vsyncId{42}; EXPECT_CALL(mTokenManager, - generateTokenForPredictions(frametimeline::TimelineItem(kStartTime.ns(), - kEndTime.ns(), - kPresentTime.ns()))) + generateTokenForPredictions( + frametimeline::TimelineItem(kStartTime.ns(), kEndTime.ns(), + kPresentTime.ns(), kPresentTime.ns()))) .WillOnce(Return(ftl::to_underlying(vsyncId))); EXPECT_CALL(*mEventQueue.mHandler, dispatchFrame(vsyncId, kPresentTime)).Times(1); EXPECT_NO_FATAL_FAILURE( diff --git a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp index c879280e57..5c25f34ae7 100644 --- a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp +++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp @@ -17,7 +17,8 @@ #undef LOG_TAG #define LOG_TAG "PowerAdvisorTest" -#include <DisplayHardware/PowerAdvisor.h> +#include "PowerAdvisor/PowerAdvisor.h" + #include <android_os.h> #include <binder/Status.h> #include <com_android_graphics_surfaceflinger_flags.h> @@ -29,18 +30,17 @@ #include <ui/DisplayId.h> #include <chrono> #include <future> -#include "TestableSurfaceFlinger.h" -#include "mock/DisplayHardware/MockPowerHalController.h" -#include "mock/DisplayHardware/MockPowerHintSessionWrapper.h" +#include "mock/PowerAdvisor/MockPowerHalController.h" +#include "mock/PowerAdvisor/MockPowerHintSessionWrapper.h" using namespace android; -using namespace android::Hwc2::mock; +using namespace android::adpf::mock; using namespace android::hardware::power; using namespace std::chrono_literals; using namespace testing; using namespace android::power; -namespace android::Hwc2::impl { +namespace android::adpf::impl { class PowerAdvisorTest : public testing::Test { public: @@ -73,7 +73,6 @@ public: void testGpuScenario(GpuTestConfig& config, WorkDuration& ret); protected: - TestableSurfaceFlinger mFlinger; std::unique_ptr<PowerAdvisor> mPowerAdvisor; MockPowerHalController* mMockPowerHalController; std::shared_ptr<MockPowerHintSessionWrapper> mMockPowerHintSession; @@ -85,6 +84,7 @@ protected: int64_t mSessionId = 123; SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel, true); SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, false); + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_fmq_sf, false); }; bool PowerAdvisorTest::sessionExists() { @@ -97,7 +97,7 @@ int64_t PowerAdvisorTest::toNanos(Duration d) { } void PowerAdvisorTest::SetUp() { - mPowerAdvisor = std::make_unique<impl::PowerAdvisor>(*mFlinger.flinger()); + mPowerAdvisor = std::make_unique<impl::PowerAdvisor>([]() {}, 80ms); mPowerAdvisor->mPowerHal = std::make_unique<NiceMock<MockPowerHalController>>(); mMockPowerHalController = reinterpret_cast<MockPowerHalController*>(mPowerAdvisor->mPowerHal.get()); @@ -184,6 +184,7 @@ void PowerAdvisorTest::testGpuScenario(GpuTestConfig& config, WorkDuration& ret) SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_gpu_sf, config.adpfGpuFlagOn); SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, config.usesFmq); + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_fmq_sf, config.usesFmq); mPowerAdvisor->onBootFinished(); bool expectsFmqSuccess = config.usesSharedFmqFlag && !config.fmqFull; if (config.usesFmq) { @@ -789,6 +790,7 @@ TEST_F(PowerAdvisorTest, fmq_sendTargetAndActualDuration_queueFull) { TEST_F(PowerAdvisorTest, fmq_sendHint) { SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true); + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_fmq_sf, true); mPowerAdvisor->onBootFinished(); SetUpFmq(true, false); auto startTime = uptimeNanos(); @@ -807,6 +809,7 @@ TEST_F(PowerAdvisorTest, fmq_sendHint) { TEST_F(PowerAdvisorTest, fmq_sendHint_noSharedFlag) { SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true); + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_fmq_sf, true); mPowerAdvisor->onBootFinished(); SetUpFmq(false, false); SessionHint hint; @@ -821,6 +824,7 @@ TEST_F(PowerAdvisorTest, fmq_sendHint_noSharedFlag) { TEST_F(PowerAdvisorTest, fmq_sendHint_queueFull) { SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true); + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_fmq_sf, true); mPowerAdvisor->onBootFinished(); SetUpFmq(true, true); ASSERT_EQ(mBackendFmq->availableToRead(), 2uL); @@ -839,4 +843,4 @@ TEST_F(PowerAdvisorTest, fmq_sendHint_queueFull) { } } // namespace -} // namespace android::Hwc2::impl +} // namespace android::adpf::impl diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index adbd868a28..9b3cba56e0 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -2112,6 +2112,46 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_Touch EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch); } +TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_touchBoost_twoUids_arr) { + if (GetParam() != Config::FrameRateOverride::Enabled) { + return; + } + + SET_FLAG_FOR_TEST(flags::vrr_config, true); + // Device with VRR config mode + auto selector = createSelector(kVrrMode_120, kModeId120); + + std::vector<LayerRequirement> layers = {{.ownerUid = 1234, .weight = 1.f}, + {.ownerUid = 5678, .weight = 1.f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + + lr1.vote = LayerVoteType::ExplicitCategory; + lr1.frameRateCategory = FrameRateCategory::Normal; + lr1.name = "ExplicitCategory Normal"; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.desiredRefreshRate = 30_Hz; + lr2.name = "30Hz ExplicitDefault"; + auto actualRankedFrameRates = selector.getRankedFrameRates(layers, {.touch = true}); + // No global touch boost, for example a game that uses setFrameRate(30, default compatibility). + // However see 60 due to Normal vote. + EXPECT_FRAME_RATE_MODE(kVrrMode120TE240, 60_Hz, + actualRankedFrameRates.ranking.front().frameRateMode); + EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch); + + lr1.vote = LayerVoteType::ExplicitCategory; + lr1.frameRateCategory = FrameRateCategory::HighHint; + lr1.name = "ExplicitCategory HighHint"; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.desiredRefreshRate = 30_Hz; + lr2.name = "30Hz ExplicitDefault"; + // Gets touch boost because the touched (HighHint) app is different from the 30 Default app. + actualRankedFrameRates = selector.getRankedFrameRates(layers, {.touch = true}); + EXPECT_FRAME_RATE_MODE(kVrrMode120TE240, 120_Hz, + actualRankedFrameRates.ranking.front().frameRateMode); + EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch); +} + TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_idleTimer_60_120_nonVrr) { SET_FLAG_FOR_TEST(flags::vrr_config, false); @@ -3697,6 +3737,51 @@ TEST_P(RefreshRateSelectorTest, getFrameRateOverrides_twoUids) { EXPECT_TRUE(frameRateOverrides.empty()); } +TEST_P(RefreshRateSelectorTest, getFrameRateOverrides_twoUids_arr) { + if (GetParam() != Config::FrameRateOverride::Enabled) { + return; + } + + SET_FLAG_FOR_TEST(flags::vrr_config, true); + // Device with VRR config mode + auto selector = createSelector(kVrrMode_120, kModeId120); + + std::vector<LayerRequirement> layers = {{.ownerUid = 1234, .weight = 1.f}, + {.ownerUid = 5678, .weight = 1.f}}; + auto& lr1 = layers[0]; + auto& lr2 = layers[1]; + + lr1.vote = LayerVoteType::ExplicitCategory; + lr1.frameRateCategory = FrameRateCategory::Normal; + lr1.name = "ExplicitCategory Normal"; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.desiredRefreshRate = 30_Hz; + lr2.name = "30Hz ExplicitDefault"; + // No global touch boost, for example a game that uses setFrameRate(30, default compatibility). + // The `displayFrameRate` is 60. + // However 30 Default app still gets frame rate override. + auto frameRateOverrides = selector.getFrameRateOverrides(layers, 60_Hz, {}); + EXPECT_EQ(2u, frameRateOverrides.size()); + ASSERT_EQ(1u, frameRateOverrides.count(1234)); + EXPECT_EQ(60_Hz, frameRateOverrides.at(1234)); + ASSERT_EQ(1u, frameRateOverrides.count(5678)); + EXPECT_EQ(30_Hz, frameRateOverrides.at(5678)); + + lr1.vote = LayerVoteType::ExplicitCategory; + lr1.frameRateCategory = FrameRateCategory::HighHint; + lr1.name = "ExplicitCategory HighHint"; + lr2.vote = LayerVoteType::ExplicitDefault; + lr2.desiredRefreshRate = 30_Hz; + lr2.name = "30Hz ExplicitDefault"; + // Gets touch boost because the touched (HighHint) app is different from the 30 Default app. + // The `displayFrameRate` is 120 (late touch boost). + // However 30 Default app still gets frame rate override. + frameRateOverrides = selector.getFrameRateOverrides(layers, 120_Hz, {}); + EXPECT_EQ(1u, frameRateOverrides.size()); + ASSERT_EQ(1u, frameRateOverrides.count(5678)); + EXPECT_EQ(30_Hz, frameRateOverrides.at(5678)); +} + TEST_P(RefreshRateSelectorTest, getFrameRateOverrides_withFrameRateCategory) { if (GetParam() == Config::FrameRateOverride::Disabled) { return; @@ -4582,5 +4667,47 @@ TEST_P(RefreshRateSelectorTest, renderFrameRatesForVrr) { EXPECT_EQ(120_Hz, primaryRefreshRates[i].modePtr->getPeakFps()); } } + +TEST_P(RefreshRateSelectorTest, getSupportedFrameRates) { + if (GetParam() != Config::FrameRateOverride::Enabled) { + return; + } + + auto selector = createSelector(kModes_60_90, kModeId90); + const FpsRange range60 = {0_Hz, 60_Hz}; + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy( + {kModeId60, {range60, range60}, {range60, range60}})); + + // Irrespective of the policy we get the full range of possible frame rates + const std::vector<float> expected = {90.0f, 60.0f, 45.0f, 30.0f, 22.5f, 20.0f}; + + const auto allSupportedFrameRates = selector.getSupportedFrameRates(); + ASSERT_EQ(expected.size(), allSupportedFrameRates.size()); + for (size_t i = 0; i < expected.size(); i++) { + EXPECT_EQ(expected[i], allSupportedFrameRates[i]) + << "expected " << expected[i] << " received " << allSupportedFrameRates[i]; + } +} + +TEST_P(RefreshRateSelectorTest, getSupportedFrameRatesArr) { + if (GetParam() != Config::FrameRateOverride::Enabled) { + return; + } + + SET_FLAG_FOR_TEST(flags::vrr_config, true); + const auto selector = createSelector(kVrrMode_120, kModeId120); + + const std::vector<float> expected = {120.0f, 80.0f, 60.0f, 48.0f, 40.0f, 34.285f, + 30.0f, 26.666f, 24.0f, 21.818f, 20.0f}; + + const auto allSupportedFrameRates = selector.getSupportedFrameRates(); + ASSERT_EQ(expected.size(), allSupportedFrameRates.size()); + constexpr float kEpsilon = 0.001f; + for (size_t i = 0; i < expected.size(); i++) { + EXPECT_TRUE(std::abs(expected[i] - allSupportedFrameRates[i]) <= kEpsilon) + << "expected " << expected[i] << " received " << allSupportedFrameRates[i]; + } +} } // namespace } // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index ac09cbcea6..1fc874dad8 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -222,7 +222,7 @@ TEST_F(SchedulerTest, emitModeChangeEvent) { const auto selectorPtr = std::make_shared<RefreshRateSelector>(kDisplay1Modes, kDisplay1Mode120->getId()); mScheduler->registerDisplay(kDisplayId1, selectorPtr); - mScheduler->onDisplayModeChanged(kDisplayId1, kDisplay1Mode120_120); + mScheduler->onDisplayModeChanged(kDisplayId1, kDisplay1Mode120_120, true); mScheduler->setContentRequirements({kLayer}); @@ -250,7 +250,7 @@ TEST_F(SchedulerTest, emitModeChangeEvent) { EXPECT_CALL(*mEventThread, onModeChanged(kDisplay1Mode120_120)).Times(1); mScheduler->touchTimerCallback(TimerState::Reset); - mScheduler->onDisplayModeChanged(kDisplayId1, kDisplay1Mode120_120); + mScheduler->onDisplayModeChanged(kDisplayId1, kDisplay1Mode120_120, true); } TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) { diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp index 86996214b5..b0dd5c21f8 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -34,7 +34,7 @@ using namespace com::android::graphics::surfaceflinger; static_cast<hal::HWConfigId>( \ ftl::to_underlying(modeId)), \ _, _)) \ - .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE))) + .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(hal::Error::NONE))) namespace android { namespace { diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp index 20a3315169..6cc6322bfc 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp @@ -18,12 +18,13 @@ #define LOG_TAG "LibSurfaceFlingerUnittests" #include <gui/SurfaceComposerClient.h> +#include "DisplayHardware/Hal.h" #include "DisplayTransactionTestHelpers.h" namespace android { using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; -using android::hardware::graphics::composer::V2_1::Error; +using android::hardware::graphics::composer::hal::Error; class NotifyExpectedPresentTest : public DisplayTransactionTest { public: diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp index c3934e64f8..3ae5ed9451 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp @@ -21,6 +21,8 @@ #include "CommitAndCompositeTest.h" +#include "DisplayHardware/Hal.h" + using namespace std::chrono_literals; using testing::_; using testing::Return; @@ -40,7 +42,7 @@ TEST_F(SurfaceFlingerPowerHintTest, sendDurationsIncludingHwcWaitTime) { EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _, _)).WillOnce([] { constexpr Duration kMockHwcRunTime = 20ms; std::this_thread::sleep_for(kMockHwcRunTime); - return hardware::graphics::composer::V2_1::Error::NONE; + return hardware::graphics::composer::hal::Error::NONE; }); EXPECT_CALL(*mPowerAdvisor, reportActualWorkDuration()).Times(1); @@ -61,7 +63,7 @@ TEST_F(SurfaceFlingerPowerHintTest, inactiveOnDisplayDoze) { EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _, _)).WillOnce([] { constexpr Duration kMockHwcRunTime = 20ms; std::this_thread::sleep_for(kMockHwcRunTime); - return hardware::graphics::composer::V2_1::Error::NONE; + return hardware::graphics::composer::hal::Error::NONE; }); EXPECT_CALL(*mPowerAdvisor, reportActualWorkDuration()).Times(0); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index c043b880ec..7f0b7a6585 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -44,22 +44,22 @@ #include "NativeWindowSurface.h" #include "RenderArea.h" #include "Scheduler/RefreshRateSelector.h" +#include "Scheduler/VSyncTracker.h" +#include "Scheduler/VsyncController.h" #include "SurfaceFlinger.h" #include "TestableScheduler.h" #include "android/gui/ISurfaceComposerClient.h" + #include "mock/DisplayHardware/MockComposer.h" #include "mock/DisplayHardware/MockDisplayMode.h" -#include "mock/DisplayHardware/MockPowerAdvisor.h" #include "mock/MockEventThread.h" #include "mock/MockFrameTimeline.h" #include "mock/MockFrameTracer.h" #include "mock/MockSchedulerCallback.h" -#include "mock/system/window/MockNativeWindow.h" - -#include "Scheduler/VSyncTracker.h" -#include "Scheduler/VsyncController.h" #include "mock/MockVSyncTracker.h" #include "mock/MockVsyncController.h" +#include "mock/PowerAdvisor/MockPowerAdvisor.h" +#include "mock/system/window/MockNativeWindow.h" namespace android { @@ -190,7 +190,7 @@ public: &mFlinger->mCompositionEngine->getHwComposer()); } - void setupPowerAdvisor(std::unique_ptr<Hwc2::PowerAdvisor> powerAdvisor) { + void setupPowerAdvisor(std::unique_ptr<adpf::PowerAdvisor> powerAdvisor) { mFlinger->mPowerAdvisor = std::move(powerAdvisor); } @@ -472,12 +472,10 @@ public: ScreenCaptureResults captureResults; auto displayState = std::optional{display->getCompositionDisplay()->getState()}; auto layers = getLayerSnapshotsFn(); - auto layerFEs = mFlinger->extractLayerFEs(layers); return mFlinger->renderScreenImpl(renderArea.get(), buffer, regionSampling, false /* grayscale */, false /* isProtected */, - false /* attachGainmap */, captureResults, displayState, - layers, layerFEs); + captureResults, displayState, layers); } auto getLayerSnapshotsForScreenshotsFn(ui::LayerStack layerStack, uint32_t uid) { @@ -637,7 +635,7 @@ public: void destroyAllLayerHandles() { ftl::FakeGuard guard(kMainThreadContext); for (auto [layerId, legacyLayer] : mFlinger->mLegacyLayers) { - mFlinger->onHandleDestroyed(nullptr, legacyLayer, layerId); + mFlinger->onHandleDestroyed(legacyLayer, layerId); } } @@ -1162,7 +1160,7 @@ private: scheduler::mock::NoOpSchedulerCallback mNoOpSchedulerCallback; std::unique_ptr<frametimeline::impl::TokenManager> mTokenManager; scheduler::TestableScheduler* mScheduler = nullptr; - Hwc2::mock::PowerAdvisor mPowerAdvisor; + adpf::mock::PowerAdvisor mPowerAdvisor; }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index fab1f6d451..1e8cd0a0ca 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -387,7 +387,7 @@ public: state.state.what = what; if (what & layer_state_t::eCropChanged) { - state.state.crop = Rect(1, 2, 3, 4); + state.state.crop = FloatRect(1, 2, 3, 4); } if (what & layer_state_t::eFlagsChanged) { state.state.flags = layer_state_t::eEnableBackpressure; diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index f472d8fefe..0d5266e113 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -20,6 +20,7 @@ #include "DisplayHardware/ComposerHal.h" #include "DisplayHardware/HWC2.h" +#include "DisplayHardware/Hal.h" namespace android { @@ -34,9 +35,9 @@ using android::hardware::graphics::common::V1_2::ColorMode; using android::hardware::graphics::common::V1_2::Dataspace; using android::hardware::graphics::common::V1_2::PixelFormat; +using android::hardware::graphics::composer::hal::Error; using android::hardware::graphics::composer::V2_1::Config; using android::hardware::graphics::composer::V2_1::Display; -using android::hardware::graphics::composer::V2_1::Error; using android::hardware::graphics::composer::V2_1::IComposer; using android::hardware::graphics::composer::V2_1::Layer; using android::hardware::graphics::composer::V2_4::IComposerCallback; @@ -142,8 +143,8 @@ public: V2_4::Error(Display, Config, std::vector<VsyncPeriodNanos>*)); MOCK_METHOD2(getDisplayVsyncPeriod, V2_4::Error(Display, VsyncPeriodNanos*)); MOCK_METHOD4(setActiveConfigWithConstraints, - V2_4::Error(Display, Config, const IComposerClient::VsyncPeriodChangeConstraints&, - VsyncPeriodChangeTimeline*)); + Error(Display, Config, const IComposerClient::VsyncPeriodChangeConstraints&, + VsyncPeriodChangeTimeline*)); MOCK_METHOD2(setAutoLowLatencyMode, V2_4::Error(Display, bool)); MOCK_METHOD2(setBootDisplayConfig, Error(Display, Config)); MOCK_METHOD1(clearBootDisplayConfig, Error(Display)); @@ -182,10 +183,13 @@ public: MOCK_METHOD(Error, notifyExpectedPresent, (Display, nsecs_t, int32_t)); MOCK_METHOD( Error, getRequestedLuts, - (Display, + (Display, std::vector<Layer>*, std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*)); MOCK_METHOD(Error, setLayerLuts, - (Display, Layer, std::vector<aidl::android::hardware::graphics::composer3::Lut>&)); + (Display, Layer, aidl::android::hardware::graphics::composer3::Luts&)); + MOCK_METHOD(Error, getMaxLayerPictureProfiles, (Display, int32_t*)); + MOCK_METHOD(Error, setDisplayPictureProfileId, (Display, PictureProfileId id)); + MOCK_METHOD(Error, setLayerPictureProfileId, (Display, Layer, PictureProfileId id)); }; } // namespace Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h index 5edd2cd9e3..ec065a773c 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h @@ -17,6 +17,7 @@ #pragma once #include <gmock/gmock.h> +#include <cstdint> #include "DisplayHardware/HWC2.h" @@ -52,7 +53,7 @@ public: (override)); MOCK_METHOD(hal::Error, getName, (std::string *), (const, override)); MOCK_METHOD(hal::Error, getRequests, - (hal::DisplayRequest *, (std::unordered_map<Layer *, hal::LayerRequest> *)), + (hal::DisplayRequest*, (std::unordered_map<Layer*, hal::LayerRequest>*)), (override)); MOCK_METHOD((ftl::Expected<ui::DisplayConnectionType, hal::Error>), getConnectionType, (), (const, override)); @@ -85,8 +86,8 @@ public: MOCK_METHOD(ftl::Future<hal::Error>, setDisplayBrightness, (float, float, const Hwc2::Composer::DisplayBrightnessOptions &), (override)); MOCK_METHOD(hal::Error, setActiveConfigWithConstraints, - (hal::HWConfigId, const hal::VsyncPeriodChangeConstraints &, - hal::VsyncPeriodChangeTimeline *), + (hal::HWConfigId, const hal::VsyncPeriodChangeConstraints&, + hal::VsyncPeriodChangeTimeline*), (override)); MOCK_METHOD(hal::Error, setBootDisplayConfig, (hal::HWConfigId), (override)); MOCK_METHOD(hal::Error, clearBootDisplayConfig, (), (override)); @@ -111,7 +112,9 @@ public: (aidl::android::hardware::graphics::composer3::OverlayProperties *), (const override)); MOCK_METHOD(hal::Error, getRequestedLuts, - (std::vector<aidl::android::hardware::graphics::composer3::DisplayLuts::LayerLut>*), + (HWC2::Display::LayerLuts*, HWC2::Display::LutFileDescriptorMapper&), (override)); + MOCK_METHOD(hal::Error, getMaxLayerPictureProfiles, (int32_t*), (override)); + MOCK_METHOD(hal::Error, setPictureProfileHandle, (const android::PictureProfileHandle&), (override)); }; @@ -126,6 +129,8 @@ public: (uint32_t, const android::sp<android::GraphicBuffer> &, const android::sp<android::Fence> &), (override)); + MOCK_METHOD(hal::Error, setBufferSlotsToClear, + (const std::vector<uint32_t>& slotsToClear, uint32_t activeBufferSlot), (override)); MOCK_METHOD(hal::Error, setSurfaceDamage, (const android::Region &), (override)); MOCK_METHOD(hal::Error, setBlendMode, (hal::BlendMode), (override)); MOCK_METHOD(hal::Error, setColor, (aidl::android::hardware::graphics::composer3::Color), @@ -147,8 +152,10 @@ public: (const std::string &, bool, const std::vector<uint8_t> &), (override)); MOCK_METHOD(hal::Error, setBrightness, (float), (override)); MOCK_METHOD(hal::Error, setBlockingRegion, (const android::Region &), (override)); - MOCK_METHOD(hal::Error, setLuts, - (std::vector<aidl::android::hardware::graphics::composer3::Lut>&), (override)); + MOCK_METHOD(hal::Error, setLuts, (aidl::android::hardware::graphics::composer3::Luts&), + (override)); + MOCK_METHOD(hal::Error, setPictureProfileHandle, (const android::PictureProfileHandle&), + (override)); }; } // namespace android::HWC2::mock diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWComposer.cpp index ae52670fe2..f3106332fc 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.cpp +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWComposer.cpp @@ -16,17 +16,11 @@ #include "MockHWComposer.h" -namespace android { - -// This will go away once HWComposer is moved into the "backend" library -HWComposer::~HWComposer() = default; - -namespace mock { +namespace android::mock { // The Google Mock documentation recommends explicit non-header instantiations // for better compile time performance. HWComposer::HWComposer() = default; HWComposer::~HWComposer() = default; -} // namespace mock -} // namespace android +} // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWComposer.h new file mode 100644 index 0000000000..88f83d2e07 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWComposer.h @@ -0,0 +1,156 @@ +/* + * Copyright 2024 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 <gmock/gmock.h> + +#include "DisplayHardware/HWComposer.h" + +namespace android::mock { + +class HWComposer : public android::HWComposer { +public: + using HWDisplayId = android::hardware::graphics::composer::hal::HWDisplayId; + using PowerMode = android::hardware::graphics::composer::hal::PowerMode; + + HWComposer(); + ~HWComposer() override; + + MOCK_METHOD(void, setCallback, (HWC2::ComposerCallback&), (override)); + MOCK_METHOD(bool, getDisplayIdentificationData, + (HWDisplayId, uint8_t*, DisplayIdentificationData*), (const, override)); + MOCK_METHOD(bool, hasCapability, (aidl::android::hardware::graphics::composer3::Capability), + (const, override)); + MOCK_METHOD(bool, hasDisplayCapability, + (HalDisplayId, aidl::android::hardware::graphics::composer3::DisplayCapability), + (const, override)); + + MOCK_METHOD(size_t, getMaxVirtualDisplayCount, (), (const, override)); + MOCK_METHOD(size_t, getMaxVirtualDisplayDimension, (), (const, override)); + MOCK_METHOD(bool, allocateVirtualDisplay, (HalVirtualDisplayId, ui::Size, ui::PixelFormat*), + (override)); + MOCK_METHOD(void, allocatePhysicalDisplay, + (hal::HWDisplayId, PhysicalDisplayId, std::optional<ui::Size>), (override)); + + MOCK_METHOD(std::shared_ptr<HWC2::Layer>, createLayer, (HalDisplayId), (override)); + MOCK_METHOD(status_t, getDeviceCompositionChanges, + (HalDisplayId, bool, std::optional<std::chrono::steady_clock::time_point>, nsecs_t, + Fps, std::optional<android::HWComposer::DeviceRequestedChanges>*)); + MOCK_METHOD(status_t, setClientTarget, + (HalDisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&, ui::Dataspace, + float), + (override)); + MOCK_METHOD(status_t, presentAndGetReleaseFences, + (HalDisplayId, std::optional<std::chrono::steady_clock::time_point>), (override)); + MOCK_METHOD(status_t, executeCommands, (HalDisplayId)); + MOCK_METHOD(status_t, setPowerMode, (PhysicalDisplayId, PowerMode), (override)); + MOCK_METHOD(status_t, setColorTransform, (HalDisplayId, const mat4&), (override)); + MOCK_METHOD(void, disconnectDisplay, (HalDisplayId), (override)); + MOCK_METHOD(sp<Fence>, getPresentFence, (HalDisplayId), (const, override)); + MOCK_METHOD(nsecs_t, getPresentTimestamp, (PhysicalDisplayId), (const, override)); + MOCK_METHOD(sp<Fence>, getLayerReleaseFence, (HalDisplayId, HWC2::Layer*), (const, override)); + MOCK_METHOD(status_t, setOutputBuffer, + (HalVirtualDisplayId, const sp<Fence>&, const sp<GraphicBuffer>&), (override)); + MOCK_METHOD(void, clearReleaseFences, (HalDisplayId), (override)); + MOCK_METHOD(status_t, getHdrCapabilities, (HalDisplayId, HdrCapabilities*), (override)); + MOCK_METHOD(int32_t, getSupportedPerFrameMetadata, (HalDisplayId), (const, override)); + MOCK_METHOD(std::vector<ui::RenderIntent>, getRenderIntents, (HalDisplayId, ui::ColorMode), + (const, override)); + MOCK_METHOD(mat4, getDataspaceSaturationMatrix, (HalDisplayId, ui::Dataspace), (override)); + MOCK_METHOD(status_t, getDisplayedContentSamplingAttributes, + (HalDisplayId, ui::PixelFormat*, ui::Dataspace*, uint8_t*), (override)); + MOCK_METHOD(status_t, setDisplayContentSamplingEnabled, (HalDisplayId, bool, uint8_t, uint64_t), + (override)); + MOCK_METHOD(status_t, getDisplayedContentSample, + (HalDisplayId, uint64_t, uint64_t, DisplayedFrameStats*), (override)); + MOCK_METHOD(ftl::Future<status_t>, setDisplayBrightness, + (PhysicalDisplayId, float, float, const Hwc2::Composer::DisplayBrightnessOptions&), + (override)); + MOCK_METHOD(std::optional<DisplayIdentificationInfo>, onHotplug, + (hal::HWDisplayId, hal::Connection), (override)); + MOCK_METHOD(bool, updatesDeviceProductInfoOnHotplugReconnect, (), (const, override)); + MOCK_METHOD(std::optional<PhysicalDisplayId>, onVsync, (hal::HWDisplayId, int64_t)); + MOCK_METHOD(void, setVsyncEnabled, (PhysicalDisplayId, hal::Vsync), (override)); + MOCK_METHOD(bool, isConnected, (PhysicalDisplayId), (const, override)); + MOCK_METHOD(std::vector<HWComposer::HWCDisplayMode>, getModes, (PhysicalDisplayId, int32_t), + (const, override)); + MOCK_METHOD((ftl::Expected<hal::HWConfigId, status_t>), getActiveMode, (PhysicalDisplayId), + (const, override)); + MOCK_METHOD(std::vector<ui::ColorMode>, getColorModes, (PhysicalDisplayId), (const, override)); + MOCK_METHOD(status_t, setActiveColorMode, (PhysicalDisplayId, ui::ColorMode, ui::RenderIntent), + (override)); + MOCK_METHOD(ui::DisplayConnectionType, getDisplayConnectionType, (PhysicalDisplayId), + (const, override)); + MOCK_METHOD(bool, isVsyncPeriodSwitchSupported, (PhysicalDisplayId), (const, override)); + MOCK_METHOD((ftl::Expected<nsecs_t, status_t>), getDisplayVsyncPeriod, (PhysicalDisplayId), + (const, override)); + MOCK_METHOD(status_t, setActiveModeWithConstraints, + (PhysicalDisplayId, hal::HWConfigId, const hal::VsyncPeriodChangeConstraints&, + hal::VsyncPeriodChangeTimeline*), + (override)); + MOCK_METHOD(status_t, setBootDisplayMode, (PhysicalDisplayId, hal::HWConfigId), (override)); + MOCK_METHOD(status_t, clearBootDisplayMode, (PhysicalDisplayId), (override)); + MOCK_METHOD(std::optional<hal::HWConfigId>, getPreferredBootDisplayMode, (PhysicalDisplayId), + (override)); + + MOCK_METHOD(std::vector<aidl::android::hardware::graphics::common::HdrConversionCapability>, + getHdrConversionCapabilities, (), (const, override)); + MOCK_METHOD(status_t, setHdrConversionStrategy, + (aidl::android::hardware::graphics::common::HdrConversionStrategy, + aidl::android::hardware::graphics::common::Hdr*), + (override)); + MOCK_METHOD(status_t, setAutoLowLatencyMode, (PhysicalDisplayId, bool), (override)); + MOCK_METHOD(status_t, getSupportedContentTypes, + (PhysicalDisplayId, std::vector<hal::ContentType>*), (const, override)); + MOCK_METHOD(status_t, setContentType, (PhysicalDisplayId, hal::ContentType)), (override); + MOCK_METHOD((const std::unordered_map<std::string, bool>&), getSupportedLayerGenericMetadata, + (), (const, override)); + MOCK_METHOD(void, dump, (std::string&), (const, override)); + MOCK_METHOD(void, dumpOverlayProperties, (std::string&), (const, override)); + MOCK_METHOD(android::Hwc2::Composer*, getComposer, (), (const, override)); + + MOCK_METHOD(hal::HWDisplayId, getPrimaryHwcDisplayId, (), (const, override)); + MOCK_METHOD(PhysicalDisplayId, getPrimaryDisplayId, (), (const, override)); + MOCK_METHOD(bool, isHeadless, (), (const, override)); + + MOCK_METHOD(std::optional<PhysicalDisplayId>, toPhysicalDisplayId, (hal::HWDisplayId), + (const, override)); + MOCK_METHOD(std::optional<hal::HWDisplayId>, fromPhysicalDisplayId, (PhysicalDisplayId), + (const, override)); + MOCK_METHOD(status_t, getDisplayDecorationSupport, + (PhysicalDisplayId, + std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>* + support), + (override)); + MOCK_METHOD(status_t, setIdleTimerEnabled, (PhysicalDisplayId, std::chrono::milliseconds), + (override)); + MOCK_METHOD(bool, hasDisplayIdleTimerCapability, (PhysicalDisplayId), (const, override)); + MOCK_METHOD(Hwc2::AidlTransform, getPhysicalDisplayOrientation, (PhysicalDisplayId), + (const, override)); + MOCK_METHOD(bool, getValidateSkipped, (HalDisplayId), (const, override)); + MOCK_METHOD(const aidl::android::hardware::graphics::composer3::OverlayProperties&, + getOverlaySupport, (), (const, override)); + MOCK_METHOD(status_t, setRefreshRateChangedCallbackDebugEnabled, (PhysicalDisplayId, bool)); + MOCK_METHOD(status_t, notifyExpectedPresent, (PhysicalDisplayId, TimePoint, Fps)); + MOCK_METHOD(HWC2::Display::LutFileDescriptorMapper&, getLutFileDescriptorMapper, (), + (override)); + MOCK_METHOD(int32_t, getMaxLayerPictureProfiles, (PhysicalDisplayId)); + MOCK_METHOD(status_t, setDisplayPictureProfileHandle, + (PhysicalDisplayId, const PictureProfileHandle&)); +}; + +} // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h deleted file mode 100644 index ed1405b058..0000000000 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "binder/Status.h" - -// FMQ library in IPower does questionable conversions -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#include <aidl/android/hardware/power/IPower.h> -#pragma clang diagnostic pop - -#include <gmock/gmock.h> - -using aidl::android::hardware::power::Boost; -using aidl::android::hardware::power::ChannelConfig; -using aidl::android::hardware::power::IPower; -using aidl::android::hardware::power::IPowerHintSession; -using aidl::android::hardware::power::SessionConfig; -using aidl::android::hardware::power::SessionTag; - -using aidl::android::hardware::power::Mode; -using android::binder::Status; - -namespace android::Hwc2::mock { - -class MockIPower : public IPower { -public: - MockIPower(); - - MOCK_METHOD(ndk::ScopedAStatus, isBoostSupported, (Boost boost, bool* ret), (override)); - MOCK_METHOD(ndk::ScopedAStatus, setBoost, (Boost boost, int32_t durationMs), (override)); - MOCK_METHOD(ndk::ScopedAStatus, isModeSupported, (Mode mode, bool* ret), (override)); - MOCK_METHOD(ndk::ScopedAStatus, setMode, (Mode mode, bool enabled), (override)); - MOCK_METHOD(ndk::ScopedAStatus, createHintSession, - (int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, - int64_t durationNanos, std::shared_ptr<IPowerHintSession>* session), - (override)); - MOCK_METHOD(ndk::ScopedAStatus, getHintSessionPreferredRate, (int64_t * rate), (override)); - MOCK_METHOD(ndk::ScopedAStatus, createHintSessionWithConfig, - (int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, - int64_t durationNanos, SessionTag tag, SessionConfig* config, - std::shared_ptr<IPowerHintSession>* _aidl_return), - (override)); - MOCK_METHOD(ndk::ScopedAStatus, getSessionChannel, - (int32_t tgid, int32_t uid, ChannelConfig* _aidl_return), (override)); - MOCK_METHOD(ndk::ScopedAStatus, closeSessionChannel, (int32_t tgid, int32_t uid), (override)); - MOCK_METHOD(ndk::ScopedAStatus, getInterfaceVersion, (int32_t * version), (override)); - MOCK_METHOD(ndk::ScopedAStatus, getInterfaceHash, (std::string * hash), (override)); - MOCK_METHOD(ndk::SpAIBinder, asBinder, (), (override)); - MOCK_METHOD(bool, isRemote, (), (override)); -}; - -} // namespace android::Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 7398cbebe3..3036fec456 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -30,9 +30,12 @@ public: MOCK_METHOD(sp<EventThreadConnection>, createEventConnection, (EventRegistrationFlags), (const, override)); MOCK_METHOD(void, enableSyntheticVsync, (bool), (override)); + MOCK_METHOD(void, omitVsyncDispatching, (bool), (override)); MOCK_METHOD(void, onHotplugReceived, (PhysicalDisplayId, bool), (override)); MOCK_METHOD(void, onHotplugConnectionError, (int32_t), (override)); MOCK_METHOD(void, onModeChanged, (const scheduler::FrameRateMode&), (override)); + MOCK_METHOD(void, onModeRejected, (PhysicalDisplayId displayId, DisplayModeId modeId), + (override)); MOCK_METHOD(void, onFrameRateOverridesChanged, (PhysicalDisplayId, std::vector<FrameRateOverride>), (override)); MOCK_METHOD(void, dump, (std::string&), (const, override)); @@ -52,6 +55,7 @@ public: MOCK_METHOD(void, onHdcpLevelsChanged, (PhysicalDisplayId displayId, int32_t connectedLevel, int32_t maxLevel), (override)); + MOCK_METHOD(void, addBufferStuffedUids, (BufferStuffingMap), (override)); }; } // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h index 45f86fa1a8..59f0966047 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h +++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h @@ -19,6 +19,8 @@ #include <gmock/gmock.h> #include <optional> +#include "Layer.h" + namespace android::mock { class MockLayer : public Layer { @@ -26,8 +28,11 @@ public: MockLayer(SurfaceFlinger* flinger, std::string name) : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) {} - MockLayer(SurfaceFlinger* flinger, std::string name, std::optional<uint32_t> uid) - : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {}, uid)) {} + MockLayer(SurfaceFlinger* flinger, std::string name, std::optional<uint32_t> id) + : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {}, id)) {} + + MockLayer(SurfaceFlinger* flinger, std::optional<uint32_t> id) + : Layer(LayerCreationArgs(flinger, nullptr, "TestLayer", 0, {}, id)) {} explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {} diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.cpp b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.cpp index 1ba38a822a..f4c1e52537 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.cpp +++ b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.cpp @@ -16,10 +16,10 @@ #include "MockPowerAdvisor.h" -namespace android::Hwc2::mock { +namespace android::adpf::mock { // Explicit default instantiation is recommended. PowerAdvisor::PowerAdvisor() = default; PowerAdvisor::~PowerAdvisor() = default; -} // namespace android::Hwc2::mock +} // namespace android::adpf::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h index 4efdfe877b..5c4512a2df 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h +++ b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h @@ -18,11 +18,11 @@ #include <gmock/gmock.h> -#include "DisplayHardware/PowerAdvisor.h" +#include "PowerAdvisor/PowerAdvisor.h" -namespace android::Hwc2::mock { +namespace android::adpf::mock { -class PowerAdvisor : public android::Hwc2::PowerAdvisor { +class PowerAdvisor : public android::adpf::PowerAdvisor { public: PowerAdvisor(); ~PowerAdvisor() override; @@ -65,4 +65,4 @@ public: MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (Duration targetDuration), (override)); }; -} // namespace android::Hwc2::mock +} // namespace android::adpf::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.cpp b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerHalController.cpp index 3ec5c2d09b..3b8de55607 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.cpp +++ b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerHalController.cpp @@ -16,9 +16,9 @@ #include "MockPowerHalController.h" -namespace android::Hwc2::mock { +namespace android::adpf::mock { MockPowerHalController::MockPowerHalController() = default; MockPowerHalController::~MockPowerHalController() = default; -} // namespace android::Hwc2::mock +} // namespace android::adpf::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerHalController.h index af1862d1cf..891f507c0c 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h +++ b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerHalController.h @@ -19,10 +19,7 @@ #include <gmock/gmock.h> #include <scheduler/Time.h> -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" #include <powermanager/PowerHalController.h> -#pragma clang diagnostic pop namespace android { namespace hardware { @@ -32,7 +29,7 @@ class IPower; } // namespace hardware } // namespace android -namespace android::Hwc2::mock { +namespace android::adpf::mock { using android::power::HalResult; @@ -57,6 +54,8 @@ public: MOCK_METHOD(HalResult<aidl::android::hardware::power::ChannelConfig>, getSessionChannel, (int tgid, int uid), (override)); MOCK_METHOD(HalResult<void>, closeSessionChannel, (int tgid, int uid), (override)); + MOCK_METHOD(HalResult<aidl::android::hardware::power::SupportInfo>, getSupportInfo, (), + (override)); }; -} // namespace android::Hwc2::mock
\ No newline at end of file +} // namespace android::adpf::mock
\ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHintSessionWrapper.cpp b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerHintSessionWrapper.cpp index d383283d8e..cb39783b77 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHintSessionWrapper.cpp +++ b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerHintSessionWrapper.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ -#include "mock/DisplayHardware/MockPowerHintSessionWrapper.h" +#include "MockPowerHintSessionWrapper.h" -namespace android::Hwc2::mock { +namespace android::adpf::mock { // Explicit default instantiation is recommended. MockPowerHintSessionWrapper::MockPowerHintSessionWrapper() : power::PowerHintSessionWrapper(nullptr) {} -} // namespace android::Hwc2::mock +} // namespace android::adpf::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHintSessionWrapper.h b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerHintSessionWrapper.h index bc6950cccb..4518de8c16 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHintSessionWrapper.h +++ b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerHintSessionWrapper.h @@ -16,13 +16,7 @@ #pragma once -#include "binder/Status.h" - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#include <aidl/android/hardware/power/IPower.h> #include <powermanager/PowerHintSessionWrapper.h> -#pragma clang diagnostic pop #include <gmock/gmock.h> @@ -34,7 +28,7 @@ using android::binder::Status; using namespace aidl::android::hardware::power; -namespace android::Hwc2::mock { +namespace android::adpf::mock { class MockPowerHintSessionWrapper : public power::PowerHintSessionWrapper { public: @@ -52,4 +46,4 @@ public: MOCK_METHOD(power::HalResult<SessionConfig>, getSessionConfig, (), (override)); }; -} // namespace android::Hwc2::mock +} // namespace android::adpf::mock |