/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" // #define LOG_NDEBUG 0 #undef LOG_TAG #define LOG_TAG "HWComposer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "HWComposer.h" #include #include #include #include #include #include #include #include #include #include "../Layer.h" // needed only for debugging #include "../SurfaceFlingerProperties.h" #include "ComposerHal.h" #include "HWC2.h" #define LOG_HWC_DISPLAY_ERROR(hwcDisplayId, msg) \ ALOGE("%s failed for HWC display %" PRIu64 ": %s", __FUNCTION__, hwcDisplayId, msg) #define LOG_DISPLAY_ERROR(displayId, msg) \ ALOGE("%s failed for display %s: %s", __FUNCTION__, to_string(displayId).c_str(), msg) #define LOG_HWC_ERROR(what, error, displayId) \ ALOGE("%s: %s failed for display %s: %s (%d)", __FUNCTION__, what, \ to_string(displayId).c_str(), to_string(error).c_str(), static_cast(error)) #define RETURN_IF_INVALID_DISPLAY(displayId, ...) \ do { \ if (mDisplayData.count(displayId) == 0) { \ LOG_DISPLAY_ERROR(displayId, "Invalid display"); \ return __VA_ARGS__; \ } \ } while (false) #define RETURN_IF_HWC_ERROR_FOR(what, error, displayId, ...) \ do { \ if (error != hal::Error::NONE) { \ LOG_HWC_ERROR(what, error, displayId); \ return __VA_ARGS__; \ } \ } while (false) #define RETURN_IF_HWC_ERROR(error, displayId, ...) \ RETURN_IF_HWC_ERROR_FOR(__FUNCTION__, error, displayId, __VA_ARGS__) using aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::DisplayCapability; namespace hal = android::hardware::graphics::composer::hal; namespace android { HWComposer::~HWComposer() = default; namespace impl { HWComposer::HWComposer(std::unique_ptr composer) : mComposer(std::move(composer)), mMaxVirtualDisplayDimension(static_cast(sysprop::max_virtual_display_dimension(0))), mUpdateDeviceProductInfoOnHotplugReconnect( sysprop::update_device_product_info_on_hotplug_reconnect(false)) {} HWComposer::HWComposer(const std::string& composerServiceName) : HWComposer(Hwc2::Composer::create(composerServiceName)) {} HWComposer::~HWComposer() { mDisplayData.clear(); } void HWComposer::setCallback(HWC2::ComposerCallback& callback) { loadCapabilities(); loadLayerMetadataSupport(); if (mRegisteredCallback) { ALOGW("Callback already registered. Ignored extra registration attempt."); return; } mRegisteredCallback = true; mComposer->registerCallback(callback); } bool HWComposer::getDisplayIdentificationData(hal::HWDisplayId hwcDisplayId, uint8_t* outPort, DisplayIdentificationData* outData) const { const auto error = static_cast( mComposer->getDisplayIdentificationData(hwcDisplayId, outPort, outData)); if (error != hal::Error::NONE) { if (error != hal::Error::UNSUPPORTED) { LOG_HWC_DISPLAY_ERROR(hwcDisplayId, to_string(error).c_str()); } return false; } return true; } bool HWComposer::hasCapability(Capability capability) const { return mCapabilities.count(capability) > 0; } bool HWComposer::hasDisplayCapability(HalDisplayId displayId, DisplayCapability capability) const { RETURN_IF_INVALID_DISPLAY(displayId, false); return mDisplayData.at(displayId).hwcDisplay->hasCapability(capability); } std::optional HWComposer::onHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) { switch (connection) { case hal::Connection::CONNECTED: return onHotplugConnect(hwcDisplayId); case hal::Connection::DISCONNECTED: return onHotplugDisconnect(hwcDisplayId); case hal::Connection::INVALID: return {}; } } bool HWComposer::updatesDeviceProductInfoOnHotplugReconnect() const { return mUpdateDeviceProductInfoOnHotplugReconnect; } bool HWComposer::onVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp) { const auto displayId = toPhysicalDisplayId(hwcDisplayId); if (!displayId) { LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid HWC display"); return false; } RETURN_IF_INVALID_DISPLAY(*displayId, false); auto& displayData = mDisplayData[*displayId]; { // There have been reports of HWCs that signal several vsync events // with the same timestamp when turning the display off and on. This // is a bug in the HWC implementation, but filter the extra events // out here so they don't cause havoc downstream. if (timestamp == displayData.lastHwVsync) { ALOGW("Ignoring duplicate VSYNC event from HWC for display %s (t=%" PRId64 ")", to_string(*displayId).c_str(), timestamp); return false; } displayData.lastHwVsync = timestamp; } const auto tag = "HW_VSYNC_" + to_string(*displayId); ATRACE_INT(tag.c_str(), displayData.vsyncTraceToggle); displayData.vsyncTraceToggle = !displayData.vsyncTraceToggle; return true; } size_t HWComposer::getMaxVirtualDisplayCount() const { return mComposer->getMaxVirtualDisplayCount(); } size_t HWComposer::getMaxVirtualDisplayDimension() const { return mMaxVirtualDisplayDimension; } bool HWComposer::allocateVirtualDisplay(HalVirtualDisplayId displayId, ui::Size resolution, ui::PixelFormat* format) { if (!resolution.isValid()) { ALOGE("%s: Invalid resolution %dx%d", __func__, resolution.width, resolution.height); return false; } const uint32_t width = static_cast(resolution.width); const uint32_t height = static_cast(resolution.height); if (mMaxVirtualDisplayDimension > 0 && (width > mMaxVirtualDisplayDimension || height > mMaxVirtualDisplayDimension)) { ALOGE("%s: Resolution %ux%u exceeds maximum dimension %zu", __func__, width, height, mMaxVirtualDisplayDimension); return false; } hal::HWDisplayId hwcDisplayId; const auto error = static_cast( mComposer->createVirtualDisplay(width, height, format, &hwcDisplayId)); RETURN_IF_HWC_ERROR_FOR("createVirtualDisplay", error, displayId, false); auto display = std::make_unique(*mComposer.get(), mCapabilities, hwcDisplayId, hal::DisplayType::VIRTUAL); display->setConnected(true); auto& displayData = mDisplayData[displayId]; displayData.hwcDisplay = std::move(display); return true; } void HWComposer::allocatePhysicalDisplay(hal::HWDisplayId hwcDisplayId, PhysicalDisplayId displayId) { mPhysicalDisplayIdMap[hwcDisplayId] = displayId; if (!mPrimaryHwcDisplayId) { mPrimaryHwcDisplayId = hwcDisplayId; } auto& displayData = mDisplayData[displayId]; auto newDisplay = std::make_unique(*mComposer.get(), mCapabilities, hwcDisplayId, hal::DisplayType::PHYSICAL); newDisplay->setConnected(true); displayData.hwcDisplay = std::move(newDisplay); } int32_t HWComposer::getAttribute(hal::HWDisplayId hwcDisplayId, hal::HWConfigId configId, hal::Attribute attribute) const { int32_t value = 0; auto error = static_cast( mComposer->getDisplayAttribute(hwcDisplayId, configId, attribute, &value)); RETURN_IF_HWC_ERROR_FOR("getDisplayAttribute", error, *toPhysicalDisplayId(hwcDisplayId), -1); return value; } std::shared_ptr HWComposer::createLayer(HalDisplayId displayId) { RETURN_IF_INVALID_DISPLAY(displayId, nullptr); auto expected = mDisplayData[displayId].hwcDisplay->createLayer(); if (!expected.has_value()) { auto error = std::move(expected).error(); RETURN_IF_HWC_ERROR(error, displayId, nullptr); } return std::move(expected).value(); } bool HWComposer::isConnected(PhysicalDisplayId displayId) const { if (mDisplayData.count(displayId)) { return mDisplayData.at(displayId).hwcDisplay->isConnected(); } return false; } std::vector HWComposer::getModes(PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, {}); const auto hwcDisplayId = mDisplayData.at(displayId).hwcDisplay->getId(); std::vector configIds; auto error = static_cast(mComposer->getDisplayConfigs(hwcDisplayId, &configIds)); RETURN_IF_HWC_ERROR_FOR("getDisplayConfigs", error, *toPhysicalDisplayId(hwcDisplayId), {}); std::vector modes; modes.reserve(configIds.size()); for (auto configId : configIds) { modes.push_back(HWCDisplayMode{ .hwcId = configId, .width = getAttribute(hwcDisplayId, configId, hal::Attribute::WIDTH), .height = getAttribute(hwcDisplayId, configId, hal::Attribute::HEIGHT), .vsyncPeriod = getAttribute(hwcDisplayId, configId, hal::Attribute::VSYNC_PERIOD), .dpiX = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X), .dpiY = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y), .configGroup = getAttribute(hwcDisplayId, configId, hal::Attribute::CONFIG_GROUP), }); } return modes; } std::optional HWComposer::getActiveMode(PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, std::nullopt); const auto hwcId = *fromPhysicalDisplayId(displayId); ALOGV("[%" PRIu64 "] getActiveMode", hwcId); hal::HWConfigId configId; auto error = static_cast(mComposer->getActiveConfig(hwcId, &configId)); if (error == hal::Error::BAD_CONFIG) { LOG_DISPLAY_ERROR(displayId, "No active mode"); return std::nullopt; } return configId; } // Composer 2.4 ui::DisplayConnectionType HWComposer::getDisplayConnectionType(PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, ui::DisplayConnectionType::Internal); const auto& hwcDisplay = mDisplayData.at(displayId).hwcDisplay; ui::DisplayConnectionType type; const auto error = hwcDisplay->getConnectionType(&type); const auto FALLBACK_TYPE = hwcDisplay->getId() == mPrimaryHwcDisplayId ? ui::DisplayConnectionType::Internal : ui::DisplayConnectionType::External; RETURN_IF_HWC_ERROR(error, displayId, FALLBACK_TYPE); return type; } bool HWComposer::isVsyncPeriodSwitchSupported(PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, false); return mDisplayData.at(displayId).hwcDisplay->isVsyncPeriodSwitchSupported(); } status_t HWComposer::getDisplayVsyncPeriod(PhysicalDisplayId displayId, nsecs_t* outVsyncPeriod) const { RETURN_IF_INVALID_DISPLAY(displayId, 0); if (!isVsyncPeriodSwitchSupported(displayId)) { return INVALID_OPERATION; } const auto hwcId = *fromPhysicalDisplayId(displayId); Hwc2::VsyncPeriodNanos vsyncPeriodNanos = 0; auto error = static_cast(mComposer->getDisplayVsyncPeriod(hwcId, &vsyncPeriodNanos)); RETURN_IF_HWC_ERROR(error, displayId, 0); *outVsyncPeriod = static_cast(vsyncPeriodNanos); return NO_ERROR; } std::vector HWComposer::getColorModes(PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, {}); std::vector modes; auto error = mDisplayData.at(displayId).hwcDisplay->getColorModes(&modes); RETURN_IF_HWC_ERROR(error, displayId, {}); return modes; } status_t HWComposer::setActiveColorMode(PhysicalDisplayId displayId, ui::ColorMode mode, ui::RenderIntent renderIntent) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); auto& displayData = mDisplayData[displayId]; auto error = displayData.hwcDisplay->setColorMode(mode, renderIntent); RETURN_IF_HWC_ERROR_FOR(("setColorMode(" + decodeColorMode(mode) + ", " + decodeRenderIntent(renderIntent) + ")") .c_str(), error, displayId, UNKNOWN_ERROR); return NO_ERROR; } void HWComposer::setVsyncEnabled(PhysicalDisplayId displayId, hal::Vsync enabled) { RETURN_IF_INVALID_DISPLAY(displayId); auto& displayData = mDisplayData[displayId]; // 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 // affect other threads. std::lock_guard lock(displayData.vsyncEnabledLock); if (enabled == displayData.vsyncEnabled) { return; } ATRACE_CALL(); auto error = displayData.hwcDisplay->setVsyncEnabled(enabled); RETURN_IF_HWC_ERROR(error, displayId); displayData.vsyncEnabled = enabled; const auto tag = "HW_VSYNC_ON_" + to_string(displayId); ATRACE_INT(tag.c_str(), enabled == hal::Vsync::ENABLE ? 1 : 0); } status_t HWComposer::setClientTarget(HalDisplayId displayId, uint32_t slot, const sp& acquireFence, const sp& target, ui::Dataspace dataspace) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); ALOGV("%s for display %s", __FUNCTION__, to_string(displayId).c_str()); auto& hwcDisplay = mDisplayData[displayId].hwcDisplay; auto error = hwcDisplay->setClientTarget(slot, target, acquireFence, dataspace); RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE); return NO_ERROR; } status_t HWComposer::getDeviceCompositionChanges( HalDisplayId displayId, bool frameUsesClientComposition, std::chrono::steady_clock::time_point earliestPresentTime, const std::shared_ptr& previousPresentFence, nsecs_t expectedPresentTime, std::optional* outChanges) { ATRACE_CALL(); RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); auto& displayData = mDisplayData[displayId]; auto& hwcDisplay = displayData.hwcDisplay; if (!hwcDisplay->isConnected()) { return NO_ERROR; } uint32_t numTypes = 0; uint32_t numRequests = 0; hal::Error error = hal::Error::NONE; // First try to skip validate altogether. We can do that when // 1. The previous frame has not been presented yet or already passed the // earliest time to present. Otherwise, we may present a frame too early. // 2. There is no client composition. Otherwise, we first need to render the // client target buffer. const bool canSkipValidate = [&] { // We must call validate if we have client composition if (frameUsesClientComposition) { return false; } // If composer supports getting the expected present time, we can skip // as composer will make sure to prevent early presentation if (mComposer->isSupported(Hwc2::Composer::OptionalFeature::ExpectedPresentTime)) { return true; } // composer doesn't support getting the expected present time. We can only // skip validate if we know that we are not going to present early. return std::chrono::steady_clock::now() >= earliestPresentTime || previousPresentFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING; }(); displayData.validateWasSkipped = false; if (canSkipValidate) { sp outPresentFence; uint32_t state = UINT32_MAX; error = hwcDisplay->presentOrValidate(expectedPresentTime, &numTypes, &numRequests, &outPresentFence, &state); if (!hasChangesError(error)) { RETURN_IF_HWC_ERROR_FOR("presentOrValidate", error, displayId, UNKNOWN_ERROR); } if (state == 1) { //Present Succeeded. std::unordered_map> releaseFences; error = hwcDisplay->getReleaseFences(&releaseFences); displayData.releaseFences = std::move(releaseFences); displayData.lastPresentFence = outPresentFence; displayData.validateWasSkipped = true; displayData.presentError = error; return NO_ERROR; } // Present failed but Validate ran. } else { error = hwcDisplay->validate(expectedPresentTime, &numTypes, &numRequests); } ALOGV("SkipValidate failed, Falling back to SLOW validate/present"); if (!hasChangesError(error)) { RETURN_IF_HWC_ERROR_FOR("validate", error, displayId, BAD_INDEX); } android::HWComposer::DeviceRequestedChanges::ChangedTypes changedTypes; changedTypes.reserve(numTypes); error = hwcDisplay->getChangedCompositionTypes(&changedTypes); RETURN_IF_HWC_ERROR_FOR("getChangedCompositionTypes", error, displayId, BAD_INDEX); auto displayRequests = static_cast(0); android::HWComposer::DeviceRequestedChanges::LayerRequests layerRequests; layerRequests.reserve(numRequests); error = hwcDisplay->getRequests(&displayRequests, &layerRequests); RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX); DeviceRequestedChanges::ClientTargetProperty clientTargetProperty; error = hwcDisplay->getClientTargetProperty(&clientTargetProperty); outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests), std::move(layerRequests), std::move(clientTargetProperty)}); error = hwcDisplay->acceptChanges(); RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX); return NO_ERROR; } sp HWComposer::getPresentFence(HalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE); return mDisplayData.at(displayId).lastPresentFence; } sp HWComposer::getLayerReleaseFence(HalDisplayId displayId, HWC2::Layer* layer) const { RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE); const auto& displayFences = mDisplayData.at(displayId).releaseFences; auto fence = displayFences.find(layer); if (fence == displayFences.end()) { ALOGV("getLayerReleaseFence: Release fence not found"); return Fence::NO_FENCE; } return fence->second; } status_t HWComposer::presentAndGetReleaseFences( HalDisplayId displayId, std::chrono::steady_clock::time_point earliestPresentTime, const std::shared_ptr& previousPresentFence) { ATRACE_CALL(); RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); auto& displayData = mDisplayData[displayId]; auto& hwcDisplay = displayData.hwcDisplay; if (displayData.validateWasSkipped) { // explicitly flush all pending commands auto error = static_cast(mComposer->executeCommands()); RETURN_IF_HWC_ERROR_FOR("executeCommands", error, displayId, UNKNOWN_ERROR); RETURN_IF_HWC_ERROR_FOR("present", displayData.presentError, displayId, UNKNOWN_ERROR); return NO_ERROR; } const bool waitForEarliestPresent = !mComposer->isSupported(Hwc2::Composer::OptionalFeature::ExpectedPresentTime) && previousPresentFence->getSignalTime() != Fence::SIGNAL_TIME_PENDING; if (waitForEarliestPresent) { ATRACE_NAME("wait for earliest present time"); std::this_thread::sleep_until(earliestPresentTime); } auto error = hwcDisplay->present(&displayData.lastPresentFence); RETURN_IF_HWC_ERROR_FOR("present", error, displayId, UNKNOWN_ERROR); std::unordered_map> releaseFences; error = hwcDisplay->getReleaseFences(&releaseFences); RETURN_IF_HWC_ERROR_FOR("getReleaseFences", error, displayId, UNKNOWN_ERROR); displayData.releaseFences = std::move(releaseFences); return NO_ERROR; } status_t HWComposer::setPowerMode(PhysicalDisplayId displayId, hal::PowerMode mode) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); 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: case hal::PowerMode::ON: ALOGV("setPowerMode: Calling HWC %s", to_string(mode).c_str()); { auto error = hwcDisplay->setPowerMode(mode); if (error != hal::Error::NONE) { LOG_HWC_ERROR(("setPowerMode(" + to_string(mode) + ")").c_str(), error, displayId); } } break; case hal::PowerMode::DOZE: case hal::PowerMode::DOZE_SUSPEND: ALOGV("setPowerMode: Calling HWC %s", to_string(mode).c_str()); { bool supportsDoze = false; auto error = hwcDisplay->supportsDoze(&supportsDoze); if (error != hal::Error::NONE) { LOG_HWC_ERROR("supportsDoze", error, displayId); } if (!supportsDoze) { mode = hal::PowerMode::ON; } error = hwcDisplay->setPowerMode(mode); if (error != hal::Error::NONE) { LOG_HWC_ERROR(("setPowerMode(" + to_string(mode) + ")").c_str(), error, displayId); } } break; default: ALOGV("setPowerMode: Not calling HWC"); break; } return NO_ERROR; } status_t HWComposer::setActiveModeWithConstraints( PhysicalDisplayId displayId, hal::HWConfigId hwcModeId, const hal::VsyncPeriodChangeConstraints& constraints, hal::VsyncPeriodChangeTimeline* outTimeline) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); auto error = mDisplayData[displayId].hwcDisplay->setActiveConfigWithConstraints(hwcModeId, constraints, outTimeline); RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } status_t HWComposer::setColorTransform(HalDisplayId displayId, const mat4& transform) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); auto& displayData = mDisplayData[displayId]; auto error = displayData.hwcDisplay->setColorTransform(transform); RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } void HWComposer::disconnectDisplay(HalDisplayId displayId) { RETURN_IF_INVALID_DISPLAY(displayId); auto& displayData = mDisplayData[displayId]; const auto hwcDisplayId = displayData.hwcDisplay->getId(); mPhysicalDisplayIdMap.erase(hwcDisplayId); mDisplayData.erase(displayId); // Reset the primary display ID if we're disconnecting it. // This way isHeadless() will return false, which is necessary // because getPrimaryDisplayId() will crash. if (mPrimaryHwcDisplayId == hwcDisplayId) { mPrimaryHwcDisplayId.reset(); } } status_t HWComposer::setOutputBuffer(HalVirtualDisplayId displayId, const sp& acquireFence, const sp& buffer) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto& displayData = mDisplayData[displayId]; auto error = displayData.hwcDisplay->setOutputBuffer(buffer, acquireFence); RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } void HWComposer::clearReleaseFences(HalDisplayId displayId) { RETURN_IF_INVALID_DISPLAY(displayId); mDisplayData[displayId].releaseFences.clear(); } status_t HWComposer::getHdrCapabilities(HalDisplayId displayId, HdrCapabilities* outCapabilities) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); auto& hwcDisplay = mDisplayData[displayId].hwcDisplay; auto error = hwcDisplay->getHdrCapabilities(outCapabilities); RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } int32_t HWComposer::getSupportedPerFrameMetadata(HalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, 0); return mDisplayData.at(displayId).hwcDisplay->getSupportedPerFrameMetadata(); } std::vector HWComposer::getRenderIntents(HalDisplayId displayId, ui::ColorMode colorMode) const { RETURN_IF_INVALID_DISPLAY(displayId, {}); std::vector renderIntents; auto error = mDisplayData.at(displayId).hwcDisplay->getRenderIntents(colorMode, &renderIntents); RETURN_IF_HWC_ERROR(error, displayId, {}); return renderIntents; } mat4 HWComposer::getDataspaceSaturationMatrix(HalDisplayId displayId, ui::Dataspace dataspace) { RETURN_IF_INVALID_DISPLAY(displayId, {}); mat4 matrix; auto error = mDisplayData[displayId].hwcDisplay->getDataspaceSaturationMatrix(dataspace, &matrix); RETURN_IF_HWC_ERROR(error, displayId, {}); return matrix; } status_t HWComposer::getDisplayedContentSamplingAttributes(HalDisplayId displayId, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, uint8_t* outComponentMask) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = mDisplayData[displayId] .hwcDisplay->getDisplayedContentSamplingAttributes(outFormat, outDataspace, outComponentMask); if (error == hal::Error::UNSUPPORTED) RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } status_t HWComposer::setDisplayContentSamplingEnabled(HalDisplayId displayId, bool enabled, uint8_t componentMask, uint64_t maxFrames) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = mDisplayData[displayId].hwcDisplay->setDisplayContentSamplingEnabled(enabled, componentMask, maxFrames); if (error == hal::Error::UNSUPPORTED) RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); if (error == hal::Error::BAD_PARAMETER) RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE); RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } status_t HWComposer::getDisplayedContentSample(HalDisplayId displayId, uint64_t maxFrames, uint64_t timestamp, DisplayedFrameStats* outStats) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = mDisplayData[displayId].hwcDisplay->getDisplayedContentSample(maxFrames, timestamp, outStats); RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } ftl::Future HWComposer::setDisplayBrightness( PhysicalDisplayId displayId, float brightness, float brightnessNits, const Hwc2::Composer::DisplayBrightnessOptions& options) { RETURN_IF_INVALID_DISPLAY(displayId, ftl::yield(BAD_INDEX)); auto& display = mDisplayData[displayId].hwcDisplay; return display->setDisplayBrightness(brightness, brightnessNits, options) .then([displayId](hal::Error error) -> status_t { if (error == hal::Error::UNSUPPORTED) { RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); } if (error == hal::Error::BAD_PARAMETER) { RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE); } RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; }); } bool HWComposer::getValidateSkipped(HalDisplayId displayId) const { if (mDisplayData.count(displayId) == 0) { return false; } return mDisplayData.at(displayId).validateWasSkipped; } status_t HWComposer::setBootDisplayMode(PhysicalDisplayId displayId, hal::HWConfigId displayModeId) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = mDisplayData[displayId].hwcDisplay->setBootDisplayConfig(displayModeId); if (error == hal::Error::UNSUPPORTED) { RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); } if (error == hal::Error::BAD_PARAMETER) { RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE); } RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } status_t HWComposer::clearBootDisplayMode(PhysicalDisplayId displayId) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = mDisplayData[displayId].hwcDisplay->clearBootDisplayConfig(); if (error == hal::Error::UNSUPPORTED) { RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); } if (error == hal::Error::BAD_PARAMETER) { RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE); } RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } std::optional HWComposer::getPreferredBootDisplayMode( PhysicalDisplayId displayId) { RETURN_IF_INVALID_DISPLAY(displayId, std::nullopt); hal::HWConfigId displayModeId; const auto error = mDisplayData[displayId].hwcDisplay->getPreferredBootDisplayConfig(&displayModeId); if (error != hal::Error::NONE) { LOG_DISPLAY_ERROR(displayId, to_string(error).c_str()); return std::nullopt; } return displayModeId; } status_t HWComposer::getDisplayDecorationSupport( PhysicalDisplayId displayId, std::optional* support) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = mDisplayData[displayId].hwcDisplay->getDisplayDecorationSupport(support); if (error == hal::Error::UNSUPPORTED) { RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); } if (error == hal::Error::BAD_PARAMETER) { RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE); } RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } status_t HWComposer::setAutoLowLatencyMode(PhysicalDisplayId displayId, bool on) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = mDisplayData[displayId].hwcDisplay->setAutoLowLatencyMode(on); if (error == hal::Error::UNSUPPORTED) { RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); } if (error == hal::Error::BAD_PARAMETER) { RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE); } RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } status_t HWComposer::getSupportedContentTypes( PhysicalDisplayId displayId, std::vector* outSupportedContentTypes) const { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = mDisplayData.at(displayId).hwcDisplay->getSupportedContentTypes( outSupportedContentTypes); RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } status_t HWComposer::setContentType(PhysicalDisplayId displayId, hal::ContentType contentType) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = mDisplayData[displayId].hwcDisplay->setContentType(contentType); if (error == hal::Error::UNSUPPORTED) { RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); } if (error == hal::Error::BAD_PARAMETER) { RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE); } RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } const std::unordered_map& HWComposer::getSupportedLayerGenericMetadata() const { return mSupportedLayerGenericMetadata; } void HWComposer::dump(std::string& result) const { result.append(mComposer->dumpDebugInfo()); } std::optional HWComposer::toPhysicalDisplayId( hal::HWDisplayId hwcDisplayId) const { if (const auto it = mPhysicalDisplayIdMap.find(hwcDisplayId); it != mPhysicalDisplayIdMap.end()) { return it->second; } return {}; } std::optional HWComposer::fromPhysicalDisplayId( PhysicalDisplayId displayId) const { if (const auto it = mDisplayData.find(displayId); it != mDisplayData.end()) { return it->second.hwcDisplay->getId(); } return {}; } bool HWComposer::shouldIgnoreHotplugConnect(hal::HWDisplayId hwcDisplayId, bool hasDisplayIdentificationData) const { if (mHasMultiDisplaySupport && !hasDisplayIdentificationData) { ALOGE("Ignoring connection of display %" PRIu64 " without identification data", hwcDisplayId); return true; } // 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; } return false; } std::optional HWComposer::onHotplugConnect( hal::HWDisplayId hwcDisplayId) { std::optional info; if (const auto displayId = toPhysicalDisplayId(hwcDisplayId)) { info = DisplayIdentificationInfo{.id = *displayId, .name = std::string(), .deviceProductInfo = std::nullopt}; if (mUpdateDeviceProductInfoOnHotplugReconnect) { uint8_t port; DisplayIdentificationData data; getDisplayIdentificationData(hwcDisplayId, &port, &data); if (auto newInfo = parseDisplayIdentificationData(port, data)) { info->deviceProductInfo = std::move(newInfo->deviceProductInfo); } else { ALOGE("Failed to parse identification data for display %" PRIu64, hwcDisplayId); } } } else { uint8_t port; DisplayIdentificationData data; const bool hasDisplayIdentificationData = getDisplayIdentificationData(hwcDisplayId, &port, &data); if (mPhysicalDisplayIdMap.empty()) { mHasMultiDisplaySupport = hasDisplayIdentificationData; ALOGI("Switching to %s multi-display mode", mHasMultiDisplaySupport ? "generalized" : "legacy"); } if (shouldIgnoreHotplugConnect(hwcDisplayId, hasDisplayIdentificationData)) { return {}; } info = [this, hwcDisplayId, &port, &data, hasDisplayIdentificationData] { const bool isPrimary = !mPrimaryHwcDisplayId; if (mHasMultiDisplaySupport) { if (const auto info = parseDisplayIdentificationData(port, data)) { return *info; } ALOGE("Failed to parse identification data for display %" PRIu64, hwcDisplayId); } else { ALOGW_IF(hasDisplayIdentificationData, "Ignoring identification data for display %" PRIu64, hwcDisplayId); port = isPrimary ? LEGACY_DISPLAY_TYPE_PRIMARY : LEGACY_DISPLAY_TYPE_EXTERNAL; } return DisplayIdentificationInfo{.id = PhysicalDisplayId::fromPort(port), .name = isPrimary ? "Primary display" : "Secondary display", .deviceProductInfo = std::nullopt}; }(); } if (!isConnected(info->id)) { allocatePhysicalDisplay(hwcDisplayId, info->id); } return info; } std::optional HWComposer::onHotplugDisconnect( hal::HWDisplayId hwcDisplayId) { LOG_ALWAYS_FATAL_IF(hwcDisplayId == mPrimaryHwcDisplayId, "Primary display cannot be disconnected."); const auto displayId = toPhysicalDisplayId(hwcDisplayId); if (!displayId) { LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid HWC display"); return {}; } // The display will later be destroyed by a call to // destroyDisplay(). For now we just mark it disconnected. if (isConnected(*displayId)) { mDisplayData[*displayId].hwcDisplay->setConnected(false); } else { LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Already disconnected"); } // The cleanup of Disconnect is handled through HWComposer::disconnectDisplay // via SurfaceFlinger's onHotplugReceived callback handling return DisplayIdentificationInfo{.id = *displayId, .name = std::string(), .deviceProductInfo = std::nullopt}; } void HWComposer::loadCapabilities() { static_assert(sizeof(hal::Capability) == sizeof(int32_t), "Capability size has changed"); auto capabilities = mComposer->getCapabilities(); for (auto capability : capabilities) { mCapabilities.emplace(capability); } } status_t HWComposer::setIdleTimerEnabled(PhysicalDisplayId displayId, std::chrono::milliseconds timeout) { ATRACE_CALL(); RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = mDisplayData[displayId].hwcDisplay->setIdleTimerEnabled(timeout); if (error == hal::Error::UNSUPPORTED) { RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); } if (error == hal::Error::BAD_PARAMETER) { RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE); } RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); return NO_ERROR; } bool HWComposer::hasDisplayIdleTimerCapability(PhysicalDisplayId displayId) const { RETURN_IF_INVALID_DISPLAY(displayId, false); return mDisplayData.at(displayId).hwcDisplay->hasDisplayIdleTimerCapability(); } Hwc2::AidlTransform HWComposer::getPhysicalDisplayOrientation(PhysicalDisplayId displayId) const { ATRACE_CALL(); RETURN_IF_INVALID_DISPLAY(displayId, Hwc2::AidlTransform::NONE); Hwc2::AidlTransform outTransform; const auto& hwcDisplay = mDisplayData.at(displayId).hwcDisplay; const auto error = hwcDisplay->getPhysicalDisplayOrientation(&outTransform); RETURN_IF_HWC_ERROR(error, displayId, Hwc2::AidlTransform::NONE); return outTransform; } void HWComposer::loadLayerMetadataSupport() { mSupportedLayerGenericMetadata.clear(); std::vector supportedMetadataKeyInfo; const auto error = mComposer->getLayerGenericMetadataKeys(&supportedMetadataKeyInfo); if (error != hardware::graphics::composer::V2_4::Error::NONE) { if (error != hardware::graphics::composer::V2_4::Error::UNSUPPORTED) { ALOGE("%s: %s failed: %s (%d)", __FUNCTION__, "getLayerGenericMetadataKeys", toString(error).c_str(), static_cast(error)); } return; } for (const auto& [name, mandatory] : supportedMetadataKeyInfo) { mSupportedLayerGenericMetadata.emplace(name, mandatory); } } } // namespace impl } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion"