Show a patch.

GET /api/1.1/patches/10344/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 10344,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/10344/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/10344/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/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": "<20201105001546.1690179-8-niklas.soderlund@ragnatech.se>",
    "date": "2020-11-05T00:15:42",
    "name": "[libcamera-devel,07/11] libcamera: ipa: ipu3: Add an IPA skeleton for the IPU3 pipeline",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "37e77f98c4bb0338f9af88dc1664fc1f63464e70",
    "submitter": {
        "id": 5,
        "url": "https://patchwork.libcamera.org/api/1.1/people/5/?format=api",
        "name": "Niklas Söderlund",
        "email": "niklas.soderlund@ragnatech.se"
    },
    "delegate": {
        "id": 16,
        "url": "https://patchwork.libcamera.org/api/1.1/users/16/?format=api",
        "username": "neg",
        "first_name": "Niklas",
        "last_name": "Söderlund",
        "email": "niklas.soderlund@ragnatech.se"
    },
    "mbox": "https://patchwork.libcamera.org/patch/10344/mbox/",
    "series": [
        {
            "id": 1447,
            "url": "https://patchwork.libcamera.org/api/1.1/series/1447/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=1447",
            "date": "2020-11-05T00:15:35",
            "name": "libcamera: ipu3: Attach to an skeleton IPA",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/1447/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/10344/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/10344/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 60E3BBDB89\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  5 Nov 2020 00:16:22 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 6241162CEE;\n\tThu,  5 Nov 2020 01:16:21 +0100 (CET)",
            "from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net\n\t[195.74.38.228])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3383062C94\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  5 Nov 2020 01:16:20 +0100 (CET)",
            "from bismarck.berto.se (p4fca2458.dip0.t-ipconnect.de\n\t[79.202.36.88])\n\tby bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA\n\tid 6d95e3c3-1efa-11eb-8a9c-005056917a89;\n\tThu, 05 Nov 2020 01:04:09 +0100 (CET)"
        ],
        "X-Halon-ID": "6d95e3c3-1efa-11eb-8a9c-005056917a89",
        "Authorized-sender": "niklas.soderlund@fsdn.se",
        "From": "=?utf-8?q?Niklas_S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Thu,  5 Nov 2020 01:15:42 +0100",
        "Message-Id": "<20201105001546.1690179-8-niklas.soderlund@ragnatech.se>",
        "X-Mailer": "git-send-email 2.29.2",
        "In-Reply-To": "<20201105001546.1690179-1-niklas.soderlund@ragnatech.se>",
        "References": "<20201105001546.1690179-1-niklas.soderlund@ragnatech.se>",
        "MIME-Version": "1.0",
        "Subject": "[libcamera-devel] [PATCH 07/11] libcamera: ipa: ipu3: Add an IPA\n\tskeleton for the IPU3 pipeline",
        "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>",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "base64",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "Add an empty IPA skeleton for the IPU3 pipeline. The skeleton IPA do\nhandle the flow of parameter and statistic buffers but does not read or\nwrite anything in the buffers. It also allows the IPA to set sensor\ncontrols but does not implement any logic to set optimal values and\ninstead set the V4L2 exposure and gain controls to max and keeps them at\nthat setting.\n\nThis IPA is meant as a base to allow the pipeline handler to be wired up\nto an IPA. The image algorithms can then later be added to the IPA\nindependent from also having to also add plumbing to the pipeline\nhandler.\n\nSigned-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n---\n include/libcamera/ipa/ipu3.h |  22 ++++\n src/ipa/ipu3/ipu3.cpp        | 237 +++++++++++++++++++++++++++++++++++\n src/ipa/ipu3/meson.build     |  21 ++++\n src/ipa/meson.build          |   2 +-\n 4 files changed, 281 insertions(+), 1 deletion(-)\n create mode 100644 include/libcamera/ipa/ipu3.h\n create mode 100644 src/ipa/ipu3/ipu3.cpp\n create mode 100644 src/ipa/ipu3/meson.build",
    "diff": "diff --git a/include/libcamera/ipa/ipu3.h b/include/libcamera/ipa/ipu3.h\nnew file mode 100644\nindex 0000000000000000..7c240a46b97dee28\n--- /dev/null\n+++ b/include/libcamera/ipa/ipu3.h\n@@ -0,0 +1,22 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2020, Google Inc.\n+ *\n+ * ipu3.h - Image Processing Algorithm interface for IPU3\n+ */\n+#ifndef __LIBCAMERA_IPA_INTERFACE_IPU3_H__\n+#define __LIBCAMERA_IPA_INTERFACE_IPU3_H__\n+\n+#ifndef __DOXYGEN__\n+\n+enum IPU3Operations {\n+\tIPU3_IPA_ACTION_SET_SENSOR_CONTROLS = 1,\n+\tIPU3_IPA_ACTION_PARAM_FILLED = 2,\n+\tIPU3_IPA_ACTION_METADATA_READY = 3,\n+\tIPU3_IPA_EVENT_PARSE_STAT = 4,\n+\tIPU3_IPA_EVENT_FILL_PARAMS = 5,\n+};\n+\n+#endif /* __DOXYGEN__ */\n+\n+#endif /* __LIBCAMERA_IPA_INTERFACE_IPU3_H__ */\ndiff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp\nnew file mode 100644\nindex 0000000000000000..cdcd9b9ff013e0cc\n--- /dev/null\n+++ b/src/ipa/ipu3/ipu3.cpp\n@@ -0,0 +1,237 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2020, Google Inc.\n+ *\n+ * ipu3.cpp - IPU3 Image Processing Algorithms\n+ */\n+\n+#include <algorithm>\n+#include <math.h>\n+#include <queue>\n+#include <stdint.h>\n+#include <string.h>\n+#include <sys/mman.h>\n+\n+#include <linux/intel-ipu3.h>\n+#include <linux/v4l2-controls.h>\n+\n+#include <libcamera/buffer.h>\n+#include <libcamera/control_ids.h>\n+#include <libcamera/ipa/ipa_interface.h>\n+#include <libcamera/ipa/ipa_module_info.h>\n+#include <libcamera/ipa/ipu3.h>\n+#include <libcamera/request.h>\n+\n+#include <libipa/ipa_interface_wrapper.h>\n+\n+#include \"libcamera/internal/log.h\"\n+\n+namespace libcamera {\n+\n+LOG_DEFINE_CATEGORY(IPAIPU3)\n+\n+class IPAIPU3 : public IPAInterface\n+{\n+public:\n+\tint init([[maybe_unused]] const IPASettings &settings) override\n+\t{\n+\t\treturn 0;\n+\t}\n+\tint start() override { return 0; }\n+\tvoid stop() override {}\n+\n+\tvoid configure(const CameraSensorInfo &info,\n+\t\t       const std::map<unsigned int, IPAStream> &streamConfig,\n+\t\t       const std::map<unsigned int, const ControlInfoMap &> &entityControls,\n+\t\t       const IPAOperationData &ipaConfig,\n+\t\t       IPAOperationData *response) override;\n+\tvoid mapBuffers(const std::vector<IPABuffer> &buffers) override;\n+\tvoid unmapBuffers(const std::vector<unsigned int> &ids) override;\n+\tvoid processEvent(const IPAOperationData &event) override;\n+\n+private:\n+\tvoid fillParams(unsigned int frame, ipu3_uapi_params *params,\n+\t\t\tconst ControlList &controls);\n+\n+\tvoid parseStatistics(unsigned int frame,\n+\t\t\t     const ipu3_uapi_stats_3a *stats);\n+\n+\tvoid setControls(unsigned int frame);\n+\n+\tstd::map<unsigned int, FrameBuffer> buffers_;\n+\tstd::map<unsigned int, void *> buffersMemory_;\n+\n+\tControlInfoMap ctrls_;\n+\n+\t/* Camera sensor controls. */\n+\tuint32_t exposure_;\n+\tuint32_t minExposure_;\n+\tuint32_t maxExposure_;\n+\tuint32_t gain_;\n+\tuint32_t minGain_;\n+\tuint32_t maxGain_;\n+};\n+\n+void IPAIPU3::configure([[maybe_unused]] const CameraSensorInfo &info,\n+\t\t\t[[maybe_unused]] const std::map<unsigned int, IPAStream> &streamConfig,\n+\t\t\tconst std::map<unsigned int, const ControlInfoMap &> &entityControls,\n+\t\t\t[[maybe_unused]] const IPAOperationData &ipaConfig,\n+\t\t\t[[maybe_unused]] IPAOperationData *result)\n+{\n+\tif (entityControls.empty())\n+\t\treturn;\n+\n+\tctrls_ = entityControls.at(0);\n+\n+\tconst auto itExp = ctrls_.find(V4L2_CID_EXPOSURE);\n+\tif (itExp == ctrls_.end()) {\n+\t\tLOG(IPAIPU3, Error) << \"Can't find exposure control\";\n+\t\treturn;\n+\t}\n+\n+\tconst auto itGain = ctrls_.find(V4L2_CID_ANALOGUE_GAIN);\n+\tif (itGain == ctrls_.end()) {\n+\t\tLOG(IPAIPU3, Error) << \"Can't find gain control\";\n+\t\treturn;\n+\t}\n+\n+\tminExposure_ = std::max<uint32_t>(itExp->second.min().get<int32_t>(), 1);\n+\tmaxExposure_ = itExp->second.max().get<int32_t>();\n+\texposure_ = maxExposure_;\n+\n+\tminGain_ = std::max<uint32_t>(itGain->second.min().get<int32_t>(), 1);\n+\tmaxGain_ = itGain->second.max().get<int32_t>();\n+\tgain_ = maxGain_;\n+\n+\tsetControls(0);\n+}\n+\n+void IPAIPU3::mapBuffers(const std::vector<IPABuffer> &buffers)\n+{\n+\tfor (const IPABuffer &buffer : buffers) {\n+\t\tauto elem = buffers_.emplace(std::piecewise_construct,\n+\t\t\t\t\t     std::forward_as_tuple(buffer.id),\n+\t\t\t\t\t     std::forward_as_tuple(buffer.planes));\n+\t\tconst FrameBuffer &fb = elem.first->second;\n+\n+\t\tbuffersMemory_[buffer.id] = mmap(NULL,\n+\t\t\t\t\t\t fb.planes()[0].length,\n+\t\t\t\t\t\t PROT_READ | PROT_WRITE,\n+\t\t\t\t\t\t MAP_SHARED,\n+\t\t\t\t\t\t fb.planes()[0].fd.fd(),\n+\t\t\t\t\t\t 0);\n+\n+\t\tif (buffersMemory_[buffer.id] == MAP_FAILED) {\n+\t\t\tint ret = -errno;\n+\t\t\tLOG(IPAIPU3, Fatal) << \"Failed to mmap buffer: \"\n+\t\t\t\t\t    << strerror(-ret);\n+\t\t}\n+\t}\n+}\n+\n+void IPAIPU3::unmapBuffers(const std::vector<unsigned int> &ids)\n+{\n+\tfor (unsigned int id : ids) {\n+\t\tconst auto fb = buffers_.find(id);\n+\t\tif (fb == buffers_.end())\n+\t\t\tcontinue;\n+\n+\t\tmunmap(buffersMemory_[id], fb->second.planes()[0].length);\n+\t\tbuffersMemory_.erase(id);\n+\t\tbuffers_.erase(id);\n+\t}\n+}\n+\n+void IPAIPU3::processEvent(const IPAOperationData &event)\n+{\n+\tswitch (event.operation) {\n+\tcase IPU3_IPA_EVENT_PARSE_STAT: {\n+\t\tunsigned int frame = event.data[0];\n+\t\tunsigned int bufferId = event.data[1];\n+\n+\t\tconst ipu3_uapi_stats_3a *stats =\n+\t\t\tstatic_cast<ipu3_uapi_stats_3a *>(buffersMemory_[bufferId]);\n+\n+\t\tparseStatistics(frame, stats);\n+\t\tbreak;\n+\t}\n+\tcase IPU3_IPA_EVENT_FILL_PARAMS: {\n+\t\tunsigned int frame = event.data[0];\n+\t\tunsigned int bufferId = event.data[1];\n+\n+\t\tipu3_uapi_params *params =\n+\t\t\tstatic_cast<ipu3_uapi_params *>(buffersMemory_[bufferId]);\n+\n+\t\tfillParams(frame, params, event.controls[0]);\n+\t\tbreak;\n+\t}\n+\tdefault:\n+\t\tLOG(IPAIPU3, Error) << \"Unknown event \" << event.operation;\n+\t\tbreak;\n+\t}\n+}\n+\n+void IPAIPU3::fillParams(unsigned int frame, ipu3_uapi_params *params,\n+\t\t\t [[maybe_unused]] const ControlList &controls)\n+{\n+\t/* Prepare parameters buffer. */\n+\tmemset(params, 0, sizeof(*params));\n+\n+\t/* \\todo Fill in parameters buffer. */\n+\n+\tIPAOperationData op;\n+\top.operation = IPU3_IPA_ACTION_PARAM_FILLED;\n+\n+\tqueueFrameAction.emit(frame, op);\n+\n+\t/* \\todo Calculate new values for exposure_ and gain_. */\n+\tsetControls(frame);\n+}\n+\n+void IPAIPU3::parseStatistics(unsigned int frame,\n+\t\t\t      [[maybe_unused]] const ipu3_uapi_stats_3a *stats)\n+{\n+\tControlList ctrls(controls::controls);\n+\n+\t/* \\todo React to statistics and update internal state machine. */\n+\t/* \\todo Add meta-data information to ctrls. */\n+\n+\tIPAOperationData op;\n+\top.operation = IPU3_IPA_ACTION_METADATA_READY;\n+\top.controls.push_back(ctrls);\n+\n+\tqueueFrameAction.emit(frame, op);\n+}\n+\n+void IPAIPU3::setControls(unsigned int frame)\n+{\n+\tIPAOperationData op;\n+\top.operation = IPU3_IPA_ACTION_SET_SENSOR_CONTROLS;\n+\n+\tControlList ctrls(ctrls_);\n+\tctrls.set(V4L2_CID_EXPOSURE, static_cast<int32_t>(exposure_));\n+\tctrls.set(V4L2_CID_ANALOGUE_GAIN, static_cast<int32_t>(gain_));\n+\top.controls.push_back(ctrls);\n+\n+\tqueueFrameAction.emit(frame, op);\n+}\n+\n+/*\n+ * External IPA module interface\n+ */\n+\n+extern \"C\" {\n+const struct IPAModuleInfo ipaModuleInfo = {\n+\tIPA_MODULE_API_VERSION,\n+\t1,\n+\t\"PipelineHandlerIPU3\",\n+\t\"ipu3\",\n+};\n+\n+struct ipa_context *ipaCreate()\n+{\n+\treturn new IPAInterfaceWrapper(std::make_unique<IPAIPU3>());\n+}\n+}\n+\n+} /* namespace libcamera */\ndiff --git a/src/ipa/ipu3/meson.build b/src/ipa/ipu3/meson.build\nnew file mode 100644\nindex 0000000000000000..a7e18f06b62bef3e\n--- /dev/null\n+++ b/src/ipa/ipu3/meson.build\n@@ -0,0 +1,21 @@\n+# SPDX-License-Identifier: CC0-1.0\n+\n+ipa_name = 'ipa_ipu3'\n+\n+mod = shared_module(ipa_name,\n+                    'ipu3.cpp',\n+                    name_prefix : '',\n+                    include_directories : [ipa_includes, libipa_includes],\n+                    dependencies : libcamera_dep,\n+                    link_with : libipa,\n+                    install : true,\n+                    install_dir : ipa_install_dir)\n+\n+if ipa_sign_module\n+    custom_target(ipa_name + '.so.sign',\n+                  input : mod,\n+                  output : ipa_name + '.so.sign',\n+                  command : [ ipa_sign, ipa_priv_key, '@INPUT@', '@OUTPUT@' ],\n+                  install : false,\n+                  build_by_default : true)\n+endif\ndiff --git a/src/ipa/meson.build b/src/ipa/meson.build\nindex 5a5de267c1477d24..9d623f227a1f9feb 100644\n--- a/src/ipa/meson.build\n+++ b/src/ipa/meson.build\n@@ -19,7 +19,7 @@ subdir('libipa')\n \n ipa_sign = files('ipa-sign.sh')\n \n-ipas = ['raspberrypi', 'rkisp1', 'vimc']\n+ipas = ['ipu3', 'raspberrypi', 'rkisp1', 'vimc']\n ipa_names = []\n \n foreach pipeline : get_option('pipelines')\n",
    "prefixes": [
        "libcamera-devel",
        "07/11"
    ]
}