[{"id":3374,"web_url":"https://patchwork.libcamera.org/comment/3374/","msgid":"<20200107230421.GR4871@pendragon.ideasonboard.com>","date":"2020-01-07T23:04:21","subject":"Re: [libcamera-devel] [PATCH v2 11/25] libcamera: v4l2_videodevice:\n\tAdd V4L2BufferCache to deal with index mapping","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Niklas,\n\nThank you for the patch.\n\nOn Mon, Dec 30, 2019 at 01:04:56PM +0100, Niklas Söderlund wrote:\n> In preparation for the FrameBuffer interface add a class that will deal\n> with keeping the cache between dmafds and V4L2 video device buffer\n\ns/dmafds/dmabuf file descriptors/\n\n> indexes.\n> \n> This initial implement ensures that no hot association is lost while its\n\ns/implement/implementation/\n\n> eviction strategy could be improved in the future.\n> \n> Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> ---\n> * Changes since v1\n> - fetch() take a const reference instead of a const pointer\n> - Rename argument for V4L2BufferCache()\n> - Rename V4L2BufferCache::CacheInfo to V4L2BufferCache::Entry.\n> - Turn V4L2BufferCache::Entry into a class with constructors for\n>   foo.emplace_back().\n> - Rename V4L2BufferCache::fetch() to V4L2BufferCache::get()\n> - Make use of operator==\n> - Large updates of documentation.\n> ---\n>  src/libcamera/include/v4l2_videodevice.h | 58 +++++++++++++-\n>  src/libcamera/v4l2_videodevice.cpp       | 98 +++++++++++++++++++++++-\n>  2 files changed, 152 insertions(+), 4 deletions(-)\n> \n> diff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h\n> index 1f52fe0120831fa3..9fc2082b2e7f7219 100644\n> --- a/src/libcamera/include/v4l2_videodevice.h\n> +++ b/src/libcamera/include/v4l2_videodevice.h\n> @@ -11,7 +11,9 @@\n>  #include <vector>\n>  \n>  #include <linux/videodev2.h>\n> +#include <memory>\n>  \n> +#include <libcamera/buffer.h>\n>  #include <libcamera/geometry.h>\n>  #include <libcamera/pixelformats.h>\n>  #include <libcamera/signal.h>\n> @@ -22,9 +24,6 @@\n>  \n>  namespace libcamera {\n>  \n> -class Buffer;\n> -class BufferMemory;\n> -class BufferPool;\n>  class EventNotifier;\n>  class MediaDevice;\n>  class MediaEntity;\n> @@ -105,6 +104,59 @@ struct V4L2Capability final : v4l2_capability {\n>  \t}\n>  };\n>  \n> +class V4L2BufferCache\n> +{\n> +public:\n> +\tV4L2BufferCache(unsigned int numEntries);\n> +\tV4L2BufferCache(const std::vector<std::unique_ptr<FrameBuffer>> &buffers);\n> +\n> +\tint get(const FrameBuffer &buffer);\n> +\tvoid put(unsigned int index);\n> +\n> +private:\n> +\tclass Entry\n> +\t{\n> +\tpublic:\n> +\t\tEntry(bool free, const std::vector<FrameBuffer::Plane> &planes)\n\nWould it make sense to pass a const reference to a FrameBuffer here ? It\nwould simplify the callers.\n\n> +\t\t\t: free(free)\n> +\t\t{\n> +\t\t\tfor (const FrameBuffer::Plane &plane : planes)\n> +\t\t\t\tlast.emplace_back(plane);\n\nlast isn't a very descriptive name I think, should this be called planes\n?\n\n> +\t\t}\n> +\n> +\t\tbool operator==(const std::vector<FrameBuffer::Plane> &planes)\n\nSame here, const reference to a FrameBuffer ?\n\n> +\t\t{\n> +\t\t\tif (last.size() != planes.size())\n> +\t\t\t\treturn false;\n> +\n> +\t\t\tfor (unsigned int i = 0; i < planes.size(); i++)\n> +\t\t\t\tif (last[i].fd != planes[i].fd.fd() ||\n> +\t\t\t\t    last[i].length != planes[i].length)\n> +\t\t\t\t\treturn false;\n> +\t\t\treturn true;\n> +\t\t}\n> +\n\nCould we avoid making these two methods inline ?\n\n> +\t\tbool free;\n> +\n> +\tprivate:\n> +\t\tclass Plane\n\nYou can make this a struct.\n\nReviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n\n> +\t\t{\n> +\t\tpublic:\n> +\t\t\tPlane(const FrameBuffer::Plane &plane)\n> +\t\t\t\t: fd(plane.fd.fd()), length(plane.length)\n> +\t\t\t{\n> +\t\t\t}\n> +\n> +\t\t\tint fd;\n> +\t\t\tunsigned int length;\n> +\t\t};\n> +\n> +\t\tstd::vector<Plane> last;\n> +\t};\n> +\n> +\tstd::vector<Entry> cache_;\n> +};\n> +\n>  class V4L2DeviceFormat\n>  {\n>  public:\n> diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp\n> index 51112d197068cf0a..c9e17c44bfe17c3b 100644\n> --- a/src/libcamera/v4l2_videodevice.cpp\n> +++ b/src/libcamera/v4l2_videodevice.cpp\n> @@ -19,7 +19,6 @@\n>  \n>  #include <linux/drm_fourcc.h>\n>  \n> -#include <libcamera/buffer.h>\n>  #include <libcamera/event_notifier.h>\n>  \n>  #include \"log.h\"\n> @@ -134,6 +133,103 @@ LOG_DECLARE_CATEGORY(V4L2)\n>   * \\return True if the video device provides Streaming I/O IOCTLs\n>   */\n>  \n> +/**\n> + * \\class V4L2BufferCache\n> + * \\brief Hot cache of associations between V4L2 buffer indexes and FrameBuffer\n> + *\n> + * When importing buffers, V4L2 performs lazy mapping of dmabuf instances at\n> + * VIDIOC_QBUF (or VIDIOC_PREPARE_BUF) time and keeps the mapping associated\n> + * with the V4L2 buffer, as identified by its index. If the same V4L2 buffer is\n> + * then reused and queued with different dmabufs, the old dmabufs will be\n> + * unmapped and the new ones mapped. To keep this process efficient, it is\n> + * crucial to consistently use the same V4L2 buffer for given dmabufs through\n> + * the whole duration of a capture cycle.\n> + *\n> + * The V4L2BufferCache class keeps a map of previous dmabufs to V4L2 buffer\n> + * index associations to help selecting V4L2 buffers. It tracks, for every\n> + * entry, if the V4L2 buffer is in use, and offers lookup of the best free V4L2\n> + * buffer for a set of dmabufs.\n> + */\n> +\n> +/**\n> + * \\brief Create an empty cache with \\a numEntries entries\n> + * \\param[in] numEntries Number of entries to reserve in the cache\n> + *\n> + * Create a cache with \\a numEntries entries all marked as unused. The entries\n> + * will be populated as the cache is used. This is typically used to implement\n> + * buffer import, with buffers added to the cache as they are queued.\n> + */\n> +V4L2BufferCache::V4L2BufferCache(unsigned int numEntries)\n> +{\n> +\tcache_.resize(numEntries, Entry(true, {}));\n> +}\n> +\n> +/**\n> + * \\brief Create a pre-populated cache\n> + * \\param[in] buffers Array of buffers to pre-populated with\n> + *\n> + * Create a cache pre-populated with \\a buffers. This is typically used to\n> + * implement buffer export, with all buffers added to the cache when they are\n> + * allocated.\n> + */\n> +V4L2BufferCache::V4L2BufferCache(const std::vector<std::unique_ptr<FrameBuffer>> &buffers)\n> +{\n> +\tfor (const std::unique_ptr<FrameBuffer> &buffer : buffers)\n> +\t\tcache_.emplace_back(true, buffer->planes());\n> +}\n> +\n> +/**\n> + * \\brief Find the best V4L2 buffer for a FrameBuffer\n> + * \\param[in] buffer The FrameBuffer\n> + *\n> + * Find the best V4L2 buffer index to be used for the FrameBuffer \\a buffer\n> + * based on previous mappings of frame buffers to V4L2 buffers. If a free V4L2\n> + * buffer previously used with the same dmabufs as \\a buffer is found in the\n> + * cache, return its index. Otherwise return the index of the first free V4L2\n> + * buffer and record its association with the dmabufs of \\a buffer.\n> + *\n> + * \\return The index of the best V4L2 buffer, or -ENOENT if no free V4L2 buffer\n> + * is available\n> + */\n> +int V4L2BufferCache::get(const FrameBuffer &buffer)\n> +{\n> +\tconst std::vector<FrameBuffer::Plane> &planes = buffer.planes();\n> +\tint use = -1;\n> +\n> +\tfor (unsigned int index = 0; index < cache_.size(); index++) {\n> +\t\tconst Entry &entry = cache_[index];\n> +\n> +\t\tif (!entry.free)\n> +\t\t\tcontinue;\n> +\n> +\t\tif (use < 0)\n> +\t\t\tuse = index;\n> +\n> +\t\t/* Try to find a cache hit by comparing the planes. */\n> +\t\tif (cache_[index] == planes) {\n> +\t\t\tuse = index;\n> +\t\t\tbreak;\n> +\t\t}\n> +\t}\n> +\n> +\tif (use < 0)\n> +\t\treturn -ENOENT;\n> +\n> +\tcache_[use] = Entry(false, planes);\n> +\n> +\treturn use;\n> +}\n> +\n> +/**\n> + * \\brief Mark buffer \\a index as free in the cache\n> + * \\param[in] index The V4L2 buffer index\n> + */\n> +void V4L2BufferCache::put(unsigned int index)\n> +{\n> +\tASSERT(index < cache_.size());\n> +\tcache_[index].free = true;\n> +}\n> +\n>  /**\n>   * \\class V4L2DeviceFormat\n>   * \\brief The V4L2 video device image format and sizes","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3A75660612\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  8 Jan 2020 00:04:34 +0100 (CET)","from pendragon.ideasonboard.com (81-175-216-236.bb.dnainternet.fi\n\t[81.175.216.236])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 5287252F;\n\tWed,  8 Jan 2020 00:04:33 +0100 (CET)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1578438273;\n\tbh=P77GEn+1eDsaBFPPqwZGcZzRN5D6qo84GIV2IYP8Fak=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=X/7GvO0PXXXRnThuSrfJP6BqQZ6erXuUZb/vqOTQW4G3yAocc06SXnv0dki2i561R\n\tQDBxfbfk7OqqJ1otYjEEL4+KjSfdPbqZBDkQ2LpUzwYDGaE24Pr3FX1/dDcH4jFZhZ\n\tKwGGKj0uIrfe7H3yKdjuPPExKbTa6KzbXv3oXXQE=","Date":"Wed, 8 Jan 2020 01:04:21 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Niklas =?utf-8?q?S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20200107230421.GR4871@pendragon.ideasonboard.com>","References":"<20191230120510.938333-1-niklas.soderlund@ragnatech.se>\n\t<20191230120510.938333-12-niklas.soderlund@ragnatech.se>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20191230120510.938333-12-niklas.soderlund@ragnatech.se>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH v2 11/25] libcamera: v4l2_videodevice:\n\tAdd V4L2BufferCache to deal with index mapping","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Tue, 07 Jan 2020 23:04:34 -0000"}},{"id":3380,"web_url":"https://patchwork.libcamera.org/comment/3380/","msgid":"<20200108011947.GV4871@pendragon.ideasonboard.com>","date":"2020-01-08T01:19:47","subject":"Re: [libcamera-devel] [PATCH v2 11/25] libcamera: v4l2_videodevice:\n\tAdd V4L2BufferCache to deal with index mapping","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Niklas,\n\nOne more thing.\n\nOn Wed, Jan 08, 2020 at 01:04:21AM +0200, Laurent Pinchart wrote:\n> On Mon, Dec 30, 2019 at 01:04:56PM +0100, Niklas Söderlund wrote:\n> > In preparation for the FrameBuffer interface add a class that will deal\n> > with keeping the cache between dmafds and V4L2 video device buffer\n> \n> s/dmafds/dmabuf file descriptors/\n> \n> > indexes.\n> > \n> > This initial implement ensures that no hot association is lost while its\n> \n> s/implement/implementation/\n> \n> > eviction strategy could be improved in the future.\n\nNow that the index won't be visible to applications, the tests won't be\nable to catch cache trashing :-S I think we need to instrument this\nclass. It's a bit out of scope for this series, but could you at least\nadd a miss counter, a LOG(Debug) in the destructor to print it, and a\n\"\\todo Expose the miss counter through an instrumentation API\" ?\n\n> > Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> > ---\n> > * Changes since v1\n> > - fetch() take a const reference instead of a const pointer\n> > - Rename argument for V4L2BufferCache()\n> > - Rename V4L2BufferCache::CacheInfo to V4L2BufferCache::Entry.\n> > - Turn V4L2BufferCache::Entry into a class with constructors for\n> >   foo.emplace_back().\n> > - Rename V4L2BufferCache::fetch() to V4L2BufferCache::get()\n> > - Make use of operator==\n> > - Large updates of documentation.\n> > ---\n> >  src/libcamera/include/v4l2_videodevice.h | 58 +++++++++++++-\n> >  src/libcamera/v4l2_videodevice.cpp       | 98 +++++++++++++++++++++++-\n> >  2 files changed, 152 insertions(+), 4 deletions(-)\n> > \n> > diff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h\n> > index 1f52fe0120831fa3..9fc2082b2e7f7219 100644\n> > --- a/src/libcamera/include/v4l2_videodevice.h\n> > +++ b/src/libcamera/include/v4l2_videodevice.h\n> > @@ -11,7 +11,9 @@\n> >  #include <vector>\n> >  \n> >  #include <linux/videodev2.h>\n> > +#include <memory>\n> >  \n> > +#include <libcamera/buffer.h>\n> >  #include <libcamera/geometry.h>\n> >  #include <libcamera/pixelformats.h>\n> >  #include <libcamera/signal.h>\n> > @@ -22,9 +24,6 @@\n> >  \n> >  namespace libcamera {\n> >  \n> > -class Buffer;\n> > -class BufferMemory;\n> > -class BufferPool;\n> >  class EventNotifier;\n> >  class MediaDevice;\n> >  class MediaEntity;\n> > @@ -105,6 +104,59 @@ struct V4L2Capability final : v4l2_capability {\n> >  \t}\n> >  };\n> >  \n> > +class V4L2BufferCache\n> > +{\n> > +public:\n> > +\tV4L2BufferCache(unsigned int numEntries);\n> > +\tV4L2BufferCache(const std::vector<std::unique_ptr<FrameBuffer>> &buffers);\n> > +\n> > +\tint get(const FrameBuffer &buffer);\n> > +\tvoid put(unsigned int index);\n> > +\n> > +private:\n> > +\tclass Entry\n> > +\t{\n> > +\tpublic:\n> > +\t\tEntry(bool free, const std::vector<FrameBuffer::Plane> &planes)\n> \n> Would it make sense to pass a const reference to a FrameBuffer here ? It\n> would simplify the callers.\n> \n> > +\t\t\t: free(free)\n> > +\t\t{\n> > +\t\t\tfor (const FrameBuffer::Plane &plane : planes)\n> > +\t\t\t\tlast.emplace_back(plane);\n> \n> last isn't a very descriptive name I think, should this be called planes\n> ?\n> \n> > +\t\t}\n> > +\n> > +\t\tbool operator==(const std::vector<FrameBuffer::Plane> &planes)\n> \n> Same here, const reference to a FrameBuffer ?\n> \n> > +\t\t{\n> > +\t\t\tif (last.size() != planes.size())\n> > +\t\t\t\treturn false;\n> > +\n> > +\t\t\tfor (unsigned int i = 0; i < planes.size(); i++)\n> > +\t\t\t\tif (last[i].fd != planes[i].fd.fd() ||\n> > +\t\t\t\t    last[i].length != planes[i].length)\n> > +\t\t\t\t\treturn false;\n> > +\t\t\treturn true;\n> > +\t\t}\n> > +\n> \n> Could we avoid making these two methods inline ?\n> \n> > +\t\tbool free;\n> > +\n> > +\tprivate:\n> > +\t\tclass Plane\n> \n> You can make this a struct.\n> \n> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> \n> > +\t\t{\n> > +\t\tpublic:\n> > +\t\t\tPlane(const FrameBuffer::Plane &plane)\n> > +\t\t\t\t: fd(plane.fd.fd()), length(plane.length)\n> > +\t\t\t{\n> > +\t\t\t}\n> > +\n> > +\t\t\tint fd;\n> > +\t\t\tunsigned int length;\n> > +\t\t};\n> > +\n> > +\t\tstd::vector<Plane> last;\n> > +\t};\n> > +\n> > +\tstd::vector<Entry> cache_;\n> > +};\n> > +\n> >  class V4L2DeviceFormat\n> >  {\n> >  public:\n> > diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp\n> > index 51112d197068cf0a..c9e17c44bfe17c3b 100644\n> > --- a/src/libcamera/v4l2_videodevice.cpp\n> > +++ b/src/libcamera/v4l2_videodevice.cpp\n> > @@ -19,7 +19,6 @@\n> >  \n> >  #include <linux/drm_fourcc.h>\n> >  \n> > -#include <libcamera/buffer.h>\n> >  #include <libcamera/event_notifier.h>\n> >  \n> >  #include \"log.h\"\n> > @@ -134,6 +133,103 @@ LOG_DECLARE_CATEGORY(V4L2)\n> >   * \\return True if the video device provides Streaming I/O IOCTLs\n> >   */\n> >  \n> > +/**\n> > + * \\class V4L2BufferCache\n> > + * \\brief Hot cache of associations between V4L2 buffer indexes and FrameBuffer\n> > + *\n> > + * When importing buffers, V4L2 performs lazy mapping of dmabuf instances at\n> > + * VIDIOC_QBUF (or VIDIOC_PREPARE_BUF) time and keeps the mapping associated\n> > + * with the V4L2 buffer, as identified by its index. If the same V4L2 buffer is\n> > + * then reused and queued with different dmabufs, the old dmabufs will be\n> > + * unmapped and the new ones mapped. To keep this process efficient, it is\n> > + * crucial to consistently use the same V4L2 buffer for given dmabufs through\n> > + * the whole duration of a capture cycle.\n> > + *\n> > + * The V4L2BufferCache class keeps a map of previous dmabufs to V4L2 buffer\n> > + * index associations to help selecting V4L2 buffers. It tracks, for every\n> > + * entry, if the V4L2 buffer is in use, and offers lookup of the best free V4L2\n> > + * buffer for a set of dmabufs.\n> > + */\n> > +\n> > +/**\n> > + * \\brief Create an empty cache with \\a numEntries entries\n> > + * \\param[in] numEntries Number of entries to reserve in the cache\n> > + *\n> > + * Create a cache with \\a numEntries entries all marked as unused. The entries\n> > + * will be populated as the cache is used. This is typically used to implement\n> > + * buffer import, with buffers added to the cache as they are queued.\n> > + */\n> > +V4L2BufferCache::V4L2BufferCache(unsigned int numEntries)\n> > +{\n> > +\tcache_.resize(numEntries, Entry(true, {}));\n> > +}\n> > +\n> > +/**\n> > + * \\brief Create a pre-populated cache\n> > + * \\param[in] buffers Array of buffers to pre-populated with\n> > + *\n> > + * Create a cache pre-populated with \\a buffers. This is typically used to\n> > + * implement buffer export, with all buffers added to the cache when they are\n> > + * allocated.\n> > + */\n> > +V4L2BufferCache::V4L2BufferCache(const std::vector<std::unique_ptr<FrameBuffer>> &buffers)\n> > +{\n> > +\tfor (const std::unique_ptr<FrameBuffer> &buffer : buffers)\n> > +\t\tcache_.emplace_back(true, buffer->planes());\n> > +}\n> > +\n> > +/**\n> > + * \\brief Find the best V4L2 buffer for a FrameBuffer\n> > + * \\param[in] buffer The FrameBuffer\n> > + *\n> > + * Find the best V4L2 buffer index to be used for the FrameBuffer \\a buffer\n> > + * based on previous mappings of frame buffers to V4L2 buffers. If a free V4L2\n> > + * buffer previously used with the same dmabufs as \\a buffer is found in the\n> > + * cache, return its index. Otherwise return the index of the first free V4L2\n> > + * buffer and record its association with the dmabufs of \\a buffer.\n> > + *\n> > + * \\return The index of the best V4L2 buffer, or -ENOENT if no free V4L2 buffer\n> > + * is available\n> > + */\n> > +int V4L2BufferCache::get(const FrameBuffer &buffer)\n> > +{\n> > +\tconst std::vector<FrameBuffer::Plane> &planes = buffer.planes();\n> > +\tint use = -1;\n> > +\n> > +\tfor (unsigned int index = 0; index < cache_.size(); index++) {\n> > +\t\tconst Entry &entry = cache_[index];\n> > +\n> > +\t\tif (!entry.free)\n> > +\t\t\tcontinue;\n> > +\n> > +\t\tif (use < 0)\n> > +\t\t\tuse = index;\n> > +\n> > +\t\t/* Try to find a cache hit by comparing the planes. */\n> > +\t\tif (cache_[index] == planes) {\n> > +\t\t\tuse = index;\n> > +\t\t\tbreak;\n> > +\t\t}\n> > +\t}\n> > +\n> > +\tif (use < 0)\n> > +\t\treturn -ENOENT;\n> > +\n> > +\tcache_[use] = Entry(false, planes);\n> > +\n> > +\treturn use;\n> > +}\n> > +\n> > +/**\n> > + * \\brief Mark buffer \\a index as free in the cache\n> > + * \\param[in] index The V4L2 buffer index\n> > + */\n> > +void V4L2BufferCache::put(unsigned int index)\n> > +{\n> > +\tASSERT(index < cache_.size());\n> > +\tcache_[index].free = true;\n> > +}\n> > +\n> >  /**\n> >   * \\class V4L2DeviceFormat\n> >   * \\brief The V4L2 video device image format and sizes","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 4AFF860612\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  8 Jan 2020 02:20:00 +0100 (CET)","from pendragon.ideasonboard.com (81-175-216-236.bb.dnainternet.fi\n\t[81.175.216.236])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 63B0A52F;\n\tWed,  8 Jan 2020 02:19:59 +0100 (CET)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1578446400;\n\tbh=8eeVu+NgbeVBknutRp0KVblaglAzbYn/06+U9sv+lFo=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=K4+kXEnNXbvOQr4ZG0IaX4lZSOupBi0riA9FuM4px3uDKF9gKIbkJrJdn58nZRto6\n\tenTx/gjR0h0/HQ4dSVG7W49cGd9gtSCwU+jpRes3MDRptQuFX9hEzt7wnZzHTvVurr\n\tvxGuS390P5dYN3WRaet5IzuAQuzTZqpP0S0q7A0E=","Date":"Wed, 8 Jan 2020 03:19:47 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Niklas =?utf-8?q?S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20200108011947.GV4871@pendragon.ideasonboard.com>","References":"<20191230120510.938333-1-niklas.soderlund@ragnatech.se>\n\t<20191230120510.938333-12-niklas.soderlund@ragnatech.se>\n\t<20200107230421.GR4871@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20200107230421.GR4871@pendragon.ideasonboard.com>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH v2 11/25] libcamera: v4l2_videodevice:\n\tAdd V4L2BufferCache to deal with index mapping","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Wed, 08 Jan 2020 01:20:00 -0000"}}]