Loading media/codec2/hal/client/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ cc_library { name: "libcodec2_client", srcs: [ "GraphicsTracker.cpp", "client.cpp", "output.cpp", ], Loading Loading @@ -50,6 +51,7 @@ cc_library { "libgui", "libhidlbase", "liblog", "libnativewindow", "libstagefright_bufferpool@2.0.1", "libui", "libutils", Loading media/codec2/hal/client/GraphicsTracker.cpp 0 → 100644 +836 −0 File added.Preview size limit exceeded, changes collapsed. Show changes media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h 0 → 100644 +306 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <android/hardware_buffer.h> #include <android-base/unique_fd.h> #include <gui/IGraphicBufferProducer.h> #include <atomic> #include <condition_variable> #include <map> #include <memory> #include <mutex> #include <set> #include <thread> #include <C2Buffer.h> namespace aidl::android::hardware::media::c2::implementation { using ::android::IGraphicBufferProducer; using ::android::GraphicBuffer; using ::android::Fence; using ::android::PixelFormat; using ::android::sp; /** * The class allocates AHardwareBuffer(GraphicBuffer)s using BufferQueue. * * The class tracks and manages outstanding # of allocations for buffer * recycling. So Graphics operations which affects # of outstanding allocation * should be done via the class. (e.g. rendering a buffer to display) * * The class is supposed to be wrapped into IGraphicBufferAllocator AIDL interface, * and the interface will be passed to HAL for a specific BlockPool instance. * * The class has one to one relation with HAL side Graphic C2BlockPool. * The life cycle of the class is tied to a HAL side BlockPool object. * * So, reset()/stop() of HAL which related to blokcpool destruction will terminate the * use of the class. And a new instance should be created in order for start() * of HAL. */ class GraphicsTracker { public: static std::shared_ptr<GraphicsTracker> CreateGraphicsTracker(int maxDequeueCount) { GraphicsTracker *p = new GraphicsTracker(maxDequeueCount); std::shared_ptr<GraphicsTracker> sp(p); return sp; } ~GraphicsTracker(); /** * Configure a new surface to render/allocate graphic blocks. * * Graphic blocks from the old surface will be migrated to the new surface, * if possible. Configuring to a null surface is possible in the case, * an allocation request will be fulfilled by a direct allocation(not using * BQ). generation should be different to the previous generations. * * @param[in] igbp the new surface to configure * @param[in] generation identifier for each configured surface */ c2_status_t configureGraphics(const sp<IGraphicBufferProducer>& igbp, uint32_t generation); /** * Configure max # of outstanding allocations at any given time. * * @param[in] maxDequeueCount max # of outstanding allocation to configure */ c2_status_t configureMaxDequeueCount(int maxDequeueCount); /** * Allocates a AHardwareBuffer. * * @param[in] width width * @param[in] height height * @param[in] PixelFormat pixel format which describes color format and etc * @param[in] usage gralloc usage bits * @param[out] buf the allocated buffer * @param[out] fence fence for the allocated buffer * @return C2_OK the buffer is allocated * C2_BAD_STATE stop() is called and in stopped state * C2_BLOCKING should be waited to allocate * C2_NO_MEMORY out of memory * C2_CORRUPTED */ c2_status_t allocate(uint32_t width, uint32_t height, PixelFormat format, uint64_t usage, AHardwareBuffer **buf, sp<Fence> *fence); /** * Deallocates a AHardwareBuffer * * @param[in] bufId id of the buffer to deallocate * @param[in] fence i/o fence for the buffer * @return C2_OK the buffer is successfully deallocated. * C2_DUPLICATE deallocation/render request is pending already. * C2_NOT_FOUND the buffer with the id is not allocated. */ c2_status_t deallocate(uint64_t bufId, const sp<Fence> &fence); /** * Render a GraphicBlock which is associated to a pending allocated buffer * * @param[in] block GraphicBlock * @param[in] input render input params to Graphics * @param[out] output render output params from Graphics * @return C2_OK the buffer is now ready to render * C2_BAD_STATE there is no surface to render. * (null surface mode or life cycle ends) * C2_DUPLICATE deallocation/render request is pending already. * C2_NOT_FOUND the buffer with the id is not allocated. * C2_REFUSED the buffer is refused to render from Graphics * C2_CORRUPTED */ c2_status_t render(const C2ConstGraphicBlock& block, const IGraphicBufferProducer::QueueBufferInput& input, IGraphicBufferProducer::QueueBufferOutput *output); /** * Notifies when a Buffer is ready to allocate from Graphics. * If generation does not match to the current, notifications via the interface * will be ignored. (In the case, the notifications are from one of the old surfaces * which is no longer used.) * * @param[in] generation generation id for specifying Graphics(BQ) */ void onReleased(uint32_t generation); /** * Get waitable fds for events.(allocate is ready, end of life cycle) * * @param[out] allocFd eventFd which signals being ready to allocate * @param[out] statusFd eventFd which signals end of life cycle. * When signaled no more allocate is possible. * @return C2_OK * C2_NO_MEMORY Max # of fd reached.(not really a memory issue) */ c2_status_t getWaitableFds(int *allocFd, int *statusFd); /** * Ends to use the class. after the call, allocate will fail. */ void stop(); private: static constexpr int kDefaultMaxDequeue = 2; struct BufferCache; struct BufferItem { bool mInit; uint64_t mId; uint32_t mGeneration; int mSlot; AHardwareBuffer *mBuf; uint64_t mUsage; // Gralloc usage format, not AHB sp<Fence> mFence; // Create from a GraphicBuffer BufferItem(uint32_t generation, int slot, const sp<GraphicBuffer>& buf, const sp<Fence> &fence); // Create from an AHB (no slot information) // Should be attached to IGBP for rendering BufferItem(uint32_t generation, AHardwareBuffer_Desc *desc, AHardwareBuffer *pBuf); ~BufferItem(); sp<GraphicBuffer> updateBuffer(uint64_t newUsage, uint32_t newGeneration); }; struct BufferCache { static constexpr int kNumSlots = ::android::BufferQueueDefs::NUM_BUFFER_SLOTS; uint64_t mBqId; uint32_t mGeneration; ::android::sp<IGraphicBufferProducer> mIgbp; // Maps slotId to buffer // IGBP::dequeueBuffer(), IGBP::queueBuffer() and IGBP::cancelBuffer() // require slotId. std::map<int, std::shared_ptr<BufferItem>> mBuffers; // block slot use, while deallocating(cancel, render and etc) struct BlockedSlot { std::mutex l; std::condition_variable cv; bool blocked; BlockedSlot() : blocked{false} {} ~BlockedSlot() = default; }; BlockedSlot mBlockedSlots[kNumSlots]; BufferCache() : mBqId{0ULL}, mGeneration{0}, mIgbp{nullptr} {} BufferCache(uint64_t bqId, uint32_t generation, const sp<IGraphicBufferProducer>& igbp) : mBqId{bqId}, mGeneration{generation}, mIgbp{igbp} {} void waitOnSlot(int slot); void blockSlot(int slot); void unblockSlot(int slot); }; std::shared_ptr<BufferCache> mBufferCache; // Maps bufferId to buffer std::map<uint64_t, std::shared_ptr<BufferItem>> mDequeued; std::set<uint64_t> mDeallocating; int mMaxDequeue; int mMaxDequeueRequested; int mMaxDequeueCommitted; uint32_t mMaxDequeueRequestedSeqId; uint32_t mMaxDequeueCommittedSeqId; int mDequeueable; // TODO: statistics uint64_t mTotalDequeued; //uint64_t mTotalQueued; uint64_t mTotalCancelled; uint64_t mTotalDropped; uint64_t mTotalReleased; bool mInConfig; std::mutex mLock; // locks for data synchronization std::mutex mConfigLock; // locks for configuration change. std::atomic<bool> mStopped; ::android::base::unique_fd mAllocEventFd; // eventfd in semaphore mode which // mirrors mDqueueable. ::android::base::unique_fd mStopEventFd; // eventfd which indicates the life // cycle of the class being stopped. std::thread mEventQueueThread; // Thread to handle interrupted // writes to eventfd{s}. std::mutex mEventLock; std::condition_variable mEventCv; bool mStopEventThread; int mIncDequeueable; // pending # of write to increase dequeueable eventfd bool mStopRequest; // pending write to statusfd private: explicit GraphicsTracker(int maxDequeueCount); // return {@code true} only when dequeue config adjust happened. // {@code updateDequeueConf} is an output parameter, and returns // {@code true} only when the current dequeue conf is required to be // updated to IGBP(BQ) as a result of the adjust. bool adjustDequeueConfLocked(bool *updateDequeueConf); void updateDequeueConf(); c2_status_t requestAllocate(std::shared_ptr<BufferCache> *cache); c2_status_t requestDeallocate(uint64_t bid, const sp<Fence> &fence, bool *completed, bool *updateDequeue, std::shared_ptr<BufferCache> *cache, int *slotId, sp<Fence> *rFence); c2_status_t requestRender(uint64_t bid, std::shared_ptr<BufferCache> *cache, std::shared_ptr<BufferItem> *pBuffer, bool *updateDequeue); void commitAllocate(c2_status_t res, const std::shared_ptr<BufferCache> &cache, bool cached, int slotId, const sp<Fence> &fence, std::shared_ptr<BufferItem> *buffer, bool *updateDequeue); void commitDeallocate(std::shared_ptr<BufferCache> &cache, int slotId, uint64_t bid); void commitRender(uint64_t origBid, const std::shared_ptr<BufferCache> &cache, const std::shared_ptr<BufferItem> &buffer, bool *updateDequeue); c2_status_t _allocate( const std::shared_ptr<BufferCache> &cache, uint32_t width, uint32_t height, PixelFormat format, int64_t usage, bool *cached, int *rSlotId, sp<Fence> *rFence, std::shared_ptr<BufferItem> *buffer); void writeIncDequeueable(int inc); void processEvent(); }; } // namespace aidl::android::hardware::media::c2::implementation Loading
media/codec2/hal/client/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ cc_library { name: "libcodec2_client", srcs: [ "GraphicsTracker.cpp", "client.cpp", "output.cpp", ], Loading Loading @@ -50,6 +51,7 @@ cc_library { "libgui", "libhidlbase", "liblog", "libnativewindow", "libstagefright_bufferpool@2.0.1", "libui", "libutils", Loading
media/codec2/hal/client/GraphicsTracker.cpp 0 → 100644 +836 −0 File added.Preview size limit exceeded, changes collapsed. Show changes
media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h 0 → 100644 +306 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <android/hardware_buffer.h> #include <android-base/unique_fd.h> #include <gui/IGraphicBufferProducer.h> #include <atomic> #include <condition_variable> #include <map> #include <memory> #include <mutex> #include <set> #include <thread> #include <C2Buffer.h> namespace aidl::android::hardware::media::c2::implementation { using ::android::IGraphicBufferProducer; using ::android::GraphicBuffer; using ::android::Fence; using ::android::PixelFormat; using ::android::sp; /** * The class allocates AHardwareBuffer(GraphicBuffer)s using BufferQueue. * * The class tracks and manages outstanding # of allocations for buffer * recycling. So Graphics operations which affects # of outstanding allocation * should be done via the class. (e.g. rendering a buffer to display) * * The class is supposed to be wrapped into IGraphicBufferAllocator AIDL interface, * and the interface will be passed to HAL for a specific BlockPool instance. * * The class has one to one relation with HAL side Graphic C2BlockPool. * The life cycle of the class is tied to a HAL side BlockPool object. * * So, reset()/stop() of HAL which related to blokcpool destruction will terminate the * use of the class. And a new instance should be created in order for start() * of HAL. */ class GraphicsTracker { public: static std::shared_ptr<GraphicsTracker> CreateGraphicsTracker(int maxDequeueCount) { GraphicsTracker *p = new GraphicsTracker(maxDequeueCount); std::shared_ptr<GraphicsTracker> sp(p); return sp; } ~GraphicsTracker(); /** * Configure a new surface to render/allocate graphic blocks. * * Graphic blocks from the old surface will be migrated to the new surface, * if possible. Configuring to a null surface is possible in the case, * an allocation request will be fulfilled by a direct allocation(not using * BQ). generation should be different to the previous generations. * * @param[in] igbp the new surface to configure * @param[in] generation identifier for each configured surface */ c2_status_t configureGraphics(const sp<IGraphicBufferProducer>& igbp, uint32_t generation); /** * Configure max # of outstanding allocations at any given time. * * @param[in] maxDequeueCount max # of outstanding allocation to configure */ c2_status_t configureMaxDequeueCount(int maxDequeueCount); /** * Allocates a AHardwareBuffer. * * @param[in] width width * @param[in] height height * @param[in] PixelFormat pixel format which describes color format and etc * @param[in] usage gralloc usage bits * @param[out] buf the allocated buffer * @param[out] fence fence for the allocated buffer * @return C2_OK the buffer is allocated * C2_BAD_STATE stop() is called and in stopped state * C2_BLOCKING should be waited to allocate * C2_NO_MEMORY out of memory * C2_CORRUPTED */ c2_status_t allocate(uint32_t width, uint32_t height, PixelFormat format, uint64_t usage, AHardwareBuffer **buf, sp<Fence> *fence); /** * Deallocates a AHardwareBuffer * * @param[in] bufId id of the buffer to deallocate * @param[in] fence i/o fence for the buffer * @return C2_OK the buffer is successfully deallocated. * C2_DUPLICATE deallocation/render request is pending already. * C2_NOT_FOUND the buffer with the id is not allocated. */ c2_status_t deallocate(uint64_t bufId, const sp<Fence> &fence); /** * Render a GraphicBlock which is associated to a pending allocated buffer * * @param[in] block GraphicBlock * @param[in] input render input params to Graphics * @param[out] output render output params from Graphics * @return C2_OK the buffer is now ready to render * C2_BAD_STATE there is no surface to render. * (null surface mode or life cycle ends) * C2_DUPLICATE deallocation/render request is pending already. * C2_NOT_FOUND the buffer with the id is not allocated. * C2_REFUSED the buffer is refused to render from Graphics * C2_CORRUPTED */ c2_status_t render(const C2ConstGraphicBlock& block, const IGraphicBufferProducer::QueueBufferInput& input, IGraphicBufferProducer::QueueBufferOutput *output); /** * Notifies when a Buffer is ready to allocate from Graphics. * If generation does not match to the current, notifications via the interface * will be ignored. (In the case, the notifications are from one of the old surfaces * which is no longer used.) * * @param[in] generation generation id for specifying Graphics(BQ) */ void onReleased(uint32_t generation); /** * Get waitable fds for events.(allocate is ready, end of life cycle) * * @param[out] allocFd eventFd which signals being ready to allocate * @param[out] statusFd eventFd which signals end of life cycle. * When signaled no more allocate is possible. * @return C2_OK * C2_NO_MEMORY Max # of fd reached.(not really a memory issue) */ c2_status_t getWaitableFds(int *allocFd, int *statusFd); /** * Ends to use the class. after the call, allocate will fail. */ void stop(); private: static constexpr int kDefaultMaxDequeue = 2; struct BufferCache; struct BufferItem { bool mInit; uint64_t mId; uint32_t mGeneration; int mSlot; AHardwareBuffer *mBuf; uint64_t mUsage; // Gralloc usage format, not AHB sp<Fence> mFence; // Create from a GraphicBuffer BufferItem(uint32_t generation, int slot, const sp<GraphicBuffer>& buf, const sp<Fence> &fence); // Create from an AHB (no slot information) // Should be attached to IGBP for rendering BufferItem(uint32_t generation, AHardwareBuffer_Desc *desc, AHardwareBuffer *pBuf); ~BufferItem(); sp<GraphicBuffer> updateBuffer(uint64_t newUsage, uint32_t newGeneration); }; struct BufferCache { static constexpr int kNumSlots = ::android::BufferQueueDefs::NUM_BUFFER_SLOTS; uint64_t mBqId; uint32_t mGeneration; ::android::sp<IGraphicBufferProducer> mIgbp; // Maps slotId to buffer // IGBP::dequeueBuffer(), IGBP::queueBuffer() and IGBP::cancelBuffer() // require slotId. std::map<int, std::shared_ptr<BufferItem>> mBuffers; // block slot use, while deallocating(cancel, render and etc) struct BlockedSlot { std::mutex l; std::condition_variable cv; bool blocked; BlockedSlot() : blocked{false} {} ~BlockedSlot() = default; }; BlockedSlot mBlockedSlots[kNumSlots]; BufferCache() : mBqId{0ULL}, mGeneration{0}, mIgbp{nullptr} {} BufferCache(uint64_t bqId, uint32_t generation, const sp<IGraphicBufferProducer>& igbp) : mBqId{bqId}, mGeneration{generation}, mIgbp{igbp} {} void waitOnSlot(int slot); void blockSlot(int slot); void unblockSlot(int slot); }; std::shared_ptr<BufferCache> mBufferCache; // Maps bufferId to buffer std::map<uint64_t, std::shared_ptr<BufferItem>> mDequeued; std::set<uint64_t> mDeallocating; int mMaxDequeue; int mMaxDequeueRequested; int mMaxDequeueCommitted; uint32_t mMaxDequeueRequestedSeqId; uint32_t mMaxDequeueCommittedSeqId; int mDequeueable; // TODO: statistics uint64_t mTotalDequeued; //uint64_t mTotalQueued; uint64_t mTotalCancelled; uint64_t mTotalDropped; uint64_t mTotalReleased; bool mInConfig; std::mutex mLock; // locks for data synchronization std::mutex mConfigLock; // locks for configuration change. std::atomic<bool> mStopped; ::android::base::unique_fd mAllocEventFd; // eventfd in semaphore mode which // mirrors mDqueueable. ::android::base::unique_fd mStopEventFd; // eventfd which indicates the life // cycle of the class being stopped. std::thread mEventQueueThread; // Thread to handle interrupted // writes to eventfd{s}. std::mutex mEventLock; std::condition_variable mEventCv; bool mStopEventThread; int mIncDequeueable; // pending # of write to increase dequeueable eventfd bool mStopRequest; // pending write to statusfd private: explicit GraphicsTracker(int maxDequeueCount); // return {@code true} only when dequeue config adjust happened. // {@code updateDequeueConf} is an output parameter, and returns // {@code true} only when the current dequeue conf is required to be // updated to IGBP(BQ) as a result of the adjust. bool adjustDequeueConfLocked(bool *updateDequeueConf); void updateDequeueConf(); c2_status_t requestAllocate(std::shared_ptr<BufferCache> *cache); c2_status_t requestDeallocate(uint64_t bid, const sp<Fence> &fence, bool *completed, bool *updateDequeue, std::shared_ptr<BufferCache> *cache, int *slotId, sp<Fence> *rFence); c2_status_t requestRender(uint64_t bid, std::shared_ptr<BufferCache> *cache, std::shared_ptr<BufferItem> *pBuffer, bool *updateDequeue); void commitAllocate(c2_status_t res, const std::shared_ptr<BufferCache> &cache, bool cached, int slotId, const sp<Fence> &fence, std::shared_ptr<BufferItem> *buffer, bool *updateDequeue); void commitDeallocate(std::shared_ptr<BufferCache> &cache, int slotId, uint64_t bid); void commitRender(uint64_t origBid, const std::shared_ptr<BufferCache> &cache, const std::shared_ptr<BufferItem> &buffer, bool *updateDequeue); c2_status_t _allocate( const std::shared_ptr<BufferCache> &cache, uint32_t width, uint32_t height, PixelFormat format, int64_t usage, bool *cached, int *rSlotId, sp<Fence> *rFence, std::shared_ptr<BufferItem> *buffer); void writeIncDequeueable(int inc); void processEvent(); }; } // namespace aidl::android::hardware::media::c2::implementation