Patch Detail
Show a patch.
GET /api/patches/13451/?format=api
{ "id": 13451, "url": "https://patchwork.libcamera.org/api/patches/13451/?format=api", "web_url": "https://patchwork.libcamera.org/patch/13451/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20210823131221.1034059-9-hiroh@chromium.org>", "date": "2021-08-23T13:12:19", "name": "[libcamera-devel,RFC,v2,08/10] libcamera: v4l2_videodevice: Create color-format planes in createBuffer()", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "0a36f1236f9fb2e01d7e841a1b5645beff9dafdc", "submitter": { "id": 63, "url": "https://patchwork.libcamera.org/api/people/63/?format=api", "name": "Hirokazu Honda", "email": "hiroh@chromium.org" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/13451/mbox/", "series": [ { "id": 2386, "url": "https://patchwork.libcamera.org/api/series/2386/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=2386", "date": "2021-08-23T13:12:11", "name": "Add offset to FrameBuffer::Plane", "version": 2, "mbox": "https://patchwork.libcamera.org/series/2386/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/13451/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/13451/checks/", "tags": {}, "headers": { "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>", "X-Original-To": "parsemail@patchwork.libcamera.org", "Delivered-To": "parsemail@patchwork.libcamera.org", "Received": [ "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id E8748BD87C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 23 Aug 2021 13:12:52 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id AE0C4688CA;\n\tMon, 23 Aug 2021 15:12:52 +0200 (CEST)", "from mail-pj1-x102a.google.com (mail-pj1-x102a.google.com\n\t[IPv6:2607:f8b0:4864:20::102a])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id CE245688A2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 23 Aug 2021 15:12:50 +0200 (CEST)", "by mail-pj1-x102a.google.com with SMTP id\n\toc2-20020a17090b1c0200b00179e56772d6so8740143pjb.4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 23 Aug 2021 06:12:50 -0700 (PDT)", "from hiroh2.tok.corp.google.com\n\t([2401:fa00:8f:203:184e:5d20:8fcb:dfcd])\n\tby smtp.gmail.com with ESMTPSA id\n\tj4sm18596891pgi.6.2021.08.23.06.12.45\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tMon, 23 Aug 2021 06:12:47 -0700 (PDT)" ], "Authentication-Results": "lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=chromium.org header.i=@chromium.org\n\theader.b=\"oQtRZi4d\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org;\n\ts=google; \n\th=from:to:cc:subject:date:message-id:in-reply-to:references\n\t:mime-version:content-transfer-encoding;\n\tbh=VMr5JtxGWOv7zUWIkxNhnnNOPhxrXVqs3DGz83bed2o=;\n\tb=oQtRZi4dzIa+jp/glNpWyFwy8GQ91ucY/Z976CgvNCp8Ms1gqXwk+oJMQFJuPUqB4w\n\tAs8p5pQEYMvnrVhSdkqbdhWIFASUVHQr9cC5pk2X+NTTja5wLp4IGMUVCNw4m4ZRMZGO\n\tZhtrmC5KtZ09oAay3AgYcVxpA/pG7cao2gGGk=", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references:mime-version:content-transfer-encoding;\n\tbh=VMr5JtxGWOv7zUWIkxNhnnNOPhxrXVqs3DGz83bed2o=;\n\tb=U+hDxNS4WSjVcLFSlYpaN8iv2Q68sfSeRZ9f8wtc3iC1lQ7b2tZiyMzY1fsCWF7V/T\n\tkIkhI6ElCeUJqP1cEciBUEFESFR8t4BN8w/lcBfjb3BabfZyaFDzI2aCgzJWPOt9Rclx\n\tVdj8WNXhs3ar6V67LBd2hoxMhbdLJrOIOaBBOr4HJhIYtKYlB3B5Y3yXhE9aL2bsjpaQ\n\tvwOkWBj8R32dmRfzCjHabbmfdoK9WA3A6vFtW+sW5y6ls/4X4mG0v0RV7V2oYsV+PbWJ\n\tg1sLnF9FKohFrpqdtRkCrhs7t6B+djMn2sFQjIA9mM+sIdfGFKhAIPSgTMFIEKUj9stP\n\thRLg==", "X-Gm-Message-State": "AOAM530+HzaJpvEVC/rEPttWRyPM+/U7QRzmPllAlpR4ePJoIAgVd/xQ\n\tabrAcPL/PkljJyUn4WTcLKBOMG59Re3FCA==", "X-Google-Smtp-Source": "ABdhPJyPsSab1RGWFDgFHWDr4ZYputxNeETibeqf6j9Ppl3aA+NwX9rKFdladJPpi5JS6+lXWWa6fw==", "X-Received": "by 2002:a17:90a:708c:: with SMTP id\n\tg12mr20365493pjk.13.1629724368327; \n\tMon, 23 Aug 2021 06:12:48 -0700 (PDT)", "From": "Hirokazu Honda <hiroh@chromium.org>", "To": "libcamera-devel@lists.libcamera.org", "Date": "Mon, 23 Aug 2021 22:12:19 +0900", "Message-Id": "<20210823131221.1034059-9-hiroh@chromium.org>", "X-Mailer": "git-send-email 2.33.0.rc2.250.ged5fa647cd-goog", "In-Reply-To": "<20210823131221.1034059-1-hiroh@chromium.org>", "References": "<20210823131221.1034059-1-hiroh@chromium.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Subject": "[libcamera-devel] [RFC PATCH v2 08/10] libcamera: v4l2_videodevice:\n\tCreate color-format planes in createBuffer()", "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>", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "V4L2VideDevice::createBuffer() creates the same number of\nFrameBuffer::Planes as V4L2 format planes. Therefore, if the v4l2\nformat single is single-planar format, the created number of\nFrameBuffer::Planes is 1.\nIt should rather create the same number of FrameBuffer::Planes as the\ncolor format planes.\n\nSigned-off-by: Hirokazu Honda <hiroh@chromium.org>\n---\n include/libcamera/internal/v4l2_videodevice.h | 9 +-\n src/libcamera/v4l2_videodevice.cpp | 147 ++++++++++++++----\n test/v4l2_videodevice/buffer_cache.cpp | 6 +-\n 3 files changed, 128 insertions(+), 34 deletions(-)", "diff": "diff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h\nindex e767ec84..69bb964a 100644\n--- a/include/libcamera/internal/v4l2_videodevice.h\n+++ b/include/libcamera/internal/v4l2_videodevice.h\n@@ -114,8 +114,9 @@ struct V4L2Capability final : v4l2_capability {\n class V4L2BufferCache\n {\n public:\n-\tV4L2BufferCache(unsigned int numEntries);\n-\tV4L2BufferCache(const std::vector<std::unique_ptr<FrameBuffer>> &buffers);\n+\tV4L2BufferCache(unsigned int numEntries, unsigned int numPlanes);\n+\tV4L2BufferCache(const std::vector<std::unique_ptr<FrameBuffer>> &buffers,\n+\t\t\tunsigned int numPlanes);\n \t~V4L2BufferCache();\n \n \tint get(const FrameBuffer &buffer);\n@@ -126,7 +127,8 @@ private:\n \t{\n \tpublic:\n \t\tEntry();\n-\t\tEntry(bool free, uint64_t lastUsed, const FrameBuffer &buffer);\n+\t\tEntry(bool free, uint64_t lastUsed, unsigned int numPlanes,\n+\t\t const FrameBuffer &buffer);\n \n \t\tbool operator==(const FrameBuffer &buffer) const;\n \n@@ -149,6 +151,7 @@ private:\n \n \tstd::atomic<uint64_t> lastUsedCounter_;\n \tstd::vector<Entry> cache_;\n+\tunsigned int numPlanes_;\n \t/* \\todo Expose the miss counter through an instrumentation API. */\n \tunsigned int missCounter_;\n };\ndiff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp\nindex ce60dff6..42b66bd3 100644\n--- a/src/libcamera/v4l2_videodevice.cpp\n+++ b/src/libcamera/v4l2_videodevice.cpp\n@@ -25,6 +25,7 @@\n \n #include <libcamera/file_descriptor.h>\n \n+#include \"libcamera/internal/formats.h\"\n #include \"libcamera/internal/media_device.h\"\n #include \"libcamera/internal/media_object.h\"\n \n@@ -158,12 +159,13 @@ LOG_DECLARE_CATEGORY(V4L2)\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+ * Create a cache with \\a numEntries entries all marked as unused. The entry is\n+ * for \\a numPlanes planes V4L2 buffer. The entries will be populated as the\n+ * cache is used. This is typically used to implement buffer import, with\n+ * buffers added to the cache as they are queued.\n */\n-V4L2BufferCache::V4L2BufferCache(unsigned int numEntries)\n-\t: lastUsedCounter_(1), missCounter_(0)\n+V4L2BufferCache::V4L2BufferCache(unsigned int numEntries, unsigned int numPlanes)\n+\t: lastUsedCounter_(1), numPlanes_(numPlanes), missCounter_(0)\n {\n \tcache_.resize(numEntries);\n }\n@@ -172,16 +174,18 @@ V4L2BufferCache::V4L2BufferCache(unsigned int numEntries)\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+ * Create a cache pre-populated with \\a buffers. The entry is for \\a numPlanes\n+ * planes V4L2 buffer. This is typically used to implement buffer export, with\n+ * all buffers added to the cache when they are allocated.\n */\n-V4L2BufferCache::V4L2BufferCache(const std::vector<std::unique_ptr<FrameBuffer>> &buffers)\n-\t: lastUsedCounter_(1), missCounter_(0)\n+V4L2BufferCache::V4L2BufferCache(const std::vector<std::unique_ptr<FrameBuffer>> &buffers,\n+\t\t\t\t unsigned int numPlanes)\n+\t: lastUsedCounter_(1), numPlanes_(numPlanes), missCounter_(0)\n {\n \tfor (const std::unique_ptr<FrameBuffer> &buffer : buffers)\n \t\tcache_.emplace_back(true,\n \t\t\t\t lastUsedCounter_.fetch_add(1, std::memory_order_acq_rel),\n+\t\t\t\t numPlanes_,\n \t\t\t\t *buffer.get());\n }\n \n@@ -237,6 +241,7 @@ int V4L2BufferCache::get(const FrameBuffer &buffer)\n \n \tcache_[use] = Entry(false,\n \t\t\t lastUsedCounter_.fetch_add(1, std::memory_order_acq_rel),\n+\t\t\t numPlanes_,\n \t\t\t buffer);\n \n \treturn use;\n@@ -257,24 +262,47 @@ V4L2BufferCache::Entry::Entry()\n {\n }\n \n-V4L2BufferCache::Entry::Entry(bool free, uint64_t lastUsed, const FrameBuffer &buffer)\n+V4L2BufferCache::Entry::Entry(bool free, uint64_t lastUsed,\n+\t\t\t unsigned int numPlanes, const FrameBuffer &buffer)\n \t: free_(free), lastUsed_(lastUsed)\n {\n-\tfor (const FrameBuffer::Plane &plane : buffer.planes())\n-\t\tplanes_.emplace_back(plane);\n+\tASSERT(numPlanes <= buffer.planes().size());\n+\tunsigned int length = 0;\n+\tfor (const FrameBuffer::Plane &plane : buffer.planes()) {\n+\t\tASSERT(plane.offset == length);\n+\t\tlength += plane.length;\n+\n+\t\tif (planes_.size() < numPlanes)\n+\t\t\tplanes_.emplace_back(plane);\n+\t}\n+\n+\tif (numPlanes == 1) {\n+\t\tplanes_[0].length = length;\n+\t}\n }\n \n bool V4L2BufferCache::Entry::operator==(const FrameBuffer &buffer) const\n {\n \tconst std::vector<FrameBuffer::Plane> &planes = buffer.planes();\n \n-\tif (planes_.size() != planes.size())\n+\tif (planes_.size() != planes.size() || planes_.size() == 1)\n \t\treturn false;\n-\n-\tfor (unsigned int i = 0; i < planes.size(); i++)\n-\t\tif (planes_[i].fd != planes[i].fd.fd() ||\n-\t\t planes_[i].length != planes[i].length)\n+\tif (planes_.size() == 1) {\n+\t\tunsigned int length = 0;\n+\t\tfor (unsigned int i = 0; i < planes.size(); i++) {\n+\t\t\tif (planes_[0].fd != planes[i].fd.fd())\n+\t\t\t\treturn false;\n+\t\t\tlength += planes[i].length;\n+\t\t}\n+\t\tif (length != planes_[0].length)\n \t\t\treturn false;\n+\t} else {\n+\t\tfor (unsigned int i = 0; i < planes.size(); i++)\n+\t\t\tif (planes_[i].fd != planes[i].fd.fd() ||\n+\t\t\t planes_[i].length != planes[i].length)\n+\t\t\t\treturn false;\n+\t}\n+\n \treturn true;\n }\n \n@@ -1152,8 +1180,13 @@ int V4L2VideoDevice::requestBuffers(unsigned int count,\n * successful return the driver's internal buffer management is initialized in\n * MMAP mode, and the video device is ready to accept queueBuffer() calls.\n *\n- * The number of planes and the plane sizes for the allocation are determined\n- * by the currently active format on the device as set by setFormat().\n+ * The number of planes and their offsets and sizes are determined by the\n+ * currently active format on the device as set by setFormat(). They do not map\n+ * to the V4L2 buffer planes, but to colour planes of the pixel format. For\n+ * instance, if the active format is formats::NV12, the allocated FrameBuffer\n+ * instances will have two planes, for the luma and chroma components,\n+ * regardless of whether the device uses V4L2_PIX_FMT_NV12 or\n+ * V4L2_PIX_FMT_NV12M.\n *\n * Buffers allocated with this function shall later be free with\n * releaseBuffers(). If buffers have already been allocated with\n@@ -1167,11 +1200,19 @@ int V4L2VideoDevice::requestBuffers(unsigned int count,\n int V4L2VideoDevice::allocateBuffers(unsigned int count,\n \t\t\t\t std::vector<std::unique_ptr<FrameBuffer>> *buffers)\n {\n-\tint ret = createBuffers(count, buffers);\n+\tV4L2DeviceFormat format{};\n+\tint ret = getFormat(&format);\n+\tif (ret < 0) {\n+\t\tLOG(V4L2, Error)\n+\t\t\t<< \"Failed to get format: \" << strerror(-ret);\n+\t\treturn ret;\n+\t}\n+\n+\tret = createBuffers(count, buffers);\n \tif (ret < 0)\n \t\treturn ret;\n \n-\tcache_ = new V4L2BufferCache(*buffers);\n+\tcache_ = new V4L2BufferCache(*buffers, format.planesCount);\n \tmemoryType_ = V4L2_MEMORY_MMAP;\n \n \treturn ret;\n@@ -1190,8 +1231,13 @@ int V4L2VideoDevice::allocateBuffers(unsigned int count,\n * usable with any V4L2 video device in DMABUF mode, or with other dmabuf\n * importers.\n *\n- * The number of planes and the plane sizes for the allocation are determined\n- * by the currently active format on the device as set by setFormat().\n+ * The number of planes and their offsets and sizes are determined by the\n+ * currently active format on the device as set by setFormat(). They do not map\n+ * to the V4L2 buffer planes, but to colour planes of the pixel format. For\n+ * instance, if the active format is formats::NV12, the allocated FrameBuffer\n+ * instances will have two planes, for the luma and chroma components,\n+ * regardless of whether the device uses V4L2_PIX_FMT_NV12 or\n+ * V4L2_PIX_FMT_NV12M.\n *\n * Multiple independent sets of buffers can be allocated with multiple calls to\n * this function. Device-specific limitations may apply regarding the minimum\n@@ -1283,12 +1329,49 @@ std::unique_ptr<FrameBuffer> V4L2VideoDevice::createBuffer(unsigned int index)\n \n \t\tFrameBuffer::Plane plane;\n \t\tplane.fd = std::move(fd);\n-\t\tplane.length = multiPlanar ?\n-\t\t\tbuf.m.planes[nplane].length : buf.length;\n+\t\t/*\n+\t\t * V4L2 API doesn't provide dmabuf offset information of plane.\n+\t\t * Set 0 as a placeholder offset.\n+\t\t * \\todo Set the right offset once V4L2 API provides a way.\n+\t\t */\n+\t\tplane.offset = 0;\n+\t\tplane.length = multiPlanar ? buf.m.planes[nplane].length : buf.length;\n \n \t\tplanes.push_back(std::move(plane));\n \t}\n \n+\t/*\n+\t * Get V4L2DeviceFormat of the frame buffer. If it is V4L2 single-planar\n+\t * format, overwrite FrameBuffer::Plane to make it color format planes.\n+\t * */\n+\tV4L2DeviceFormat format{};\n+\tret = getFormat(&format);\n+\tif (ret < 0) {\n+\t\tLOG(V4L2, Error)\n+\t\t\t<< \"Failed to get format: \" << strerror(-ret);\n+\t\treturn nullptr;\n+\t}\n+\n+\tconst auto &info = PixelFormatInfo::info(format.fourcc);\n+\tif (info.isValid() && info.numPlanes() != numPlanes) {\n+\t\tASSERT(numPlanes == 1u);\n+\t\tconst size_t numColorPlanes = info.numPlanes();\n+\t\tplanes.resize(numColorPlanes);\n+\t\tconst FileDescriptor &fd = planes[0].fd;\n+\t\tsize_t offset = 0;\n+\t\tfor (size_t i = 0; i < numColorPlanes; ++i) {\n+\t\t\tplanes[i].fd = fd;\n+\t\t\tplanes[i].offset = offset;\n+\n+\t\t\tconst unsigned int vertSubSample =\n+\t\t\t\tinfo.planes[i].verticalSubSampling;\n+\t\t\tplanes[i].length =\n+\t\t\t\tinfo.stride(format.size.width, i, 1u) *\n+\t\t\t\t((format.size.height + vertSubSample - 1) / vertSubSample);\n+\t\t\toffset += planes[i].length;\n+\t\t}\n+\t}\n+\n \treturn std::make_unique<FrameBuffer>(std::move(planes));\n }\n \n@@ -1342,11 +1425,19 @@ int V4L2VideoDevice::importBuffers(unsigned int count)\n \n \tmemoryType_ = V4L2_MEMORY_DMABUF;\n \n-\tint ret = requestBuffers(count, V4L2_MEMORY_DMABUF);\n+\tV4L2DeviceFormat format{};\n+\tint ret = getFormat(&format);\n+\tif (ret < 0) {\n+\t\tLOG(V4L2, Error)\n+\t\t\t<< \"Failed to get format: \" << strerror(-ret);\n+\t\treturn ret;\n+\t}\n+\n+\tret = requestBuffers(count, V4L2_MEMORY_DMABUF);\n \tif (ret)\n \t\treturn ret;\n \n-\tcache_ = new V4L2BufferCache(count);\n+\tcache_ = new V4L2BufferCache(count, format.planesCount);\n \n \tLOG(V4L2, Debug) << \"Prepared to import \" << count << \" buffers\";\n \ndiff --git a/test/v4l2_videodevice/buffer_cache.cpp b/test/v4l2_videodevice/buffer_cache.cpp\nindex b3f2bec1..48f748bc 100644\n--- a/test/v4l2_videodevice/buffer_cache.cpp\n+++ b/test/v4l2_videodevice/buffer_cache.cpp\n@@ -166,7 +166,7 @@ public:\n \t\t * Test cache of same size as there are buffers, the cache is\n \t\t * created from a list of buffers and will be pre-populated.\n \t\t */\n-\t\tV4L2BufferCache cacheFromBuffers(buffers);\n+\t\tV4L2BufferCache cacheFromBuffers(buffers, 1u);\n \n \t\tif (testSequential(&cacheFromBuffers, buffers) != TestPass)\n \t\t\treturn TestFail;\n@@ -181,7 +181,7 @@ public:\n \t\t * Test cache of same size as there are buffers, the cache is\n \t\t * not pre-populated.\n \t\t */\n-\t\tV4L2BufferCache cacheFromNumbers(numBuffers);\n+\t\tV4L2BufferCache cacheFromNumbers(numBuffers, 1u);\n \n \t\tif (testSequential(&cacheFromNumbers, buffers) != TestPass)\n \t\t\treturn TestFail;\n@@ -196,7 +196,7 @@ public:\n \t\t * Test cache half the size of number of buffers used, the cache\n \t\t * is not pre-populated.\n \t\t */\n-\t\tV4L2BufferCache cacheHalf(numBuffers / 2);\n+\t\tV4L2BufferCache cacheHalf(numBuffers / 2, 1u);\n \n \t\tif (testRandom(&cacheHalf, buffers) != TestPass)\n \t\t\treturn TestFail;\n", "prefixes": [ "libcamera-devel", "RFC", "v2", "08/10" ] }