{"id":9936,"url":"https://patchwork.libcamera.org/api/1.1/patches/9936/?format=json","web_url":"https://patchwork.libcamera.org/patch/9936/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20201002143154.468162-29-paul.elder@ideasonboard.com>","date":"2020-10-02T14:31:44","name":"[libcamera-devel,v3,28/38] libcamera: pipeline, ipa: raspberrypi: Use new data definition","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"3f01c1762c404a77ecb907494d32e56e38bf8955","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/1.1/people/17/?format=json","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/9936/mbox/","series":[{"id":1348,"url":"https://patchwork.libcamera.org/api/1.1/series/1348/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=1348","date":"2020-10-02T14:31:16","name":"IPA isolation implementation","version":3,"mbox":"https://patchwork.libcamera.org/series/1348/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/9936/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/9936/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 409D3C3B5C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  2 Oct 2020 14:33:15 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0E09963BEB;\n\tFri,  2 Oct 2020 16:33:15 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2469C63B98\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  2 Oct 2020 16:33:14 +0200 (CEST)","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 59870FD1;\n\tFri,  2 Oct 2020 16:33:12 +0200 (CEST)"],"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=\"bjMpCGWo\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1601649193;\n\tbh=S5Rg7iFnqfc+mBlGOhMRPE6Kt8lTSXx0AE4MBIRiwb4=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=bjMpCGWoM1suodHyEKC/jTQe83ySZJN+MIbMWY23Mkm3NxHoDwLOC7qPLv0KIHPIS\n\ti5P7iytjb0xRhn8OyUmZlnzpz3pREc20bvtYtlLrwI2X2BrKkF6wpVI9jDC2/dR/oO\n\tP2qWT0So1bjaaXfpTi58PPJj92/qfDIUBNVU48Us=","From":"Paul Elder <paul.elder@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Date":"Fri,  2 Oct 2020 23:31:44 +0900","Message-Id":"<20201002143154.468162-29-paul.elder@ideasonboard.com>","X-Mailer":"git-send-email 2.27.0","In-Reply-To":"<20201002143154.468162-1-paul.elder@ideasonboard.com>","References":"<20201002143154.468162-1-paul.elder@ideasonboard.com>","MIME-Version":"1.0","Subject":"[libcamera-devel] [PATCH v3 28/38] 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 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           |  37 ++--\n src/ipa/raspberrypi/raspberrypi.cpp           | 160 +++++++----------\n .../pipeline/raspberrypi/raspberrypi.cpp      | 164 +++++++++---------\n 3 files changed, 167 insertions(+), 194 deletions(-)","diff":"diff --git a/include/libcamera/ipa/raspberrypi.h b/include/libcamera/ipa/raspberrypi.h\nindex 58262f6c..211fd1ca 100644\n--- a/include/libcamera/ipa/raspberrypi.h\n+++ b/include/libcamera/ipa/raspberrypi.h\n@@ -26,22 +26,27 @@ 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(0, static_cast<int32_t>(controls::MeteringModeMax)) },\n-\t{ &controls::AeConstraintMode, ControlInfo(0, static_cast<int32_t>(controls::ConstraintModeMax)) },\n-\t{ &controls::AeExposureMode, ControlInfo(0, static_cast<int32_t>(controls::ExposureModeMax)) },\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(0, static_cast<int32_t>(controls::AwbModeMax)) },\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+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(0, static_cast<int32_t>(controls::MeteringModeMax)) },\n+\t\t{ &controls::AeConstraintMode, ControlInfo(0, static_cast<int32_t>(controls::ConstraintModeMax)) },\n+\t\t{ &controls::AeExposureMode, ControlInfo(0, static_cast<int32_t>(controls::ExposureModeMax)) },\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(0, static_cast<int32_t>(controls::AwbModeMax)) },\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};\n };\n \n } /* namespace RPi */\ndiff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp\nindex b0c7d1c1..0e23a476 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_generated.h>\n #include <libcamera/request.h>\n #include <libcamera/span.h>\n \n@@ -60,7 +61,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@@ -68,6 +69,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@@ -82,12 +84,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::IspPreparePayload &data) override;\n \n private:\n \tvoid setMode(const CameraSensorInfo &sensorInfo);\n@@ -144,6 +148,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@@ -193,15 +202,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@@ -225,32 +232,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::RPI_IPA_CONFIG_STAGGERED_WRITE;\n+\t\tresult->staggeredWriteResult_.gainDelay_ = gainDelay;\n+\t\tresult->staggeredWriteResult_.exposureDelay_ = exposureDelay;\n+\t\tresult->staggeredWriteResult_.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::RPI_IPA_CONFIG_LS_TABLE) {\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@@ -272,18 +275,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::RPI_IPA_CONFIG_DROP_FRAMES;\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@@ -308,9 +308,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::RPI_IPA_CONFIG_SENSOR;\n+\t\tresult->controls_ = ctrls;\n \t}\n \n \tlastMode_ = mode_;\n@@ -348,56 +348,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::IspPreparePayload &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@@ -498,6 +480,8 @@ void IPARPi::queueRequest(const ControlList &controls)\n \t/* Clear the return metadata buffer. */\n \tlibcameraMetadata_.clear();\n \n+\tLOG(IPARPI, Info) << \"Request ctrl length: \" << controls.size();\n+\n \tfor (auto const &ctrl : controls) {\n \t\tLOG(IPARPI, Info) << \"Request ctrl: \"\n \t\t\t\t  << controls::controls.at(ctrl.first)->name()\n@@ -710,10 +694,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@@ -774,12 +755,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@@ -835,10 +812,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@@ -1068,7 +1042,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@@ -1145,9 +1119,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 d4d04c0d..60ec07ea 100644\n--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n@@ -16,7 +16,9 @@\n #include <libcamera/control_ids.h>\n #include <libcamera/file_descriptor.h>\n #include <libcamera/formats.h>\n+#include <libcamera/ipa/ipa_proxy_raspberrypi.h>\n #include <libcamera/ipa/raspberrypi.h>\n+#include <libcamera/ipa/raspberrypi_generated.h>\n #include <libcamera/logging.h>\n #include <libcamera/property_ids.h>\n #include <libcamera/request.h>\n@@ -144,7 +146,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@@ -156,6 +162,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@@ -441,6 +449,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@@ -1093,11 +1102,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@@ -1113,8 +1127,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@@ -1134,7 +1148,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@@ -1143,8 +1157,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::RPI_IPA_CONFIG_LS_TABLE;\n+\t\tipaConfig.lsTableHandle_ = lsTable_;\n+\t\tipaConfig.lsTableHandleStatic_ = lsTable_.fd();\n \t}\n \n \tCameraSensorInfo sensorInfo = {};\n@@ -1155,22 +1170,23 @@ 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::RPI_IPA_CONFIG_STAGGERED_WRITE) {\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\tresult.staggeredWriteResult_.gainDelay_ },\n+\t\t\t\t\t{ V4L2_CID_EXPOSURE,\n+\t\t\t\t\tresult.staggeredWriteResult_.exposureDelay_ } });\n+\t\t\tsensorMetadata_ = result.staggeredWriteResult_.sensorMetadata_;\n \t\t}\n \n \t\t/*\n@@ -1187,86 +1203,70 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)\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::RPI_IPA_CONFIG_SENSOR) {\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::RPI_IPA_CONFIG_DROP_FRAMES) {\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 \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+\thandleStreamBuffer(buffer, &isp_[Isp::Stats]);\n+\t/* Fill the Request metadata buffer with what the IPA has provided */\n+\trequestQueue_.front()->metadata() = std::move(controls);\n+\tstate_ = State::IpaComplete;\n+\thandleState();\n+}\n+\n+void RPiCameraData::runIsp(uint32_t bufferId)\n+{\n \tif (state_ == State::Stopped)\n-\t\tgoto done;\n+\t\thandleState();\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 */\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-\n-\t\thandleStreamBuffer(buffer, &isp_[Isp::Stats]);\n-\t\t/* Fill the Request metadata buffer with what the IPA has provided */\n-\t\trequestQueue_.front()->metadata() = std::move(action.controls[0]);\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@@ -1366,10 +1366,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@@ -1542,7 +1539,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@@ -1593,9 +1589,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/* Ready to use the buffers, pop them off the queue. */\n \tbayerQueue_.pop();\n@@ -1611,10 +1605,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::IspPreparePayload ispPrepare;\n+\tispPrepare.embeddedbufferId_ = RPi::BufferMask::EMBEDDED_DATA | embeddedId;\n+\tispPrepare.bayerbufferId_ = RPi::BufferMask::BAYER_DATA | bayerId;\n+\tipa_->signalIspPrepare(ispPrepare);\n }\n \n void RPiCameraData::tryFlushQueues()\n","prefixes":["libcamera-devel","v3","28/38"]}