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

Commit 23b867a4 authored by Dominik Laskowski's avatar Dominik Laskowski
Browse files

SF: Remove fixed-size array for VSYNC events

EventThread maintains two DisplayEventReceiver::Event instances to store
the latest VSYNC state for the internal and external displays, regardless
of their connection status. This CL removes the (unused) latter instance,
replaces the former with VSyncState, and generalizes event processing by
queuing up VSYNC events along with hotplug events.

The VSyncState lifetime will be tied to hotplug events in a future CL.

Bug: 74619554
Test: libsurfaceflinger_unittest
Test: dumpsys SurfaceFlinger --vsync
Change-Id: I5fbc1d08259145387dab73596a0cfe4624c35676
parent d9e4de63
Loading
Loading
Loading
Loading
+37 −49
Original line number Original line Diff line number Diff line
@@ -79,6 +79,20 @@ std::string toString(const DisplayEventReceiver::Event& event) {
    }
    }
}
}


DisplayEventReceiver::Event makeHotplug(uint32_t displayId, nsecs_t timestamp, bool connected) {
    DisplayEventReceiver::Event event;
    event.header = {DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, displayId, timestamp};
    event.hotplug.connected = connected;
    return event;
}

DisplayEventReceiver::Event makeVSync(uint32_t displayId, nsecs_t timestamp, uint32_t count) {
    DisplayEventReceiver::Event event;
    event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp};
    event.vsync.count = count;
    return event;
}

} // namespace
} // namespace


EventThreadConnection::EventThreadConnection(EventThread* eventThread,
EventThreadConnection::EventThreadConnection(EventThread* eventThread,
@@ -149,12 +163,6 @@ EventThread::EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSr
    if (src == nullptr) {
    if (src == nullptr) {
        mVSyncSource = mVSyncSourceUnique.get();
        mVSyncSource = mVSyncSourceUnique.get();
    }
    }
    for (auto& event : mVSyncEvent) {
        event.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
        event.header.id = 0;
        event.header.timestamp = 0;
        event.vsync.count = 0;
    }


    mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {
    mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {
        std::unique_lock<std::mutex> lock(mMutex);
        std::unique_lock<std::mutex> lock(mMutex);
@@ -253,41 +261,32 @@ void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection,


void EventThread::onScreenReleased() {
void EventThread::onScreenReleased() {
    std::lock_guard<std::mutex> lock(mMutex);
    std::lock_guard<std::mutex> lock(mMutex);
    if (!mUseSoftwareVSync) {
    if (!mVSyncState.synthetic) {
        // disable reliance on h/w vsync
        mVSyncState.synthetic = true;
        mUseSoftwareVSync = true;
        mCondition.notify_all();
        mCondition.notify_all();
    }
    }
}
}


void EventThread::onScreenAcquired() {
void EventThread::onScreenAcquired() {
    std::lock_guard<std::mutex> lock(mMutex);
    std::lock_guard<std::mutex> lock(mMutex);
    if (mUseSoftwareVSync) {
    if (mVSyncState.synthetic) {
        // resume use of h/w vsync
        mVSyncState.synthetic = false;
        mUseSoftwareVSync = false;
        mCondition.notify_all();
        mCondition.notify_all();
    }
    }
}
}


void EventThread::onVSyncEvent(nsecs_t timestamp) {
void EventThread::onVSyncEvent(nsecs_t timestamp) {
    std::lock_guard<std::mutex> lock(mMutex);
    std::lock_guard<std::mutex> lock(mMutex);
    mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;

    mVSyncEvent[0].header.id = 0;
    mPendingEvents.push_back(makeVSync(mVSyncState.displayId, timestamp, ++mVSyncState.count));
    mVSyncEvent[0].header.timestamp = timestamp;
    mVSyncEvent[0].vsync.count++;
    mCondition.notify_all();
    mCondition.notify_all();
}
}


void EventThread::onHotplugReceived(DisplayType displayType, bool connected) {
void EventThread::onHotplugReceived(DisplayType displayType, bool connected) {
    std::lock_guard<std::mutex> lock(mMutex);
    std::lock_guard<std::mutex> lock(mMutex);


    DisplayEventReceiver::Event event;
    const uint32_t displayId = displayType == DisplayType::Primary ? 0 : 1;
    event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG;
    mPendingEvents.push_back(makeHotplug(displayId, systemTime(), connected));
    event.header.id = displayType == DisplayType::Primary ? 0 : 1;
    event.header.timestamp = systemTime();
    event.hotplug.connected = connected;

    mPendingEvents.push_back(event);
    mCondition.notify_all();
    mCondition.notify_all();
}
}


@@ -301,19 +300,14 @@ void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
        if (!mPendingEvents.empty()) {
        if (!mPendingEvents.empty()) {
            event = mPendingEvents.front();
            event = mPendingEvents.front();
            mPendingEvents.pop_front();
            mPendingEvents.pop_front();
        } else {
        }
            for (auto& vsyncEvent : mVSyncEvent) {

                if (vsyncEvent.header.timestamp) {
        const bool vsyncPending =
                    event = vsyncEvent;
                event && event->header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
                    vsyncEvent.header.timestamp = 0;


                    if (mInterceptVSyncsCallback) {
        if (mInterceptVSyncsCallback && vsyncPending) {
            mInterceptVSyncsCallback(event->header.timestamp);
            mInterceptVSyncsCallback(event->header.timestamp);
        }
        }
                    break;
                }
            }
        }


        bool vsyncRequested = false;
        bool vsyncRequested = false;


@@ -338,9 +332,6 @@ void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
            consumers.clear();
            consumers.clear();
        }
        }


        const bool vsyncPending =
                event && event->header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC;

        // Here we figure out if we need to enable or disable vsyncs
        // Here we figure out if we need to enable or disable vsyncs
        if (vsyncPending && !vsyncRequested) {
        if (vsyncPending && !vsyncRequested) {
            // we received a VSYNC but we have no clients
            // we received a VSYNC but we have no clients
@@ -364,15 +355,13 @@ void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
        if (vsyncRequested) {
        if (vsyncRequested) {
            // Generate a fake VSYNC after a long timeout in case the driver stalls. When the
            // Generate a fake VSYNC after a long timeout in case the driver stalls. When the
            // display is off, keep feeding clients at 60 Hz.
            // display is off, keep feeding clients at 60 Hz.
            const bool softwareSync = mUseSoftwareVSync;
            const auto timeout = mVSyncState.synthetic ? 16ms : 1000ms;
            const auto timeout = softwareSync ? 16ms : 1000ms;
            if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
            if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
                ALOGW_IF(!softwareSync, "Faking VSYNC due to driver stall");
                ALOGW_IF(!mVSyncState.synthetic, "Faking VSYNC due to driver stall");


                mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
                mPendingEvents.push_back(makeVSync(mVSyncState.displayId,
                mVSyncEvent[0].header.id = 0;
                                                   systemTime(SYSTEM_TIME_MONOTONIC),
                mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
                                                   ++mVSyncState.count));
                mVSyncEvent[0].vsync.count++;
            }
            }
        } else {
        } else {
            mCondition.wait(lock);
            mCondition.wait(lock);
@@ -425,8 +414,7 @@ void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
}
}


void EventThread::enableVSyncLocked() {
void EventThread::enableVSyncLocked() {
    if (!mUseSoftwareVSync) {
    if (!mVSyncState.synthetic) {
        // never enable h/w VSYNC when screen is off
        if (!mVsyncEnabled) {
        if (!mVsyncEnabled) {
            mVsyncEnabled = true;
            mVsyncEnabled = true;
            mVSyncSource->setCallback(this);
            mVSyncSource->setCallback(this);
@@ -448,8 +436,8 @@ void EventThread::dump(std::string& result) const {
    std::lock_guard<std::mutex> lock(mMutex);
    std::lock_guard<std::mutex> lock(mMutex);


    StringAppendF(&result, "%s: VSYNC %s\n", mThreadName, mDebugVsyncEnabled ? "on" : "off");
    StringAppendF(&result, "%s: VSYNC %s\n", mThreadName, mDebugVsyncEnabled ? "on" : "off");
    StringAppendF(&result, "  software VSYNC: %s\n", mUseSoftwareVSync ? "on" : "off");
    StringAppendF(&result, "  VSyncState{displayId=%u, count=%u%s}\n", mVSyncState.displayId,
    StringAppendF(&result, "  VSYNC count: %u\n", mVSyncEvent[0].vsync.count);
                  mVSyncState.count, mVSyncState.synthetic ? ", synthetic" : "");


    StringAppendF(&result, "  pending events (count=%zu):\n", mPendingEvents.size());
    StringAppendF(&result, "  pending events (count=%zu):\n", mPendingEvents.size());
    for (const auto& event : mPendingEvents) {
    for (const auto& event : mPendingEvents) {
+14 −3
Original line number Original line Diff line number Diff line
@@ -18,7 +18,6 @@


#include <sys/types.h>
#include <sys/types.h>


#include <array>
#include <condition_variable>
#include <condition_variable>
#include <cstdint>
#include <cstdint>
#include <deque>
#include <deque>
@@ -199,8 +198,20 @@ private:


    std::vector<wp<EventThreadConnection>> mDisplayEventConnections GUARDED_BY(mMutex);
    std::vector<wp<EventThreadConnection>> mDisplayEventConnections GUARDED_BY(mMutex);
    std::deque<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
    std::deque<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
    std::array<DisplayEventReceiver::Event, 2> mVSyncEvent GUARDED_BY(mMutex);

    bool mUseSoftwareVSync GUARDED_BY(mMutex) = false;
    // VSYNC state of connected display.
    struct VSyncState {
        uint32_t displayId = 0;

        // Number of VSYNC events since display was connected.
        uint32_t count = 0;

        // True if VSYNC should be faked, e.g. when display is off.
        bool synthetic = false;
    };

    VSyncState mVSyncState GUARDED_BY(mMutex);

    bool mVsyncEnabled GUARDED_BY(mMutex) = false;
    bool mVsyncEnabled GUARDED_BY(mMutex) = false;
    bool mKeepRunning GUARDED_BY(mMutex) = true;
    bool mKeepRunning GUARDED_BY(mMutex) = true;