From patchwork Tue Nov 26 23:36:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 2366 Return-Path: Received: from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net [195.74.38.229]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A561C61C6F for ; Wed, 27 Nov 2019 00:39:38 +0100 (CET) X-Halon-ID: 01c2c0f2-10a6-11ea-a0b9-005056917f90 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p54ac5865.dip0.t-ipconnect.de [84.172.88.101]) by bin-vsp-out-02.atm.binero.net (Halon) with ESMTPA id 01c2c0f2-10a6-11ea-a0b9-005056917f90; Wed, 27 Nov 2019 00:39:37 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 27 Nov 2019 00:36:08 +0100 Message-Id: <20191126233620.1695316-19-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191126233620.1695316-1-niklas.soderlund@ragnatech.se> References: <20191126233620.1695316-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 18/30] libcamera: v4l2_videodevice: Add V4L2BufferCache to deal with index mapping X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 26 Nov 2019 23:39:39 -0000 In preparation for the FrameBuffer interface add a class which will deal with keeping the cache between dmafds and V4L2 video device buffer indexes. This initial implement ensures that no hot association is lost while its eviction strategy could be improved in the future. Signed-off-by: Niklas Söderlund --- src/libcamera/include/v4l2_videodevice.h | 20 ++++- src/libcamera/v4l2_videodevice.cpp | 105 ++++++++++++++++++++++- 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h index 34bbff41760753bd..254f8797af42dd8a 100644 --- a/src/libcamera/include/v4l2_videodevice.h +++ b/src/libcamera/include/v4l2_videodevice.h @@ -12,6 +12,7 @@ #include +#include #include #include #include @@ -22,7 +23,6 @@ namespace libcamera { -class Buffer; class BufferMemory; class BufferPool; class EventNotifier; @@ -105,6 +105,24 @@ struct V4L2Capability final : v4l2_capability { } }; +class V4L2BufferCache +{ +public: + V4L2BufferCache(unsigned int size); + V4L2BufferCache(const std::vector buffers); + + int fetch(const FrameBuffer *buffer); + void put(unsigned int index); + +private: + struct CacheInfo { + bool free; + std::vector last; + }; + + std::vector cache_; +}; + class V4L2DeviceFormat { public: diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index a05dd6a1f7d86eaa..c82f2829601bd14c 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -19,7 +19,6 @@ #include -#include #include #include "log.h" @@ -134,6 +133,110 @@ LOG_DECLARE_CATEGORY(V4L2) * \return True if the video device provides Streaming I/O IOCTLs */ +/** + * \class V4L2BufferCache + * \brief Hot cache of associations between V4L2 index and FrameBuffer + * + * There is performance to be gained if the same V4L2 buffer index can be + * reused for the same FrameBuffer object as the kernel don't have to redo + * the mapping. The V4L2BufferCache tries to keep a hot-cache of mappings + * between the two. + * + * If there is a cache miss is not critical, everything still works as expected. + */ + +/** + * \brief Create a empty cache of a given size + * \param[in] size Size of cache to create + * + * Create a cold cache with \a size entries. The cache will be populated as + * it's being used. + */ +V4L2BufferCache::V4L2BufferCache(unsigned int size) +{ + cache_.resize(size, { .free = true, .last = {} }); +} + +/** + * \brief Create a pre-populated cache + * \param[in] buffers Array of buffers to pre-populated with + * + * Create a warm cache from \a buffers. + */ +V4L2BufferCache::V4L2BufferCache(const std::vector buffers) +{ + for (const FrameBuffer *buffer : buffers) + cache_.push_back({ .free = true, .last = buffer->planes() }); +} + +/** + * \brief Fetch a index from the cache + * \param[in] buffer FrameBuffer to match + * + * Try to find \a buffer in cache and if it's free reuse the last used index + * for this buffer. If the buffer have never been seen or if have been evinced + * from the cache the first free index is pieced instead. Likewise if the last + * used index is in use a new free index is picked. + * + * When an index is picked it is marked as in-use and returned to the caller. + * The association is also recorded so it if possible can reused the next time + * the FrameBuffer is seen. + * + * \return V4L2 buffer index + */ +int V4L2BufferCache::fetch(const FrameBuffer *buffer) +{ + int use = -1; + + for (unsigned int index = 0; index < cache_.size(); index++) { + if (!cache_[index].free) + continue; + + if (use < 0) + use = index; + + /* Try to find a cache hit by comparing the planes. */ + std::vector planes = buffer->planes(); + if (cache_[index].last.size() != planes.size()) + continue; + + bool match = true; + for (unsigned int i = 0; i < planes.size(); i++) { + if (cache_[index].last[i].fd != planes[i].fd || + cache_[index].last[i].length != planes[i].length) { + match = false; + break; + } + } + + if (!match) + continue; + + use = index; + break; + } + + if (use < 0) + return -ENOENT; + + cache_[use].free = false; + cache_[use].last = buffer->planes(); + + return use; +} + +/** + * \brief Pit a V4L2 index back in the cache + * \param[in] index V4L2 index + * + * Mark the \a index as free in the cache so it can be reused. + */ +void V4L2BufferCache::put(unsigned int index) +{ + ASSERT(index < cache_.size()); + cache_[index].free = true; +} + /** * \class V4L2DeviceFormat * \brief The V4L2 video device image format and sizes