Loading services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +9 −5 Original line number Diff line number Diff line Loading @@ -111,11 +111,15 @@ public: MOCK_CONST_METHOD1(dump, void(std::string&)); MOCK_CONST_METHOD0(getComposer, android::Hwc2::Composer*()); MOCK_CONST_METHOD1(getHwcDisplayId, std::optional<hal::HWDisplayId>(int32_t)); MOCK_CONST_METHOD0(getInternalHwcDisplayId, std::optional<hal::HWDisplayId>()); MOCK_CONST_METHOD0(getExternalHwcDisplayId, std::optional<hal::HWDisplayId>()); MOCK_CONST_METHOD1(toPhysicalDisplayId, std::optional<PhysicalDisplayId>(hal::HWDisplayId)); MOCK_CONST_METHOD1(fromPhysicalDisplayId, std::optional<hal::HWDisplayId>(PhysicalDisplayId)); 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)); }; } // namespace mock Loading services/surfaceflinger/DisplayDevice.h +1 −1 Original line number Diff line number Diff line Loading @@ -273,7 +273,7 @@ private: std::atomic<nsecs_t> mLastHwVsync = 0; // TODO(b/74619554): Remove special cases for primary display. // TODO(b/182939859): Remove special cases for primary display. const bool mIsPrimary; uint32_t mFlags = 0; Loading services/surfaceflinger/DisplayHardware/HWComposer.cpp +16 −32 Original line number Diff line number Diff line Loading @@ -212,8 +212,6 @@ bool HWComposer::onVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp) { RETURN_IF_INVALID_DISPLAY(*displayId, false); auto& displayData = mDisplayData[*displayId]; LOG_FATAL_IF(displayData.isVirtual, "%s: Invalid operation on virtual display with ID %s", __FUNCTION__, to_string(*displayId).c_str()); { // There have been reports of HWCs that signal several vsync events Loading Loading @@ -271,7 +269,6 @@ bool HWComposer::allocateVirtualDisplay(HalVirtualDisplayId displayId, ui::Size display->setConnected(true); auto& displayData = mDisplayData[displayId]; displayData.hwcDisplay = std::move(display); displayData.isVirtual = true; return true; } Loading @@ -279,10 +276,8 @@ void HWComposer::allocatePhysicalDisplay(hal::HWDisplayId hwcDisplayId, PhysicalDisplayId displayId) { mPhysicalDisplayIdMap[hwcDisplayId] = displayId; if (!mInternalHwcDisplayId) { mInternalHwcDisplayId = hwcDisplayId; } else if (mInternalHwcDisplayId != hwcDisplayId && !mExternalHwcDisplayId) { mExternalHwcDisplayId = hwcDisplayId; if (!mPrimaryHwcDisplayId) { mPrimaryHwcDisplayId = hwcDisplayId; } auto& displayData = mDisplayData[displayId]; Loading Loading @@ -372,7 +367,7 @@ ui::DisplayConnectionType HWComposer::getDisplayConnectionType(PhysicalDisplayId ui::DisplayConnectionType type; const auto error = hwcDisplay->getConnectionType(&type); const auto FALLBACK_TYPE = hwcDisplay->getId() == mInternalHwcDisplayId const auto FALLBACK_TYPE = hwcDisplay->getId() == mPrimaryHwcDisplayId ? ui::DisplayConnectionType::Internal : ui::DisplayConnectionType::External; Loading Loading @@ -428,9 +423,6 @@ void HWComposer::setVsyncEnabled(PhysicalDisplayId displayId, hal::Vsync enabled RETURN_IF_INVALID_DISPLAY(displayId); auto& displayData = mDisplayData[displayId]; LOG_FATAL_IF(displayData.isVirtual, "%s: Invalid operation on virtual display with ID %s", __FUNCTION__, to_string(displayId).c_str()); // NOTE: we use our own internal lock here because we have to call // into the HWC with the lock held, and we want to make sure // that even if HWC blocks (which it shouldn't), it won't Loading Loading @@ -597,14 +589,11 @@ status_t HWComposer::presentAndGetReleaseFences( status_t HWComposer::setPowerMode(PhysicalDisplayId displayId, hal::PowerMode mode) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto& displayData = mDisplayData[displayId]; LOG_FATAL_IF(displayData.isVirtual, "%s: Invalid operation on virtual display with ID %s", __FUNCTION__, to_string(displayId).c_str()); if (mode == hal::PowerMode::OFF) { setVsyncEnabled(displayId, hal::Vsync::DISABLE); } const auto& displayData = mDisplayData[displayId]; auto& hwcDisplay = displayData.hwcDisplay; switch (mode) { case hal::PowerMode::OFF: Loading Loading @@ -677,13 +666,8 @@ void HWComposer::disconnectDisplay(HalDisplayId displayId) { RETURN_IF_INVALID_DISPLAY(displayId); auto& displayData = mDisplayData[displayId]; const auto hwcDisplayId = displayData.hwcDisplay->getId(); LOG_ALWAYS_FATAL_IF(hwcDisplayId == mPrimaryHwcDisplayId); // TODO(b/74619554): Select internal/external display from remaining displays. if (hwcDisplayId == mInternalHwcDisplayId) { mInternalHwcDisplayId.reset(); } else if (hwcDisplayId == mExternalHwcDisplayId) { mExternalHwcDisplayId.reset(); } mPhysicalDisplayIdMap.erase(hwcDisplayId); mDisplayData.erase(displayId); } Loading @@ -693,9 +677,6 @@ status_t HWComposer::setOutputBuffer(HalVirtualDisplayId displayId, const sp<Fen RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto& displayData = mDisplayData[displayId]; LOG_FATAL_IF(!displayData.isVirtual, "%s: Invalid operation on physical display with ID %s", __FUNCTION__, to_string(displayId).c_str()); auto error = displayData.hwcDisplay->setOutputBuffer(buffer, acquireFence); RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; Loading Loading @@ -853,8 +834,7 @@ std::optional<PhysicalDisplayId> HWComposer::toPhysicalDisplayId( std::optional<hal::HWDisplayId> HWComposer::fromPhysicalDisplayId( PhysicalDisplayId displayId) const { if (const auto it = mDisplayData.find(displayId); it != mDisplayData.end() && !it->second.isVirtual) { if (const auto it = mDisplayData.find(displayId); it != mDisplayData.end()) { return it->second.hwcDisplay->getId(); } return {}; Loading @@ -868,7 +848,8 @@ bool HWComposer::shouldIgnoreHotplugConnect(hal::HWDisplayId hwcDisplayId, return true; } if (!mHasMultiDisplaySupport && mInternalHwcDisplayId && mExternalHwcDisplayId) { // Legacy mode only supports IDs LEGACY_DISPLAY_TYPE_PRIMARY and LEGACY_DISPLAY_TYPE_EXTERNAL. if (!mHasMultiDisplaySupport && mPhysicalDisplayIdMap.size() == 2) { ALOGE("Ignoring connection of tertiary display %" PRIu64, hwcDisplayId); return true; } Loading Loading @@ -909,7 +890,7 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect( } info = [this, hwcDisplayId, &port, &data, hasDisplayIdentificationData] { const bool isPrimary = !mInternalHwcDisplayId; const bool isPrimary = !mPrimaryHwcDisplayId; if (mHasMultiDisplaySupport) { if (const auto info = parseDisplayIdentificationData(port, data)) { return *info; Loading @@ -922,8 +903,8 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect( } return DisplayIdentificationInfo{.id = PhysicalDisplayId::fromPort(port), .name = isPrimary ? "Internal display" : "External display", .name = isPrimary ? "Primary display" : "Secondary display", .deviceProductInfo = std::nullopt}; }(); } Loading @@ -936,9 +917,12 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect( std::optional<DisplayIdentificationInfo> HWComposer::onHotplugDisconnect( hal::HWDisplayId hwcDisplayId) { LOG_ALWAYS_FATAL_IF(hwcDisplayId == mPrimaryHwcDisplayId, "Primary display cannot be disconnected."); const auto displayId = toPhysicalDisplayId(hwcDisplayId); if (!displayId) { ALOGE("Ignoring disconnection of invalid HWC display %" PRIu64, hwcDisplayId); LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid HWC display"); return {}; } Loading @@ -947,7 +931,7 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugDisconnect( if (isConnected(*displayId)) { mDisplayData[*displayId].hwcDisplay->setConnected(false); } else { ALOGW("Attempted to disconnect unknown display %" PRIu64, hwcDisplayId); LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Already disconnected"); } // The cleanup of Disconnect is handled through HWComposer::disconnectDisplay // via SurfaceFlinger's onHotplugReceived callback handling Loading services/surfaceflinger/DisplayHardware/HWComposer.h +20 −18 Original line number Diff line number Diff line Loading @@ -14,8 +14,7 @@ * limitations under the License. */ #ifndef ANDROID_SF_HWCOMPOSER_H #define ANDROID_SF_HWCOMPOSER_H #pragma once #include <cstdint> #include <future> Loading Loading @@ -228,14 +227,18 @@ public: virtual const std::unordered_map<std::string, bool>& getSupportedLayerGenericMetadata() const = 0; // for debugging ---------------------------------------------------------- virtual void dump(std::string& out) const = 0; virtual Hwc2::Composer* getComposer() const = 0; // TODO(b/74619554): Remove special cases for internal/external display. virtual std::optional<hal::HWDisplayId> getInternalHwcDisplayId() const = 0; virtual std::optional<hal::HWDisplayId> getExternalHwcDisplayId() const = 0; // Returns the first display connected at boot. It cannot be disconnected, which implies an // internal connection type. Its connection via HWComposer::onHotplug, which in practice is // immediately after HWComposer construction, must occur before any call to this function. // // TODO(b/182939859): Remove special cases for primary display. virtual hal::HWDisplayId getPrimaryHwcDisplayId() const = 0; virtual PhysicalDisplayId getPrimaryDisplayId() const = 0; virtual bool isHeadless() const = 0; virtual std::optional<PhysicalDisplayId> toPhysicalDisplayId(hal::HWDisplayId) const = 0; virtual std::optional<hal::HWDisplayId> fromPhysicalDisplayId(PhysicalDisplayId) const = 0; Loading Loading @@ -366,14 +369,19 @@ public: Hwc2::Composer* getComposer() const override { return mComposer.get(); } // TODO(b/74619554): Remove special cases for internal/external display. std::optional<hal::HWDisplayId> getInternalHwcDisplayId() const override { return mInternalHwcDisplayId; hal::HWDisplayId getPrimaryHwcDisplayId() const override { LOG_ALWAYS_FATAL_IF(!mPrimaryHwcDisplayId, "Missing HWC primary display"); return *mPrimaryHwcDisplayId; } std::optional<hal::HWDisplayId> getExternalHwcDisplayId() const override { return mExternalHwcDisplayId; PhysicalDisplayId getPrimaryDisplayId() const override { const auto id = toPhysicalDisplayId(getPrimaryHwcDisplayId()); LOG_ALWAYS_FATAL_IF(!id, "Missing primary display"); return *id; } virtual bool isHeadless() const override { return !mPrimaryHwcDisplayId; } std::optional<PhysicalDisplayId> toPhysicalDisplayId(hal::HWDisplayId) const override; std::optional<hal::HWDisplayId> fromPhysicalDisplayId(PhysicalDisplayId) const override; Loading @@ -382,12 +390,9 @@ private: friend TestableSurfaceFlinger; struct DisplayData { bool isVirtual = false; std::unique_ptr<HWC2::Display> hwcDisplay; sp<Fence> lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences; buffer_handle_t outbufHandle = nullptr; sp<Fence> outbufAcquireFence = Fence::NO_FENCE; bool validateWasSkipped; hal::Error presentError; Loading Loading @@ -418,8 +423,7 @@ private: bool mRegisteredCallback = false; std::unordered_map<hal::HWDisplayId, PhysicalDisplayId> mPhysicalDisplayIdMap; std::optional<hal::HWDisplayId> mInternalHwcDisplayId; std::optional<hal::HWDisplayId> mExternalHwcDisplayId; std::optional<hal::HWDisplayId> mPrimaryHwcDisplayId; bool mHasMultiDisplaySupport = false; const size_t mMaxVirtualDisplayDimension; Loading @@ -428,5 +432,3 @@ private: } // namespace impl } // namespace android #endif // ANDROID_SF_HWCOMPOSER_H services/surfaceflinger/SurfaceFlinger.cpp +72 −75 Original line number Diff line number Diff line Loading @@ -618,17 +618,14 @@ void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) { } std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const { const auto internalDisplayId = getInternalDisplayIdLocked(); if (!internalDisplayId) { return {}; } std::vector<PhysicalDisplayId> displayIds; displayIds.reserve(mPhysicalDisplayTokens.size()); displayIds.push_back(*internalDisplayId); const auto internalDisplayId = getInternalDisplayIdLocked(); displayIds.push_back(internalDisplayId); for (const auto& [id, token] : mPhysicalDisplayTokens) { if (id != *internalDisplayId) { if (id != internalDisplayId) { displayIds.push_back(id); } } Loading Loading @@ -795,10 +792,10 @@ void SurfaceFlinger::init() { // Process any initial hotplug and resulting display changes. processDisplayHotplugEventsLocked(); const auto display = getDefaultDisplayDeviceLocked(); LOG_ALWAYS_FATAL_IF(!display, "Missing internal display after registering composer callback."); LOG_ALWAYS_FATAL_IF(!display, "Missing primary display after registering composer callback."); const auto displayId = display->getPhysicalId(); LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(displayId), "Internal display is disconnected."); "Primary display is disconnected."); // initialize our drawing state mDrawingState = mCurrentState; Loading Loading @@ -967,6 +964,11 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken, return NAME_NOT_FOUND; } const auto displayId = PhysicalDisplayId::tryCast(display->getId()); if (!displayId) { return INVALID_OPERATION; } info->activeDisplayModeId = static_cast<int32_t>(display->getActiveMode()->getId().value()); const auto& supportedModes = display->getSupportedModes(); Loading Loading @@ -1026,18 +1028,18 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken, } info->activeColorMode = display->getCompositionDisplay()->getState().colorMode; const auto displayId = display->getPhysicalId(); info->supportedColorModes = getDisplayColorModes(displayId); info->supportedColorModes = getDisplayColorModes(*display); info->hdrCapabilities = display->getHdrCapabilities(); info->autoLowLatencyModeSupported = getHwComposer().hasDisplayCapability(displayId, getHwComposer().hasDisplayCapability(*displayId, hal::DisplayCapability::AUTO_LOW_LATENCY_MODE); std::vector<hal::ContentType> types; getHwComposer().getSupportedContentTypes(displayId, &types); getHwComposer().getSupportedContentTypes(*displayId, &types); info->gameContentTypeSupported = std::any_of(types.begin(), types.end(), [](auto type) { return type == hal::ContentType::GAME; }); return NO_ERROR; } Loading Loading @@ -1261,15 +1263,15 @@ void SurfaceFlinger::disableExpensiveRendering() { }).wait(); } std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(PhysicalDisplayId displayId) { auto modes = getHwComposer().getColorModes(displayId); bool isInternalDisplay = displayId == getInternalDisplayIdLocked(); std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(const DisplayDevice& display) { auto modes = getHwComposer().getColorModes(display.getPhysicalId()); // If it's built-in display and the configuration claims it's not wide color capable, // 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 (isInternalDisplay && !hasWideColorDisplay) { if (display.getConnectionType() == ui::DisplayConnectionType::Internal && !hasWideColorDisplay) { const auto newEnd = std::remove_if(modes.begin(), modes.end(), isWideColorMode); modes.erase(newEnd, modes.end()); } Loading @@ -1293,35 +1295,40 @@ status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayTok } status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) { schedule([=]() MAIN_THREAD { const auto displayId = getPhysicalDisplayIdLocked(displayToken); if (!displayId) { ALOGE("Invalid display token %p", displayToken.get()); return; } const auto modes = getDisplayColorModes(*displayId); bool exists = std::find(std::begin(modes), std::end(modes), mode) != std::end(modes); if (mode < ColorMode::NATIVE || !exists) { ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p", decodeColorMode(mode).c_str(), mode, displayToken.get()); return; if (!displayToken) { return BAD_VALUE; } auto future = schedule([=]() MAIN_THREAD -> status_t { const auto display = getDisplayDeviceLocked(displayToken); if (!display) { ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p", decodeColorMode(mode).c_str(), mode, displayToken.get()); } else if (display->isVirtual()) { return NAME_NOT_FOUND; } if (display->isVirtual()) { ALOGW("Attempt to set active color mode %s (%d) for virtual display", decodeColorMode(mode).c_str(), mode); } else { display->getCompositionDisplay()->setColorProfile( compositionengine::Output::ColorProfile{mode, Dataspace::UNKNOWN, RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN}); return INVALID_OPERATION; } }).wait(); const auto modes = getDisplayColorModes(*display); const bool exists = std::find(modes.begin(), modes.end(), mode) != modes.end(); if (mode < ColorMode::NATIVE || !exists) { ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p", decodeColorMode(mode).c_str(), mode, displayToken.get()); return BAD_VALUE; } display->getCompositionDisplay()->setColorProfile( {mode, Dataspace::UNKNOWN, RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN}); return NO_ERROR; }); return future.get(); } void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) { Loading Loading @@ -1737,8 +1744,8 @@ void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate, void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) { ALOGI("%s(%" PRIu64 ", %s)", __func__, hwcDisplayId, connection == hal::Connection::CONNECTED ? "connected" : "disconnected"); const bool connected = connection == hal::Connection::CONNECTED; ALOGI("%s HAL display %" PRIu64, connected ? "Connecting" : "Disconnecting", hwcDisplayId); // Only lock if we're not on the main thread. This function is normally // called on a hwbinder thread, but for the primary display it's called on Loading Loading @@ -1930,13 +1937,9 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT } if (mRefreshRateOverlaySpinner) { if (Mutex::Autolock lock(mStateLock); const auto display = getDefaultDisplayDeviceLocked()) { if (display) { Mutex::Autolock lock(mStateLock); if (const auto display = getDefaultDisplayDeviceLocked()) { display->onInvalidate(); } else { ALOGW("%s: default display is null", __func__); } } } Loading Loading @@ -2840,7 +2843,7 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, setPowerModeInternal(display, hal::PowerMode::ON); // TODO(b/175678251) Call a listener instead. if (currentState.physical->hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) { if (currentState.physical->hwcDisplayId == getHwComposer().getPrimaryHwcDisplayId()) { updateInternalDisplayVsyncLocked(display); } } Loading Loading @@ -5691,12 +5694,10 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r // Inject a hotplug connected event for the primary display. This will deallocate and // reallocate the display state including framebuffers. case 1037: { std::optional<hal::HWDisplayId> hwcId; { Mutex::Autolock lock(mStateLock); hwcId = getHwComposer().getInternalHwcDisplayId(); } onComposerHalHotplug(*hwcId, hal::Connection::CONNECTED); const hal::HWDisplayId hwcId = (Mutex::Autolock(mStateLock), getHwComposer().getPrimaryHwcDisplayId()); onComposerHalHotplug(hwcId, hal::Connection::CONNECTED); return NO_ERROR; } // Modify the max number of display frames stored within FrameTimeline Loading Loading @@ -6778,33 +6779,29 @@ int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate, } status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const { const auto maxSupportedRefreshRate = [&] { const auto display = getDefaultDisplayDevice(); if (display) { return display->refreshRateConfigs().getSupportedRefreshRateRange().max; Fps maxRefreshRate(60.f); if (!getHwComposer().isHeadless()) { if (const auto display = getDefaultDisplayDevice()) { maxRefreshRate = display->refreshRateConfigs().getSupportedRefreshRateRange().max; } ALOGW("%s: default display is null", __func__); return Fps(60); }(); *buffers = getMaxAcquiredBufferCountForRefreshRate(maxSupportedRefreshRate); } *buffers = getMaxAcquiredBufferCountForRefreshRate(maxRefreshRate); return NO_ERROR; } int SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const { const auto refreshRate = [&] { const auto frameRateOverride = mScheduler->getFrameRateOverride(uid); if (frameRateOverride.has_value()) { return frameRateOverride.value(); } Fps refreshRate(60.f); const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); if (display) { return display->refreshRateConfigs().getCurrentRefreshRate().getFps(); if (const auto frameRateOverride = mScheduler->getFrameRateOverride(uid)) { refreshRate = *frameRateOverride; } else if (!getHwComposer().isHeadless()) { if (const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked())) { refreshRate = display->refreshRateConfigs().getCurrentRefreshRate().getFps(); } } ALOGW("%s: default display is null", __func__); return Fps(60); }(); return getMaxAcquiredBufferCountForRefreshRate(refreshRate); } Loading Loading
services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +9 −5 Original line number Diff line number Diff line Loading @@ -111,11 +111,15 @@ public: MOCK_CONST_METHOD1(dump, void(std::string&)); MOCK_CONST_METHOD0(getComposer, android::Hwc2::Composer*()); MOCK_CONST_METHOD1(getHwcDisplayId, std::optional<hal::HWDisplayId>(int32_t)); MOCK_CONST_METHOD0(getInternalHwcDisplayId, std::optional<hal::HWDisplayId>()); MOCK_CONST_METHOD0(getExternalHwcDisplayId, std::optional<hal::HWDisplayId>()); MOCK_CONST_METHOD1(toPhysicalDisplayId, std::optional<PhysicalDisplayId>(hal::HWDisplayId)); MOCK_CONST_METHOD1(fromPhysicalDisplayId, std::optional<hal::HWDisplayId>(PhysicalDisplayId)); 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)); }; } // namespace mock Loading
services/surfaceflinger/DisplayDevice.h +1 −1 Original line number Diff line number Diff line Loading @@ -273,7 +273,7 @@ private: std::atomic<nsecs_t> mLastHwVsync = 0; // TODO(b/74619554): Remove special cases for primary display. // TODO(b/182939859): Remove special cases for primary display. const bool mIsPrimary; uint32_t mFlags = 0; Loading
services/surfaceflinger/DisplayHardware/HWComposer.cpp +16 −32 Original line number Diff line number Diff line Loading @@ -212,8 +212,6 @@ bool HWComposer::onVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp) { RETURN_IF_INVALID_DISPLAY(*displayId, false); auto& displayData = mDisplayData[*displayId]; LOG_FATAL_IF(displayData.isVirtual, "%s: Invalid operation on virtual display with ID %s", __FUNCTION__, to_string(*displayId).c_str()); { // There have been reports of HWCs that signal several vsync events Loading Loading @@ -271,7 +269,6 @@ bool HWComposer::allocateVirtualDisplay(HalVirtualDisplayId displayId, ui::Size display->setConnected(true); auto& displayData = mDisplayData[displayId]; displayData.hwcDisplay = std::move(display); displayData.isVirtual = true; return true; } Loading @@ -279,10 +276,8 @@ void HWComposer::allocatePhysicalDisplay(hal::HWDisplayId hwcDisplayId, PhysicalDisplayId displayId) { mPhysicalDisplayIdMap[hwcDisplayId] = displayId; if (!mInternalHwcDisplayId) { mInternalHwcDisplayId = hwcDisplayId; } else if (mInternalHwcDisplayId != hwcDisplayId && !mExternalHwcDisplayId) { mExternalHwcDisplayId = hwcDisplayId; if (!mPrimaryHwcDisplayId) { mPrimaryHwcDisplayId = hwcDisplayId; } auto& displayData = mDisplayData[displayId]; Loading Loading @@ -372,7 +367,7 @@ ui::DisplayConnectionType HWComposer::getDisplayConnectionType(PhysicalDisplayId ui::DisplayConnectionType type; const auto error = hwcDisplay->getConnectionType(&type); const auto FALLBACK_TYPE = hwcDisplay->getId() == mInternalHwcDisplayId const auto FALLBACK_TYPE = hwcDisplay->getId() == mPrimaryHwcDisplayId ? ui::DisplayConnectionType::Internal : ui::DisplayConnectionType::External; Loading Loading @@ -428,9 +423,6 @@ void HWComposer::setVsyncEnabled(PhysicalDisplayId displayId, hal::Vsync enabled RETURN_IF_INVALID_DISPLAY(displayId); auto& displayData = mDisplayData[displayId]; LOG_FATAL_IF(displayData.isVirtual, "%s: Invalid operation on virtual display with ID %s", __FUNCTION__, to_string(displayId).c_str()); // NOTE: we use our own internal lock here because we have to call // into the HWC with the lock held, and we want to make sure // that even if HWC blocks (which it shouldn't), it won't Loading Loading @@ -597,14 +589,11 @@ status_t HWComposer::presentAndGetReleaseFences( status_t HWComposer::setPowerMode(PhysicalDisplayId displayId, hal::PowerMode mode) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto& displayData = mDisplayData[displayId]; LOG_FATAL_IF(displayData.isVirtual, "%s: Invalid operation on virtual display with ID %s", __FUNCTION__, to_string(displayId).c_str()); if (mode == hal::PowerMode::OFF) { setVsyncEnabled(displayId, hal::Vsync::DISABLE); } const auto& displayData = mDisplayData[displayId]; auto& hwcDisplay = displayData.hwcDisplay; switch (mode) { case hal::PowerMode::OFF: Loading Loading @@ -677,13 +666,8 @@ void HWComposer::disconnectDisplay(HalDisplayId displayId) { RETURN_IF_INVALID_DISPLAY(displayId); auto& displayData = mDisplayData[displayId]; const auto hwcDisplayId = displayData.hwcDisplay->getId(); LOG_ALWAYS_FATAL_IF(hwcDisplayId == mPrimaryHwcDisplayId); // TODO(b/74619554): Select internal/external display from remaining displays. if (hwcDisplayId == mInternalHwcDisplayId) { mInternalHwcDisplayId.reset(); } else if (hwcDisplayId == mExternalHwcDisplayId) { mExternalHwcDisplayId.reset(); } mPhysicalDisplayIdMap.erase(hwcDisplayId); mDisplayData.erase(displayId); } Loading @@ -693,9 +677,6 @@ status_t HWComposer::setOutputBuffer(HalVirtualDisplayId displayId, const sp<Fen RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto& displayData = mDisplayData[displayId]; LOG_FATAL_IF(!displayData.isVirtual, "%s: Invalid operation on physical display with ID %s", __FUNCTION__, to_string(displayId).c_str()); auto error = displayData.hwcDisplay->setOutputBuffer(buffer, acquireFence); RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; Loading Loading @@ -853,8 +834,7 @@ std::optional<PhysicalDisplayId> HWComposer::toPhysicalDisplayId( std::optional<hal::HWDisplayId> HWComposer::fromPhysicalDisplayId( PhysicalDisplayId displayId) const { if (const auto it = mDisplayData.find(displayId); it != mDisplayData.end() && !it->second.isVirtual) { if (const auto it = mDisplayData.find(displayId); it != mDisplayData.end()) { return it->second.hwcDisplay->getId(); } return {}; Loading @@ -868,7 +848,8 @@ bool HWComposer::shouldIgnoreHotplugConnect(hal::HWDisplayId hwcDisplayId, return true; } if (!mHasMultiDisplaySupport && mInternalHwcDisplayId && mExternalHwcDisplayId) { // Legacy mode only supports IDs LEGACY_DISPLAY_TYPE_PRIMARY and LEGACY_DISPLAY_TYPE_EXTERNAL. if (!mHasMultiDisplaySupport && mPhysicalDisplayIdMap.size() == 2) { ALOGE("Ignoring connection of tertiary display %" PRIu64, hwcDisplayId); return true; } Loading Loading @@ -909,7 +890,7 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect( } info = [this, hwcDisplayId, &port, &data, hasDisplayIdentificationData] { const bool isPrimary = !mInternalHwcDisplayId; const bool isPrimary = !mPrimaryHwcDisplayId; if (mHasMultiDisplaySupport) { if (const auto info = parseDisplayIdentificationData(port, data)) { return *info; Loading @@ -922,8 +903,8 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect( } return DisplayIdentificationInfo{.id = PhysicalDisplayId::fromPort(port), .name = isPrimary ? "Internal display" : "External display", .name = isPrimary ? "Primary display" : "Secondary display", .deviceProductInfo = std::nullopt}; }(); } Loading @@ -936,9 +917,12 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect( std::optional<DisplayIdentificationInfo> HWComposer::onHotplugDisconnect( hal::HWDisplayId hwcDisplayId) { LOG_ALWAYS_FATAL_IF(hwcDisplayId == mPrimaryHwcDisplayId, "Primary display cannot be disconnected."); const auto displayId = toPhysicalDisplayId(hwcDisplayId); if (!displayId) { ALOGE("Ignoring disconnection of invalid HWC display %" PRIu64, hwcDisplayId); LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid HWC display"); return {}; } Loading @@ -947,7 +931,7 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugDisconnect( if (isConnected(*displayId)) { mDisplayData[*displayId].hwcDisplay->setConnected(false); } else { ALOGW("Attempted to disconnect unknown display %" PRIu64, hwcDisplayId); LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Already disconnected"); } // The cleanup of Disconnect is handled through HWComposer::disconnectDisplay // via SurfaceFlinger's onHotplugReceived callback handling Loading
services/surfaceflinger/DisplayHardware/HWComposer.h +20 −18 Original line number Diff line number Diff line Loading @@ -14,8 +14,7 @@ * limitations under the License. */ #ifndef ANDROID_SF_HWCOMPOSER_H #define ANDROID_SF_HWCOMPOSER_H #pragma once #include <cstdint> #include <future> Loading Loading @@ -228,14 +227,18 @@ public: virtual const std::unordered_map<std::string, bool>& getSupportedLayerGenericMetadata() const = 0; // for debugging ---------------------------------------------------------- virtual void dump(std::string& out) const = 0; virtual Hwc2::Composer* getComposer() const = 0; // TODO(b/74619554): Remove special cases for internal/external display. virtual std::optional<hal::HWDisplayId> getInternalHwcDisplayId() const = 0; virtual std::optional<hal::HWDisplayId> getExternalHwcDisplayId() const = 0; // Returns the first display connected at boot. It cannot be disconnected, which implies an // internal connection type. Its connection via HWComposer::onHotplug, which in practice is // immediately after HWComposer construction, must occur before any call to this function. // // TODO(b/182939859): Remove special cases for primary display. virtual hal::HWDisplayId getPrimaryHwcDisplayId() const = 0; virtual PhysicalDisplayId getPrimaryDisplayId() const = 0; virtual bool isHeadless() const = 0; virtual std::optional<PhysicalDisplayId> toPhysicalDisplayId(hal::HWDisplayId) const = 0; virtual std::optional<hal::HWDisplayId> fromPhysicalDisplayId(PhysicalDisplayId) const = 0; Loading Loading @@ -366,14 +369,19 @@ public: Hwc2::Composer* getComposer() const override { return mComposer.get(); } // TODO(b/74619554): Remove special cases for internal/external display. std::optional<hal::HWDisplayId> getInternalHwcDisplayId() const override { return mInternalHwcDisplayId; hal::HWDisplayId getPrimaryHwcDisplayId() const override { LOG_ALWAYS_FATAL_IF(!mPrimaryHwcDisplayId, "Missing HWC primary display"); return *mPrimaryHwcDisplayId; } std::optional<hal::HWDisplayId> getExternalHwcDisplayId() const override { return mExternalHwcDisplayId; PhysicalDisplayId getPrimaryDisplayId() const override { const auto id = toPhysicalDisplayId(getPrimaryHwcDisplayId()); LOG_ALWAYS_FATAL_IF(!id, "Missing primary display"); return *id; } virtual bool isHeadless() const override { return !mPrimaryHwcDisplayId; } std::optional<PhysicalDisplayId> toPhysicalDisplayId(hal::HWDisplayId) const override; std::optional<hal::HWDisplayId> fromPhysicalDisplayId(PhysicalDisplayId) const override; Loading @@ -382,12 +390,9 @@ private: friend TestableSurfaceFlinger; struct DisplayData { bool isVirtual = false; std::unique_ptr<HWC2::Display> hwcDisplay; sp<Fence> lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences; buffer_handle_t outbufHandle = nullptr; sp<Fence> outbufAcquireFence = Fence::NO_FENCE; bool validateWasSkipped; hal::Error presentError; Loading Loading @@ -418,8 +423,7 @@ private: bool mRegisteredCallback = false; std::unordered_map<hal::HWDisplayId, PhysicalDisplayId> mPhysicalDisplayIdMap; std::optional<hal::HWDisplayId> mInternalHwcDisplayId; std::optional<hal::HWDisplayId> mExternalHwcDisplayId; std::optional<hal::HWDisplayId> mPrimaryHwcDisplayId; bool mHasMultiDisplaySupport = false; const size_t mMaxVirtualDisplayDimension; Loading @@ -428,5 +432,3 @@ private: } // namespace impl } // namespace android #endif // ANDROID_SF_HWCOMPOSER_H
services/surfaceflinger/SurfaceFlinger.cpp +72 −75 Original line number Diff line number Diff line Loading @@ -618,17 +618,14 @@ void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) { } std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIdsLocked() const { const auto internalDisplayId = getInternalDisplayIdLocked(); if (!internalDisplayId) { return {}; } std::vector<PhysicalDisplayId> displayIds; displayIds.reserve(mPhysicalDisplayTokens.size()); displayIds.push_back(*internalDisplayId); const auto internalDisplayId = getInternalDisplayIdLocked(); displayIds.push_back(internalDisplayId); for (const auto& [id, token] : mPhysicalDisplayTokens) { if (id != *internalDisplayId) { if (id != internalDisplayId) { displayIds.push_back(id); } } Loading Loading @@ -795,10 +792,10 @@ void SurfaceFlinger::init() { // Process any initial hotplug and resulting display changes. processDisplayHotplugEventsLocked(); const auto display = getDefaultDisplayDeviceLocked(); LOG_ALWAYS_FATAL_IF(!display, "Missing internal display after registering composer callback."); LOG_ALWAYS_FATAL_IF(!display, "Missing primary display after registering composer callback."); const auto displayId = display->getPhysicalId(); LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(displayId), "Internal display is disconnected."); "Primary display is disconnected."); // initialize our drawing state mDrawingState = mCurrentState; Loading Loading @@ -967,6 +964,11 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken, return NAME_NOT_FOUND; } const auto displayId = PhysicalDisplayId::tryCast(display->getId()); if (!displayId) { return INVALID_OPERATION; } info->activeDisplayModeId = static_cast<int32_t>(display->getActiveMode()->getId().value()); const auto& supportedModes = display->getSupportedModes(); Loading Loading @@ -1026,18 +1028,18 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken, } info->activeColorMode = display->getCompositionDisplay()->getState().colorMode; const auto displayId = display->getPhysicalId(); info->supportedColorModes = getDisplayColorModes(displayId); info->supportedColorModes = getDisplayColorModes(*display); info->hdrCapabilities = display->getHdrCapabilities(); info->autoLowLatencyModeSupported = getHwComposer().hasDisplayCapability(displayId, getHwComposer().hasDisplayCapability(*displayId, hal::DisplayCapability::AUTO_LOW_LATENCY_MODE); std::vector<hal::ContentType> types; getHwComposer().getSupportedContentTypes(displayId, &types); getHwComposer().getSupportedContentTypes(*displayId, &types); info->gameContentTypeSupported = std::any_of(types.begin(), types.end(), [](auto type) { return type == hal::ContentType::GAME; }); return NO_ERROR; } Loading Loading @@ -1261,15 +1263,15 @@ void SurfaceFlinger::disableExpensiveRendering() { }).wait(); } std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(PhysicalDisplayId displayId) { auto modes = getHwComposer().getColorModes(displayId); bool isInternalDisplay = displayId == getInternalDisplayIdLocked(); std::vector<ColorMode> SurfaceFlinger::getDisplayColorModes(const DisplayDevice& display) { auto modes = getHwComposer().getColorModes(display.getPhysicalId()); // If it's built-in display and the configuration claims it's not wide color capable, // 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 (isInternalDisplay && !hasWideColorDisplay) { if (display.getConnectionType() == ui::DisplayConnectionType::Internal && !hasWideColorDisplay) { const auto newEnd = std::remove_if(modes.begin(), modes.end(), isWideColorMode); modes.erase(newEnd, modes.end()); } Loading @@ -1293,35 +1295,40 @@ status_t SurfaceFlinger::getDisplayNativePrimaries(const sp<IBinder>& displayTok } status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) { schedule([=]() MAIN_THREAD { const auto displayId = getPhysicalDisplayIdLocked(displayToken); if (!displayId) { ALOGE("Invalid display token %p", displayToken.get()); return; } const auto modes = getDisplayColorModes(*displayId); bool exists = std::find(std::begin(modes), std::end(modes), mode) != std::end(modes); if (mode < ColorMode::NATIVE || !exists) { ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p", decodeColorMode(mode).c_str(), mode, displayToken.get()); return; if (!displayToken) { return BAD_VALUE; } auto future = schedule([=]() MAIN_THREAD -> status_t { const auto display = getDisplayDeviceLocked(displayToken); if (!display) { ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p", decodeColorMode(mode).c_str(), mode, displayToken.get()); } else if (display->isVirtual()) { return NAME_NOT_FOUND; } if (display->isVirtual()) { ALOGW("Attempt to set active color mode %s (%d) for virtual display", decodeColorMode(mode).c_str(), mode); } else { display->getCompositionDisplay()->setColorProfile( compositionengine::Output::ColorProfile{mode, Dataspace::UNKNOWN, RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN}); return INVALID_OPERATION; } }).wait(); const auto modes = getDisplayColorModes(*display); const bool exists = std::find(modes.begin(), modes.end(), mode) != modes.end(); if (mode < ColorMode::NATIVE || !exists) { ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p", decodeColorMode(mode).c_str(), mode, displayToken.get()); return BAD_VALUE; } display->getCompositionDisplay()->setColorProfile( {mode, Dataspace::UNKNOWN, RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN}); return NO_ERROR; }); return future.get(); } void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) { Loading Loading @@ -1737,8 +1744,8 @@ void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate, void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) { ALOGI("%s(%" PRIu64 ", %s)", __func__, hwcDisplayId, connection == hal::Connection::CONNECTED ? "connected" : "disconnected"); const bool connected = connection == hal::Connection::CONNECTED; ALOGI("%s HAL display %" PRIu64, connected ? "Connecting" : "Disconnecting", hwcDisplayId); // Only lock if we're not on the main thread. This function is normally // called on a hwbinder thread, but for the primary display it's called on Loading Loading @@ -1930,13 +1937,9 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT } if (mRefreshRateOverlaySpinner) { if (Mutex::Autolock lock(mStateLock); const auto display = getDefaultDisplayDeviceLocked()) { if (display) { Mutex::Autolock lock(mStateLock); if (const auto display = getDefaultDisplayDeviceLocked()) { display->onInvalidate(); } else { ALOGW("%s: default display is null", __func__); } } } Loading Loading @@ -2840,7 +2843,7 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, setPowerModeInternal(display, hal::PowerMode::ON); // TODO(b/175678251) Call a listener instead. if (currentState.physical->hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) { if (currentState.physical->hwcDisplayId == getHwComposer().getPrimaryHwcDisplayId()) { updateInternalDisplayVsyncLocked(display); } } Loading Loading @@ -5691,12 +5694,10 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r // Inject a hotplug connected event for the primary display. This will deallocate and // reallocate the display state including framebuffers. case 1037: { std::optional<hal::HWDisplayId> hwcId; { Mutex::Autolock lock(mStateLock); hwcId = getHwComposer().getInternalHwcDisplayId(); } onComposerHalHotplug(*hwcId, hal::Connection::CONNECTED); const hal::HWDisplayId hwcId = (Mutex::Autolock(mStateLock), getHwComposer().getPrimaryHwcDisplayId()); onComposerHalHotplug(hwcId, hal::Connection::CONNECTED); return NO_ERROR; } // Modify the max number of display frames stored within FrameTimeline Loading Loading @@ -6778,33 +6779,29 @@ int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate, } status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const { const auto maxSupportedRefreshRate = [&] { const auto display = getDefaultDisplayDevice(); if (display) { return display->refreshRateConfigs().getSupportedRefreshRateRange().max; Fps maxRefreshRate(60.f); if (!getHwComposer().isHeadless()) { if (const auto display = getDefaultDisplayDevice()) { maxRefreshRate = display->refreshRateConfigs().getSupportedRefreshRateRange().max; } ALOGW("%s: default display is null", __func__); return Fps(60); }(); *buffers = getMaxAcquiredBufferCountForRefreshRate(maxSupportedRefreshRate); } *buffers = getMaxAcquiredBufferCountForRefreshRate(maxRefreshRate); return NO_ERROR; } int SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const { const auto refreshRate = [&] { const auto frameRateOverride = mScheduler->getFrameRateOverride(uid); if (frameRateOverride.has_value()) { return frameRateOverride.value(); } Fps refreshRate(60.f); const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()); if (display) { return display->refreshRateConfigs().getCurrentRefreshRate().getFps(); if (const auto frameRateOverride = mScheduler->getFrameRateOverride(uid)) { refreshRate = *frameRateOverride; } else if (!getHwComposer().isHeadless()) { if (const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked())) { refreshRate = display->refreshRateConfigs().getCurrentRefreshRate().getFps(); } } ALOGW("%s: default display is null", __func__); return Fps(60); }(); return getMaxAcquiredBufferCountForRefreshRate(refreshRate); } Loading