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

Commit 6955da70 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Read from BufferReleaseChannel in background thread" into main

parents 37aae76c 5ab65e9e
Loading
Loading
Loading
Loading
+151 −10
Original line number Original line Diff line number Diff line
@@ -22,11 +22,14 @@


#include <com_android_graphics_libgui_flags.h>
#include <com_android_graphics_libgui_flags.h>
#include <cutils/atomic.h>
#include <cutils/atomic.h>
#include <ftl/fake_guard.h>
#include <gui/BLASTBufferQueue.h>
#include <gui/BLASTBufferQueue.h>
#include <gui/BufferItemConsumer.h>
#include <gui/BufferItemConsumer.h>
#include <gui/BufferQueueConsumer.h>
#include <gui/BufferQueueConsumer.h>
#include <gui/BufferQueueCore.h>
#include <gui/BufferQueueCore.h>
#include <gui/BufferQueueProducer.h>
#include <gui/BufferQueueProducer.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>


#include <gui/FrameRateUtils.h>
#include <gui/FrameRateUtils.h>
#include <gui/GLConsumer.h>
#include <gui/GLConsumer.h>
@@ -74,6 +77,12 @@ namespace android {
    std::unique_lock _lock{mutex};        \
    std::unique_lock _lock{mutex};        \
    base::ScopedLockAssertion assumeLocked(mutex);
    base::ScopedLockAssertion assumeLocked(mutex);


#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
static ReleaseBufferCallback EMPTY_RELEASE_CALLBACK =
        [](const ReleaseCallbackId&, const sp<Fence>& /*releaseFence*/,
           std::optional<uint32_t> /*currentMaxAcquiredBufferCount*/) {};
#endif

void BLASTBufferItemConsumer::onDisconnect() {
void BLASTBufferItemConsumer::onDisconnect() {
    Mutex::Autolock lock(mMutex);
    Mutex::Autolock lock(mMutex);
    mPreviouslyConnected = mCurrentlyConnected;
    mPreviouslyConnected = mCurrentlyConnected;
@@ -215,6 +224,12 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinati
            },
            },
            this);
            this);


#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
    std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> bufferReleaseConsumer;
    gui::BufferReleaseChannel::open(mName, bufferReleaseConsumer, mBufferReleaseProducer);
    mBufferReleaseReader = std::make_shared<BufferReleaseReader>(std::move(bufferReleaseConsumer));
#endif

    BQA_LOGV("BLASTBufferQueue created");
    BQA_LOGV("BLASTBufferQueue created");
}
}


@@ -244,6 +259,9 @@ BLASTBufferQueue::~BLASTBufferQueue() {
void BLASTBufferQueue::onFirstRef() {
void BLASTBufferQueue::onFirstRef() {
    // safe default, most producers are expected to override this
    // safe default, most producers are expected to override this
    mProducer->setMaxDequeuedBufferCount(2);
    mProducer->setMaxDequeuedBufferCount(2);
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
    mBufferReleaseThread.start(sp<BLASTBufferQueue>::fromExisting(this));
#endif
}
}


void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
@@ -269,6 +287,9 @@ void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width,
    if (surfaceControlChanged) {
    if (surfaceControlChanged) {
        t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
        t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
                   layer_state_t::eEnableBackpressure);
                   layer_state_t::eEnableBackpressure);
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
        t.setBufferReleaseChannel(mSurfaceControl, mBufferReleaseProducer);
#endif
        applyTransaction = true;
        applyTransaction = true;
    }
    }
    mTransformHint = mSurfaceControl->getTransformHint();
    mTransformHint = mSurfaceControl->getTransformHint();
@@ -386,6 +407,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence
                                                    stat.latchTime,
                                                    stat.latchTime,
                                                    stat.frameEventStats.dequeueReadyTime);
                                                    stat.frameEventStats.dequeueReadyTime);
                }
                }
#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
                auto currFrameNumber = stat.frameEventStats.frameNumber;
                auto currFrameNumber = stat.frameEventStats.frameNumber;
                std::vector<ReleaseCallbackId> staleReleases;
                std::vector<ReleaseCallbackId> staleReleases;
                for (const auto& [key, value]: mSubmitted) {
                for (const auto& [key, value]: mSubmitted) {
@@ -401,6 +423,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence
                                                stat.currentMaxAcquiredBufferCount,
                                                stat.currentMaxAcquiredBufferCount,
                                                true /* fakeRelease */);
                                                true /* fakeRelease */);
                }
                }
#endif
            } else {
            } else {
                BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback");
                BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback");
            }
            }
@@ -411,6 +434,15 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence
    }
    }
}
}


void BLASTBufferQueue::flushShadowQueue() {
    BQA_LOGV("flushShadowQueue");
    int numFramesToFlush = mNumFrameAvailable;
    while (numFramesToFlush > 0) {
        acquireNextBufferLocked(std::nullopt);
        numFramesToFlush--;
    }
}

// Unlike transactionCallbackThunk the release buffer callback does not extend the life of the
// Unlike transactionCallbackThunk the release buffer callback does not extend the life of the
// BBQ. This is because if the BBQ is destroyed, then the buffers will be released by the client.
// BBQ. This is because if the BBQ is destroyed, then the buffers will be released by the client.
// So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer.
// So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer.
@@ -428,15 +460,6 @@ ReleaseBufferCallback BLASTBufferQueue::makeReleaseBufferCallbackThunk() {
    };
    };
}
}


void BLASTBufferQueue::flushShadowQueue() {
    BQA_LOGV("flushShadowQueue");
    int numFramesToFlush = mNumFrameAvailable;
    while (numFramesToFlush > 0) {
        acquireNextBufferLocked(std::nullopt);
        numFramesToFlush--;
    }
}

void BLASTBufferQueue::releaseBufferCallback(
void BLASTBufferQueue::releaseBufferCallback(
        const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
        const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
        std::optional<uint32_t> currentMaxAcquiredBufferCount) {
        std::optional<uint32_t> currentMaxAcquiredBufferCount) {
@@ -617,7 +640,12 @@ status_t BLASTBufferQueue::acquireNextBufferLocked(
                           bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
                           bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
                           bufferItem.mScalingMode, crop);
                           bufferItem.mScalingMode, crop);


#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
    ReleaseBufferCallback releaseBufferCallback =
            applyTransaction ? EMPTY_RELEASE_CALLBACK : makeReleaseBufferCallbackThunk();
#else
    auto releaseBufferCallback = makeReleaseBufferCallbackThunk();
    auto releaseBufferCallback = makeReleaseBufferCallbackThunk();
#endif
    sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;
    sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;


    nsecs_t dequeueTime = -1;
    nsecs_t dequeueTime = -1;
@@ -1359,7 +1387,120 @@ bool BLASTBufferQueue::isSameSurfaceControl(const sp<SurfaceControl>& surfaceCon
void BLASTBufferQueue::setTransactionHangCallback(
void BLASTBufferQueue::setTransactionHangCallback(
        std::function<void(const std::string&)> callback) {
        std::function<void(const std::string&)> callback) {
    std::lock_guard _lock{mMutex};
    std::lock_guard _lock{mMutex};
    mTransactionHangCallback = callback;
    mTransactionHangCallback = std::move(callback);
}
}


#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)

BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader(
        std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> endpoint)
      : mEndpoint{std::move(endpoint)} {
    mEpollFd = android::base::unique_fd{epoll_create1(0)};
    LOG_ALWAYS_FATAL_IF(!mEpollFd.ok(),
                        "Failed to create buffer release epoll file descriptor. errno=%d "
                        "message='%s'",
                        errno, strerror(errno));

    epoll_event registerEndpointFd{};
    registerEndpointFd.events = EPOLLIN;
    registerEndpointFd.data.fd = mEndpoint->getFd();
    status_t status =
            epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mEndpoint->getFd(), &registerEndpointFd);
    LOG_ALWAYS_FATAL_IF(status == -1,
                        "Failed to register buffer release consumer file descriptor with epoll. "
                        "errno=%d message='%s'",
                        errno, strerror(errno));

    mEventFd = android::base::unique_fd(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
    LOG_ALWAYS_FATAL_IF(!mEventFd.ok(),
                        "Failed to create buffer release event file descriptor. errno=%d "
                        "message='%s'",
                        errno, strerror(errno));

    epoll_event registerEventFd{};
    registerEventFd.events = EPOLLIN;
    registerEventFd.data.fd = mEventFd.get();
    status = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mEventFd.get(), &registerEventFd);
    LOG_ALWAYS_FATAL_IF(status == -1,
                        "Failed to register buffer release event file descriptor with epoll. "
                        "errno=%d message='%s'",
                        errno, strerror(errno));
}

BLASTBufferQueue::BufferReleaseReader& BLASTBufferQueue::BufferReleaseReader::operator=(
        BufferReleaseReader&& other) {
    if (this != &other) {
        ftl::FakeGuard guard{mMutex};
        ftl::FakeGuard otherGuard{other.mMutex};
        mEndpoint = std::move(other.mEndpoint);
        mEpollFd = std::move(other.mEpollFd);
        mEventFd = std::move(other.mEventFd);
    }
    return *this;
}

status_t BLASTBufferQueue::BufferReleaseReader::readBlocking(ReleaseCallbackId& outId,
                                                             sp<Fence>& outFence,
                                                             uint32_t& outMaxAcquiredBufferCount) {
    epoll_event event{};
    while (true) {
        int eventCount = epoll_wait(mEpollFd.get(), &event, 1 /* maxevents */, -1 /* timeout */);
        if (eventCount == 1) {
            break;
        }
        if (eventCount == -1 && errno != EINTR) {
            ALOGE("epoll_wait error while waiting for buffer release. errno=%d message='%s'", errno,
                  strerror(errno));
        }
    }

    if (event.data.fd == mEventFd.get()) {
        uint64_t value;
        if (read(mEventFd.get(), &value, sizeof(uint64_t)) == -1 && errno != EWOULDBLOCK) {
            ALOGE("error while reading from eventfd. errno=%d message='%s'", errno,
                  strerror(errno));
        }
        return WOULD_BLOCK;
    }

    std::lock_guard lock{mMutex};
    return mEndpoint->readReleaseFence(outId, outFence, outMaxAcquiredBufferCount);
}

void BLASTBufferQueue::BufferReleaseReader::interruptBlockingRead() {
    uint64_t value = 1;
    if (write(mEventFd.get(), &value, sizeof(uint64_t)) == -1) {
        ALOGE("failed to notify dequeue event. errno=%d message='%s'", errno, strerror(errno));
    }
}

void BLASTBufferQueue::BufferReleaseThread::start(const sp<BLASTBufferQueue>& bbq) {
    mRunning = std::make_shared<std::atomic_bool>(true);
    mReader = bbq->mBufferReleaseReader;
    std::thread([running = mRunning, reader = mReader, weakBbq = wp<BLASTBufferQueue>(bbq)]() {
        pthread_setname_np(pthread_self(), "BufferReleaseThread");
        while (*running) {
            ReleaseCallbackId id;
            sp<Fence> fence;
            uint32_t maxAcquiredBufferCount;
            if (status_t status = reader->readBlocking(id, fence, maxAcquiredBufferCount);
                status != OK) {
                continue;
            }
            sp<BLASTBufferQueue> bbq = weakBbq.promote();
            if (!bbq) {
                return;
            }
            bbq->releaseBufferCallback(id, fence, maxAcquiredBufferCount);
        }
    }).detach();
}

BLASTBufferQueue::BufferReleaseThread::~BufferReleaseThread() {
    *mRunning = false;
    mReader->interruptBlockingRead();
}

#endif

} // namespace android
} // namespace android
+45 −0
Original line number Original line Diff line number Diff line
@@ -331,6 +331,51 @@ private:
    std::function<void(const std::string&)> mTransactionHangCallback;
    std::function<void(const std::string&)> mTransactionHangCallback;


    std::unordered_set<uint64_t> mSyncedFrameNumbers GUARDED_BY(mMutex);
    std::unordered_set<uint64_t> mSyncedFrameNumbers GUARDED_BY(mMutex);

#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
    class BufferReleaseReader {
    public:
        BufferReleaseReader() = default;
        BufferReleaseReader(std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint>);
        BufferReleaseReader& operator=(BufferReleaseReader&&);

        // Block until we can read a buffer release message.
        //
        // Returns:
        // * OK if a ReleaseCallbackId and Fence were successfully read.
        // * WOULD_BLOCK if the blocking read was interrupted by interruptBlockingRead.
        // * UNKNOWN_ERROR if something went wrong.
        status_t readBlocking(ReleaseCallbackId& outId, sp<Fence>& outReleaseFence,
                              uint32_t& outMaxAcquiredBufferCount);

        // Signals the reader's eventfd to wake up any threads waiting on readBlocking.
        void interruptBlockingRead();

    private:
        std::mutex mMutex;
        std::unique_ptr<gui::BufferReleaseChannel::ConsumerEndpoint> mEndpoint GUARDED_BY(mMutex);
        android::base::unique_fd mEpollFd;
        android::base::unique_fd mEventFd;
    };

    // BufferReleaseChannel is used to communicate buffer releases from SurfaceFlinger to
    // the client. See BBQBufferQueueProducer::dequeueBuffer for details.
    std::shared_ptr<BufferReleaseReader> mBufferReleaseReader;
    std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseProducer;

    class BufferReleaseThread {
    public:
        BufferReleaseThread() = default;
        ~BufferReleaseThread();
        void start(const sp<BLASTBufferQueue>&);

    private:
        std::shared_ptr<std::atomic_bool> mRunning;
        std::shared_ptr<BufferReleaseReader> mReader;
    };

    BufferReleaseThread mBufferReleaseThread;
#endif
};
};


} // namespace android
} // namespace android
+19 −4
Original line number Original line Diff line number Diff line
@@ -2529,15 +2529,24 @@ void Layer::cloneDrawingState(const Layer* from) {
void Layer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
void Layer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
                                      const sp<GraphicBuffer>& buffer, uint64_t framenumber,
                                      const sp<GraphicBuffer>& buffer, uint64_t framenumber,
                                      const sp<Fence>& releaseFence) {
                                      const sp<Fence>& releaseFence) {
    if (!listener) {
    if (!listener && !mBufferReleaseChannel) {
        return;
        return;
    }
    }

    SFTRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber);
    SFTRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber);

    ReleaseCallbackId callbackId{buffer->getId(), framenumber};
    const sp<Fence>& fence = releaseFence ? releaseFence : Fence::NO_FENCE;
    uint32_t currentMaxAcquiredBufferCount =
    uint32_t currentMaxAcquiredBufferCount =
            mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid);
            mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid);
    listener->onReleaseBuffer({buffer->getId(), framenumber},

                              releaseFence ? releaseFence : Fence::NO_FENCE,
    if (listener) {
                              currentMaxAcquiredBufferCount);
        listener->onReleaseBuffer(callbackId, fence, currentMaxAcquiredBufferCount);
    }

    if (mBufferReleaseChannel) {
        mBufferReleaseChannel->writeReleaseFence(callbackId, fence, currentMaxAcquiredBufferCount);
    }
}
}


sp<CallbackHandle> Layer::findCallbackHandle() {
sp<CallbackHandle> Layer::findCallbackHandle() {
@@ -2655,6 +2664,7 @@ void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult,


void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
    for (const auto& handle : mDrawingState.callbackHandles) {
    for (const auto& handle : mDrawingState.callbackHandles) {
        handle->bufferReleaseChannel = mBufferReleaseChannel;
        handle->transformHint = mTransformHint;
        handle->transformHint = mTransformHint;
        handle->dequeueReadyTime = dequeueReadyTime;
        handle->dequeueReadyTime = dequeueReadyTime;
        handle->currentMaxAcquiredBufferCount =
        handle->currentMaxAcquiredBufferCount =
@@ -4093,6 +4103,11 @@ bool Layer::setTrustedPresentationInfo(TrustedPresentationThresholds const& thre
    return haveTrustedPresentationListener;
    return haveTrustedPresentationListener;
}
}


void Layer::setBufferReleaseChannel(
        const std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint>& channel) {
    mBufferReleaseChannel = channel;
}

void Layer::updateLastLatchTime(nsecs_t latchTime) {
void Layer::updateLastLatchTime(nsecs_t latchTime) {
    mLastLatchTime = latchTime;
    mLastLatchTime = latchTime;
}
}
+3 −0
Original line number Original line Diff line number Diff line
@@ -543,6 +543,7 @@ public:
    };
    };


    BufferInfo mBufferInfo;
    BufferInfo mBufferInfo;
    std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> mBufferReleaseChannel;


    // implements compositionengine::LayerFE
    // implements compositionengine::LayerFE
    const compositionengine::LayerFECompositionState* getCompositionState() const;
    const compositionengine::LayerFECompositionState* getCompositionState() const;
@@ -798,6 +799,8 @@ public:


    bool setTrustedPresentationInfo(TrustedPresentationThresholds const& thresholds,
    bool setTrustedPresentationInfo(TrustedPresentationThresholds const& thresholds,
                                    TrustedPresentationListener const& listener);
                                    TrustedPresentationListener const& listener);
    void setBufferReleaseChannel(
            const std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint>& channel);


    // Creates a new handle each time, so we only expect
    // Creates a new handle each time, so we only expect
    // this to be called once.
    // this to be called once.
+4 −0
Original line number Original line Diff line number Diff line
@@ -5115,6 +5115,10 @@ uint32_t SurfaceFlinger::updateLayerCallbacksAndStats(const FrameTimelineInfo& f
        }
        }
    }
    }


    if (what & layer_state_t::eBufferReleaseChannelChanged) {
        layer->setBufferReleaseChannel(s.bufferReleaseChannel);
    }

    const auto& requestedLayerState = mLayerLifecycleManager.getLayerFromId(layer->getSequence());
    const auto& requestedLayerState = mLayerLifecycleManager.getLayerFromId(layer->getSequence());
    bool willPresentCurrentTransaction = requestedLayerState &&
    bool willPresentCurrentTransaction = requestedLayerState &&
            (requestedLayerState->hasReadyFrame() ||
            (requestedLayerState->hasReadyFrame() ||
Loading