Show a patch.

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

{
    "id": 10580,
    "url": "https://patchwork.libcamera.org/api/patches/10580/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/10580/",
    "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": "<20201205103106.242080-18-paul.elder@ideasonboard.com>",
    "date": "2020-12-05T10:31:00",
    "name": "[libcamera-devel,v5,17/23] libcamera: pipeline, ipa: raspberrypi: Use new data definition",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "49c058bc98e80282377fb6b8f58adf5932b1c420",
    "submitter": {
        "id": 17,
        "url": "https://patchwork.libcamera.org/api/people/17/?format=api",
        "name": "Paul Elder",
        "email": "paul.elder@ideasonboard.com"
    },
    "delegate": {
        "id": 17,
        "url": "https://patchwork.libcamera.org/api/users/17/?format=api",
        "username": "epaul",
        "first_name": "Paul",
        "last_name": "Elder",
        "email": "paul.elder@ideasonboard.com"
    },
    "mbox": "https://patchwork.libcamera.org/patch/10580/mbox/",
    "series": [
        {
            "id": 1506,
            "url": "https://patchwork.libcamera.org/api/series/1506/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=1506",
            "date": "2020-12-05T10:30:43",
            "name": "IPA isolation implementation",
            "version": 5,
            "mbox": "https://patchwork.libcamera.org/series/1506/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/10580/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/10580/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 DBCD4BDB20\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSat,  5 Dec 2020 10:31:57 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A6CED63615;\n\tSat,  5 Dec 2020 11:31:57 +0100 (CET)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 03579635F0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat,  5 Dec 2020 11:31:56 +0100 (CET)",
            "from pyrite.rasen.tech (unknown\n\t[IPv6:2400:4051:61:600:2c71:1b79:d06d:5032])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id AC9A82A4;\n\tSat,  5 Dec 2020 11:31:53 +0100 (CET)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"Gg79zLgt\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1607164314;\n\tbh=qaDeDaQdueNdCoLtO2W55iBEQzIKdvjmIoo0AWSSbRc=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=Gg79zLgtC8+IzXscz8oncjMPAL68ZebQeP0mqHKcj1F6VSx/JE5td+soxAIA/Zkqr\n\tIJjlc7LvZZI7egWk/p5S5hYIQrb0akP2yTfgmdSUwS/+1oZZO2F//FcKAHNcH2xtsZ\n\tl3d4OyLkhSO09sRwWKhldH/tYzs/XwQN2Z8ZPaTo=",
        "From": "Paul Elder <paul.elder@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Sat,  5 Dec 2020 19:31:00 +0900",
        "Message-Id": "<20201205103106.242080-18-paul.elder@ideasonboard.com>",
        "X-Mailer": "git-send-email 2.27.0",
        "In-Reply-To": "<20201205103106.242080-1-paul.elder@ideasonboard.com>",
        "References": "<20201205103106.242080-1-paul.elder@ideasonboard.com>",
        "MIME-Version": "1.0",
        "Subject": "[libcamera-devel] [PATCH v5 17/23] libcamera: pipeline,\n\tipa: raspberrypi: Use new data definition",
        "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=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "Now that we can generate custom functions and data structures with mojo,\nswitch the raspberrypi pipeline handler and IPA to use the custom data\nstructures as defined in the mojom data definition file.\n\nSigned-off-by: Paul Elder <paul.elder@ideasonboard.com>\n\n---\nChanges in v5:\n- minor fixes\n- use new struct names\n\nChanges in v4:\n- rename Controls to controls\n- use the renamed header (raspberrypi_ipa_interface.h)\n\nChanges in v3:\n- use ipa::rpi namespace\n- rebase on the RPi namespace patch series newly merged into master\n\nChanges in v2:\n- rebased on \"libcamera: pipeline: ipa: raspberrypi: Rework drop frame\n  signalling\"\n- use newly customized RPi IPA interface\n---\n include/libcamera/ipa/raspberrypi.h           |  41 ++--\n src/ipa/raspberrypi/raspberrypi.cpp           | 158 ++++++--------\n .../pipeline/raspberrypi/raspberrypi.cpp      | 193 +++++++++---------\n 3 files changed, 182 insertions(+), 210 deletions(-)",
    "diff": "diff --git a/include/libcamera/ipa/raspberrypi.h b/include/libcamera/ipa/raspberrypi.h\nindex df30b4a2..e145de3f 100644\n--- a/include/libcamera/ipa/raspberrypi.h\n+++ b/include/libcamera/ipa/raspberrypi.h\n@@ -28,24 +28,29 @@ enum BufferMask {\n static constexpr unsigned int MaxLsGridSize = 32 << 10;\n \n /* List of controls handled by the Raspberry Pi IPA */\n-static const ControlInfoMap Controls = {\n-\t{ &controls::AeEnable, ControlInfo(false, true) },\n-\t{ &controls::ExposureTime, ControlInfo(0, 999999) },\n-\t{ &controls::AnalogueGain, ControlInfo(1.0f, 32.0f) },\n-\t{ &controls::AeMeteringMode, ControlInfo(controls::AeMeteringModeValues) },\n-\t{ &controls::AeConstraintMode, ControlInfo(controls::AeConstraintModeValues) },\n-\t{ &controls::AeExposureMode, ControlInfo(controls::AeExposureModeValues) },\n-\t{ &controls::ExposureValue, ControlInfo(0.0f, 16.0f) },\n-\t{ &controls::AwbEnable, ControlInfo(false, true) },\n-\t{ &controls::ColourGains, ControlInfo(0.0f, 32.0f) },\n-\t{ &controls::AwbMode, ControlInfo(controls::AwbModeValues) },\n-\t{ &controls::Brightness, ControlInfo(-1.0f, 1.0f) },\n-\t{ &controls::Contrast, ControlInfo(0.0f, 32.0f) },\n-\t{ &controls::Saturation, ControlInfo(0.0f, 32.0f) },\n-\t{ &controls::Sharpness, ControlInfo(0.0f, 16.0f, 1.0f) },\n-\t{ &controls::ColourCorrectionMatrix, ControlInfo(-16.0f, 16.0f) },\n-\t{ &controls::ScalerCrop, ControlInfo(Rectangle{}, Rectangle(65535, 65535, 65535, 65535), Rectangle{}) },\n-};\n+static ControlInfoMap controls;\n+\n+inline void initializeRPiControls()\n+{\n+\tcontrols = {\n+\t\t{ &controls::AeEnable, ControlInfo(false, true) },\n+\t\t{ &controls::ExposureTime, ControlInfo(0, 999999) },\n+\t\t{ &controls::AnalogueGain, ControlInfo(1.0f, 32.0f) },\n+\t\t{ &controls::AeMeteringMode, ControlInfo(controls::AeMeteringModeValues) },\n+\t\t{ &controls::AeConstraintMode, ControlInfo(controls::AeConstraintModeValues) },\n+\t\t{ &controls::AeExposureMode, ControlInfo(controls::AeExposureModeValues) },\n+\t\t{ &controls::ExposureValue, ControlInfo(0.0f, 16.0f) },\n+\t\t{ &controls::AwbEnable, ControlInfo(false, true) },\n+\t\t{ &controls::ColourGains, ControlInfo(0.0f, 32.0f) },\n+\t\t{ &controls::AwbMode, ControlInfo(controls::AwbModeValues) },\n+\t\t{ &controls::Brightness, ControlInfo(-1.0f, 1.0f) },\n+\t\t{ &controls::Contrast, ControlInfo(0.0f, 32.0f) },\n+\t\t{ &controls::Saturation, ControlInfo(0.0f, 32.0f) },\n+\t\t{ &controls::Sharpness, ControlInfo(0.0f, 16.0f, 1.0f) },\n+\t\t{ &controls::ColourCorrectionMatrix, ControlInfo(-16.0f, 16.0f) },\n+\t\t{ &controls::ScalerCrop, ControlInfo(Rectangle{}, Rectangle(65535, 65535, 65535, 65535), Rectangle{}) },\n+\t};\n+}\n \n } /* namespace RPi */\n \ndiff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp\nindex 4dc02dc8..29e4854e 100644\n--- a/src/ipa/raspberrypi/raspberrypi.cpp\n+++ b/src/ipa/raspberrypi/raspberrypi.cpp\n@@ -19,6 +19,7 @@\n #include <libcamera/ipa/ipa_interface.h>\n #include <libcamera/ipa/ipa_module_info.h>\n #include <libcamera/ipa/raspberrypi.h>\n+#include <libcamera/ipa/raspberrypi_ipa_interface.h>\n #include <libcamera/request.h>\n #include <libcamera/span.h>\n \n@@ -59,7 +60,7 @@ constexpr unsigned int DefaultExposureTime = 20000;\n \n LOG_DEFINE_CATEGORY(IPARPI)\n \n-class IPARPi : public IPAInterface\n+class IPARPi : public ipa::rpi::IPARPiInterface\n {\n public:\n \tIPARPi()\n@@ -67,6 +68,7 @@ public:\n \t\t  frameCount_(0), checkCount_(0), mistrustCount_(0),\n \t\t  lsTable_(nullptr)\n \t{\n+\t\tRPi::initializeRPiControls();\n \t}\n \n \t~IPARPi()\n@@ -81,12 +83,14 @@ public:\n \n \tvoid configure(const CameraSensorInfo &sensorInfo,\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 &data,\n-\t\t       IPAOperationData *response) override;\n+\t\t       const std::map<unsigned int, ControlInfoMap> &entityControls,\n+\t\t       const ipa::rpi::ConfigInput &data,\n+\t\t       ipa::rpi::ConfigOutput *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+\tvoid signalStatReady(const uint32_t bufferId) override;\n+\tvoid signalQueueRequest(const ControlList &controls) override;\n+\tvoid signalIspPrepare(const ipa::rpi::ISPConfig &data) override;\n \n private:\n \tvoid setMode(const CameraSensorInfo &sensorInfo);\n@@ -142,6 +146,11 @@ private:\n \n \t/* LS table allocation passed in from the pipeline handler. */\n \tFileDescriptor lsTableHandle_;\n+\t/*\n+\t * LS table allocation passed in from the pipeline handler,\n+\t * in the context of the pipeline handler.\n+\t */\n+\tint32_t lsTableHandlePH_;\n \tvoid *lsTable_;\n };\n \n@@ -191,15 +200,13 @@ void IPARPi::setMode(const CameraSensorInfo &sensorInfo)\n \n void IPARPi::configure(const CameraSensorInfo &sensorInfo,\n \t\t       [[maybe_unused]] 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 *result)\n+\t\t       const std::map<unsigned int, ControlInfoMap> &entityControls,\n+\t\t       const ipa::rpi::ConfigInput &ipaConfig,\n+\t\t       ipa::rpi::ConfigOutput *result)\n {\n \tif (entityControls.empty())\n \t\treturn;\n \n-\tresult->operation = 0;\n-\n \tunicamCtrls_ = entityControls.at(0);\n \tispCtrls_ = entityControls.at(1);\n \n@@ -223,32 +230,28 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo,\n \t\thelper_->GetDelays(exposureDelay, gainDelay);\n \t\tsensorMetadata = helper_->SensorEmbeddedDataPresent();\n \n-\t\tresult->data.push_back(gainDelay);\n-\t\tresult->data.push_back(exposureDelay);\n-\t\tresult->data.push_back(sensorMetadata);\n-\n-\t\tresult->operation |= RPi::IPA_CONFIG_STAGGERED_WRITE;\n+\t\tresult->op_ |= ipa::rpi::ConfigStaggeredWrite;\n+\t\tresult->sensorConfig_.gainDelay_ = gainDelay;\n+\t\tresult->sensorConfig_.exposureDelay_ = exposureDelay;\n+\t\tresult->sensorConfig_.sensorMetadata_ = sensorMetadata;\n \t}\n \n \t/* Re-assemble camera mode using the sensor info. */\n \tsetMode(sensorInfo);\n \n-\t/*\n-\t * The ipaConfig.data always gives us the user transform first. Note that\n-\t * this will always make the LS table pointer (if present) element 1.\n-\t */\n-\tmode_.transform = static_cast<libcamera::Transform>(ipaConfig.data[0]);\n+\tmode_.transform = static_cast<libcamera::Transform>(ipaConfig.transform_);\n \n \t/* Store the lens shading table pointer and handle if available. */\n-\tif (ipaConfig.operation & RPi::IPA_CONFIG_LS_TABLE) {\n+\tif (ipaConfig.op_ & ipa::rpi::ConfigLsTable) {\n \t\t/* Remove any previous table, if there was one. */\n \t\tif (lsTable_) {\n \t\t\tmunmap(lsTable_, RPi::MaxLsGridSize);\n \t\t\tlsTable_ = nullptr;\n \t\t}\n \n-\t\t/* Map the LS table buffer into user space (now element 1). */\n-\t\tlsTableHandle_ = FileDescriptor(ipaConfig.data[1]);\n+\t\t/* Map the LS table buffer into user space. */\n+\t\tlsTableHandle_ = FileDescriptor(ipaConfig.lsTableHandle_);\n+\t\tlsTableHandlePH_ = ipaConfig.lsTableHandleStatic_;\n \t\tif (lsTableHandle_.isValid()) {\n \t\t\tlsTable_ = mmap(nullptr, RPi::MaxLsGridSize, PROT_READ | PROT_WRITE,\n \t\t\t\t\tMAP_SHARED, lsTableHandle_.fd(), 0);\n@@ -270,18 +273,15 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo,\n \t */\n \tframeCount_ = 0;\n \tcheckCount_ = 0;\n-\tunsigned int dropFrame = 0;\n+\tresult->op_ |= ipa::rpi::ConfigDropFrames;\n \tif (controllerInit_) {\n-\t\tdropFrame = helper_->HideFramesModeSwitch();\n+\t\tresult->dropFrameCount_ = helper_->HideFramesModeSwitch();\n \t\tmistrustCount_ = helper_->MistrustFramesModeSwitch();\n \t} else {\n-\t\tdropFrame = helper_->HideFramesStartup();\n+\t\tresult->dropFrameCount_ = helper_->HideFramesStartup();\n \t\tmistrustCount_ = helper_->MistrustFramesStartup();\n \t}\n \n-\tresult->data.push_back(dropFrame);\n-\tresult->operation |= RPi::IPA_CONFIG_DROP_FRAMES;\n-\n \t/* These zero values mean not program anything (unless overwritten). */\n \tstruct AgcStatus agcStatus;\n \tagcStatus.shutter_time = 0.0;\n@@ -306,9 +306,9 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo,\n \tif (agcStatus.shutter_time != 0.0 && agcStatus.analogue_gain != 0.0) {\n \t\tControlList ctrls(unicamCtrls_);\n \t\tapplyAGC(&agcStatus, ctrls);\n-\t\tresult->controls.push_back(ctrls);\n \n-\t\tresult->operation |= RPi::IPA_CONFIG_SENSOR;\n+\t\tresult->op_ |= ipa::rpi::ConfigSensor;\n+\t\tresult->controls_ = std::move(ctrls);\n \t}\n \n \tlastMode_ = mode_;\n@@ -333,56 +333,38 @@ void IPARPi::unmapBuffers(const std::vector<unsigned int> &ids)\n \t}\n }\n \n-void IPARPi::processEvent(const IPAOperationData &event)\n+void IPARPi::signalStatReady(const uint32_t bufferId)\n {\n-\tswitch (event.operation) {\n-\tcase RPi::IPA_EVENT_SIGNAL_STAT_READY: {\n-\t\tunsigned int bufferId = event.data[0];\n-\n-\t\tif (++checkCount_ != frameCount_) /* assert here? */\n-\t\t\tLOG(IPARPI, Error) << \"WARNING: Prepare/Process mismatch!!!\";\n-\t\tif (frameCount_ > mistrustCount_)\n-\t\t\tprocessStats(bufferId);\n-\n-\t\treportMetadata();\n-\n-\t\tIPAOperationData op;\n-\t\top.operation = RPi::IPA_ACTION_STATS_METADATA_COMPLETE;\n-\t\top.data = { bufferId & RPi::BufferMask::ID };\n-\t\top.controls = { libcameraMetadata_ };\n-\t\tqueueFrameAction.emit(0, op);\n-\t\tbreak;\n-\t}\n+\tif (++checkCount_ != frameCount_) /* assert here? */\n+\t\tLOG(IPARPI, Error) << \"WARNING: Prepare/Process mismatch!!!\";\n+\tif (frameCount_ > mistrustCount_)\n+\t\tprocessStats(bufferId);\n \n-\tcase RPi::IPA_EVENT_SIGNAL_ISP_PREPARE: {\n-\t\tunsigned int embeddedbufferId = event.data[0];\n-\t\tunsigned int bayerbufferId = event.data[1];\n+\treportMetadata();\n \n-\t\t/*\n-\t\t * At start-up, or after a mode-switch, we may want to\n-\t\t * avoid running the control algos for a few frames in case\n-\t\t * they are \"unreliable\".\n-\t\t */\n-\t\tprepareISP(embeddedbufferId);\n-\t\tframeCount_++;\n-\n-\t\t/* Ready to push the input buffer into the ISP. */\n-\t\tIPAOperationData op;\n-\t\top.operation = RPi::IPA_ACTION_RUN_ISP;\n-\t\top.data = { bayerbufferId & RPi::BufferMask::ID };\n-\t\tqueueFrameAction.emit(0, op);\n-\t\tbreak;\n-\t}\n+\tstatsMetadataComplete.emit(bufferId & RPi::BufferMask::ID, libcameraMetadata_);\n+}\n \n-\tcase RPi::IPA_EVENT_QUEUE_REQUEST: {\n-\t\tqueueRequest(event.controls[0]);\n-\t\tbreak;\n-\t}\n+void IPARPi::signalQueueRequest(const ControlList &controls)\n+{\n+\tqueueRequest(controls);\n+}\n \n-\tdefault:\n-\t\tLOG(IPARPI, Error) << \"Unknown event \" << event.operation;\n-\t\tbreak;\n-\t}\n+void IPARPi::signalIspPrepare(const ipa::rpi::ISPConfig &data)\n+{\n+\tunsigned int embeddedbufferId = data.embeddedbufferId_;\n+\tunsigned int bayerbufferId = data.bayerbufferId_;\n+\n+\t/*\n+\t * At start-up, or after a mode-switch, we may want to\n+\t * avoid running the control algos for a few frames in case\n+\t * they are \"unreliable\".\n+\t */\n+\tprepareISP(embeddedbufferId);\n+\tframeCount_++;\n+\n+\t/* Ready to push the input buffer into the ISP. */\n+\trunIsp.emit(bayerbufferId & RPi::BufferMask::ID);\n }\n \n void IPARPi::reportMetadata()\n@@ -693,10 +675,7 @@ void IPARPi::queueRequest(const ControlList &controls)\n \n void IPARPi::returnEmbeddedBuffer(unsigned int bufferId)\n {\n-\tIPAOperationData op;\n-\top.operation = RPi::IPA_ACTION_EMBEDDED_COMPLETE;\n-\top.data = { bufferId & RPi::BufferMask::ID };\n-\tqueueFrameAction.emit(0, op);\n+\tembeddedComplete.emit(bufferId & RPi::BufferMask::ID);\n }\n \n void IPARPi::prepareISP(unsigned int bufferId)\n@@ -757,12 +736,8 @@ void IPARPi::prepareISP(unsigned int bufferId)\n \t\tif (dpcStatus)\n \t\t\tapplyDPC(dpcStatus, ctrls);\n \n-\t\tif (!ctrls.empty()) {\n-\t\t\tIPAOperationData op;\n-\t\t\top.operation = RPi::IPA_ACTION_V4L2_SET_ISP;\n-\t\t\top.controls.push_back(ctrls);\n-\t\t\tqueueFrameAction.emit(0, op);\n-\t\t}\n+\t\tif (!ctrls.empty())\n+\t\t\tsetIsp.emit(ctrls);\n \t}\n }\n \n@@ -819,10 +794,7 @@ void IPARPi::processStats(unsigned int bufferId)\n \t\tControlList ctrls(unicamCtrls_);\n \t\tapplyAGC(&agcStatus, ctrls);\n \n-\t\tIPAOperationData op;\n-\t\top.operation = RPi::IPA_ACTION_V4L2_SET_STAGGERED;\n-\t\top.controls.push_back(ctrls);\n-\t\tqueueFrameAction.emit(0, op);\n+\t\tsetStaggered.emit(ctrls);\n \t}\n }\n \n@@ -1052,7 +1024,7 @@ void IPARPi::applyLS(const struct AlscStatus *lsStatus, ControlList &ctrls)\n \t\t.grid_width = w,\n \t\t.grid_stride = w,\n \t\t.grid_height = h,\n-\t\t.dmabuf = lsTableHandle_.fd(),\n+\t\t.dmabuf = lsTableHandlePH_,\n \t\t.ref_transform = 0,\n \t\t.corner_sampled = 1,\n \t\t.gain_format = GAIN_FORMAT_U4P10\n@@ -1129,9 +1101,9 @@ const struct IPAModuleInfo ipaModuleInfo = {\n \t\"raspberrypi\",\n };\n \n-struct ipa_context *ipaCreate()\n+IPAInterface *ipaCreate()\n {\n-\treturn new IPAInterfaceWrapper(std::make_unique<IPARPi>());\n+\treturn new IPARPi();\n }\n \n } /* extern \"C\" */\ndiff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\nindex 6fcdf557..f11c4112 100644\n--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n@@ -17,6 +17,8 @@\n #include <libcamera/file_descriptor.h>\n #include <libcamera/formats.h>\n #include <libcamera/ipa/raspberrypi.h>\n+#include <libcamera/ipa/raspberrypi_ipa_interface.h>\n+#include <libcamera/ipa/raspberrypi_ipa_proxy.h>\n #include <libcamera/logging.h>\n #include <libcamera/property_ids.h>\n #include <libcamera/request.h>\n@@ -145,7 +147,11 @@ public:\n \tint loadIPA();\n \tint configureIPA(const CameraConfiguration *config);\n \n-\tvoid queueFrameAction(unsigned int frame, const IPAOperationData &action);\n+\tvoid statsMetadataComplete(uint32_t bufferId, const ControlList &controls);\n+\tvoid runIsp(uint32_t bufferId);\n+\tvoid embeddedComplete(uint32_t bufferId);\n+\tvoid setIsp(const ControlList &controls);\n+\tvoid setStaggered(const ControlList &controls);\n \n \t/* bufferComplete signal handlers. */\n \tvoid unicamBufferDequeue(FrameBuffer *buffer);\n@@ -157,6 +163,8 @@ public:\n \tvoid handleExternalBuffer(FrameBuffer *buffer, RPi::Stream *stream);\n \tvoid handleState();\n \n+\tstd::unique_ptr<ipa::rpi::IPAProxyRPi> ipa_;\n+\n \tCameraSensor *sensor_;\n \t/* Array of Unicam and ISP device streams and associated buffers/streams. */\n \tRPi::Device<Unicam, 2> unicam_;\n@@ -453,6 +461,7 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()\n PipelineHandlerRPi::PipelineHandlerRPi(CameraManager *manager)\n \t: PipelineHandler(manager), unicam_(nullptr), isp_(nullptr)\n {\n+\tRPi::initializeRPiControls();\n }\n \n CameraConfiguration *PipelineHandlerRPi::generateConfiguration(Camera *camera,\n@@ -941,7 +950,7 @@ bool PipelineHandlerRPi::match(DeviceEnumerator *enumerator)\n \t}\n \n \t/* Register the controls that the Raspberry Pi IPA can handle. */\n-\tdata->controlInfo_ = RPi::Controls;\n+\tdata->controlInfo_ = RPi::controls;\n \t/* Initialize the camera properties. */\n \tdata->properties_ = data->sensor_->properties();\n \n@@ -1127,11 +1136,16 @@ void RPiCameraData::frameStarted(uint32_t sequence)\n \n int RPiCameraData::loadIPA()\n {\n-\tipa_ = IPAManager::createIPA(pipe_, 1, 1);\n+\tipa_ = IPAManager::createIPA<ipa::rpi::IPAProxyRPi>(pipe_, 1, 1);\n+\n \tif (!ipa_)\n \t\treturn -ENOENT;\n \n-\tipa_->queueFrameAction.connect(this, &RPiCameraData::queueFrameAction);\n+\tipa_->statsMetadataComplete.connect(this, &RPiCameraData::statsMetadataComplete);\n+\tipa_->runIsp.connect(this, &RPiCameraData::runIsp);\n+\tipa_->embeddedComplete.connect(this, &RPiCameraData::embeddedComplete);\n+\tipa_->setIsp.connect(this, &RPiCameraData::setIsp);\n+\tipa_->setStaggered.connect(this, &RPiCameraData::setStaggered);\n \n \tIPASettings settings{\n \t\t.configurationFile = ipa_->configurationFile(sensor_->model() + \".json\")\n@@ -1147,8 +1161,8 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)\n \t\tstatic_cast<const RPiCameraConfiguration *>(config);\n \n \tstd::map<unsigned int, IPAStream> streamConfig;\n-\tstd::map<unsigned int, const ControlInfoMap &> entityControls;\n-\tIPAOperationData ipaConfig = {};\n+\tstd::map<unsigned int, ControlInfoMap> entityControls;\n+\tipa::rpi::ConfigInput ipaConfig;\n \n \t/* Get the device format to pass to the IPA. */\n \tV4L2DeviceFormat sensorFormat;\n@@ -1168,7 +1182,7 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)\n \tentityControls.emplace(1, isp_[Isp::Input].dev()->controls());\n \n \t/* Always send the user transform to the IPA. */\n-\tipaConfig.data = { static_cast<unsigned int>(config->transform) };\n+\tipaConfig.transform_ = static_cast<unsigned int>(config->transform);\n \n \t/* Allocate the lens shading table via dmaHeap and pass to the IPA. */\n \tif (!lsTable_.isValid()) {\n@@ -1177,8 +1191,9 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)\n \t\t\treturn -ENOMEM;\n \n \t\t/* Allow the IPA to mmap the LS table via the file descriptor. */\n-\t\tipaConfig.operation = RPi::IPA_CONFIG_LS_TABLE;\n-\t\tipaConfig.data.push_back(static_cast<unsigned int>(lsTable_.fd()));\n+\t\tipaConfig.op_ |= ipa::rpi::ConfigLsTable;\n+\t\tipaConfig.lsTableHandle_ = lsTable_;\n+\t\tipaConfig.lsTableHandleStatic_ = lsTable_.fd();\n \t}\n \n \t/* We store the CameraSensorInfo for digital zoom calculations. */\n@@ -1189,34 +1204,35 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)\n \t}\n \n \t/* Ready the IPA - it must know about the sensor resolution. */\n-\tIPAOperationData result;\n+\tipa::rpi::ConfigOutput result;\n \n \tipa_->configure(sensorInfo_, streamConfig, entityControls, ipaConfig,\n \t\t\t&result);\n \n-\tunsigned int resultIdx = 0;\n-\tif (result.operation & RPi::IPA_CONFIG_STAGGERED_WRITE) {\n+\tif (result.op_ & ipa::rpi::ConfigStaggeredWrite) {\n \t\t/*\n \t\t * Setup our staggered control writer with the sensor default\n \t\t * gain and exposure delays.\n \t\t */\n \t\tif (!staggeredCtrl_) {\n \t\t\tstaggeredCtrl_.init(unicam_[Unicam::Image].dev(),\n-\t\t\t\t\t    { { V4L2_CID_ANALOGUE_GAIN, result.data[resultIdx++] },\n-\t\t\t\t\t      { V4L2_CID_EXPOSURE, result.data[resultIdx++] } });\n-\t\t\tsensorMetadata_ = result.data[resultIdx++];\n+\t\t\t\t\t    { { V4L2_CID_ANALOGUE_GAIN,\n+\t\t\t\t\t\tresult.sensorConfig_.gainDelay_ },\n+\t\t\t\t\t      { V4L2_CID_EXPOSURE,\n+\t\t\t\t\t\tresult.sensorConfig_.exposureDelay_ } });\n+\t\t\tsensorMetadata_ = result.sensorConfig_.sensorMetadata_;\n \t\t}\n \t}\n \n-\tif (result.operation & RPi::IPA_CONFIG_SENSOR) {\n-\t\tconst ControlList &ctrls = result.controls[0];\n+\tif (result.op_ & ipa::rpi::ConfigSensor) {\n+\t\tconst ControlList &ctrls = result.controls_;\n \t\tif (!staggeredCtrl_.set(ctrls))\n \t\t\tLOG(RPI, Error) << \"V4L2 staggered set failed\";\n \t}\n \n-\tif (result.operation & RPi::IPA_CONFIG_DROP_FRAMES) {\n+\tif (result.op_ & ipa::rpi::ConfigDropFrames) {\n \t\t/* Configure the number of dropped frames required on startup. */\n-\t\tdropFrameCount_ = result.data[resultIdx++];\n+\t\tdropFrameCount_ = result.dropFrameCount_;\n \t}\n \n \t/*\n@@ -1235,90 +1251,75 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)\n \treturn 0;\n }\n \n-void RPiCameraData::queueFrameAction([[maybe_unused]] unsigned int frame,\n-\t\t\t\t     const IPAOperationData &action)\n+void RPiCameraData::statsMetadataComplete(uint32_t bufferId, const ControlList &controls)\n {\n-\t/*\n-\t * The following actions can be handled when the pipeline handler is in\n-\t * a stopped state.\n-\t */\n-\tswitch (action.operation) {\n-\tcase RPi::IPA_ACTION_V4L2_SET_STAGGERED: {\n-\t\tconst ControlList &controls = action.controls[0];\n-\t\tif (!staggeredCtrl_.set(controls))\n-\t\t\tLOG(RPI, Error) << \"V4L2 staggered set failed\";\n-\t\tgoto done;\n-\t}\n+\tif (state_ == State::Stopped)\n+\t\thandleState();\n \n-\tcase RPi::IPA_ACTION_V4L2_SET_ISP: {\n-\t\tControlList controls = action.controls[0];\n-\t\tisp_[Isp::Input].dev()->setControls(&controls);\n-\t\tgoto done;\n-\t}\n-\t}\n+\tFrameBuffer *buffer = isp_[Isp::Stats].getBuffers().at(bufferId);\n \n-\tif (state_ == State::Stopped)\n-\t\tgoto done;\n+\thandleStreamBuffer(buffer, &isp_[Isp::Stats]);\n+\n+\t/* Fill the Request metadata buffer with what the IPA has provided */\n+\tRequest *request = requestQueue_.front();\n+\trequest->metadata() = std::move(controls);\n \n \t/*\n-\t * The following actions must not be handled when the pipeline handler\n-\t * is in a stopped state.\n+\t * Also update the ScalerCrop in the metadata with what we actually\n+\t * used. But we must first rescale that from ISP (camera mode) pixels\n+\t * back into sensor native pixels.\n+\t *\n+\t * Sending this information on every frame may be helpful.\n \t */\n-\tswitch (action.operation) {\n-\tcase RPi::IPA_ACTION_STATS_METADATA_COMPLETE: {\n-\t\tunsigned int bufferId = action.data[0];\n-\t\tFrameBuffer *buffer = isp_[Isp::Stats].getBuffers().at(bufferId);\n+\tif (updateScalerCrop_) {\n+\t\tupdateScalerCrop_ = false;\n+\t\tscalerCrop_ = ispCrop_.scaledBy(sensorInfo_.analogCrop.size(),\n+\t\t\t\t\t\tsensorInfo_.outputSize);\n+\t\tscalerCrop_.translateBy(sensorInfo_.analogCrop.topLeft());\n+\t}\n+\trequest->metadata().set(controls::ScalerCrop, scalerCrop_);\n \n-\t\thandleStreamBuffer(buffer, &isp_[Isp::Stats]);\n+\tstate_ = State::IpaComplete;\n \n-\t\t/* Fill the Request metadata buffer with what the IPA has provided */\n-\t\tRequest *request = requestQueue_.front();\n-\t\trequest->metadata() = std::move(action.controls[0]);\n+\thandleState();\n+}\n \n-\t\t/*\n-\t\t * Also update the ScalerCrop in the metadata with what we actually\n-\t\t * used. But we must first rescale that from ISP (camera mode) pixels\n-\t\t * back into sensor native pixels.\n-\t\t *\n-\t\t * Sending this information on every frame may be helpful.\n-\t\t */\n-\t\tif (updateScalerCrop_) {\n-\t\t\tupdateScalerCrop_ = false;\n-\t\t\tscalerCrop_ = ispCrop_.scaledBy(sensorInfo_.analogCrop.size(),\n-\t\t\t\t\t\t\tsensorInfo_.outputSize);\n-\t\t\tscalerCrop_.translateBy(sensorInfo_.analogCrop.topLeft());\n-\t\t}\n-\t\trequest->metadata().set(controls::ScalerCrop, scalerCrop_);\n+void RPiCameraData::runIsp(uint32_t bufferId)\n+{\n+\tif (state_ == State::Stopped)\n+\t\thandleState();\n \n-\t\tstate_ = State::IpaComplete;\n-\t\tbreak;\n-\t}\n+\tFrameBuffer *buffer = unicam_[Unicam::Image].getBuffers().at(bufferId);\n \n-\tcase RPi::IPA_ACTION_EMBEDDED_COMPLETE: {\n-\t\tunsigned int bufferId = action.data[0];\n-\t\tFrameBuffer *buffer = unicam_[Unicam::Embedded].getBuffers().at(bufferId);\n-\t\thandleStreamBuffer(buffer, &unicam_[Unicam::Embedded]);\n-\t\tbreak;\n-\t}\n+\tLOG(RPI, Debug) << \"Input re-queue to ISP, buffer id \" << bufferId\n+\t\t\t<< \", timestamp: \" << buffer->metadata().timestamp;\n \n-\tcase RPi::IPA_ACTION_RUN_ISP: {\n-\t\tunsigned int bufferId = action.data[0];\n-\t\tFrameBuffer *buffer = unicam_[Unicam::Image].getBuffers().at(bufferId);\n+\tisp_[Isp::Input].queueBuffer(buffer);\n+\tispOutputCount_ = 0;\n+\thandleState();\n+}\n \n-\t\tLOG(RPI, Debug) << \"Input re-queue to ISP, buffer id \" << bufferId\n-\t\t\t\t<< \", timestamp: \" << buffer->metadata().timestamp;\n+void RPiCameraData::embeddedComplete(uint32_t bufferId)\n+{\n+\tif (state_ == State::Stopped)\n+\t\thandleState();\n \n-\t\tisp_[Isp::Input].queueBuffer(buffer);\n-\t\tispOutputCount_ = 0;\n-\t\tbreak;\n-\t}\n+\tFrameBuffer *buffer = unicam_[Unicam::Embedded].getBuffers().at(bufferId);\n+\thandleStreamBuffer(buffer, &unicam_[Unicam::Embedded]);\n+\thandleState();\n+}\n \n-\tdefault:\n-\t\tLOG(RPI, Error) << \"Unknown action \" << action.operation;\n-\t\tbreak;\n-\t}\n+void RPiCameraData::setIsp(const ControlList &controls)\n+{\n+\tControlList ctrls = controls;\n+\tisp_[Isp::Input].dev()->setControls(&ctrls);\n+\thandleState();\n+}\n \n-done:\n+void RPiCameraData::setStaggered(const ControlList &controls)\n+{\n+\tif (!staggeredCtrl_.set(controls))\n+\t\tLOG(RPI, Error) << \"V4L2 staggered set failed\";\n \thandleState();\n }\n \n@@ -1420,10 +1421,7 @@ void RPiCameraData::ispOutputDequeue(FrameBuffer *buffer)\n \t * application until after the IPA signals so.\n \t */\n \tif (stream == &isp_[Isp::Stats]) {\n-\t\tIPAOperationData op;\n-\t\top.operation = RPi::IPA_EVENT_SIGNAL_STAT_READY;\n-\t\top.data = { RPi::BufferMask::STATS | static_cast<unsigned int>(index) };\n-\t\tipa_->processEvent(op);\n+\t\tipa_->signalStatReady(RPi::BufferMask::STATS | static_cast<unsigned int>(index));\n \t} else {\n \t\t/* Any other ISP output can be handed back to the application now. */\n \t\thandleStreamBuffer(buffer, stream);\n@@ -1595,7 +1593,6 @@ void RPiCameraData::checkRequestCompleted()\n void RPiCameraData::tryRunPipeline()\n {\n \tFrameBuffer *bayerBuffer, *embeddedBuffer;\n-\tIPAOperationData op;\n \n \t/* If any of our request or buffer queues are empty, we cannot proceed. */\n \tif (state_ != State::Idle || requestQueue_.empty() ||\n@@ -1642,9 +1639,7 @@ void RPiCameraData::tryRunPipeline()\n \t * queue the ISP output buffer listed in the request to start the HW\n \t * pipeline.\n \t */\n-\top.operation = RPi::IPA_EVENT_QUEUE_REQUEST;\n-\top.controls = { request->controls() };\n-\tipa_->processEvent(op);\n+\tipa_->signalQueueRequest(request->controls());\n \n \t/* Set our state to say the pipeline is active. */\n \tstate_ = State::Busy;\n@@ -1656,10 +1651,10 @@ void RPiCameraData::tryRunPipeline()\n \t\t\t<< \" Bayer buffer id: \" << bayerId\n \t\t\t<< \" Embedded buffer id: \" << embeddedId;\n \n-\top.operation = RPi::IPA_EVENT_SIGNAL_ISP_PREPARE;\n-\top.data = { RPi::BufferMask::EMBEDDED_DATA | embeddedId,\n-\t\t    RPi::BufferMask::BAYER_DATA | bayerId };\n-\tipa_->processEvent(op);\n+\tipa::rpi::ISPConfig ispPrepare;\n+\tispPrepare.embeddedbufferId_ = RPi::BufferMask::EMBEDDED_DATA | embeddedId;\n+\tispPrepare.bayerbufferId_ = RPi::BufferMask::BAYER_DATA | bayerId;\n+\tipa_->signalIspPrepare(ispPrepare);\n }\n \n bool RPiCameraData::findMatchingBuffers(FrameBuffer *&bayerBuffer, FrameBuffer *&embeddedBuffer)\n",
    "prefixes": [
        "libcamera-devel",
        "v5",
        "17/23"
    ]
}