Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c1f18f6f authored by Dominik Laskowski's avatar Dominik Laskowski
Browse files

SF: Remember display type in DisplayData

This obviates querying the HWC to determine if a display is physical or
virtual.

Bug: 74619554
Test: libsurfaceflinger_unittest
Change-Id: I9a18d480358f4195c66c183c70ffbe8480bd25b8
parent 0954b1d8
Loading
Loading
Loading
Loading
+35 −47
Original line number Diff line number Diff line
@@ -54,6 +54,9 @@
#include "../Layer.h"           // needed only for debugging
#include "../SurfaceFlinger.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 %d: %s", __FUNCTION__, displayId, msg)

@@ -172,32 +175,22 @@ std::optional<DisplayId> HWComposer::onHotplug(hwc2_display_t hwcDisplayId, int3
    return displayId;
}

bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t* outDisplay) {
    auto display = mHwcDevice->getDisplayById(hwcDisplayId);
    if (!display) {
        ALOGE("%s: Failed to find display %" PRIu64, __FUNCTION__, hwcDisplayId);
        return false;
    }
    auto displayType = HWC2::DisplayType::Invalid;
    auto error = display->getType(&displayType);
    if (error != HWC2::Error::None) {
        ALOGE("%s: Failed to determine type of display %" PRIu64, __FUNCTION__, display->getId());
bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t* outDisplayId) {
    const auto it = mHwcDisplaySlots.find(hwcDisplayId);
    if (it == mHwcDisplaySlots.end()) {
        LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid display");
        return false;
    }

    if (displayType == HWC2::DisplayType::Virtual) {
        ALOGE("Virtual display %" PRIu64 " passed to vsync callback",
                display->getId());
        return false;
    }
    const int32_t displayId = it->second;
    RETURN_IF_INVALID_DISPLAY(displayId, false);

    if (mHwcDisplaySlots.count(display->getId()) == 0) {
        ALOGE("Unknown physical display %" PRIu64 " passed to vsync callback",
                display->getId());
    const auto& displayData = mDisplayData[displayId];
    if (displayData.isVirtual) {
        LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
        return false;
    }

    int32_t disp = mHwcDisplaySlots[display->getId()];
    {
        Mutex::Autolock _l(mLock);

@@ -205,22 +198,22 @@ bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t
        // 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 == mLastHwVSync[disp]) {
        if (timestamp == mLastHwVSync[displayId]) {
            ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
                    timestamp);
            return false;
        }

        mLastHwVSync[disp] = timestamp;
        mLastHwVSync[displayId] = timestamp;
    }

    if (outDisplay) {
        *outDisplay = disp;
    if (outDisplayId) {
        *outDisplayId = displayId;
    }

    char tag[16];
    snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
    ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
    snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", displayId);
    ATRACE_INT(tag, ++mVSyncCounts[displayId] & 1);

    return true;
}
@@ -262,7 +255,9 @@ status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
        return NO_MEMORY;
    }

    mDisplayData[displaySlot].hwcDisplay = display;
    auto& displayData = mDisplayData[displaySlot];
    displayData.hwcDisplay = display;
    displayData.isVirtual = true;

    --mRemainingHwcVirtualDisplays;
    *outId = static_cast<int32_t>(displaySlot);
@@ -385,19 +380,19 @@ status_t HWComposer::setActiveColorMode(int32_t displayId, ui::ColorMode mode,


void HWComposer::setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled) {
    if (displayId < 0 || displayId >= HWC_DISPLAY_VIRTUAL) {
        ALOGD("setVsyncEnabled: Ignoring for virtual display %d", displayId);
    RETURN_IF_INVALID_DISPLAY(displayId);
    auto& displayData = mDisplayData[displayId];

    if (displayData.isVirtual) {
        LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
        return;
    }

    RETURN_IF_INVALID_DISPLAY(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.
    Mutex::Autolock _l(mVsyncLock);
    auto& displayData = mDisplayData[displayId];
    if (enabled != displayData.vsyncEnabled) {
        ATRACE_CALL();
        auto error = displayData.hwcDisplay->setVsyncEnabled(enabled);
@@ -621,7 +616,8 @@ status_t HWComposer::setPowerMode(int32_t displayId, int32_t intMode) {
    ALOGV("setPowerMode(%d, %d)", displayId, intMode);
    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);

    if (displayId >= VIRTUAL_DISPLAY_ID_BASE) {
    const auto& displayData = mDisplayData[displayId];
    if (displayData.isVirtual) {
        LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
        return INVALID_OPERATION;
    }
@@ -631,7 +627,7 @@ status_t HWComposer::setPowerMode(int32_t displayId, int32_t intMode) {
        setVsyncEnabled(displayId, HWC2::Vsync::Disable);
    }

    auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
    auto& hwcDisplay = displayData.hwcDisplay;
    switch (mode) {
        case HWC2::PowerMode::Off:
        case HWC2::PowerMode::On:
@@ -700,17 +696,13 @@ status_t HWComposer::setColorTransform(int32_t displayId,
    return NO_ERROR;
}

void HWComposer::disconnectDisplay(int displayId) {
    LOG_ALWAYS_FATAL_IF(displayId < 0);
void HWComposer::disconnectDisplay(int32_t displayId) {
    RETURN_IF_INVALID_DISPLAY(displayId);
    auto& displayData = mDisplayData[displayId];

    auto displayType = HWC2::DisplayType::Invalid;
    auto error = displayData.hwcDisplay->getType(&displayType);
    RETURN_IF_HWC_ERROR_FOR("getType", error, displayId);

    // If this was a virtual display, add its slot back for reuse by future
    // virtual displays
    if (displayType == HWC2::DisplayType::Virtual) {
    if (displayData.isVirtual) {
        mFreeDisplaySlots.insert(displayId);
        ++mRemainingHwcVirtualDisplays;
    }
@@ -725,18 +717,14 @@ void HWComposer::disconnectDisplay(int displayId) {
status_t HWComposer::setOutputBuffer(int32_t displayId,
        const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {
    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
    const auto& displayData = mDisplayData[displayId];

    auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
    auto displayType = HWC2::DisplayType::Invalid;
    auto error = hwcDisplay->getType(&displayType);
    RETURN_IF_HWC_ERROR_FOR("getType", error, displayId, NAME_NOT_FOUND);

    if (displayType != HWC2::DisplayType::Virtual) {
    if (!displayData.isVirtual) {
        LOG_DISPLAY_ERROR(displayId, "Invalid operation on physical display");
        return INVALID_OPERATION;
    }

    error = hwcDisplay->setOutputBuffer(buffer, acquireFence);
    auto error = displayData.hwcDisplay->setOutputBuffer(buffer, acquireFence);
    RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
    return NO_ERROR;
}
+1 −2
Original line number Diff line number Diff line
@@ -188,14 +188,13 @@ private:
    // For unit tests
    friend TestableSurfaceFlinger;

    static const int32_t VIRTUAL_DISPLAY_ID_BASE = 2;

    bool isValidDisplay(int32_t displayId) const;
    static void validateChange(HWC2::Composition from, HWC2::Composition to);

    struct cb_context;

    struct DisplayData {
        bool isVirtual = false;
        bool hasClientComposition = false;
        bool hasDeviceComposition = false;
        HWC2::Display* hwcDisplay = nullptr;