/* * 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 "Display.h" #include #include #include #include #include #include #include #include #include #include #include #include "Common.h" #include "Device.h" #include "Time.h" namespace aidl::android::hardware::graphics::composer3::impl { namespace { bool isValidColorMode(ColorMode mode) { switch (mode) { case ColorMode::NATIVE: case ColorMode::STANDARD_BT601_625: case ColorMode::STANDARD_BT601_625_UNADJUSTED: case ColorMode::STANDARD_BT601_525: case ColorMode::STANDARD_BT601_525_UNADJUSTED: case ColorMode::STANDARD_BT709: case ColorMode::DCI_P3: case ColorMode::SRGB: case ColorMode::ADOBE_RGB: case ColorMode::DISPLAY_P3: case ColorMode::BT2020: case ColorMode::BT2100_PQ: case ColorMode::BT2100_HLG: case ColorMode::DISPLAY_BT2020: return true; default: return false; } } bool isValidRenderIntent(RenderIntent intent) { switch (intent) { case RenderIntent::COLORIMETRIC: case RenderIntent::ENHANCE: case RenderIntent::TONE_MAP_COLORIMETRIC: case RenderIntent::TONE_MAP_ENHANCE: return true; default: return false; } } bool isValidPowerMode(PowerMode mode) { switch (mode) { case PowerMode::OFF: case PowerMode::DOZE: case PowerMode::DOZE_SUSPEND: case PowerMode::ON: case PowerMode::ON_SUSPEND: return true; default: return false; } } } // namespace Display::Display(FrameComposer* composer, int64_t id) : mComposer(composer), mId(id), mVsyncThread(id) { setLegacyEdid(); } Display::~Display() {} HWC3::Error Display::init(const std::vector& configs, int32_t activeConfigId, const std::optional>& edid) { std::unique_lock lock(mStateMutex); for (const DisplayConfig& config : configs) { mConfigs.emplace(config.getId(), config); } mActiveConfigId = activeConfigId; auto bootConfigIdOpt = getBootConfigId(); if (bootConfigIdOpt) { mActiveConfigId = *bootConfigIdOpt; } if (edid.has_value()) { mEdid = *edid; } auto it = mConfigs.find(activeConfigId); if (it == mConfigs.end()) { ALOGE("%s: display:%" PRId64 "missing config:%" PRId32, __FUNCTION__, mId, activeConfigId); return HWC3::Error::NoResources; } const auto& activeConfig = it->second; const auto activeConfigString = activeConfig.toString(); ALOGD("%s display:%" PRId64 " with config:%s", __FUNCTION__, mId, activeConfigString.c_str()); mVsyncThread.start(activeConfig.getVsyncPeriod()); return HWC3::Error::None; } HWC3::Error Display::updateParameters(uint32_t width, uint32_t height, uint32_t dpiX, uint32_t dpiY, uint32_t refreshRateHz, const std::optional>& edid) { DEBUG_LOG("%s: updating display:%" PRId64 " width:%d height:%d dpiX:%d dpiY:%d refreshRateHz:%d", __FUNCTION__, mId, width, height, dpiX, dpiY, refreshRateHz); std::unique_lock lock(mStateMutex); auto it = mConfigs.find(*mActiveConfigId); if (it == mConfigs.end()) { ALOGE("%s: failed to find config %" PRId32, __func__, *mActiveConfigId); return HWC3::Error::NoResources; } DisplayConfig& config = it->second; config.setAttribute(DisplayAttribute::VSYNC_PERIOD, HertzToPeriodNanos(refreshRateHz)); config.setAttribute(DisplayAttribute::WIDTH, static_cast(width)); config.setAttribute(DisplayAttribute::HEIGHT, static_cast(height)); config.setAttribute(DisplayAttribute::DPI_X, static_cast(dpiX)); config.setAttribute(DisplayAttribute::DPI_Y, static_cast(dpiY)); if (edid.has_value()) { mEdid = *edid; } return HWC3::Error::None; } HWC3::Error Display::createLayer(int64_t* outLayerId) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); std::unique_lock lock(mStateMutex); auto layer = std::make_unique(); const int64_t layerId = layer->getId(); DEBUG_LOG("%s: created layer:%" PRId64, __FUNCTION__, layerId); mLayers.emplace(layerId, std::move(layer)); *outLayerId = layerId; return HWC3::Error::None; } HWC3::Error Display::destroyLayer(int64_t layerId) { DEBUG_LOG("%s: destroy layer:%" PRId64, __FUNCTION__, layerId); std::unique_lock lock(mStateMutex); auto it = mLayers.find(layerId); if (it == mLayers.end()) { ALOGE("%s display:%" PRId64 " has no such layer:%." PRId64, __FUNCTION__, mId, layerId); return HWC3::Error::BadLayer; } mOrderedLayers.erase( std::remove_if(mOrderedLayers.begin(), // mOrderedLayers.end(), // [layerId](Layer* layer) { return layer->getId() == layerId; }), mOrderedLayers.end()); mLayers.erase(it); DEBUG_LOG("%s: destroyed layer:%" PRId64, __FUNCTION__, layerId); return HWC3::Error::None; } HWC3::Error Display::getActiveConfig(int32_t* outConfig) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); std::unique_lock lock(mStateMutex); if (!mActiveConfigId) { ALOGW("%s: display:%" PRId64 " has no active config.", __FUNCTION__, mId); return HWC3::Error::BadConfig; } *outConfig = *mActiveConfigId; return HWC3::Error::None; } HWC3::Error Display::getDisplayAttribute(int32_t configId, DisplayAttribute attribute, int32_t* outValue) { auto attributeString = toString(attribute); DEBUG_LOG("%s: display:%" PRId64 " attribute:%s", __FUNCTION__, mId, attributeString.c_str()); std::unique_lock lock(mStateMutex); auto it = mConfigs.find(configId); if (it == mConfigs.end()) { ALOGW("%s: display:%" PRId64 " bad config:%" PRId32, __FUNCTION__, mId, configId); return HWC3::Error::BadConfig; } const DisplayConfig& config = it->second; *outValue = config.getAttribute(attribute); DEBUG_LOG("%s: display:%" PRId64 " attribute:%s value is %" PRIi32, __FUNCTION__, mId, attributeString.c_str(), *outValue); return HWC3::Error::None; } HWC3::Error Display::getColorModes(std::vector* outModes) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); std::unique_lock lock(mStateMutex); outModes->clear(); outModes->insert(outModes->end(), mColorModes.begin(), mColorModes.end()); return HWC3::Error::None; } HWC3::Error Display::getDisplayCapabilities(std::vector* outCapabilities) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); outCapabilities->clear(); outCapabilities->push_back(DisplayCapability::SKIP_CLIENT_COLOR_TRANSFORM); outCapabilities->push_back(DisplayCapability::MULTI_THREADED_PRESENT); return HWC3::Error::None; } HWC3::Error Display::getDisplayConfigs(std::vector* outConfigIds) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); std::unique_lock lock(mStateMutex); outConfigIds->clear(); outConfigIds->reserve(mConfigs.size()); for (const auto& [configId, _] : mConfigs) { outConfigIds->push_back(configId); } return HWC3::Error::None; } HWC3::Error Display::getDisplayConfigurations(std::vector* outConfigs) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); std::unique_lock lock(mStateMutex); outConfigs->clear(); outConfigs->reserve(mConfigs.size()); for (const auto& [configId, displayConfig] : mConfigs) { DisplayConfiguration displayConfiguration; displayConfiguration.configId = configId; displayConfiguration.width = displayConfig.getWidth(); displayConfiguration.height = displayConfig.getHeight(); displayConfiguration.dpi = {static_cast(displayConfig.getDpiX()), static_cast(displayConfig.getDpiY())}; displayConfiguration.vsyncPeriod = displayConfig.getVsyncPeriod(); displayConfiguration.configGroup = displayConfig.getConfigGroup(); outConfigs->emplace_back(displayConfiguration); } return HWC3::Error::None; } HWC3::Error Display::getDisplayConnectionType(DisplayConnectionType* outType) { if (IsCuttlefishFoldable() || IsAutoDevice()) { // Android Auto OS needs to set all displays to INTERNAL since they're used // for the passenger displays. // Workaround to force all displays to INTERNAL for cf_x86_64_foldable. // TODO(b/193568008): Allow configuring internal/external per display. *outType = DisplayConnectionType::INTERNAL; } else { // Other devices default to the first display INTERNAL, others EXTERNAL. *outType = mId == 0 ? DisplayConnectionType::INTERNAL : DisplayConnectionType::EXTERNAL; } return HWC3::Error::None; } HWC3::Error Display::getDisplayIdentificationData(DisplayIdentification* outIdentification) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); if (outIdentification == nullptr) { return HWC3::Error::BadParameter; } outIdentification->port = static_cast(mId); outIdentification->data = mEdid; return HWC3::Error::None; } HWC3::Error Display::getDisplayName(std::string* outName) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); std::unique_lock lock(mStateMutex); *outName = mName; return HWC3::Error::None; } HWC3::Error Display::getDisplayVsyncPeriod(int32_t* outVsyncPeriod) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); std::unique_lock lock(mStateMutex); if (!mActiveConfigId) { ALOGE("%s : display:%" PRId64 " no active config", __FUNCTION__, mId); return HWC3::Error::BadConfig; } const auto it = mConfigs.find(*mActiveConfigId); if (it == mConfigs.end()) { ALOGE("%s : display:%" PRId64 " failed to find active config:%" PRId32, __FUNCTION__, mId, *mActiveConfigId); return HWC3::Error::BadConfig; } const DisplayConfig& activeConfig = it->second; *outVsyncPeriod = activeConfig.getAttribute(DisplayAttribute::VSYNC_PERIOD); return HWC3::Error::None; } HWC3::Error Display::getDisplayedContentSample(int64_t /*maxFrames*/, int64_t /*timestamp*/, DisplayContentSample* /*samples*/) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); return HWC3::Error::Unsupported; } HWC3::Error Display::getDisplayedContentSamplingAttributes( DisplayContentSamplingAttributes* /*outAttributes*/) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); return HWC3::Error::Unsupported; } HWC3::Error Display::getDisplayPhysicalOrientation(common::Transform* outOrientation) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); *outOrientation = common::Transform::NONE; return HWC3::Error::None; } HWC3::Error Display::getHdrCapabilities(HdrCapabilities* outCapabilities) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); // No supported types. outCapabilities->types.clear(); return HWC3::Error::None; } HWC3::Error Display::getPerFrameMetadataKeys(std::vector* outKeys) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); outKeys->clear(); return HWC3::Error::Unsupported; } HWC3::Error Display::getReadbackBufferAttributes(ReadbackBufferAttributes* outAttributes) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); outAttributes->format = common::PixelFormat::RGBA_8888; outAttributes->dataspace = common::Dataspace::UNKNOWN; return HWC3::Error::Unsupported; } HWC3::Error Display::getReadbackBufferFence(ndk::ScopedFileDescriptor* /*outAcquireFence*/) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); return HWC3::Error::Unsupported; } HWC3::Error Display::getRenderIntents(ColorMode mode, std::vector* outIntents) { const auto modeString = toString(mode); DEBUG_LOG("%s: display:%" PRId64 "for mode:%s", __FUNCTION__, mId, modeString.c_str()); outIntents->clear(); if (!isValidColorMode(mode)) { DEBUG_LOG("%s: display:%" PRId64 "invalid mode:%s", __FUNCTION__, mId, modeString.c_str()); return HWC3::Error::BadParameter; } outIntents->push_back(RenderIntent::COLORIMETRIC); return HWC3::Error::None; } HWC3::Error Display::getSupportedContentTypes(std::vector* outTypes) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); outTypes->clear(); return HWC3::Error::None; } HWC3::Error Display::getDecorationSupport( std::optional* outSupport) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); outSupport->reset(); return HWC3::Error::Unsupported; } HWC3::Error Display::registerCallback(const std::shared_ptr& callback) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); mVsyncThread.setCallbacks(callback); return HWC3::Error::Unsupported; } HWC3::Error Display::setActiveConfig(int32_t configId) { DEBUG_LOG("%s: display:%" PRId64 " setting active config to %" PRId32, __FUNCTION__, mId, configId); VsyncPeriodChangeConstraints constraints; constraints.desiredTimeNanos = 0; constraints.seamlessRequired = false; VsyncPeriodChangeTimeline timeline; return setActiveConfigWithConstraints(configId, constraints, &timeline); } HWC3::Error Display::setActiveConfigWithConstraints(int32_t configId, const VsyncPeriodChangeConstraints& constraints, VsyncPeriodChangeTimeline* outTimeline) { DEBUG_LOG("%s: display:%" PRId64 " config:%" PRId32, __FUNCTION__, mId, configId); if (outTimeline == nullptr) { return HWC3::Error::BadParameter; } std::unique_lock lock(mStateMutex); if (mActiveConfigId == configId) { return HWC3::Error::None; } DisplayConfig* newConfig = getConfig(configId); if (newConfig == nullptr) { ALOGE("%s: display:%" PRId64 " bad config:%" PRId32, __FUNCTION__, mId, configId); return HWC3::Error::BadConfig; } if (constraints.seamlessRequired) { if (mActiveConfigId) { DisplayConfig* oldConfig = getConfig(*mActiveConfigId); if (oldConfig == nullptr) { ALOGE("%s: display:%" PRId64 " missing config:%" PRId32, __FUNCTION__, mId, *mActiveConfigId); return HWC3::Error::NoResources; } const int32_t newConfigGroup = newConfig->getConfigGroup(); const int32_t oldConfigGroup = oldConfig->getConfigGroup(); if (newConfigGroup != oldConfigGroup) { DEBUG_LOG("%s: display:%" PRId64 " config:%" PRId32 " seamless not supported between different config groups " "old:%d vs new:%d", __FUNCTION__, mId, configId, oldConfigGroup, newConfigGroup); return HWC3::Error::SeamlessNotAllowed; } } } mActiveConfigId = configId; if (mComposer == nullptr) { ALOGE("%s: display:%" PRId64 " missing composer", __FUNCTION__, mId); return HWC3::Error::NoResources; } HWC3::Error error = mComposer->onActiveConfigChange(this); if (error != HWC3::Error::None) { ALOGE("%s: display:%" PRId64 " composer failed to handle config change", __FUNCTION__, mId); return error; } int32_t vsyncPeriod; error = getDisplayVsyncPeriod(&vsyncPeriod); if (error != HWC3::Error::None) { ALOGE("%s: display:%" PRId64 " composer failed to handle config change", __FUNCTION__, mId); return error; } return mVsyncThread.scheduleVsyncUpdate(vsyncPeriod, constraints, outTimeline); } std::optional Display::getBootConfigId() { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); if (!Device::getInstance().persistentKeyValueEnabled()) { ALOGD("%s: persistent boot config is not enabled.", __FUNCTION__); return std::nullopt; } std::unique_lock lock(mStateMutex); std::string val; HWC3::Error error = Device::getInstance().getPersistentKeyValue(std::to_string(mId), "", &val); if (error != HWC3::Error::None) { ALOGE("%s: display:%" PRId64 " failed to get persistent boot config", __FUNCTION__, mId); return std::nullopt; } if (val.empty()) { return std::nullopt; } int32_t configId = 0; if (!::android::base::ParseInt(val, &configId)) { ALOGE("%s: display:%" PRId64 " failed to parse persistent boot config from: %s", __FUNCTION__, mId, val.c_str()); return std::nullopt; } if (!hasConfig(configId)) { ALOGE("%s: display:%" PRId64 " invalid persistent boot config:%" PRId32, __FUNCTION__, mId, configId); return std::nullopt; } return configId; } HWC3::Error Display::setBootConfig(int32_t configId) { DEBUG_LOG("%s: display:%" PRId64 " config:%" PRId32, __FUNCTION__, mId, configId); std::unique_lock lock(mStateMutex); DisplayConfig* newConfig = getConfig(configId); if (newConfig == nullptr) { ALOGE("%s: display:%" PRId64 " bad config:%" PRId32, __FUNCTION__, mId, configId); return HWC3::Error::BadConfig; } const std::string key = std::to_string(mId); const std::string val = std::to_string(configId); HWC3::Error error = Device::getInstance().setPersistentKeyValue(key, val); if (error != HWC3::Error::None) { ALOGE("%s: display:%" PRId64 " failed to save persistent boot config", __FUNCTION__, mId); return error; } return HWC3::Error::None; } HWC3::Error Display::clearBootConfig() { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); std::unique_lock lock(mStateMutex); const std::string key = std::to_string(mId); const std::string val = ""; HWC3::Error error = Device::getInstance().setPersistentKeyValue(key, val); if (error != HWC3::Error::None) { ALOGE("%s: display:%" PRId64 " failed to save persistent boot config", __FUNCTION__, mId); return error; } return HWC3::Error::None; } HWC3::Error Display::getPreferredBootConfig(int32_t* outConfigId) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); std::unique_lock lock(mStateMutex); std::vector configIds; for (const auto [configId, _] : mConfigs) { configIds.push_back(configId); } *outConfigId = *std::min_element(configIds.begin(), configIds.end()); return HWC3::Error::None; } HWC3::Error Display::setAutoLowLatencyMode(bool /*on*/) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); return HWC3::Error::Unsupported; } HWC3::Error Display::setColorMode(ColorMode mode, RenderIntent intent) { const std::string modeString = toString(mode); const std::string intentString = toString(intent); DEBUG_LOG("%s: display:%" PRId64 " setting color mode:%s intent:%s", __FUNCTION__, mId, modeString.c_str(), intentString.c_str()); if (!isValidColorMode(mode)) { ALOGE("%s: display:%" PRId64 " invalid color mode:%s", __FUNCTION__, mId, modeString.c_str()); return HWC3::Error::BadParameter; } if (!isValidRenderIntent(intent)) { ALOGE("%s: display:%" PRId64 " invalid intent:%s", __FUNCTION__, mId, intentString.c_str()); return HWC3::Error::BadParameter; } std::unique_lock lock(mStateMutex); if (mColorModes.count(mode) == 0) { ALOGE("%s: display %" PRId64 " mode %s not supported", __FUNCTION__, mId, modeString.c_str()); return HWC3::Error::Unsupported; } mActiveColorMode = mode; return HWC3::Error::None; } HWC3::Error Display::setContentType(ContentType contentType) { auto contentTypeString = toString(contentType); DEBUG_LOG("%s: display:%" PRId64 " content type:%s", __FUNCTION__, mId, contentTypeString.c_str()); if (contentType != ContentType::NONE) { return HWC3::Error::Unsupported; } return HWC3::Error::None; } HWC3::Error Display::setDisplayedContentSamplingEnabled(bool /*enable*/, FormatColorComponent /*componentMask*/, int64_t /*maxFrames*/) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); return HWC3::Error::Unsupported; } HWC3::Error Display::setPowerMode(PowerMode mode) { auto modeString = toString(mode); DEBUG_LOG("%s: display:%" PRId64 " to mode:%s", __FUNCTION__, mId, modeString.c_str()); if (!isValidPowerMode(mode)) { ALOGE("%s: display:%" PRId64 " invalid mode:%s", __FUNCTION__, mId, modeString.c_str()); return HWC3::Error::BadParameter; } if (mode == PowerMode::DOZE || mode == PowerMode::DOZE_SUSPEND || mode == PowerMode::ON_SUSPEND) { ALOGE("%s display %" PRId64 " mode:%s not supported", __FUNCTION__, mId, modeString.c_str()); return HWC3::Error::Unsupported; } std::unique_lock lock(mStateMutex); if (IsCuttlefish()) { if (int fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC); fd != -1) { std::ostringstream stream; stream << "VIRTUAL_DEVICE_DISPLAY_POWER_MODE_CHANGED display=" << mId << " mode=" << modeString << std::endl; std::string message = stream.str(); write(fd, message.c_str(), message.length()); close(fd); } } mPowerMode = mode; return HWC3::Error::None; } HWC3::Error Display::setReadbackBuffer(const buffer_handle_t buffer, const ndk::ScopedFileDescriptor& fence) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); mReadbackBuffer.set(buffer, fence); return HWC3::Error::Unsupported; } HWC3::Error Display::setVsyncEnabled(bool enabled) { DEBUG_LOG("%s: display:%" PRId64 " setting vsync %s", __FUNCTION__, mId, (enabled ? "on" : "off")); std::unique_lock lock(mStateMutex); return mVsyncThread.setVsyncEnabled(enabled); } HWC3::Error Display::setIdleTimerEnabled(int32_t timeoutMs) { DEBUG_LOG("%s: display:%" PRId64 " timeout:%" PRId32, __FUNCTION__, mId, timeoutMs); (void)timeoutMs; return HWC3::Error::Unsupported; } HWC3::Error Display::setColorTransform(const std::vector& transformMatrix) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); if (transformMatrix.size() < 16) { ALOGE("%s: display:%" PRId64 " has non 4x4 matrix, size:%zu", __FUNCTION__, mId, transformMatrix.size()); return HWC3::Error::BadParameter; } std::unique_lock lock(mStateMutex); auto& colorTransform = mColorTransform.emplace(); std::copy_n(transformMatrix.data(), colorTransform.size(), colorTransform.begin()); return HWC3::Error::None; } HWC3::Error Display::setBrightness(float brightness) { DEBUG_LOG("%s: display:%" PRId64 " brightness:%f", __FUNCTION__, mId, brightness); if (brightness < 0.0f) { ALOGE("%s: display:%" PRId64 " invalid brightness:%f", __FUNCTION__, mId, brightness); return HWC3::Error::BadParameter; } return HWC3::Error::Unsupported; } HWC3::Error Display::setClientTarget(buffer_handle_t buffer, const ndk::ScopedFileDescriptor& fence, common::Dataspace /*dataspace*/, const std::vector& /*damage*/) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); std::unique_lock lock(mStateMutex); mClientTarget.set(buffer, fence); mComposer->onDisplayClientTargetSet(this); return HWC3::Error::None; } HWC3::Error Display::setOutputBuffer(buffer_handle_t /*buffer*/, const ndk::ScopedFileDescriptor& /*fence*/) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); // TODO: for virtual display return HWC3::Error::None; } HWC3::Error Display::setExpectedPresentTime( const std::optional& expectedPresentTime) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); if (!expectedPresentTime.has_value()) { return HWC3::Error::None; } std::unique_lock lock(mStateMutex); mExpectedPresentTime.emplace(asTimePoint(expectedPresentTime->timestampNanos)); return HWC3::Error::None; } HWC3::Error Display::validate(DisplayChanges* outChanges) { ATRACE_CALL(); DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); std::unique_lock lock(mStateMutex); mPendingChanges.reset(); mOrderedLayers.clear(); mOrderedLayers.reserve(mLayers.size()); for (auto& [_, layerPtr] : mLayers) { mOrderedLayers.push_back(layerPtr.get()); } std::sort(mOrderedLayers.begin(), mOrderedLayers.end(), [](const Layer* layerA, const Layer* layerB) { const auto zA = layerA->getZOrder(); const auto zB = layerB->getZOrder(); if (zA != zB) { return zA < zB; } return layerA->getId() < layerB->getId(); }); if (mComposer == nullptr) { ALOGE("%s: display:%" PRId64 " missing composer", __FUNCTION__, mId); return HWC3::Error::NoResources; } HWC3::Error error = mComposer->validateDisplay(this, &mPendingChanges); if (error != HWC3::Error::None) { ALOGE("%s: display:%" PRId64 " failed to validate", __FUNCTION__, mId); return error; } if (mPendingChanges.hasAnyChanges()) { mPresentFlowState = PresentFlowState::WAITING_FOR_ACCEPT; DEBUG_LOG("%s: display:%" PRId64 " now WAITING_FOR_ACCEPT", __FUNCTION__, mId); } else { mPresentFlowState = PresentFlowState::WAITING_FOR_PRESENT; DEBUG_LOG("%s: display:%" PRId64 " now WAITING_FOR_PRESENT", __FUNCTION__, mId); } *outChanges = mPendingChanges; return HWC3::Error::None; } HWC3::Error Display::acceptChanges() { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); std::unique_lock lock(mStateMutex); switch (mPresentFlowState) { case PresentFlowState::WAITING_FOR_VALIDATE: { ALOGE("%s: display %" PRId64 " failed, not validated", __FUNCTION__, mId); return HWC3::Error::NotValidated; } case PresentFlowState::WAITING_FOR_ACCEPT: case PresentFlowState::WAITING_FOR_PRESENT: { break; } } if (mPendingChanges.compositionChanges) { const ChangedCompositionTypes& compositionChanges = *mPendingChanges.compositionChanges; for (const ChangedCompositionLayer& compositionChange : compositionChanges.layers) { const auto layerId = compositionChange.layer; const auto layerComposition = compositionChange.composition; auto* layer = getLayer(layerId); if (layer == nullptr) { ALOGE("%s: display:%" PRId64 " layer:%" PRId64 " dropped before acceptChanges()?", __FUNCTION__, mId, layerId); continue; } layer->setCompositionType(layerComposition); } } mPendingChanges.reset(); mPresentFlowState = PresentFlowState::WAITING_FOR_PRESENT; DEBUG_LOG("%s: display:%" PRId64 " now WAITING_FOR_PRESENT", __FUNCTION__, mId); return HWC3::Error::None; } HWC3::Error Display::present( ::android::base::unique_fd* outDisplayFence, std::unordered_map* outLayerFences) { ATRACE_CALL(); DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); outDisplayFence->reset(); outLayerFences->clear(); std::unique_lock lock(mStateMutex); switch (mPresentFlowState) { case PresentFlowState::WAITING_FOR_VALIDATE: { ALOGE("%s: display %" PRId64 " failed, not validated", __FUNCTION__, mId); return HWC3::Error::NotValidated; } case PresentFlowState::WAITING_FOR_ACCEPT: { ALOGE("%s: display %" PRId64 " failed, changes not accepted", __FUNCTION__, mId); return HWC3::Error::NotValidated; } case PresentFlowState::WAITING_FOR_PRESENT: { break; } } mPresentFlowState = PresentFlowState::WAITING_FOR_VALIDATE; DEBUG_LOG("%s: display:%" PRId64 " now WAITING_FOR_VALIDATE", __FUNCTION__, mId); if (mComposer == nullptr) { ALOGE("%s: display:%" PRId64 " missing composer", __FUNCTION__, mId); return HWC3::Error::NoResources; } return mComposer->presentDisplay(this, outDisplayFence, outLayerFences); } bool Display::hasConfig(int32_t configId) const { return mConfigs.find(configId) != mConfigs.end(); } DisplayConfig* Display::getConfig(int32_t configId) { auto it = mConfigs.find(configId); if (it != mConfigs.end()) { return &it->second; } return nullptr; } HWC3::Error Display::setEdid(std::vector edid) { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); mEdid = edid; return HWC3::Error::None; } void Display::setLegacyEdid() { // thess EDIDs are carefully generated according to the EDID spec version 1.3, // more info can be found from the following file: // frameworks/native/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp // approved pnp ids can be found here: https://uefi.org/pnp_id_list // pnp id: GGL, name: EMU_display_0, last byte is checksum // display id is local:8141603649153536 static constexpr const std::array kEdid0 = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1c, 0xec, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1b, 0x10, 0x01, 0x03, 0x80, 0x50, 0x2d, 0x78, 0x0a, 0x0d, 0xc9, 0xa0, 0x57, 0x47, 0x98, 0x27, 0x12, 0x48, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x45, 0x4d, 0x55, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x30, 0x00, 0x4b}; // pnp id: GGL, name: EMU_display_1 // display id is local:8140900251843329 static constexpr const std::array kEdid1 = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1c, 0xec, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1b, 0x10, 0x01, 0x03, 0x80, 0x50, 0x2d, 0x78, 0x0a, 0x0d, 0xc9, 0xa0, 0x57, 0x47, 0x98, 0x27, 0x12, 0x48, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x45, 0x4d, 0x55, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x31, 0x00, 0x3b}; // pnp id: GGL, name: EMU_display_2 // display id is local:8140940453066754 static constexpr const std::array kEdid2 = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1c, 0xec, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1b, 0x10, 0x01, 0x03, 0x80, 0x50, 0x2d, 0x78, 0x0a, 0x0d, 0xc9, 0xa0, 0x57, 0x47, 0x98, 0x27, 0x12, 0x48, 0x4c, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x45, 0x4d, 0x55, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x32, 0x00, 0x49}; mEdid.clear(); switch (mId) { case 0: { mEdid.insert(mEdid.end(), kEdid0.begin(), kEdid0.end()); break; } case 1: { mEdid.insert(mEdid.end(), kEdid1.begin(), kEdid1.end()); break; } case 2: { mEdid.insert(mEdid.end(), kEdid2.begin(), kEdid2.end()); break; } default: { mEdid.insert(mEdid.end(), kEdid2.begin(), kEdid2.end()); const size_t size = mEdid.size(); // Update the name to EMU_display_ mEdid[size - 3] = '0' + (uint8_t)mId; // Update the checksum byte uint8_t checksum = -(uint8_t)std::accumulate(mEdid.data(), mEdid.data() + size - 1, static_cast(0)); mEdid[size - 1] = checksum; break; } } } Layer* Display::getLayer(int64_t layerId) { auto it = mLayers.find(layerId); if (it == mLayers.end()) { ALOGE("%s Unknown layer:%" PRId64, __FUNCTION__, layerId); return nullptr; } return it->second.get(); } buffer_handle_t Display::waitAndGetClientTargetBuffer() { DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId); ::android::base::unique_fd fence = mClientTarget.getFence(); if (fence.ok()) { int err = sync_wait(fence.get(), 3000); if (err < 0 && errno == ETIME) { ALOGE("%s waited on fence %" PRId32 " for 3000 ms", __FUNCTION__, fence.get()); } } return mClientTarget.getBuffer(); } } // namespace aidl::android::hardware::graphics::composer3::impl