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

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

SF: Refactor event dispatch

This CL refactors the EventThread loop to simplify control flow, remove
redundant state, avoid gratuitous allocation, and improve readability.

It also adds a dumpsys flag for VSYNC information.

Bug: 74619554
Test: libsurfaceflinger_unittest
Test: dumpsys SurfaceFlinger --vsync
Change-Id: I2d875349031ae2869fb370a8a090c71b0e181482
parent c2867147
Loading
Loading
Loading
Loading
+177 −159
Original line number Original line Diff line number Diff line
@@ -19,8 +19,11 @@
#include <pthread.h>
#include <pthread.h>
#include <sched.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/types.h>

#include <chrono>
#include <chrono>
#include <cstdint>
#include <cstdint>
#include <optional>
#include <type_traits>


#include <android-base/stringprintf.h>
#include <android-base/stringprintf.h>


@@ -35,18 +38,52 @@
#include "EventThread.h"
#include "EventThread.h"


using namespace std::chrono_literals;
using namespace std::chrono_literals;
using android::base::StringAppendF;

// ---------------------------------------------------------------------------


namespace android {
namespace android {


// ---------------------------------------------------------------------------
using base::StringAppendF;
using base::StringPrintf;

namespace {

auto vsyncPeriod(VSyncRequest request) {
    return static_cast<std::underlying_type_t<VSyncRequest>>(request);
}

std::string toString(VSyncRequest request) {
    switch (request) {
        case VSyncRequest::None:
            return "VSyncRequest::None";
        case VSyncRequest::Single:
            return "VSyncRequest::Single";
        default:
            return StringPrintf("VSyncRequest::Periodic{period=%d}", vsyncPeriod(request));
    }
}

std::string toString(const EventThreadConnection& connection) {
    return StringPrintf("Connection{%p, %s}", &connection,
                        toString(connection.vsyncRequest).c_str());
}

std::string toString(const DisplayEventReceiver::Event& event) {
    switch (event.header.type) {
        case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
            return StringPrintf("Hotplug{displayId=%u, %s}", event.header.id,
                                event.hotplug.connected ? "connected" : "disconnected");
        case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
            return StringPrintf("VSync{displayId=%u, count=%u}", event.header.id,
                                event.vsync.count);
        default:
            return "Event{}";
    }
}

} // namespace


EventThreadConnection::EventThreadConnection(EventThread* eventThread,
EventThreadConnection::EventThreadConnection(EventThread* eventThread,
                                             ResyncCallback resyncCallback)
                                             ResyncCallback resyncCallback)
      : resyncCallback(std::move(resyncCallback)),
      : resyncCallback(std::move(resyncCallback)),
        count(-1),
        mEventThread(eventThread),
        mEventThread(eventThread),
        mChannel(gui::BitTube::DefaultSize) {}
        mChannel(gui::BitTube::DefaultSize) {}


@@ -65,8 +102,8 @@ status_t EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) {
    return NO_ERROR;
    return NO_ERROR;
}
}


status_t EventThreadConnection::setVsyncRate(uint32_t count) {
status_t EventThreadConnection::setVsyncRate(uint32_t rate) {
    mEventThread->setVsyncRate(count, this);
    mEventThread->setVsyncRate(rate, this);
    return NO_ERROR;
    return NO_ERROR;
}
}


@@ -107,7 +144,8 @@ EventThread::EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSr
                         InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
                         InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
      : mVSyncSource(src),
      : mVSyncSource(src),
        mVSyncSourceUnique(std::move(uniqueSrc)),
        mVSyncSourceUnique(std::move(uniqueSrc)),
        mInterceptVSyncsCallback(interceptVSyncsCallback) {
        mInterceptVSyncsCallback(interceptVSyncsCallback),
        mThreadName(threadName) {
    if (src == nullptr) {
    if (src == nullptr) {
        mVSyncSource = mVSyncSourceUnique.get();
        mVSyncSource = mVSyncSourceUnique.get();
    }
    }
@@ -118,7 +156,10 @@ EventThread::EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSr
        event.vsync.count = 0;
        event.vsync.count = 0;
    }
    }


    mThread = std::thread(&EventThread::threadMain, this);
    mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {
        std::unique_lock<std::mutex> lock(mMutex);
        threadMain(lock);
    });


    pthread_setname_np(mThread.native_handle(), threadName);
    pthread_setname_np(mThread.native_handle(), threadName);


@@ -178,16 +219,19 @@ void EventThread::removeDisplayEventConnectionLocked(const wp<EventThreadConnect
    }
    }
}
}


void EventThread::setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) {
void EventThread::setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) {
    if (int32_t(count) >= 0) { // server must protect against bad params
    if (static_cast<std::underlying_type_t<VSyncRequest>>(rate) < 0) {
        return;
    }

    std::lock_guard<std::mutex> lock(mMutex);
    std::lock_guard<std::mutex> lock(mMutex);
        const int32_t new_count = (count == 0) ? -1 : count;

        if (connection->count != new_count) {
    const auto request = rate == 0 ? VSyncRequest::None : static_cast<VSyncRequest>(rate);
            connection->count = new_count;
    if (connection->vsyncRequest != request) {
        connection->vsyncRequest = request;
        mCondition.notify_all();
        mCondition.notify_all();
    }
    }
}
}
}


void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection, bool reset) {
void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection, bool reset) {
    if (mResetIdleTimer && reset) {
    if (mResetIdleTimer && reset) {
@@ -201,8 +245,8 @@ void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection,


    std::lock_guard<std::mutex> lock(mMutex);
    std::lock_guard<std::mutex> lock(mMutex);


    if (connection->count < 0) {
    if (connection->vsyncRequest == VSyncRequest::None) {
        connection->count = 0;
        connection->vsyncRequest = VSyncRequest::Single;
        mCondition.notify_all();
        mCondition.notify_all();
    }
    }
}
}
@@ -243,122 +287,66 @@ void EventThread::onHotplugReceived(DisplayType displayType, bool connected) {
    event.header.timestamp = systemTime();
    event.header.timestamp = systemTime();
    event.hotplug.connected = connected;
    event.hotplug.connected = connected;


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


void EventThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
    std::unique_lock<std::mutex> lock(mMutex);
    DisplayEventConsumers consumers;

    while (mKeepRunning) {
    while (mKeepRunning) {
        DisplayEventReceiver::Event event;
        std::optional<DisplayEventReceiver::Event> event;
        std::vector<sp<EventThreadConnection>> signalConnections;

        signalConnections = waitForEventLocked(&lock, &event);
        // Determine next event to dispatch.

        if (!mPendingEvents.empty()) {
        // dispatch events to listeners...
            event = mPendingEvents.front();
        for (const sp<EventThreadConnection>& conn : signalConnections) {
            mPendingEvents.pop_front();
            // now see if we still need to report this event
        } else {
            status_t err = conn->postEvent(event);
            for (auto& vsyncEvent : mVSyncEvent) {
            if (err == -EAGAIN || err == -EWOULDBLOCK) {
                if (vsyncEvent.header.timestamp) {
                // The destination doesn't accept events anymore, it's probably
                    event = vsyncEvent;
                // full. For now, we just drop the events on the floor.
                    vsyncEvent.header.timestamp = 0;
                // FIXME: Note that some events cannot be dropped and would have

                // to be re-sent later.
                // Right-now we don't have the ability to do this.
                ALOGW("EventThread: dropping event (%08x) for connection %p", event.header.type,
                      conn.get());
            } else if (err < 0) {
                // handle any other error on the pipe as fatal. the only
                // reasonable thing to do is to clean-up this connection.
                // The most common error we'll get here is -EPIPE.
                removeDisplayEventConnectionLocked(conn);
            }
        }
    }
}

// This will return when (1) a vsync event has been received, and (2) there was
// at least one connection interested in receiving it when we started waiting.
std::vector<sp<EventThreadConnection>> EventThread::waitForEventLocked(
        std::unique_lock<std::mutex>* lock, DisplayEventReceiver::Event* outEvent) {
    std::vector<sp<EventThreadConnection>> signalConnections;

    while (signalConnections.empty() && mKeepRunning) {
        bool eventPending = false;
        bool waitForVSync = false;

        size_t vsyncCount = 0;
        nsecs_t timestamp = 0;
        for (auto& event : mVSyncEvent) {
            timestamp = event.header.timestamp;
            if (timestamp) {
                // we have a vsync event to dispatch
                    if (mInterceptVSyncsCallback) {
                    if (mInterceptVSyncsCallback) {
                    mInterceptVSyncsCallback(timestamp);
                        mInterceptVSyncsCallback(event->header.timestamp);
                    }
                    }
                *outEvent = event;
                event.header.timestamp = 0;
                vsyncCount = event.vsync.count;
                    break;
                    break;
                }
                }
            }
            }

        if (!timestamp) {
            // no vsync event, see if there are some other event
            eventPending = !mPendingEvents.empty();
            if (eventPending) {
                // we have some other event to dispatch
                *outEvent = mPendingEvents.front();
                mPendingEvents.pop();
            }
        }
        }


        // find out connections waiting for events
        bool vsyncRequested = false;

        // Find connections that should consume this event.
        auto it = mDisplayEventConnections.begin();
        auto it = mDisplayEventConnections.begin();
        while (it != mDisplayEventConnections.end()) {
        while (it != mDisplayEventConnections.end()) {
            sp<EventThreadConnection> connection(it->promote());
            if (const auto connection = it->promote()) {
            if (connection != nullptr) {
                vsyncRequested |= connection->vsyncRequest != VSyncRequest::None;
                bool added = false;

                if (connection->count >= 0) {
                if (event && shouldConsumeEvent(*event, connection)) {
                    // we need vsync events because at least
                    consumers.push_back(connection);
                    // one connection is waiting for it
                    waitForVSync = true;
                    if (timestamp) {
                        // we consume the event only if it's time
                        // (ie: we received a vsync event)
                        if (connection->count == 0) {
                            // fired this time around
                            connection->count = -1;
                            signalConnections.push_back(connection);
                            added = true;
                        } else if (connection->count == 1 ||
                                   (vsyncCount % connection->count) == 0) {
                            // continuous event, and time to report it
                            signalConnections.push_back(connection);
                            added = true;
                        }
                    }
                }

                if (eventPending && !timestamp && !added) {
                    // we don't have a vsync event to process
                    // (timestamp==0), but we have some pending
                    // messages.
                    signalConnections.push_back(connection);
                }
                }

                ++it;
                ++it;
            } else {
            } else {
                // we couldn't promote this reference, the connection has
                // died, so clean-up!
                it = mDisplayEventConnections.erase(it);
                it = mDisplayEventConnections.erase(it);
            }
            }
        }
        }


        if (!consumers.empty()) {
            dispatchEvent(*event, consumers);
            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 (timestamp && !waitForVSync) {
        if (vsyncPending && !vsyncRequested) {
            // we received a VSYNC but we have no clients
            // we received a VSYNC but we have no clients
            // don't report it, and disable VSYNC events
            // don't report it, and disable VSYNC events
            disableVSyncLocked();
            disableVSyncLocked();
        } else if (!timestamp && waitForVSync) {
        } else if (!vsyncPending && vsyncRequested) {
            // we have at least one client, so we want vsync enabled
            // we have at least one client, so we want vsync enabled
            // (TODO: this function is called right after we finish
            // (TODO: this function is called right after we finish
            // notifying clients of a vsync, so this call will be made
            // notifying clients of a vsync, so this call will be made
@@ -368,48 +356,72 @@ std::vector<sp<EventThreadConnection>> EventThread::waitForEventLocked(
            enableVSyncLocked();
            enableVSyncLocked();
        }
        }


        // note: !timestamp implies signalConnections.isEmpty(), because we
        if (event) {
        // don't populate signalConnections if there's no vsync pending
            continue;
        if (!timestamp && !eventPending) {
        }
            // wait for something to happen

            if (waitForVSync) {
        // Wait for event or client registration/request.
                // This is where we spend most of our time, waiting
        if (vsyncRequested) {
                // for vsync events and new client registrations.
            // Generate a fake VSYNC after a long timeout in case the driver stalls. When the
                //
            // display is off, keep feeding clients at 60 Hz.
                // If the screen is off, we can't use h/w vsync, so we
            const bool softwareSync = mUseSoftwareVSync;
                // use a 16ms timeout instead.  It doesn't need to be
            const auto timeout = softwareSync ? 16ms : 1000ms;
                // precise, we just need to keep feeding our clients.
            if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
                //
                ALOGW_IF(!softwareSync, "Faking VSYNC due to driver stall");
                // We don't want to stall if there's a driver bug, so we

                // use a (long) timeout when waiting for h/w vsync, and
                // generate fake events when necessary.
                bool softwareSync = mUseSoftwareVSync;
                auto timeout = softwareSync ? 16ms : 1000ms;
                if (mCondition.wait_for(*lock, timeout) == std::cv_status::timeout) {
                    if (!softwareSync) {
                        ALOGW("Timed out waiting for hw vsync; faking it");
                    }
                    // FIXME: how do we decide which display id the fake
                    // vsync came from ?
                mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
                mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
                mVSyncEvent[0].header.id = 0;
                mVSyncEvent[0].header.id = 0;
                mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
                mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
                mVSyncEvent[0].vsync.count++;
                mVSyncEvent[0].vsync.count++;
            }
            }
        } else {
        } else {
                // Nobody is interested in vsync, so we just want to sleep.
            mCondition.wait(lock);
                // h/w vsync should be disabled, so this will wait until we
                // get a new connection, or an existing connection becomes
                // interested in receiving vsync again.
                mCondition.wait(*lock);
        }
        }
    }
    }
}
}


    // here we're guaranteed to have a timestamp and some connections to signal
bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event,
    // (The connections might have dropped out of mDisplayEventConnections
                                     const sp<EventThreadConnection>& connection) const {
    // while we were asleep, but we'll still have strong references to them.)
    switch (event.header.type) {
    return signalConnections;
        case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
            return true;

        case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
            switch (connection->vsyncRequest) {
                case VSyncRequest::None:
                    return false;
                case VSyncRequest::Single:
                    connection->vsyncRequest = VSyncRequest::None;
                    return true;
                case VSyncRequest::Periodic:
                    return true;
                default:
                    return event.vsync.count % vsyncPeriod(connection->vsyncRequest) == 0;
            }

        default:
            return false;
    }
}

void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event,
                                const DisplayEventConsumers& consumers) {
    for (const auto& consumer : consumers) {
        switch (consumer->postEvent(event)) {
            case NO_ERROR:
                break;

            case -EAGAIN:
                // TODO: Try again if pipe is full.
                ALOGW("Failed dispatching %s for %s", toString(event).c_str(),
                      toString(*consumer).c_str());
                break;

            default:
                // Treat EPIPE and other errors as fatal.
                removeDisplayEventConnectionLocked(consumer);
        }
    }
}
}


void EventThread::enableVSyncLocked() {
void EventThread::enableVSyncLocked() {
@@ -434,16 +446,22 @@ void EventThread::disableVSyncLocked() {


void EventThread::dump(std::string& result) const {
void EventThread::dump(std::string& result) const {
    std::lock_guard<std::mutex> lock(mMutex);
    std::lock_guard<std::mutex> lock(mMutex);
    StringAppendF(&result, "VSYNC state: %s\n", mDebugVsyncEnabled ? "enabled" : "disabled");

    StringAppendF(&result, "  soft-vsync: %s\n", mUseSoftwareVSync ? "enabled" : "disabled");
    StringAppendF(&result, "%s: VSYNC %s\n", mThreadName, mDebugVsyncEnabled ? "on" : "off");
    StringAppendF(&result, "  numListeners=%zu,\n  events-delivered: %u\n",
    StringAppendF(&result, "  software VSYNC: %s\n", mUseSoftwareVSync ? "on" : "off");
                  mDisplayEventConnections.size(), mVSyncEvent[0].vsync.count);
    StringAppendF(&result, "  VSYNC count: %u\n", mVSyncEvent[0].vsync.count);
    for (const wp<EventThreadConnection>& weak : mDisplayEventConnections) {

        sp<EventThreadConnection> connection = weak.promote();
    StringAppendF(&result, "  pending events (count=%zu):\n", mPendingEvents.size());
        StringAppendF(&result, "    %p: count=%d\n", connection.get(),
    for (const auto& event : mPendingEvents) {
                      connection != nullptr ? connection->count : 0);
        StringAppendF(&result, "    %s\n", toString(event).c_str());
    }
    }
    StringAppendF(&result, "  other-events-pending: %zu\n", mPendingEvents.size());

    StringAppendF(&result, "  connections (count=%zu):\n", mDisplayEventConnections.size());
    for (const auto& ptr : mDisplayEventConnections) {
        if (const auto connection = ptr.promote()) {
            StringAppendF(&result, "    %s\n", toString(*connection).c_str());
        }
    }
}
}


} // namespace impl
} // namespace impl
+23 −15
Original line number Original line Diff line number Diff line
@@ -21,8 +21,8 @@
#include <array>
#include <array>
#include <condition_variable>
#include <condition_variable>
#include <cstdint>
#include <cstdint>
#include <deque>
#include <mutex>
#include <mutex>
#include <queue>
#include <thread>
#include <thread>
#include <vector>
#include <vector>


@@ -46,6 +46,13 @@ class SurfaceFlinger;


using ResyncCallback = std::function<void()>;
using ResyncCallback = std::function<void()>;


enum class VSyncRequest {
    None = -1,
    Single = 0,
    Periodic = 1,
    // Subsequent values are periods.
};

class VSyncSource {
class VSyncSource {
public:
public:
    class Callback {
    class Callback {
@@ -68,7 +75,7 @@ public:
    virtual status_t postEvent(const DisplayEventReceiver::Event& event);
    virtual status_t postEvent(const DisplayEventReceiver::Event& event);


    status_t stealReceiveChannel(gui::BitTube* outChannel) override;
    status_t stealReceiveChannel(gui::BitTube* outChannel) override;
    status_t setVsyncRate(uint32_t count) override;
    status_t setVsyncRate(uint32_t rate) override;
    void requestNextVsync() override; // asynchronous
    void requestNextVsync() override; // asynchronous
    // Requesting Vsync for HWC does not reset the idle timer, since HWC requires a refresh
    // Requesting Vsync for HWC does not reset the idle timer, since HWC requires a refresh
    // in order to update the configs.
    // in order to update the configs.
@@ -77,10 +84,7 @@ public:
    // Called in response to requestNextVsync.
    // Called in response to requestNextVsync.
    const ResyncCallback resyncCallback;
    const ResyncCallback resyncCallback;


    // count >= 1 : continuous event. count is the vsync rate
    VSyncRequest vsyncRequest = VSyncRequest::None;
    // count == 0 : one-shot event that has not fired
    // count ==-1 : one-shot event that fired this round / disabled
    int32_t count;


private:
private:
    virtual void onFirstRef();
    virtual void onFirstRef();
@@ -113,7 +117,7 @@ public:


    virtual status_t registerDisplayEventConnection(
    virtual status_t registerDisplayEventConnection(
            const sp<EventThreadConnection>& connection) = 0;
            const sp<EventThreadConnection>& connection) = 0;
    virtual void setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) = 0;
    virtual void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) = 0;
    // Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer.
    // Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer.
    virtual void requestNextVsync(const sp<EventThreadConnection>& connection,
    virtual void requestNextVsync(const sp<EventThreadConnection>& connection,
                                  bool resetIdleTimer) = 0;
                                  bool resetIdleTimer) = 0;
@@ -137,7 +141,7 @@ public:
    sp<EventThreadConnection> createEventConnection(ResyncCallback resyncCallback) const override;
    sp<EventThreadConnection> createEventConnection(ResyncCallback resyncCallback) const override;


    status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
    status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
    void setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) override;
    void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
    void requestNextVsync(const sp<EventThreadConnection>& connection,
    void requestNextVsync(const sp<EventThreadConnection>& connection,
                          bool resetIdleTimer) override;
                          bool resetIdleTimer) override;


@@ -157,18 +161,22 @@ public:
private:
private:
    friend EventThreadTest;
    friend EventThreadTest;


    using DisplayEventConsumers = std::vector<sp<EventThreadConnection>>;

    // TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
    // TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
    EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
    EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
                InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
                InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);


    void threadMain(std::unique_lock<std::mutex>& lock) REQUIRES(mMutex);


    void threadMain();
    bool shouldConsumeEvent(const DisplayEventReceiver::Event& event,
    std::vector<sp<EventThreadConnection>> waitForEventLocked(std::unique_lock<std::mutex>* lock,
                            const sp<EventThreadConnection>& connection) const REQUIRES(mMutex);
                                                              DisplayEventReceiver::Event* event)
    void dispatchEvent(const DisplayEventReceiver::Event& event,
            REQUIRES(mMutex);
                       const DisplayEventConsumers& consumers) REQUIRES(mMutex);


    void removeDisplayEventConnectionLocked(const wp<EventThreadConnection>& connection)
    void removeDisplayEventConnectionLocked(const wp<EventThreadConnection>& connection)
            REQUIRES(mMutex);
            REQUIRES(mMutex);

    void enableVSyncLocked() REQUIRES(mMutex);
    void enableVSyncLocked() REQUIRES(mMutex);
    void disableVSyncLocked() REQUIRES(mMutex);
    void disableVSyncLocked() REQUIRES(mMutex);


@@ -181,16 +189,16 @@ private:
    // TODO(b/113612090): Once the Scheduler is complete this pointer will become obsolete.
    // TODO(b/113612090): Once the Scheduler is complete this pointer will become obsolete.
    VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr;
    VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr;
    std::unique_ptr<VSyncSource> mVSyncSourceUnique GUARDED_BY(mMutex) = nullptr;
    std::unique_ptr<VSyncSource> mVSyncSourceUnique GUARDED_BY(mMutex) = nullptr;
    // constants

    const InterceptVSyncsCallback mInterceptVSyncsCallback;
    const InterceptVSyncsCallback mInterceptVSyncsCallback;
    const char* const mThreadName;


    std::thread mThread;
    std::thread mThread;
    mutable std::mutex mMutex;
    mutable std::mutex mMutex;
    mutable std::condition_variable mCondition;
    mutable std::condition_variable mCondition;


    // protected by mLock
    std::vector<wp<EventThreadConnection>> mDisplayEventConnections GUARDED_BY(mMutex);
    std::vector<wp<EventThreadConnection>> mDisplayEventConnections GUARDED_BY(mMutex);
    std::queue<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
    std::deque<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
    std::array<DisplayEventReceiver::Event, 2> mVSyncEvent GUARDED_BY(mMutex);
    std::array<DisplayEventReceiver::Event, 2> mVSyncEvent GUARDED_BY(mMutex);
    bool mUseSoftwareVSync GUARDED_BY(mMutex) = false;
    bool mUseSoftwareVSync GUARDED_BY(mMutex) = false;
    bool mVsyncEnabled GUARDED_BY(mMutex) = false;
    bool mVsyncEnabled GUARDED_BY(mMutex) = false;
+25 −28
Original line number Original line Diff line number Diff line
@@ -4386,6 +4386,7 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args,
                {"--list"s, dumper(&SurfaceFlinger::listLayersLocked)},
                {"--list"s, dumper(&SurfaceFlinger::listLayersLocked)},
                {"--static-screen"s, dumper(&SurfaceFlinger::dumpStaticScreenStats)},
                {"--static-screen"s, dumper(&SurfaceFlinger::dumpStaticScreenStats)},
                {"--timestats"s, protoDumper(&SurfaceFlinger::dumpTimeStats)},
                {"--timestats"s, protoDumper(&SurfaceFlinger::dumpTimeStats)},
                {"--vsync"s, dumper(&SurfaceFlinger::dumpVSync)},
                {"--wide-color"s, dumper(&SurfaceFlinger::dumpWideColorInfo)},
                {"--wide-color"s, dumper(&SurfaceFlinger::dumpWideColorInfo)},
        };
        };


@@ -4469,6 +4470,26 @@ void SurfaceFlinger::appendSfConfigString(std::string& result) const {
    result.append("]");
    result.append("]");
}
}


void SurfaceFlinger::dumpVSync(std::string& result) const {
    const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
    const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
    StringAppendF(&result,
                  "         app phase: %9" PRId64 " ns\t         SF phase: %9" PRId64 " ns\n"
                  "   early app phase: %9" PRId64 " ns\t   early SF phase: %9" PRId64 " ns\n"
                  "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n"
                  "    present offset: %9" PRId64 " ns\t     VSYNC period: %9" PRId64 " ns\n\n",
                  vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, appEarlyOffset, sfEarlyOffset,
                  appEarlyGlOffset, sfEarlyGlOffset, dispSyncPresentTimeOffset, getVsyncPeriod());

    StringAppendF(&result, "Scheduler: %s\n\n", mUseScheduler ? "enabled" : "disabled");

    if (mUseScheduler) {
        mScheduler->dump(mAppConnectionHandle, result);
    } else {
        mEventThread->dump(result);
    }
}

void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const {
void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const {
    result.append("Static screen stats:\n");
    result.append("Static screen stats:\n");
    for (size_t b = 0; b < SurfaceFlingerBE::NUM_BUCKETS - 1; ++b) {
    for (size_t b = 0; b < SurfaceFlingerBE::NUM_BUCKETS - 1; ++b) {
@@ -4703,27 +4724,14 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co
    result.append("Sync configuration: ");
    result.append("Sync configuration: ");
    colorizer.reset(result);
    colorizer.reset(result);
    result.append(SyncFeatures::getInstance().toString());
    result.append(SyncFeatures::getInstance().toString());
    result.append("\n");
    result.append("\n\n");


    colorizer.bold(result);
    colorizer.bold(result);
    result.append("DispSync configuration:\n");
    result.append("VSYNC configuration:\n");
    colorizer.reset(result);
    colorizer.reset(result);

    dumpVSync(result);
    const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
    const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
    StringAppendF(&result,
                  "app phase %" PRId64 " ns, "
                  "sf phase %" PRId64 " ns, "
                  "early app phase %" PRId64 " ns, "
                  "early sf phase %" PRId64 " ns, "
                  "early app gl phase %" PRId64 " ns, "
                  "early sf gl phase %" PRId64 " ns, "
                  "present offset %" PRId64 " ns (refresh %" PRId64 " ns)\n",
                  vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, appEarlyOffset, sfEarlyOffset,
                  appEarlyGlOffset, sfEarlyGlOffset, dispSyncPresentTimeOffset, getVsyncPeriod());

    // Dump static screen stats
    result.append("\n");
    result.append("\n");

    dumpStaticScreenStats(result);
    dumpStaticScreenStats(result);
    result.append("\n");
    result.append("\n");


@@ -4797,17 +4805,6 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co


    StringAppendF(&result, "  transaction time: %f us\n", inTransactionDuration / 1000.0);
    StringAppendF(&result, "  transaction time: %f us\n", inTransactionDuration / 1000.0);


    StringAppendF(&result, "  use Scheduler: %s\n", mUseScheduler ? "true" : "false");
    /*
     * VSYNC state
     */
    if (mUseScheduler) {
        mScheduler->dump(mAppConnectionHandle, result);
    } else {
        mEventThread->dump(result);
    }
    result.append("\n");

    /*
    /*
     * Tracing state
     * Tracing state
     */
     */
+1 −0

File changed.

Preview size limit exceeded, changes collapsed.