Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  Display.cpp

  Sprache: C
 

/*
 * 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 <android-base/parseint.h>
#include <android-base/unique_fd.h>
#include <pthread.h>
#include <sched.h>
#include <sync/sync.h>
#include <sys/types.h>

#include <algorithm>
#include <atomic>
#include <numeric>
#include <sstream>
#include <thread>

#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<DisplayConfig>& configs, int32_t activeConfigId,
                          const std::optional<std::vector<uint8_t>>& edid) {
    std::unique_lock<std::recursive_mutex> 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<std::vector<uint8_t>>& 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<std::recursive_mutex> 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;
    int32_t oldVsyncPeriod = config.getAttribute(DisplayAttribute::VSYNC_PERIOD);
    int32_t newVsyncPeriod = HertzToPeriodNanos(refreshRateHz);
    if (oldVsyncPeriod != newVsyncPeriod) {
        config.setAttribute(DisplayAttribute::VSYNC_PERIOD, newVsyncPeriod);

        // Schedule a vsync update to propagate across system.
        VsyncPeriodChangeConstraints constraints;
        constraints.desiredTimeNanos = 0;

        VsyncPeriodChangeTimeline timeline;

        HWC3::Error error =
            mVsyncThread.scheduleVsyncUpdate(newVsyncPeriod, constraints, &timeline);
        if (error != HWC3::Error::None) {
            ALOGE("%s: display:%" PRId64 " composer failed to schedule vsync update", __FUNCTION__,
                  mId);
            return error;
        }
    }
    config.setAttribute(DisplayAttribute::WIDTH, static_cast<int32_t>(width));
    config.setAttribute(DisplayAttribute::HEIGHT, static_cast<int32_t>(height));
    config.setAttribute(DisplayAttribute::DPI_X, static_cast<int32_t>(dpiX));
    config.setAttribute(DisplayAttribute::DPI_Y, static_cast<int32_t>(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<std::recursive_mutex> lock(mStateMutex);

    auto layer = std::make_unique<Layer>();

    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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<ColorMode>* outModes) {
    DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId);

    std::unique_lock<std::recursive_mutex> lock(mStateMutex);

    outModes->clear();
    outModes->insert(outModes->end(), mColorModes.begin(), mColorModes.end());

    return HWC3::Error::None;
}

HWC3::Error Display::getDisplayCapabilities(std::vector<DisplayCapability>* 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<int32_t>* outConfigIds) {
    DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId);

    std::unique_lock<std::recursive_mutex> 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<DisplayConfiguration>* outConfigs) {
    DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId);

    std::unique_lock<std::recursive_mutex> 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<float>(displayConfig.getDpiX()),
                                    static_cast<float>(displayConfig.getDpiY())};
        displayConfiguration.vsyncPeriod = displayConfig.getVsyncPeriod();
        displayConfiguration.configGroup = displayConfig.getConfigGroup();
        displayConfiguration.hdrOutputType = OutputType::SYSTEM;

        outConfigs->emplace_back(displayConfiguration);
    }

    return HWC3::Error::None;
}

HWC3::Error Display::getDisplayConnectionType(DisplayConnectionType* outType) {
    *outType = DisplayConnectionType::INTERNAL;
    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<int8_t>(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<std::recursive_mutex> 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<std::recursive_mutex> 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<PerFrameMetadataKey>* 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<RenderIntent>* 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<ContentType>* outTypes) {
    DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId);

    outTypes->clear();

    return HWC3::Error::None;
}

HWC3::Error Display::getDecorationSupport(
    std::optional<common::DisplayDecorationSupport>* outSupport) {
    DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId);

    outSupport->reset();

    return HWC3::Error::Unsupported;
}

HWC3::Error Display::registerCallback(const std::shared_ptr<IComposerCallback>& 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<std::recursive_mutex> 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<int32_t> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> lock(mStateMutex);

    std::vector<int32_t> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<float>& 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<std::recursive_mutex> 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<common::Rect>& /*damage*/) {
    DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId);

    std::unique_lock<std::recursive_mutex> 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<ClockMonotonicTimestamp>& expectedPresentTime) {
    DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId);

    if (!expectedPresentTime.has_value()) {
        return HWC3::Error::None;
    }

    std::unique_lock<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<int64_t, ::android::base::unique_fd>* outLayerFences) {
    ATRACE_CALL();

    DEBUG_LOG("%s: display:%" PRId64, __FUNCTION__, mId);

    outDisplayFence->reset();
    outLayerFences->clear();

    std::unique_lock<std::recursive_mutex> 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<uint8_t> 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<uint8_t, 128> 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<uint8_t, 128> 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<uint8_t, 128> 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_<mID>
            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<uint8_t>(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

Messung V0.5 in Prozent
C=95 H=96 G=95

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet am  2026-06-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik