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

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

SF: Introduce a configure stage

Decouple hotplug processing from commit of display transactions, as a
step toward per-display commit/composite. The configure stage will be
responsible for mode setting as well.

Bug: 241285876
Test: libsurfaceflinger_unittest
Change-Id: I72b7223760fa5896debb046f158845a0b4f4599a
parent add53b16
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -158,6 +158,19 @@ void MessageQueue::postMessage(sp<MessageHandler>&& handler) {
    mLooper->sendMessage(handler, Message());
}

void MessageQueue::scheduleConfigure() {
    struct ConfigureHandler : MessageHandler {
        explicit ConfigureHandler(ICompositor& compositor) : compositor(compositor) {}

        void handleMessage(const Message&) override { compositor.configure(); }

        ICompositor& compositor;
    };

    // TODO(b/241285876): Batch configure tasks that happen within some duration.
    postMessage(sp<ConfigureHandler>::make(mCompositor));
}

void MessageQueue::scheduleFrame() {
    ATRACE_CALL();

+3 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
namespace android {

struct ICompositor {
    virtual void configure() = 0;
    virtual bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) = 0;
    virtual void composite(TimePoint frameTime, VsyncId) = 0;
    virtual void sample() = 0;
@@ -78,6 +79,7 @@ public:
    virtual void setInjector(sp<EventThreadConnection>) = 0;
    virtual void waitMessage() = 0;
    virtual void postMessage(sp<MessageHandler>&&) = 0;
    virtual void scheduleConfigure() = 0;
    virtual void scheduleFrame() = 0;

    using Clock = std::chrono::steady_clock;
@@ -152,6 +154,7 @@ public:
    void waitMessage() override;
    void postMessage(sp<MessageHandler>&&) override;

    void scheduleConfigure() override;
    void scheduleFrame() override;

    std::optional<Clock::time_point> getScheduledFrameTime() const override;
+1 −0
Original line number Diff line number Diff line
@@ -116,6 +116,7 @@ public:
    using Impl::getScheduledFrameTime;
    using Impl::setDuration;

    using Impl::scheduleConfigure;
    using Impl::scheduleFrame;

    // Schedule an asynchronous or synchronous task on the main thread.
+37 −32
Original line number Diff line number Diff line
@@ -763,10 +763,10 @@ chooseRenderEngineTypeViaSysProp() {

// Do not call property_set on main thread which will be blocked by init
// Use StartPropertySetThread instead.
void SurfaceFlinger::init() {
void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) {
    ALOGI(  "SurfaceFlinger's main thread ready to run. "
            "Initializing graphics H/W...");
    Mutex::Autolock _l(mStateLock);
    Mutex::Autolock lock(mStateLock);

    // Get a RenderEngine for the given display / config (can't fail)
    // TODO(b/77156734): We need to stop casting and use HAL types when possible.
@@ -806,12 +806,14 @@ void SurfaceFlinger::init() {
    }

    // Process any initial hotplug and resulting display changes.
    processDisplayHotplugEventsLocked();
    LOG_ALWAYS_FATAL_IF(!configureLocked(),
                        "Initial display configuration failed: HWC did not hotplug");
    processDisplayChangesLocked();

    const auto display = getDefaultDisplayDeviceLocked();
    LOG_ALWAYS_FATAL_IF(!display, "Missing primary display after registering composer callback.");
    const auto displayId = display->getPhysicalId();
    LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(displayId),
                        "Primary display is disconnected.");
    LOG_ALWAYS_FATAL_IF(!display, "Failed to configure the primary display");
    LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(display->getPhysicalId()),
                        "Primary display is disconnected");

    // initialize our drawing state
    mDrawingState = mCurrentState;
@@ -1869,23 +1871,14 @@ void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t t

void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId,
                                          hal::Connection connection) {
    const bool connected = connection == hal::Connection::CONNECTED;
    ALOGI("%s HAL display %" PRIu64, connected ? "Connecting" : "Disconnecting", hwcDisplayId);

    // Only lock if we're not on the main thread. This function is normally
    // called on a hwbinder thread, but for the primary display it's called on
    // the main thread with the state lock already held, so don't attempt to
    // acquire it here.
    ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);

    mPendingHotplugEvents.emplace_back(HotplugEvent{hwcDisplayId, connection});

    if (std::this_thread::get_id() == mMainThreadId) {
        // Process all pending hot plug events immediately if we are on the main thread.
        processDisplayHotplugEventsLocked();
    {
        std::lock_guard<std::mutex> lock(mHotplugMutex);
        mPendingHotplugEvents.push_back(HotplugEvent{hwcDisplayId, connection});
    }

    setTransactionFlags(eDisplayTransactionNeeded);
    if (mScheduler) {
        mScheduler->scheduleConfigure();
    }
}

void SurfaceFlinger::onComposerHalVsyncPeriodTimingChanged(
@@ -1958,6 +1951,13 @@ TimePoint SurfaceFlinger::calculateExpectedPresentTime(TimePoint frameTime) cons
    return vsyncDeadline + schedule.period();
}

void SurfaceFlinger::configure() FTL_FAKE_GUARD(kMainThreadContext) {
    Mutex::Autolock lock(mStateLock);
    if (configureLocked()) {
        setTransactionFlags(eDisplayTransactionNeeded);
    }
}

bool SurfaceFlinger::commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime)
        FTL_FAKE_GUARD(kMainThreadContext) {
    // The expectedVsyncTime, which was predicted when this frame was scheduled, is normally in the
@@ -2642,8 +2642,14 @@ std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes(
    return {modes, activeMode};
}

void SurfaceFlinger::processDisplayHotplugEventsLocked() {
    for (const auto& event : mPendingHotplugEvents) {
bool SurfaceFlinger::configureLocked() {
    std::vector<HotplugEvent> events;
    {
        std::lock_guard<std::mutex> lock(mHotplugMutex);
        events = std::move(mPendingHotplugEvents);
    }

    for (const auto& event : events) {
        std::optional<DisplayIdentificationInfo> info =
                getHwComposer().onHotplug(event.hwcDisplayId, event.connection);

@@ -2653,6 +2659,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() {

        const auto displayId = info->id;
        const auto token = mPhysicalDisplayTokens.get(displayId);
        const char* log;

        if (event.connection == hal::Connection::CONNECTED) {
            auto [supportedModes, activeMode] = loadDisplayModes(displayId);
@@ -2664,7 +2671,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() {
            }

            if (!token) {
                ALOGV("Creating display %s", to_string(displayId).c_str());
                log = "Connecting";

                DisplayDeviceState state;
                state.physical = {.id = displayId,
@@ -2681,7 +2688,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() {
                mPhysicalDisplayTokens.try_emplace(displayId, std::move(token));
                mInterceptor->saveDisplayCreation(state);
            } else {
                ALOGV("Recreating display %s", to_string(displayId).c_str());
                log = "Reconnecting";

                auto& state = mCurrentState.displays.editValueFor(token->get());
                state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId.
@@ -2692,7 +2699,7 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() {
                }
            }
        } else {
            ALOGV("Removing display %s", to_string(displayId).c_str());
            log = "Disconnecting";

            if (const ssize_t index = mCurrentState.displays.indexOfKey(token->get()); index >= 0) {
                const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
@@ -2703,15 +2710,14 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() {
            mPhysicalDisplayTokens.erase(displayId);
        }

        processDisplayChangesLocked();
        ALOGI("%s display %s (HAL ID %" PRIu64 ")", log, to_string(displayId).c_str(),
              event.hwcDisplayId);
    }

    mPendingHotplugEvents.clear();
    return !events.empty();
}

void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) {
    ALOGI("Dispatching display hotplug event displayId=%s, connected=%d",
          to_string(displayId).c_str(), connected);
    mScheduler->onHotplugReceived(mAppConnectionHandle, displayId, connected);
    mScheduler->onHotplugReceived(mSfConnectionHandle, displayId, connected);
}
@@ -3041,7 +3047,6 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) {
    const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded;
    if (displayTransactionNeeded) {
        processDisplayChangesLocked();
        processDisplayHotplugEventsLocked();
    }
    mForceTransactionDisplayChange = displayTransactionNeeded;

+19 −10
Original line number Diff line number Diff line
@@ -432,11 +432,6 @@ private:
        FINISHED,
    };

    struct HotplugEvent {
        hal::HWDisplayId hwcDisplayId;
        hal::Connection connection = hal::Connection::INVALID;
    };

    template <typename F, std::enable_if_t<!std::is_member_function_pointer_v<F>>* = nullptr>
    static Dumper dumper(F&& dump) {
        using namespace std::placeholders;
@@ -611,6 +606,9 @@ private:

    // ICompositor overrides:

    // Configures physical displays, processing hotplug and/or mode setting via the Composer HAL.
    void configure() override;

    // Commits transactions for layers and displays. Returns whether any state has been invalidated,
    // i.e. whether a frame should be composited for each display.
    bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) override;
@@ -622,9 +620,7 @@ private:
    // Samples the composited frame via RegionSamplingThread.
    void sample() override;

    /*
     * ISchedulerCallback
     */
    // ISchedulerCallback overrides:

    // Toggles hardware VSYNC by calling into HWC.
    void setVsyncEnabled(bool) override;
@@ -634,6 +630,7 @@ private:
    void kernelTimerChanged(bool expired) override;
    // Called when the frame rate override list changed to trigger an event.
    void triggerOnFrameRateOverridesChanged() override;

    // Toggles the kernel idle timer on or off depending the policy decisions around refresh rates.
    void toggleKernelIdleTimer() REQUIRES(mStateLock);
    // Get the controller and timeout that will help decide how the kernel idle timer will be
@@ -911,6 +908,13 @@ private:
    std::pair<DisplayModes, DisplayModePtr> loadDisplayModes(PhysicalDisplayId) const
            REQUIRES(mStateLock);

    // TODO(b/241285876): Move to DisplayConfigurator.
    //
    // Returns whether displays have been added/changed/removed, i.e. whether ICompositor should
    // commit display transactions.
    bool configureLocked() REQUIRES(mStateLock) REQUIRES(kMainThreadContext)
            EXCLUDES(mHotplugMutex);

    sp<DisplayDevice> setupNewDisplayDeviceInternal(
            const wp<IBinder>& displayToken,
            std::shared_ptr<compositionengine::Display> compositionDisplay,
@@ -922,7 +926,6 @@ private:
    void processDisplayChanged(const wp<IBinder>& displayToken,
                               const DisplayDeviceState& currentState,
                               const DisplayDeviceState& drawingState) REQUIRES(mStateLock);
    void processDisplayHotplugEventsLocked() REQUIRES(mStateLock);

    void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected);

@@ -1145,7 +1148,13 @@ private:

    BootStage mBootStage = BootStage::BOOTLOADER;

    std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mStateLock);
    struct HotplugEvent {
        hal::HWDisplayId hwcDisplayId;
        hal::Connection connection = hal::Connection::INVALID;
    };

    std::mutex mHotplugMutex;
    std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mHotplugMutex);

    // Displays are composited in `mDisplays` order. Internal displays are inserted at boot and
    // never removed, so take precedence over external and virtual displays.
Loading