diff options
16 files changed, 577 insertions, 287 deletions
diff --git a/libs/ui/include/ui/DisplayId.h b/libs/ui/include/ui/DisplayId.h index 9120972a42..d0c03fe39f 100644 --- a/libs/ui/include/ui/DisplayId.h +++ b/libs/ui/include/ui/DisplayId.h @@ -17,9 +17,10 @@ #pragma once #include <cstdint> -#include <optional> #include <string> +#include <ftl/optional.h> + namespace android { // ID of a physical or a virtual display. This class acts as a type safe wrapper around uint64_t. @@ -68,7 +69,7 @@ inline std::string to_string(DisplayId displayId) { // DisplayId of a physical display, such as the internal display or externally connected display. struct PhysicalDisplayId : DisplayId { - static constexpr std::optional<PhysicalDisplayId> tryCast(DisplayId id) { + static constexpr ftl::Optional<PhysicalDisplayId> tryCast(DisplayId id) { if (id.value & FLAG_VIRTUAL) { return std::nullopt; } diff --git a/libs/ui/include/ui/StaticDisplayInfo.h b/libs/ui/include/ui/StaticDisplayInfo.h index 566e4172a1..83da821f37 100644 --- a/libs/ui/include/ui/StaticDisplayInfo.h +++ b/libs/ui/include/ui/StaticDisplayInfo.h @@ -23,7 +23,7 @@ namespace android::ui { -enum class DisplayConnectionType { Internal, External }; +enum class DisplayConnectionType { Internal, External, ftl_last = External }; // Immutable information about physical display. struct StaticDisplayInfo { diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 5e9fe65225..3348cec211 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -141,19 +141,20 @@ filegroup { name: "libsurfaceflinger_sources", srcs: [ "BackgroundExecutor.cpp", - "ClientCache.cpp", "Client.cpp", - "EffectLayer.cpp", + "ClientCache.cpp", + "Display/DisplaySnapshot.cpp", "DisplayDevice.cpp", "DisplayHardware/AidlComposerHal.cpp", - "DisplayHardware/HidlComposerHal.cpp", "DisplayHardware/ComposerHal.cpp", "DisplayHardware/FramebufferSurface.cpp", "DisplayHardware/HWC2.cpp", "DisplayHardware/HWComposer.cpp", + "DisplayHardware/HidlComposerHal.cpp", "DisplayHardware/PowerAdvisor.cpp", "DisplayHardware/VirtualDisplaySurface.cpp", "DisplayRenderArea.cpp", + "EffectLayer.cpp", "Effects/Daltonizer.cpp", "EventLog/EventLog.cpp", "FlagManager.cpp", diff --git a/services/surfaceflinger/Display/DisplayMap.h b/services/surfaceflinger/Display/DisplayMap.h new file mode 100644 index 0000000000..baf0da9f1b --- /dev/null +++ b/services/surfaceflinger/Display/DisplayMap.h @@ -0,0 +1,31 @@ +/* + * 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 <ftl/small_map.h> + +namespace android::display { + +// The static capacities were chosen to exceed a typical number of physical and/or virtual displays. + +template <typename Key, typename Value> +using DisplayMap = ftl::SmallMap<Key, Value, 5>; + +template <typename Key, typename Value> +using PhysicalDisplayMap = ftl::SmallMap<Key, Value, 3>; + +} // namespace android::display diff --git a/services/surfaceflinger/Display/DisplaySnapshot.cpp b/services/surfaceflinger/Display/DisplaySnapshot.cpp new file mode 100644 index 0000000000..b4f104a74d --- /dev/null +++ b/services/surfaceflinger/Display/DisplaySnapshot.cpp @@ -0,0 +1,58 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <functional> +#include <utility> + +#include <ftl/algorithm.h> +#include <ftl/enum.h> + +#include "DisplaySnapshot.h" + +namespace android::display { + +DisplaySnapshot::DisplaySnapshot(PhysicalDisplayId displayId, + ui::DisplayConnectionType connectionType, + DisplayModes&& displayModes, + std::optional<DeviceProductInfo>&& deviceProductInfo) + : mDisplayId(displayId), + mConnectionType(connectionType), + mDisplayModes(std::move(displayModes)), + mDeviceProductInfo(std::move(deviceProductInfo)) {} + +std::optional<DisplayModeId> DisplaySnapshot::translateModeId(hal::HWConfigId hwcId) const { + return ftl::find_if(mDisplayModes, + [hwcId](const DisplayModes::value_type& pair) { + return pair.second->getHwcId() == hwcId; + }) + .transform(&ftl::to_key<DisplayModes>); +} + +void DisplaySnapshot::dump(std::string& out) const { + using namespace std::string_literals; + + out += " connectionType="s; + out += ftl::enum_string(mConnectionType); + + out += "\n deviceProductInfo="s; + if (mDeviceProductInfo) { + mDeviceProductInfo->dump(out); + } else { + out += "{}"s; + } +} + +} // namespace android::display diff --git a/services/surfaceflinger/Display/DisplaySnapshot.h b/services/surfaceflinger/Display/DisplaySnapshot.h new file mode 100644 index 0000000000..0279220b1b --- /dev/null +++ b/services/surfaceflinger/Display/DisplaySnapshot.h @@ -0,0 +1,57 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <optional> +#include <string> + +#include <ui/DisplayId.h> +#include <ui/StaticDisplayInfo.h> + +#include "../DisplayHardware/DisplayMode.h" + +namespace android::display { + +// Immutable state of a physical display, captured on hotplug. +class DisplaySnapshot { +public: + DisplaySnapshot(PhysicalDisplayId, ui::DisplayConnectionType, DisplayModes&&, + std::optional<DeviceProductInfo>&&); + + DisplaySnapshot(const DisplaySnapshot&) = delete; + DisplaySnapshot(DisplaySnapshot&&) = default; + + PhysicalDisplayId displayId() const { return mDisplayId; } + ui::DisplayConnectionType connectionType() const { return mConnectionType; } + + std::optional<DisplayModeId> translateModeId(hal::HWConfigId) const; + + const auto& displayModes() const { return mDisplayModes; } + const auto& deviceProductInfo() const { return mDeviceProductInfo; } + + void dump(std::string&) const; + +private: + const PhysicalDisplayId mDisplayId; + const ui::DisplayConnectionType mConnectionType; + + // Effectively const except in move constructor. + DisplayModes mDisplayModes; + std::optional<DeviceProductInfo> mDeviceProductInfo; +}; + +} // namespace android::display diff --git a/services/surfaceflinger/Display/PhysicalDisplay.h b/services/surfaceflinger/Display/PhysicalDisplay.h new file mode 100644 index 0000000000..cba10146b7 --- /dev/null +++ b/services/surfaceflinger/Display/PhysicalDisplay.h @@ -0,0 +1,76 @@ +/* + * 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 <functional> +#include <utility> + +#include <binder/IBinder.h> +#include <ui/DisplayId.h> +#include <utils/StrongPointer.h> + +#include "DisplayMap.h" +#include "DisplaySnapshot.h" + +namespace android::display { + +// TODO(b/229877597): Replace with AIDL type. +using DisplayToken = IBinder; + +class PhysicalDisplay { +public: + template <typename... Args> + PhysicalDisplay(sp<DisplayToken> token, Args&&... args) + : mToken(std::move(token)), mSnapshot(std::forward<Args>(args)...) {} + + PhysicalDisplay(const PhysicalDisplay&) = delete; + PhysicalDisplay(PhysicalDisplay&&) = default; + + const sp<DisplayToken>& token() const { return mToken; } + const DisplaySnapshot& snapshot() const { return mSnapshot; } + + // Transformers for PhysicalDisplays::get. + + using SnapshotRef = std::reference_wrapper<const DisplaySnapshot>; + SnapshotRef snapshotRef() const { return std::cref(mSnapshot); } + + bool isInternal() const { + return mSnapshot.connectionType() == ui::DisplayConnectionType::Internal; + } + + // Predicate for ftl::find_if on PhysicalDisplays. + static constexpr auto hasToken(const sp<DisplayToken>& token) { + return [&token](const std::pair<const PhysicalDisplayId, PhysicalDisplay>& pair) { + return pair.second.token() == token; + }; + } + +private: + const sp<DisplayToken> mToken; + + // Effectively const except in move constructor. + DisplaySnapshot mSnapshot; +}; + +using PhysicalDisplays = PhysicalDisplayMap<PhysicalDisplayId, PhysicalDisplay>; + +// Combinator for ftl::Optional<PhysicalDisplayId>::and_then. +constexpr auto getPhysicalDisplay(const PhysicalDisplays& displays) { + return [&](PhysicalDisplayId id) { return displays.get(id); }; +} + +} // namespace android::display diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 2866a34a57..ebaf35a8f2 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -39,6 +39,7 @@ #include <system/window.h> #include <ui/GraphicTypes.h> +#include "Display/DisplaySnapshot.h" #include "DisplayDevice.h" #include "Layer.h" #include "RefreshRateOverlay.h" @@ -63,12 +64,10 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) mHwComposer(args.hwComposer), mDisplayToken(args.displayToken), mSequenceId(args.sequenceId), - mConnectionType(args.connectionType), mCompositionDisplay{args.compositionDisplay}, mActiveModeFPSTrace("ActiveModeFPS -" + to_string(getId())), mActiveModeFPSHwcTrace("ActiveModeFPS_HWC -" + to_string(getId())), mPhysicalOrientation(args.physicalOrientation), - mSupportedModes(std::move(args.supportedModes)), mIsPrimary(args.isPrimary), mRefreshRateConfigs(std::move(args.refreshRateConfigs)) { mCompositionDisplay->editState().isSecure = args.isSecure; @@ -132,10 +131,6 @@ void DisplayDevice::setDisplayName(const std::string& displayName) { } } -void DisplayDevice::setDeviceProductInfo(std::optional<DeviceProductInfo> info) { - mDeviceProductInfo = std::move(info); -} - auto DisplayDevice::getInputInfo() const -> InputInfo { gui::DisplayInfo info; info.displayId = getLayerStack().id; @@ -187,16 +182,20 @@ bool DisplayDevice::isPoweredOn() const { return mPowerMode && *mPowerMode != hal::PowerMode::OFF; } -void DisplayDevice::setActiveMode(DisplayModeId id) { - const auto mode = getMode(id); - LOG_FATAL_IF(!mode, "Cannot set active mode which is not supported."); - ATRACE_INT(mActiveModeFPSTrace.c_str(), mode->getFps().getIntValue()); - mActiveMode = mode; +void DisplayDevice::setActiveMode(DisplayModeId modeId, const display::DisplaySnapshot& snapshot) { + const auto modeOpt = snapshot.displayModes().get(modeId); + LOG_ALWAYS_FATAL_IF(!modeOpt, "Unknown mode"); + + mActiveMode = modeOpt->get(); + const Fps fps = mActiveMode->getFps(); + + ATRACE_INT(mActiveModeFPSTrace.c_str(), fps.getIntValue()); + if (mRefreshRateConfigs) { - mRefreshRateConfigs->setActiveModeId(mActiveMode->getId()); + mRefreshRateConfigs->setActiveModeId(modeId); } if (mRefreshRateOverlay) { - mRefreshRateOverlay->changeRefreshRate(mActiveMode->getFps()); + mRefreshRateOverlay->changeRefreshRate(fps); } } @@ -220,25 +219,6 @@ const DisplayModePtr& DisplayDevice::getActiveMode() const { return mActiveMode; } -const DisplayModes& DisplayDevice::getSupportedModes() const { - return mSupportedModes; -} - -DisplayModePtr DisplayDevice::getMode(DisplayModeId modeId) const { - const DisplayModePtr nullMode; - return mSupportedModes.get(modeId).value_or(std::cref(nullMode)); -} - -std::optional<DisplayModeId> DisplayDevice::translateModeId(hal::HWConfigId hwcId) const { - const auto it = - std::find_if(mSupportedModes.begin(), mSupportedModes.end(), - [hwcId](const auto& pair) { return pair.second->getHwcId() == hwcId; }); - if (it != mSupportedModes.end()) { - return it->second->getId(); - } - return {}; -} - nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const { const auto physicalId = getPhysicalId(); if (!mHwComposer.isConnected(physicalId)) { @@ -268,10 +248,10 @@ ui::Dataspace DisplayDevice::getCompositionDataSpace() const { return mCompositionDisplay->getState().dataspace; } -void DisplayDevice::setLayerStack(ui::LayerStack stack) { - mCompositionDisplay->setLayerFilter({stack, isInternal()}); +void DisplayDevice::setLayerFilter(ui::LayerFilter filter) { + mCompositionDisplay->setLayerFilter(filter); if (mRefreshRateOverlay) { - mRefreshRateOverlay->setLayerStack(stack); + mRefreshRateOverlay->setLayerStack(filter.layerStack); } } @@ -343,11 +323,7 @@ std::string DisplayDevice::getDebugName() const { std::string name = "Display "s + to_string(getId()) + " ("s; - if (mConnectionType) { - name += isInternal() ? "internal"s : "external"s; - } else { - name += "virtual"s; - } + name += isVirtual() ? "virtual"s : "physical"s; if (isPrimary()) { name += ", primary"s; @@ -361,15 +337,6 @@ void DisplayDevice::dump(std::string& result) const { result += getDebugName(); - if (!isVirtual()) { - result += "\n deviceProductInfo="s; - if (mDeviceProductInfo) { - mDeviceProductInfo->dump(result); - } else { - result += "{}"s; - } - } - result += "\n powerMode="s; result += mPowerMode.has_value() ? to_string(mPowerMode.value()) : "OFF(reset)"; result += '\n'; diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 3eead178d3..d79a6b5f3d 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -65,6 +65,10 @@ class Display; class DisplaySurface; } // namespace compositionengine +namespace display { +class DisplaySnapshot; +} // namespace display + class DisplayDevice : public RefBase { public: constexpr static float sDefaultMinLumiance = 0.0; @@ -80,11 +84,8 @@ public: return mCompositionDisplay; } - std::optional<ui::DisplayConnectionType> getConnectionType() const { return mConnectionType; } - - bool isVirtual() const { return !mConnectionType; } + bool isVirtual() const { return VirtualDisplayId::tryCast(getId()).has_value(); } bool isPrimary() const { return mIsPrimary; } - bool isInternal() const { return mConnectionType == ui::DisplayConnectionType::Internal; } // isSecure indicates whether this display can be trusted to display // secure surfaces. @@ -94,7 +95,7 @@ public: int getHeight() const; ui::Size getSize() const { return {getWidth(), getHeight()}; } - void setLayerStack(ui::LayerStack); + void setLayerFilter(ui::LayerFilter); void setDisplaySize(int width, int height); void setProjection(ui::Rotation orientation, Rect viewport, Rect frame); void stageBrightness(float brightness) REQUIRES(kMainThreadContext); @@ -164,11 +165,6 @@ public: void setDisplayName(const std::string& displayName); const std::string& getDisplayName() const { return mDisplayName; } - void setDeviceProductInfo(std::optional<DeviceProductInfo> info); - const std::optional<DeviceProductInfo>& getDeviceProductInfo() const { - return mDeviceProductInfo; - } - struct InputInfo { gui::DisplayInfo info; ui::Transform transform; @@ -211,24 +207,14 @@ public: return mUpcomingActiveMode; } - void setActiveMode(DisplayModeId) REQUIRES(kMainThreadContext); + // Precondition: DisplaySnapshot must contain a mode with DisplayModeId. + void setActiveMode(DisplayModeId, const display::DisplaySnapshot&) REQUIRES(kMainThreadContext); + status_t initiateModeChange(const ActiveModeInfo&, const hal::VsyncPeriodChangeConstraints& constraints, hal::VsyncPeriodChangeTimeline* outTimeline) REQUIRES(kMainThreadContext); - // Return the immutable list of supported display modes. The HWC may report different modes - // after a hotplug reconnect event, in which case the DisplayDevice object will be recreated. - // Hotplug reconnects are common for external displays. - const DisplayModes& getSupportedModes() const; - - // Returns nullptr if the given mode ID is not supported. A previously - // supported mode may be no longer supported for some devices like TVs and - // set-top boxes after a hotplug reconnect. - DisplayModePtr getMode(DisplayModeId) const; - - std::optional<DisplayModeId> translateModeId(hal::HWConfigId) const; - // Returns the refresh rate configs for this display. scheduler::RefreshRateConfigs& refreshRateConfigs() const { return *mRefreshRateConfigs; } @@ -267,7 +253,6 @@ private: HWComposer& mHwComposer; const wp<IBinder> mDisplayToken; const int32_t mSequenceId; - const std::optional<ui::DisplayConnectionType> mConnectionType; const std::shared_ptr<compositionengine::Display> mCompositionDisplay; @@ -285,7 +270,6 @@ private: DisplayModePtr mActiveMode; std::optional<float> mStagedBrightness = std::nullopt; float mBrightness = -1.f; - const DisplayModes mSupportedModes; std::atomic<nsecs_t> mLastHwVsync = 0; @@ -294,8 +278,6 @@ private: uint32_t mFlags = 0; - std::optional<DeviceProductInfo> mDeviceProductInfo; - std::vector<ui::Hdr> mOverrideHdrTypes; std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs; @@ -313,14 +295,11 @@ private: struct DisplayDeviceState { struct Physical { PhysicalDisplayId id; - ui::DisplayConnectionType type; hardware::graphics::composer::hal::HWDisplayId hwcDisplayId; - std::optional<DeviceProductInfo> deviceProductInfo; - DisplayModes supportedModes; DisplayModePtr activeMode; bool operator==(const Physical& other) const { - return id == other.id && type == other.type && hwcDisplayId == other.hwcDisplayId; + return id == other.id && hwcDisplayId == other.hwcDisplayId; } }; @@ -356,7 +335,6 @@ struct DisplayDeviceCreationArgs { std::shared_ptr<scheduler::RefreshRateConfigs> refreshRateConfigs; int32_t sequenceId{0}; - std::optional<ui::DisplayConnectionType> connectionType; bool isSecure{false}; sp<ANativeWindow> nativeWindow; sp<compositionengine::DisplaySurface> displaySurface; @@ -367,7 +345,6 @@ struct DisplayDeviceCreationArgs { std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes; std::optional<hardware::graphics::composer::hal::PowerMode> initialPowerMode; bool isPrimary{false}; - DisplayModes supportedModes; DisplayModeId activeModeId; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index cc93db3187..1bb81c555b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -53,9 +53,10 @@ #include <configstore/Utils.h> #include <cutils/compiler.h> #include <cutils/properties.h> +#include <ftl/algorithm.h> #include <ftl/fake_guard.h> #include <ftl/future.h> -#include <ftl/small_map.h> +#include <ftl/unit.h> #include <gui/AidlStatusUtil.h> #include <gui/BufferQueue.h> #include <gui/DebugEGLImageTracker.h> @@ -108,6 +109,7 @@ #include "BufferStateLayer.h" #include "Client.h" #include "Colorizer.h" +#include "Display/DisplayMap.h" #include "DisplayDevice.h" #include "DisplayHardware/ComposerHal.h" #include "DisplayHardware/FramebufferSurface.h" @@ -172,6 +174,8 @@ using CompositionStrategyPredictionState = android::compositionengine::impl:: OutputCompositionState::CompositionStrategyPredictionState; using base::StringAppendF; +using display::PhysicalDisplay; +using display::PhysicalDisplays; using gui::DisplayInfo; using gui::GameMode; using gui::IDisplayEventConnection; @@ -594,12 +598,12 @@ void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) { std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const { std::vector<PhysicalDisplayId> displayIds; - displayIds.reserve(mPhysicalDisplayTokens.size()); + displayIds.reserve(mPhysicalDisplays.size()); const auto defaultDisplayId = getDefaultDisplayDeviceLocked()->getPhysicalId(); displayIds.push_back(defaultDisplayId); - for (const auto& [id, token] : mPhysicalDisplayTokens) { + for (const auto& [id, display] : mPhysicalDisplays) { if (id != defaultDisplayId) { displayIds.push_back(id); } @@ -608,6 +612,12 @@ std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() con return displayIds; } +std::optional<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdLocked( + const sp<display::DisplayToken>& displayToken) const { + return ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken)) + .transform(&ftl::to_key<PhysicalDisplays>); +} + sp<IBinder> SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId) const { Mutex::Autolock lock(mStateLock); return getPhysicalDisplayTokenLocked(displayId); @@ -932,16 +942,19 @@ status_t SurfaceFlinger::getStaticDisplayInfo(const sp<IBinder>& displayToken, Mutex::Autolock lock(mStateLock); - const auto display = getDisplayDeviceLocked(displayToken); - if (!display) { + const auto displayOpt = ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken)) + .transform(&ftl::to_mapped_ref<PhysicalDisplays>) + .and_then(getDisplayDeviceAndSnapshot()); + + if (!displayOpt) { return NAME_NOT_FOUND; } - if (const auto connectionType = display->getConnectionType()) - info->connectionType = *connectionType; - else { - return INVALID_OPERATION; - } + const auto& [display, snapshotRef] = *displayOpt; + const auto& snapshot = snapshotRef.get(); + + info->connectionType = snapshot.connectionType(); + info->deviceProductInfo = snapshot.deviceProductInfo(); if (mEmulatedDisplayDensity) { info->density = mEmulatedDisplayDensity; @@ -953,7 +966,6 @@ status_t SurfaceFlinger::getStaticDisplayInfo(const sp<IBinder>& displayToken, info->density /= ACONFIGURATION_DENSITY_MEDIUM; info->secure = display->isSecure(); - info->deviceProductInfo = display->getDeviceProductInfo(); info->installOrientation = display->getPhysicalOrientation(); return NO_ERROR; @@ -967,23 +979,22 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken, Mutex::Autolock lock(mStateLock); - const auto display = getDisplayDeviceLocked(displayToken); - if (!display) { + const auto displayOpt = ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken)) + .transform(&ftl::to_mapped_ref<PhysicalDisplays>) + .and_then(getDisplayDeviceAndSnapshot()); + if (!displayOpt) { return NAME_NOT_FOUND; } - const auto displayId = PhysicalDisplayId::tryCast(display->getId()); - if (!displayId) { - return INVALID_OPERATION; - } + const auto& [display, snapshotRef] = *displayOpt; + const auto& snapshot = snapshotRef.get(); - info->activeDisplayModeId = display->getActiveMode()->getId().value(); + const auto& displayModes = snapshot.displayModes(); - const auto& supportedModes = display->getSupportedModes(); info->supportedDisplayModes.clear(); - info->supportedDisplayModes.reserve(supportedModes.size()); + info->supportedDisplayModes.reserve(displayModes.size()); - for (const auto& [id, mode] : supportedModes) { + for (const auto& [id, mode] : displayModes) { ui::DisplayMode outMode; outMode.id = static_cast<int32_t>(id.value()); @@ -1027,21 +1038,24 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken, info->supportedDisplayModes.push_back(outMode); } + const PhysicalDisplayId displayId = snapshot.displayId(); + + info->activeDisplayModeId = display->getActiveMode()->getId().value(); info->activeColorMode = display->getCompositionDisplay()->getState().colorMode; - info->supportedColorModes = getDisplayColorModes(*display); + info->supportedColorModes = getDisplayColorModes(displayId); info->hdrCapabilities = display->getHdrCapabilities(); info->autoLowLatencyModeSupported = - getHwComposer().hasDisplayCapability(*displayId, + getHwComposer().hasDisplayCapability(displayId, DisplayCapability::AUTO_LOW_LATENCY_MODE); info->gameContentTypeSupported = - getHwComposer().supportsContentType(*displayId, hal::ContentType::GAME); + getHwComposer().supportsContentType(displayId, hal::ContentType::GAME); info->preferredBootDisplayMode = static_cast<ui::DisplayModeId>(-1); if (getHwComposer().hasCapability(Capability::BOOT_DISPLAY_CONFIG)) { - if (const auto hwcId = getHwComposer().getPreferredBootDisplayMode(*displayId)) { - if (const auto modeId = display->translateModeId(*hwcId)) { + if (const auto hwcId = getHwComposer().getPreferredBootDisplayMode(displayId)) { + if (const auto modeId = snapshot.translateModeId(*hwcId)) { info->preferredBootDisplayMode = modeId->value(); } } @@ -1089,39 +1103,44 @@ void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) { } } -status_t SurfaceFlinger::setActiveModeFromBackdoor(const sp<IBinder>& displayToken, int modeId) { +status_t SurfaceFlinger::setActiveModeFromBackdoor(const sp<display::DisplayToken>& displayToken, + DisplayModeId modeId) { ATRACE_CALL(); if (!displayToken) { return BAD_VALUE; } + const char* const whence = __func__; auto future = mScheduler->schedule([=]() -> status_t { - const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayToken)); - if (!display) { - ALOGE("Attempt to set allowed display modes for invalid display token %p", - displayToken.get()); + const auto displayOpt = + FTL_FAKE_GUARD(mStateLock, + ftl::find_if(mPhysicalDisplays, + PhysicalDisplay::hasToken(displayToken)) + .transform(&ftl::to_mapped_ref<PhysicalDisplays>) + .and_then(getDisplayDeviceAndSnapshot())); + if (!displayOpt) { + ALOGE("%s: Invalid physical display token %p", whence, displayToken.get()); return NAME_NOT_FOUND; } - if (display->isVirtual()) { - ALOGW("Attempt to set allowed display modes for virtual display"); - return INVALID_OPERATION; - } + const auto& [display, snapshotRef] = *displayOpt; + const auto& snapshot = snapshotRef.get(); + + const auto fpsOpt = snapshot.displayModes().get(modeId).transform( + [](const DisplayModePtr& mode) { return mode->getFps(); }); - const auto mode = display->getMode(DisplayModeId{modeId}); - if (!mode) { - ALOGW("Attempt to switch to an unsupported mode %d.", modeId); + if (!fpsOpt) { + ALOGE("%s: Invalid mode %d for display %s", whence, modeId.value(), + to_string(snapshot.displayId()).c_str()); return BAD_VALUE; } - const auto fps = mode->getFps(); + const Fps fps = *fpsOpt; // Keep the old switching type. - const auto allowGroupSwitching = + const bool allowGroupSwitching = display->refreshRateConfigs().getCurrentPolicy().allowGroupSwitching; - const scheduler::RefreshRateConfigs::Policy policy{mode->getId(), - allowGroupSwitching, - {fps, fps}}; + const scheduler::RefreshRateConfigs::Policy policy{modeId, allowGroupSwitching, {fps, fps}}; constexpr bool kOverridePolicy = false; return setDesiredDisplayModeSpecsInternal(display, policy, kOverridePolicy); @@ -1159,9 +1178,12 @@ void SurfaceFlinger::updateInternalStateWithChangedMode() { return; } - // We just created this display so we can call even if we are not on the main thread. - ftl::FakeGuard guard(kMainThreadContext); - display->setActiveMode(upcomingModeInfo.mode->getId()); + mPhysicalDisplays.get(display->getPhysicalId()) + .transform(&PhysicalDisplay::snapshotRef) + .transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) { + FTL_FAKE_GUARD(kMainThreadContext, + display->setActiveMode(upcomingModeInfo.mode->getId(), snapshot)); + })); const Fps refreshRate = upcomingModeInfo.mode->getFps(); mRefreshRateStats->setRefreshRate(refreshRate); @@ -1191,12 +1213,16 @@ void SurfaceFlinger::setActiveModeInHwcIfNeeded() { std::optional<PhysicalDisplayId> displayToUpdateImmediately; - for (const auto& iter : mDisplays) { - const auto& display = iter.second; - if (!display || !display->isInternal()) { + for (const auto& [id, physical] : mPhysicalDisplays) { + const auto& snapshot = physical.snapshot(); + + if (snapshot.connectionType() != ui::DisplayConnectionType::Internal) { continue; } + const auto display = getDisplayDeviceLocked(id); + if (!display) continue; + // Store the local variable to release the lock. const auto desiredActiveMode = display->getDesiredActiveMode(); if (!desiredActiveMode) { @@ -1210,20 +1236,23 @@ void SurfaceFlinger::setActiveModeInHwcIfNeeded() { continue; } - const auto desiredMode = display->getMode(desiredActiveMode->mode->getId()); - if (!desiredMode) { + const auto desiredModeId = desiredActiveMode->mode->getId(); + const auto refreshRateOpt = + snapshot.displayModes() + .get(desiredModeId) + .transform([](const DisplayModePtr& mode) { return mode->getFps(); }); + + if (!refreshRateOpt) { ALOGW("Desired display mode is no longer supported. Mode ID = %d", - desiredActiveMode->mode->getId().value()); + desiredModeId.value()); clearDesiredActiveModeState(display); continue; } - const auto refreshRate = desiredMode->getFps(); - ALOGV("%s changing active mode to %d(%s) for display %s", __func__, - desiredMode->getId().value(), to_string(refreshRate).c_str(), - to_string(display->getId()).c_str()); + ALOGV("%s changing active mode to %d(%s) for display %s", __func__, desiredModeId.value(), + to_string(*refreshRateOpt).c_str(), to_string(display->getId()).c_str()); - if (display->getActiveMode()->getId() == desiredActiveMode->mode->getId()) { + if (display->getActiveMode()->getId() == desiredModeId) { // we are already in the requested mode, there is nothing left to do desiredActiveModeChangeDone(display); continue; @@ -1232,8 +1261,7 @@ void SurfaceFlinger::setActiveModeInHwcIfNeeded() { // Desired active mode was set, it is different than the mode currently in use, however // allowed modes might have changed by the time we process the refresh. // Make sure the desired mode is still allowed - const auto displayModeAllowed = - display->refreshRateConfigs().isModeAllowed(desiredActiveMode->mode->getId()); + const auto displayModeAllowed = display->refreshRateConfigs().isModeAllowed(desiredModeId); if (!displayModeAllowed) { clearDesiredActiveModeState(display); continue; @@ -1295,15 +1323,18 @@ void SurfaceFlinger::disableExpensiveRendering() { future.wait(); } -std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(const DisplayDevice& display) { - auto modes = getHwComposer().getColorModes(display.getPhysicalId()); +std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(PhysicalDisplayId displayId) { + auto modes = getHwComposer().getColorModes(displayId); + + const bool isInternalDisplay = mPhysicalDisplays.get(displayId) + .transform(&PhysicalDisplay::isInternal) + .value_or(false); // If the display is internal and the configuration claims it's not wide color capable, // filter out all wide color modes. The typical reason why this happens is that the // hardware is not good enough to support GPU composition of wide color, and thus the // OEMs choose to disable this capability. - if (display.getConnectionType() == ui::DisplayConnectionType::Internal && - !hasWideColorDisplay) { + if (isInternalDisplay && !hasWideColorDisplay) { const auto newEnd = std::remove_if(modes.begin(), modes.end(), isWideColorMode); modes.erase(newEnd, modes.end()); } @@ -1319,13 +1350,13 @@ status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayTok Mutex::Autolock lock(mStateLock); - const auto display = getDisplayDeviceLocked(displayToken); + const auto display = ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken)) + .transform(&ftl::to_mapped_ref<PhysicalDisplays>); if (!display) { return NAME_NOT_FOUND; } - const auto connectionType = display->getConnectionType(); - if (connectionType != ui::DisplayConnectionType::Internal) { + if (!display.transform(&PhysicalDisplay::isInternal).value()) { return INVALID_OPERATION; } @@ -1353,7 +1384,7 @@ status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, Col return INVALID_OPERATION; } - const auto modes = getDisplayColorModes(*display); + const auto modes = getDisplayColorModes(display->getPhysicalId()); const bool exists = std::find(modes.begin(), modes.end(), mode) != modes.end(); if (mode < ColorMode::NATIVE || !exists) { @@ -1381,30 +1412,31 @@ status_t SurfaceFlinger::getBootDisplayModeSupport(bool* outSupport) const { return NO_ERROR; } -status_t SurfaceFlinger::setBootDisplayMode(const sp<IBinder>& displayToken, - ui::DisplayModeId modeId) { +status_t SurfaceFlinger::setBootDisplayMode(const sp<display::DisplayToken>& displayToken, + DisplayModeId modeId) { const char* const whence = __func__; auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) -> status_t { - const auto display = getDisplayDeviceLocked(displayToken); - if (!display) { - ALOGE("%s: Invalid display token %p", whence, displayToken.get()); + const auto snapshotOpt = + ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken)) + .transform(&ftl::to_mapped_ref<PhysicalDisplays>) + .transform(&PhysicalDisplay::snapshotRef); + + if (!snapshotOpt) { + ALOGE("%s: Invalid physical display token %p", whence, displayToken.get()); return NAME_NOT_FOUND; } - if (display->isVirtual()) { - ALOGE("%s: Invalid operation on virtual display", whence); - return INVALID_OPERATION; - } + const auto& snapshot = snapshotOpt->get(); + const auto hwcIdOpt = snapshot.displayModes().get(modeId).transform( + [](const DisplayModePtr& mode) { return mode->getHwcId(); }); - const auto displayId = display->getPhysicalId(); - const auto mode = display->getMode(DisplayModeId{modeId}); - if (!mode) { - ALOGE("%s: Invalid mode %d for display %s", whence, modeId, - to_string(displayId).c_str()); + if (!hwcIdOpt) { + ALOGE("%s: Invalid mode %d for display %s", whence, modeId.value(), + to_string(snapshot.displayId()).c_str()); return BAD_VALUE; } - return getHwComposer().setBootDisplayMode(displayId, mode->getHwcId()); + return getHwComposer().setBootDisplayMode(snapshot.displayId(), *hwcIdOpt); }); return future.get(); } @@ -2467,7 +2499,13 @@ void SurfaceFlinger::postComposition() { mTimeStats->incrementTotalFrames(); mTimeStats->setPresentFenceGlobal(presentFenceTime); - if (display && display->isInternal() && display->getPowerMode() == hal::PowerMode::ON && + const bool isInternalDisplay = display && + FTL_FAKE_GUARD(mStateLock, mPhysicalDisplays) + .get(display->getPhysicalId()) + .transform(&PhysicalDisplay::isInternal) + .value_or(false); + + if (isInternalDisplay && display && display->getPowerMode() == hal::PowerMode::ON && presentFenceTime->isValid()) { mScheduler->addPresentFence(std::move(presentFenceTime)); } @@ -2601,10 +2639,11 @@ std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes( return {}; } - DisplayModes oldModes; - if (const auto token = getPhysicalDisplayTokenLocked(displayId)) { - oldModes = getDisplayDeviceLocked(token)->getSupportedModes(); - } + const DisplayModes oldModes = mPhysicalDisplays.get(displayId) + .transform([](const PhysicalDisplay& display) { + return display.snapshot().displayModes(); + }) + .value_or(DisplayModes{}); ui::DisplayModeId nextModeId = 1 + std::accumulate(oldModes.begin(), oldModes.end(), static_cast<ui::DisplayModeId>(-1), @@ -2669,21 +2708,22 @@ bool SurfaceFlinger::configureLocked() { const char* SurfaceFlinger::processHotplug(PhysicalDisplayId displayId, hal::HWDisplayId hwcDisplayId, bool connected, DisplayIdentificationInfo&& info) { - const auto tokenOpt = mPhysicalDisplayTokens.get(displayId); + const auto displayOpt = mPhysicalDisplays.get(displayId); if (!connected) { - LOG_ALWAYS_FATAL_IF(!tokenOpt); + LOG_ALWAYS_FATAL_IF(!displayOpt); + const auto& display = displayOpt->get(); - if (const ssize_t index = mCurrentState.displays.indexOfKey(tokenOpt->get()); index >= 0) { + if (const ssize_t index = mCurrentState.displays.indexOfKey(display.token()); index >= 0) { const DisplayDeviceState& state = mCurrentState.displays.valueAt(index); mInterceptor->saveDisplayDeletion(state.sequenceId); mCurrentState.displays.removeItemsAt(index); } - mPhysicalDisplayTokens.erase(displayId); + mPhysicalDisplays.erase(displayId); return "Disconnecting"; } - auto [supportedModes, activeMode] = loadDisplayModes(displayId); + auto [displayModes, activeMode] = loadDisplayModes(displayId); if (!activeMode) { // TODO(b/241286153): Report hotplug failure to the framework. ALOGE("Failed to hotplug display %s", to_string(displayId).c_str()); @@ -2691,30 +2731,42 @@ const char* SurfaceFlinger::processHotplug(PhysicalDisplayId displayId, return nullptr; } - if (tokenOpt) { - auto& state = mCurrentState.displays.editValueFor(tokenOpt->get()); - state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId. - state.physical->supportedModes = std::move(supportedModes); - state.physical->activeMode = std::move(activeMode); + if (displayOpt) { + const auto& display = displayOpt->get(); + const auto& snapshot = display.snapshot(); + + std::optional<DeviceProductInfo> deviceProductInfo; if (getHwComposer().updatesDeviceProductInfoOnHotplugReconnect()) { - state.physical->deviceProductInfo = std::move(info.deviceProductInfo); + deviceProductInfo = std::move(info.deviceProductInfo); + } else { + deviceProductInfo = snapshot.deviceProductInfo(); } + + const auto it = + mPhysicalDisplays.try_replace(displayId, display.token(), displayId, + snapshot.connectionType(), std::move(displayModes), + std::move(deviceProductInfo)); + + auto& state = mCurrentState.displays.editValueFor(it->second.token()); + state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId. + state.physical->activeMode = std::move(activeMode); return "Reconnecting"; } + const sp<IBinder> token = sp<BBinder>::make(); + + mPhysicalDisplays.try_emplace(displayId, token, displayId, + getHwComposer().getDisplayConnectionType(displayId), + std::move(displayModes), std::move(info.deviceProductInfo)); + DisplayDeviceState state; state.physical = {.id = displayId, - .type = getHwComposer().getDisplayConnectionType(displayId), .hwcDisplayId = hwcDisplayId, - .deviceProductInfo = std::move(info.deviceProductInfo), - .supportedModes = std::move(supportedModes), .activeMode = std::move(activeMode)}; state.isSecure = true; // All physical displays are currently considered secure. state.displayName = std::move(info.name); - sp<IBinder> token = sp<BBinder>::make(); mCurrentState.displays.add(token, state); - mPhysicalDisplayTokens.try_emplace(displayId, std::move(token)); mInterceptor->saveDisplayCreation(state); return "Connecting"; } @@ -2739,8 +2791,6 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( creationArgs.supportedPerFrameMetadata = 0; if (const auto& physical = state.physical) { - creationArgs.connectionType = physical->type; - creationArgs.supportedModes = physical->supportedModes; creationArgs.activeModeId = physical->activeMode->getId(); const auto [kernelIdleTimerController, idleTimerTimeoutMs] = getKernelIdleTimerProperties(compositionDisplay->getId()); @@ -2751,9 +2801,17 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( base::GetIntProperty("debug.sf.frame_rate_multiple_threshold", 0), .idleTimerTimeout = idleTimerTimeoutMs, .kernelIdleTimerController = kernelIdleTimerController}; + creationArgs.refreshRateConfigs = - std::make_shared<scheduler::RefreshRateConfigs>(creationArgs.supportedModes, - creationArgs.activeModeId, config); + mPhysicalDisplays.get(physical->id) + .transform(&PhysicalDisplay::snapshotRef) + .transform([&](const display::DisplaySnapshot& snapshot) { + return std::make_shared< + scheduler::RefreshRateConfigs>(snapshot.displayModes(), + creationArgs.activeModeId, + config); + }) + .value_or(nullptr); } if (const auto id = PhysicalDisplayId::tryCast(compositionDisplay->getId())) { @@ -2811,13 +2869,17 @@ sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal( compositionengine::Output::ColorProfile{defaultColorMode, defaultDataSpace, RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN}); - if (!state.isVirtual()) { - FTL_FAKE_GUARD(kMainThreadContext, - display->setActiveMode(state.physical->activeMode->getId())); - display->setDeviceProductInfo(state.physical->deviceProductInfo); + + if (const auto& physical = state.physical) { + mPhysicalDisplays.get(physical->id) + .transform(&PhysicalDisplay::snapshotRef) + .transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) { + FTL_FAKE_GUARD(kMainThreadContext, + display->setActiveMode(physical->activeMode->getId(), snapshot)); + })); } - display->setLayerStack(state.layerStack); + display->setLayerFilter(makeLayerFilterForDisplay(display->getId(), state.layerStack)); display->setProjection(state.orientation, state.layerStackSpaceRect, state.orientedDisplaySpaceRect); display->setDisplayName(state.displayName); @@ -2973,7 +3035,8 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, if (const auto display = getDisplayDeviceLocked(displayToken)) { if (currentState.layerStack != drawingState.layerStack) { - display->setLayerStack(currentState.layerStack); + display->setLayerFilter( + makeLayerFilterForDisplay(display->getId(), currentState.layerStack)); } if (currentState.flags != drawingState.flags) { display->setFlags(currentState.flags); @@ -3219,7 +3282,7 @@ void SurfaceFlinger::persistDisplayBrightness(bool needsComposite) { void SurfaceFlinger::buildWindowInfos(std::vector<WindowInfo>& outWindowInfos, std::vector<DisplayInfo>& outDisplayInfos) { - ftl::SmallMap<ui::LayerStack, DisplayDevice::InputInfo, 4> displayInputInfos; + display::DisplayMap<ui::LayerStack, DisplayDevice::InputInfo> displayInputInfos; for (const auto& [_, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) { const auto layerStack = display->getLayerStack(); @@ -4718,8 +4781,12 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: return; } + const bool isInternalDisplay = mPhysicalDisplays.get(displayId) + .transform(&PhysicalDisplay::isInternal) + .value_or(false); + const auto activeDisplay = getDisplayDeviceLocked(mActiveDisplayToken); - if (activeDisplay != display && display->isInternal() && activeDisplay && + if (isInternalDisplay && activeDisplay != display && activeDisplay && activeDisplay->isPoweredOn()) { ALOGW("Trying to change power mode on non active display while the active display is ON"); } @@ -4732,7 +4799,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: const auto refreshRate = display->refreshRateConfigs().getActiveMode()->getFps(); if (*currentMode == hal::PowerMode::OFF) { // Turn on the display - if (display->isInternal() && (!activeDisplay || !activeDisplay->isPoweredOn())) { + if (isInternalDisplay && (!activeDisplay || !activeDisplay->isPoweredOn())) { onActiveDisplayChangedLocked(display); } // Keep uclamp in a separate syscall and set it before changing to RT due to b/190237315. @@ -4991,10 +5058,20 @@ void SurfaceFlinger::dumpCompositionDisplays(std::string& result) const { } void SurfaceFlinger::dumpDisplays(std::string& result) const { - for (const auto& [token, display] : mDisplays) { - display->dump(result); + for (const auto& [id, display] : mPhysicalDisplays) { + if (const auto device = getDisplayDeviceLocked(id)) { + device->dump(result); + } + display.snapshot().dump(result); result += '\n'; } + + for (const auto& [token, display] : mDisplays) { + if (display->isVirtual()) { + display->dump(result); + result += '\n'; + } + } } void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const { @@ -5793,7 +5870,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r }(); mDebugDisplayModeSetByBackdoor = false; - const status_t result = setActiveModeFromBackdoor(display, modeId); + const status_t result = setActiveModeFromBackdoor(display, DisplayModeId{modeId}); mDebugDisplayModeSetByBackdoor = result == NO_ERROR; return result; } @@ -6700,15 +6777,28 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, activeMode); } - const DisplayModePtr preferredDisplayMode = [&] { - const auto schedulerMode = mScheduler->getPreferredDisplayMode(); - if (schedulerMode && schedulerMode->getPhysicalDisplayId() == display->getPhysicalId()) { + const DisplayModePtr preferredDisplayMode = [&]() REQUIRES(mStateLock) -> DisplayModePtr { + const auto displayId = display->getPhysicalId(); + + if (const auto schedulerMode = mScheduler->getPreferredDisplayMode(); + schedulerMode && schedulerMode->getPhysicalDisplayId() == displayId) { return schedulerMode; } - return display->getMode(currentPolicy.defaultMode); + const DisplayModePtr nullMode; + return mPhysicalDisplays.get(displayId) + .transform(&PhysicalDisplay::snapshotRef) + .and_then([&](const display::DisplaySnapshot& snapshot) { + return snapshot.displayModes().get(currentPolicy.defaultMode); + }) + .value_or(std::cref(nullMode)); }(); + if (!preferredDisplayMode) { + ALOGE("%s: Preferred mode is unknown", __func__); + return NAME_NOT_FOUND; + } + ALOGV("trying to switch to Scheduler preferred mode %d (%s)", preferredDisplayMode->getId().value(), to_string(preferredDisplayMode->getFps()).c_str()); @@ -6879,9 +6969,11 @@ status_t SurfaceFlinger::setOverrideFrameRate(uid_t uid, float frameRate) { } void SurfaceFlinger::enableRefreshRateOverlay(bool enable) { - for (const auto& [ignored, display] : mDisplays) { - if (display->isInternal()) { - display->enableRefreshRateOverlay(enable, mRefreshRateOverlaySpinner); + for (const auto& [id, display] : mPhysicalDisplays) { + if (display.snapshot().connectionType() == ui::DisplayConnectionType::Internal) { + if (const auto device = getDisplayDeviceLocked(id)) { + device->enableRefreshRateOverlay(enable, mRefreshRateOverlaySpinner); + } } } } @@ -7367,8 +7459,7 @@ binder::Status SurfaceComposerAIDL::setBootDisplayMode(const sp<IBinder>& displa int displayModeId) { status_t status = checkAccessPermission(); if (status == OK) { - status = mFlinger->setBootDisplayMode(display, - static_cast<ui::DisplayModeId>(displayModeId)); + status = mFlinger->setBootDisplayMode(display, DisplayModeId{displayModeId}); } return binderStatusFromStatusT(status); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 310188512d..e9e13ef686 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -29,7 +29,6 @@ #include <cutils/atomic.h> #include <cutils/compiler.h> #include <ftl/future.h> -#include <ftl/small_map.h> #include <gui/BufferQueue.h> #include <gui/CompositorTiming.h> #include <gui/FrameTimestamps.h> @@ -59,6 +58,8 @@ #include <ui/FenceResult.h> #include "ClientCache.h" +#include "Display/DisplayMap.h" +#include "Display/PhysicalDisplay.h" #include "DisplayDevice.h" #include "DisplayHardware/HWC2.h" #include "DisplayHardware/PowerAdvisor.h" @@ -515,7 +516,7 @@ private: status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken, ui::DisplayPrimaries&); status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode); status_t getBootDisplayModeSupport(bool* outSupport) const; - status_t setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id); + status_t setBootDisplayMode(const sp<display::DisplayToken>&, DisplayModeId); status_t clearBootDisplayMode(const sp<IBinder>& displayToken); void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on); void setGameContentType(const sp<IBinder>& displayToken, bool on); @@ -651,7 +652,7 @@ private: void onInitializeDisplays() REQUIRES(mStateLock); // Sets the desired active mode bit. It obtains the lock, and sets mDesiredActiveMode. void setDesiredActiveMode(const ActiveModeInfo& info) REQUIRES(mStateLock); - status_t setActiveModeFromBackdoor(const sp<IBinder>& displayToken, int id); + status_t setActiveModeFromBackdoor(const sp<display::DisplayToken>&, DisplayModeId); // Sets the active mode and a new refresh rate in SF. void updateInternalStateWithChangedMode() REQUIRES(mStateLock); // Calls to setActiveMode on the main thread if there is a pending mode change @@ -820,6 +821,10 @@ private: // called when starting, or restarting after system_server death void initializeDisplays(); + bool isDisplayActiveLocked(const sp<const DisplayDevice>& display) const REQUIRES(mStateLock) { + return display->getDisplayToken() == mActiveDisplayToken; + } + sp<const DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) const REQUIRES(mStateLock) { return const_cast<SurfaceFlinger*>(this)->getDisplayDeviceLocked(displayToken); @@ -867,6 +872,21 @@ private: return getDefaultDisplayDeviceLocked(); } + using DisplayDeviceAndSnapshot = + std::pair<sp<DisplayDevice>, display::PhysicalDisplay::SnapshotRef>; + + // Combinator for ftl::Optional<PhysicalDisplay>::and_then. + auto getDisplayDeviceAndSnapshot() REQUIRES(mStateLock) { + return [this](const display::PhysicalDisplay& display) REQUIRES( + mStateLock) -> ftl::Optional<DisplayDeviceAndSnapshot> { + if (auto device = getDisplayDeviceLocked(display.snapshot().displayId())) { + return std::make_pair(std::move(device), display.snapshotRef()); + } + + return {}; + }; + } + // Returns the first display that matches a `bool(const DisplayDevice&)` predicate. template <typename Predicate> sp<DisplayDevice> findDisplay(Predicate p) const REQUIRES(mStateLock) { @@ -882,8 +902,13 @@ private: // region of all screens presenting this layer stack. void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty); - bool isDisplayActiveLocked(const sp<const DisplayDevice>& display) const REQUIRES(mStateLock) { - return display->getDisplayToken() == mActiveDisplayToken; + ui::LayerFilter makeLayerFilterForDisplay(DisplayId displayId, ui::LayerStack layerStack) + REQUIRES(mStateLock) { + return {layerStack, + PhysicalDisplayId::tryCast(displayId) + .and_then(display::getPhysicalDisplay(mPhysicalDisplays)) + .transform(&display::PhysicalDisplay::isInternal) + .value_or(false)}; } /* @@ -959,21 +984,16 @@ private: /* * Display identification */ - sp<IBinder> getPhysicalDisplayTokenLocked(PhysicalDisplayId displayId) const + sp<display::DisplayToken> getPhysicalDisplayTokenLocked(PhysicalDisplayId displayId) const REQUIRES(mStateLock) { - const sp<IBinder> nullToken; - return mPhysicalDisplayTokens.get(displayId).value_or(std::cref(nullToken)); + const sp<display::DisplayToken> nullToken; + return mPhysicalDisplays.get(displayId) + .transform([](const display::PhysicalDisplay& display) { return display.token(); }) + .value_or(std::cref(nullToken)); } std::optional<PhysicalDisplayId> getPhysicalDisplayIdLocked( - const sp<IBinder>& displayToken) const REQUIRES(mStateLock) { - for (const auto& [id, token] : mPhysicalDisplayTokens) { - if (token == displayToken) { - return id; - } - } - return {}; - } + const sp<display::DisplayToken>&) const REQUIRES(mStateLock); // Returns the first display connected at boot. // @@ -1063,7 +1083,7 @@ private: /* * Misc */ - std::vector<ui::ColorMode> getDisplayColorModes(const DisplayDevice&) REQUIRES(mStateLock); + std::vector<ui::ColorMode> getDisplayColorModes(PhysicalDisplayId) REQUIRES(mStateLock); static int calculateMaxAcquiredBufferCount(Fps refreshRate, std::chrono::nanoseconds presentLatency); @@ -1164,12 +1184,10 @@ private: // Displays are composited in `mDisplays` order. Internal displays are inserted at boot and // never removed, so take precedence over external and virtual displays. // - // The static capacities were chosen to exceed a typical number of physical/virtual displays. - // // May be read from any thread, but must only be written from the main thread. - ftl::SmallMap<wp<IBinder>, const sp<DisplayDevice>, 5> mDisplays GUARDED_BY(mStateLock); - ftl::SmallMap<PhysicalDisplayId, const sp<IBinder>, 3> mPhysicalDisplayTokens - GUARDED_BY(mStateLock); + display::DisplayMap<wp<IBinder>, const sp<DisplayDevice>> mDisplays GUARDED_BY(mStateLock); + + display::PhysicalDisplays mPhysicalDisplays GUARDED_BY(mStateLock); struct { DisplayIdGenerator<GpuVirtualDisplayId> gpu; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 77625b36ef..e546c2f8c9 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -309,16 +309,20 @@ struct BaseDisplayVariant { compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(), ceDisplayArgs); + constexpr auto kDisplayConnectionType = ui::DisplayConnectionType::Internal; + constexpr bool kIsPrimary = true; + test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay, - ui::DisplayConnectionType::Internal, HWC_DISPLAY, - true /* isPrimary */) + kDisplayConnectionType, HWC_DISPLAY, kIsPrimary) .setDisplaySurface(test->mDisplaySurface) .setNativeWindow(test->mNativeWindow) .setSecure(Derived::IS_SECURE) .setPowerMode(Derived::INIT_POWER_MODE) .inject(); Mock::VerifyAndClear(test->mNativeWindow.get()); - test->mDisplay->setLayerStack(LAYER_STACK); + + constexpr bool kIsInternal = kDisplayConnectionType == ui::DisplayConnectionType::Internal; + test->mDisplay->setLayerFilter({LAYER_STACK, kIsInternal}); } template <typename Case> diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp index 71f1a2bb35..73f654ba87 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp @@ -118,9 +118,7 @@ void DisplayTransactionCommitTest::verifyDisplayIsConnected(const sp<IBinder>& d ASSERT_TRUE(displayId); const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value; ASSERT_TRUE(hwcDisplayId); - expectedPhysical = {.id = *displayId, - .type = *connectionType, - .hwcDisplayId = *hwcDisplayId}; + expectedPhysical = {.id = *displayId, .hwcDisplayId = *hwcDisplayId}; } // The display should have been set up in the current display state @@ -145,10 +143,13 @@ void DisplayTransactionCommitTest::verifyPhysicalDisplayIsConnected() { const auto displayId = Case::Display::DISPLAY_ID::get(); ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); - const auto displayTokenOpt = mFlinger.mutablePhysicalDisplayTokens().get(displayId); - ASSERT_TRUE(displayTokenOpt); + const auto displayOpt = mFlinger.mutablePhysicalDisplays().get(displayId); + ASSERT_TRUE(displayOpt); - verifyDisplayIsConnected<Case>(displayTokenOpt->get()); + const auto& display = displayOpt->get(); + EXPECT_EQ(Case::Display::CONNECTION_TYPE::value, display.snapshot().connectionType()); + + verifyDisplayIsConnected<Case>(display.token()); } void DisplayTransactionCommitTest::verifyDisplayIsNotConnected(const sp<IBinder>& displayToken) { @@ -247,10 +248,10 @@ void DisplayTransactionCommitTest::processesHotplugDisconnectCommon() { // HWComposer should not have an entry for the display EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID)); - // SF should not have a display token. + // SF should not have a PhysicalDisplay. const auto displayId = Case::Display::DISPLAY_ID::get(); ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); - ASSERT_FALSE(mFlinger.mutablePhysicalDisplayTokens().contains(displayId)); + ASSERT_FALSE(mFlinger.mutablePhysicalDisplays().contains(displayId)); // The existing token should have been removed. verifyDisplayIsNotConnected(existing.token()); @@ -329,10 +330,10 @@ TEST_F(DisplayTransactionCommitTest, processesHotplugConnectThenDisconnectPrimar // HWComposer should not have an entry for the display EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID)); - // SF should not have a display token. + // SF should not have a PhysicalDisplay. const auto displayId = Case::Display::DISPLAY_ID::get(); ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); - ASSERT_FALSE(mFlinger.mutablePhysicalDisplayTokens().contains(displayId)); + ASSERT_FALSE(mFlinger.mutablePhysicalDisplays().contains(displayId)); }(), testing::KilledBySignal(SIGABRT), "Primary display cannot be disconnected."); } @@ -376,9 +377,9 @@ TEST_F(DisplayTransactionCommitTest, processesHotplugDisconnectThenConnectPrimar const auto displayId = Case::Display::DISPLAY_ID::get(); ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId)); - const auto displayTokenOpt = mFlinger.mutablePhysicalDisplayTokens().get(displayId); - ASSERT_TRUE(displayTokenOpt); - EXPECT_NE(existing.token(), displayTokenOpt->get()); + const auto displayOpt = mFlinger.mutablePhysicalDisplays().get(displayId); + ASSERT_TRUE(displayOpt); + EXPECT_NE(existing.token(), displayOpt->get().token()); // A new display should be connected in its place. verifyPhysicalDisplayIsConnected<Case>(); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp index 1756368216..9e54083615 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp @@ -253,14 +253,16 @@ struct DisplayPowerCase { using DispSync = DispSyncVariant; using Transition = TransitionVariant; - static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, PowerMode mode) { + static sp<DisplayDevice> injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, + PowerMode mode) { Display::injectHwcDisplayWithNoDefaultCapabilities(test); - auto display = Display::makeFakeExistingDisplayInjector(test); - display.inject(); - display.mutableDisplayDevice()->setPowerMode(mode); - if (display.mutableDisplayDevice()->isInternal()) { - test->mFlinger.mutableActiveDisplayToken() = - display.mutableDisplayDevice()->getDisplayToken(); + auto injector = Display::makeFakeExistingDisplayInjector(test); + const auto display = injector.inject(); + display->setPowerMode(mode); + if (injector.physicalDisplay() + .transform(&display::PhysicalDisplay::isInternal) + .value_or(false)) { + test->mFlinger.mutableActiveDisplayToken() = display->getDisplayToken(); } return display; @@ -353,8 +355,7 @@ void SetPowerModeInternalTest::transitionDisplayCommon() { // -------------------------------------------------------------------- // Invocation - mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), - Case::Transition::TARGET_POWER_MODE); + mFlinger.setPowerModeInternal(display, Case::Transition::TARGET_POWER_MODE); // -------------------------------------------------------------------- // Postconditions diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp index 6aeb3feb9a..ec2c2b4358 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp @@ -246,11 +246,14 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { .setDpiY(DEFAULT_DPI) .setGroup(0) .build(); + state.physical = {.id = *displayId, - .type = *connectionType, .hwcDisplayId = *hwcDisplayId, - .supportedModes = makeModes(activeMode), - .activeMode = std::move(activeMode)}; + .activeMode = activeMode}; + + mFlinger.mutablePhysicalDisplays().emplace_or_replace(*displayId, displayToken, *displayId, + *connectionType, + makeModes(activeMode), std::nullopt); } state.isSecure = static_cast<bool>(Case::Display::SECURE); @@ -264,7 +267,6 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { ASSERT_TRUE(device != nullptr); EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId()); - EXPECT_EQ(Case::Display::CONNECTION_TYPE::value, device->getConnectionType()); EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), device->isVirtual()); EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure()); EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary()); @@ -280,7 +282,6 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { device->receivesInput()); if constexpr (Case::Display::CONNECTION_TYPE::value) { - EXPECT_EQ(1, device->getSupportedModes().size()); EXPECT_NE(nullptr, device->getActiveMode()); EXPECT_EQ(Case::Display::HWC_ACTIVE_CONFIG_ID, device->getActiveMode()->getHwcId()); } diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 6c6c9aa684..a6b3f7c5df 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -503,6 +503,7 @@ public: */ const auto& displays() const { return mFlinger->mDisplays; } + const auto& physicalDisplays() const { return mFlinger->mPhysicalDisplays; } const auto& currentState() const { return mFlinger->mCurrentState; } const auto& drawingState() const { return mFlinger->mDrawingState; } const auto& transactionFlags() const { return mFlinger->mTransactionFlags; } @@ -515,12 +516,12 @@ public: auto& mutableCurrentState() { return mFlinger->mCurrentState; } auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; } auto& mutableDisplays() { return mFlinger->mDisplays; } + auto& mutablePhysicalDisplays() { return mFlinger->mPhysicalDisplays; } auto& mutableDrawingState() { return mFlinger->mDrawingState; } auto& mutableGeometryDirty() { return mFlinger->mGeometryDirty; } auto& mutableInterceptor() { return mFlinger->mInterceptor; } auto& mutableMainThreadId() { return mFlinger->mMainThreadId; } auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; } - auto& mutablePhysicalDisplayTokens() { return mFlinger->mPhysicalDisplayTokens; } auto& mutableTexturePool() { return mFlinger->mTexturePool; } auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; } auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; } @@ -725,14 +726,20 @@ public: : mFlinger(flinger), mCreationArgs(flinger.mFlinger, flinger.mFlinger->getHwComposer(), mDisplayToken, display), + mConnectionType(connectionType), mHwcDisplayId(hwcDisplayId) { - mCreationArgs.connectionType = connectionType; mCreationArgs.isPrimary = isPrimary; mCreationArgs.initialPowerMode = hal::PowerMode::ON; } sp<IBinder> token() const { return mDisplayToken; } + auto physicalDisplay() const { + return ftl::Optional(mCreationArgs.compositionDisplay->getDisplayId()) + .and_then(&PhysicalDisplayId::tryCast) + .and_then(display::getPhysicalDisplay(mFlinger.physicalDisplays())); + } + DisplayDeviceState& mutableDrawingDisplayState() { return mFlinger.mutableDrawingState().displays.editValueFor(mDisplayToken); } @@ -760,7 +767,7 @@ public: // the `configs` parameter in favor of an alternative setRefreshRateConfigs API. auto& setDisplayModes(DisplayModes modes, DisplayModeId activeModeId, std::shared_ptr<scheduler::RefreshRateConfigs> configs = nullptr) { - mCreationArgs.supportedModes = std::move(modes); + mDisplayModes = std::move(modes); mCreationArgs.activeModeId = activeModeId; mCreationArgs.refreshRateConfigs = std::move(configs); return *this; @@ -806,7 +813,7 @@ public: sp<DisplayDevice> inject() NO_THREAD_SAFETY_ANALYSIS { const auto displayId = mCreationArgs.compositionDisplay->getDisplayId(); - auto& modes = mCreationArgs.supportedModes; + auto& modes = mDisplayModes; auto& activeModeId = mCreationArgs.activeModeId; if (displayId && !mCreationArgs.refreshRateConfigs) { @@ -834,8 +841,13 @@ public: } } + sp<DisplayDevice> display = sp<DisplayDevice>::make(mCreationArgs); + mFlinger.mutableDisplays().emplace_or_replace(mDisplayToken, display); + DisplayDeviceState state; - if (const auto type = mCreationArgs.connectionType) { + state.isSecure = mCreationArgs.isSecure; + + if (mConnectionType) { LOG_ALWAYS_FATAL_IF(!displayId); const auto physicalId = PhysicalDisplayId::tryCast(*displayId); LOG_ALWAYS_FATAL_IF(!physicalId); @@ -845,29 +857,21 @@ public: LOG_ALWAYS_FATAL_IF(!activeMode); state.physical = {.id = *physicalId, - .type = *type, .hwcDisplayId = *mHwcDisplayId, - .deviceProductInfo = {}, - .supportedModes = modes, .activeMode = activeMode->get()}; - } - state.isSecure = mCreationArgs.isSecure; + const auto it = mFlinger.mutablePhysicalDisplays() + .emplace_or_replace(*physicalId, mDisplayToken, *physicalId, + *mConnectionType, std::move(modes), + std::nullopt) + .first; - sp<DisplayDevice> display = sp<DisplayDevice>::make(mCreationArgs); - if (!display->isVirtual()) { - display->setActiveMode(activeModeId); + display->setActiveMode(activeModeId, it->second.snapshot()); } - mFlinger.mutableDisplays().emplace_or_replace(mDisplayToken, display); mFlinger.mutableCurrentState().displays.add(mDisplayToken, state); mFlinger.mutableDrawingState().displays.add(mDisplayToken, state); - if (const auto& physical = state.physical) { - mFlinger.mutablePhysicalDisplayTokens().emplace_or_replace(physical->id, - mDisplayToken); - } - return display; } @@ -875,6 +879,8 @@ public: TestableSurfaceFlinger& mFlinger; sp<BBinder> mDisplayToken = sp<BBinder>::make(); DisplayDeviceCreationArgs mCreationArgs; + DisplayModes mDisplayModes; + const std::optional<ui::DisplayConnectionType> mConnectionType; const std::optional<hal::HWDisplayId> mHwcDisplayId; }; |