{"id":18593,"url":"https://patchwork.libcamera.org/api/1.1/patches/18593/?format=json","web_url":"https://patchwork.libcamera.org/patch/18593/","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":"<20230503122035.32026-9-naush@raspberrypi.com>","date":"2023-05-03T12:20:30","name":"[libcamera-devel,08/13] pipeline: ipa: raspberrypi: Restructure the IPA mojom interface","commit_ref":null,"pull_url":null,"state":"accepted","archived":false,"hash":"f62a09b010991d738572b01d11138a5bef2fe8b2","submitter":{"id":34,"url":"https://patchwork.libcamera.org/api/1.1/people/34/?format=json","name":"Naushir Patuck","email":"naush@raspberrypi.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/18593/mbox/","series":[{"id":3863,"url":"https://patchwork.libcamera.org/api/1.1/series/3863/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=3863","date":"2023-05-03T12:20:22","name":"Raspberry Pi: Code refactoring","version":1,"mbox":"https://patchwork.libcamera.org/series/3863/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/18593/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/18593/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 ED764C0DA4\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  3 May 2023 12:20:49 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id AE027633BC;\n\tWed,  3 May 2023 14:20:49 +0200 (CEST)","from mail-wm1-x32e.google.com (mail-wm1-x32e.google.com\n\t[IPv6:2a00:1450:4864:20::32e])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0054F633BC\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  3 May 2023 14:20:43 +0200 (CEST)","by mail-wm1-x32e.google.com with SMTP id\n\t5b1f17b1804b1-3f1950f5676so52405925e9.3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 03 May 2023 05:20:43 -0700 (PDT)","from localhost.localdomain ([93.93.133.154])\n\tby smtp.gmail.com with ESMTPSA id\n\tf23-20020a7bcd17000000b003ee443bf0c7sm1736785wmj.16.2023.05.03.05.20.41\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tWed, 03 May 2023 05:20:42 -0700 (PDT)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1683116449;\n\tbh=KWW/OtZpcceOjMoh0a0L1w7VHGL7cGC5+TaXw+I8yLI=;\n\th=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=U5uEgX1JS/znDKzKcUQH+64n5sCjVqVLPDoaWHKfaKS+fSag+jfZBf4b7MXrtMtd/\n\tgrVOQcGIrVJq93cv9wCURz7/39Euy7tMrgs6VcLXMDbqI9XO195VCRR8EbL9Jr3HIL\n\t/A0gqRVAZ/mlSjj8CCsG+Xcv5Z+zDtuQNqzcWkEqJyOAUitTotx4rQw5mxjD4aA53L\n\teyRzkSEUdRGdNOhmLwDkrM/Qlp9bIrlMrhREITEaxLOAzbCLzg/wMxO87gVTp/G+4t\n\thh4DSH6r0JtjoT6oBzE/tUmXmQszy03XCIYNxlEWC/ex5WxPBQCRGWXF5cR6XUsFEL\n\t0VQuuVJhB4brg==","v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google; t=1683116443; x=1685708443;\n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:from:to:cc:subject:date\n\t:message-id:reply-to;\n\tbh=W9uNXdGf1+0DfPtCT3PVO32tBUknN5CbYrNGpW6pPc8=;\n\tb=lEzENy+bCh3NV2j99JC9GYvUDMRN1FcNjgUjgMX0THKUoJk45w604+uzBFd5PeNzRh\n\t2rMZpVlCaT7WoYineboLmqU7BCVnVwCyLx55PT4VAm189CBPUhivBt5112o39sxPPlak\n\toRokhbakr9QyZwH6P5mOLc8unZ0BegMZG22+zCLZAJOL4V+KIEoRxpH3WoOhPar+/CQO\n\tymT10Ak5gi2dWZl3eWkiZbEe6DaNbfMNyGKRT/MG3pa7iIMsgkNeqvsD5nZQgBBZJATo\n\tt1WVgwA0eZuVbHXkB0bWskarnWsFkxy8EiEFVeH79Pv0kKkuP1xblW2RPNNJdBSzcu66\n\trNFQ=="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key; \n\tunprotected) header.d=raspberrypi.com\n\theader.i=@raspberrypi.com\n\theader.b=\"lEzENy+b\"; dkim-atps=neutral","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20221208; t=1683116443; x=1685708443;\n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc\n\t:subject:date:message-id:reply-to;\n\tbh=W9uNXdGf1+0DfPtCT3PVO32tBUknN5CbYrNGpW6pPc8=;\n\tb=HP0fJfTGWMtfafOUDyq7mVGjhnUGSFBfW4sJuvIuVc/3HcYRiD7NhJ00OMpLHL5h8D\n\tMwT9F40TVsWNmaMYxbkc66HdwRPKcx9rABF79m1/Fgfd4aM8j+TFFyO+TRmZjSdgCS40\n\tByEkjNW3CY3j4YxhSn1G/EsYzGBeXcK6es5vaAqa66p5sOAMKnpS3In49jku9+IgGYLE\n\t6I64SMSSo2XBXzWBr1mkj8Bb/e7m/fYUKd/XTzUnakiqGxIIljlmdpcKq5fz2Mpp3iw0\n\tLbgHCzXEcFNt+oH26dkvY94x4iUR/moYz1MV1dPhKw2wE8SnRMs61gxJESCshHUYiDvR\n\tr2hg==","X-Gm-Message-State":"AC+VfDxJoYr3KXrRaXPj3+YORsuRm50t9tX7D+Bf8EpkOQlsy8Hy19z6\n\tXHgqHpcwHW9qaqbgqfhmCRVMRUgAofz3rDDpjmysDg==","X-Google-Smtp-Source":"ACHHUZ7qjv6vssBZGrUrtuSAXo0RT0qvl1EWknHEDb7cK7tZ5LzIYG9UicIuVOIUd9+uaTPOG4gbMw==","X-Received":"by 2002:a1c:6a17:0:b0:3f1:9526:22da with SMTP id\n\tf23-20020a1c6a17000000b003f1952622damr15541827wmc.22.1683116442813; \n\tWed, 03 May 2023 05:20:42 -0700 (PDT)","To":"libcamera-devel@lists.libcamera.org","Date":"Wed,  3 May 2023 13:20:30 +0100","Message-Id":"<20230503122035.32026-9-naush@raspberrypi.com>","X-Mailer":"git-send-email 2.34.1","In-Reply-To":"<20230503122035.32026-1-naush@raspberrypi.com>","References":"<20230503122035.32026-1-naush@raspberrypi.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [PATCH 08/13] pipeline: ipa: raspberrypi:\n\tRestructure the IPA mojom interface","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>","From":"Naushir Patuck via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Naushir Patuck <naush@raspberrypi.com>","Cc":"Jacopo Mondi <jacopo.mondi@ideasonboard.com>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"Restructure the IPA mojom interface to be more consistent in the use\nof the API. Function parameters are now grouped into *Params structures\nand results are now returned in *Results structures.\n\nThe following pipeline -> IPA interfaces have been removed:\n\nsignalQueueRequest(libcamera.ControlList controls);\nsignalIspPrepare(ISPConfig data);\nsignalStatReady(uint32 bufferId, uint32 ipaContext);\n\nand replaced with:\n\nprepareIsp(PrepareParams params);\nprocessStats(ProcessParams params);\n\nsignalQueueRequest() is now encompassed within prepareIsp().\n\nThe following IPA -> pipeline interfaces have been removed:\n\nrunIsp(uint32 bufferId);\nembeddedComplete(uint32 bufferId);\nstatsMetadataComplete(uint32 bufferId, libcamera.ControlList controls);\n\nand replaced with the following async calls:\n\nprepareIspComplete(BufferIds buffers);\nprocessStatsComplete(BufferIds buffers);\nmetadataReady(libcamera.ControlList metadata);\n\nSigned-off-by: Naushir Patuck <naush@raspberrypi.com>\nReviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n---\n include/libcamera/ipa/raspberrypi.mojom       | 238 +++++++++++++++---\n src/ipa/rpi/vc4/raspberrypi.cpp               | 102 ++++----\n .../pipeline/rpi/vc4/raspberrypi.cpp          | 155 ++++++------\n 3 files changed, 320 insertions(+), 175 deletions(-)","diff":"diff --git a/include/libcamera/ipa/raspberrypi.mojom b/include/libcamera/ipa/raspberrypi.mojom\nindex 80e0126618c8..ba786e647ca1 100644\n--- a/include/libcamera/ipa/raspberrypi.mojom\n+++ b/include/libcamera/ipa/raspberrypi.mojom\n@@ -8,7 +8,7 @@ module ipa.RPi;\n \n import \"include/libcamera/ipa/core.mojom\";\n \n-/* Size of the LS grid allocation. */\n+/* Size of the LS grid allocation on VC4. */\n const uint32 MaxLsGridSize = 0x8000;\n \n struct SensorConfig {\n@@ -19,64 +19,123 @@ struct SensorConfig {\n \tuint32 sensorMetadata;\n };\n \n-struct IPAInitResult {\n+struct InitParams {\n+\tbool lensPresent;\n+};\n+\n+struct InitResult {\n \tSensorConfig sensorConfig;\n \tlibcamera.ControlInfoMap controlInfo;\n };\n \n-struct ISPConfig {\n-\tuint32 embeddedBufferId;\n-\tuint32 bayerBufferId;\n-\tbool embeddedBufferPresent;\n-\tlibcamera.ControlList controls;\n-\tuint32 ipaContext;\n-\tuint32 delayContext;\n+struct BufferIds {\n+\tuint32 bayer;\n+\tuint32 embedded;\n+\tuint32 stats;\n };\n \n-struct IPAConfig {\n+struct ConfigParams {\n \tuint32 transform;\n-\tlibcamera.SharedFD lsTableHandle;\n \tlibcamera.ControlInfoMap sensorControls;\n \tlibcamera.ControlInfoMap ispControls;\n \tlibcamera.ControlInfoMap lensControls;\n+        /* VC4 specific */\n+\tlibcamera.SharedFD lsTableHandle;\n };\n \n-struct IPAConfigResult {\n-       float modeSensitivity;\n-       libcamera.ControlInfoMap controlInfo;\n+struct ConfigResult {\n+\tfloat modeSensitivity;\n+\tlibcamera.ControlInfoMap controlInfo;\n+\tlibcamera.ControlList controls;\n };\n \n-struct StartConfig {\n+struct StartResult {\n \tlibcamera.ControlList controls;\n \tint32 dropFrameCount;\n };\n \n+struct PrepareParams {\n+\tBufferIds buffers;\n+\tlibcamera.ControlList sensorControls;\n+\tlibcamera.ControlList requestControls;\n+\tuint32 ipaContext;\n+\tuint32 delayContext;\n+};\n+\n+struct ProcessParams {\n+\tBufferIds buffers;\n+\tuint32 ipaContext;\n+};\n+\n interface IPARPiInterface {\n-\tinit(libcamera.IPASettings settings, bool lensPresent)\n-\t\t=> (int32 ret, IPAInitResult result);\n-\tstart(libcamera.ControlList controls) => (StartConfig startConfig);\n+\t/**\n+\t * \\fn init()\n+\t * \\brief Initialise the IPA\n+\t * \\param[in] settings Camera sensor information and configuration file\n+\t * \\param[in] params Platform specific initialisation parameters\n+\t * \\param[out] ret 0 on success or a negative error code otherwise\n+\t * \\param[out] result Static sensor configuration and controls available\n+\t *\n+\t * This function initialises the IPA for a particular sensor from the\n+\t * pipeline handler.\n+\t *\n+\t * The \\a settings conveys information about the camera sensor and\n+\t * configuration file requested by the pipeline handler.\n+\t *\n+\t * The \\a result parameter returns the sensor delay for the given camera\n+\t * as well as a ControlInfoMap of available controls that can be handled\n+\t * by the IPA.\n+\t */\n+\tinit(libcamera.IPASettings settings, InitParams params)\n+\t\t=> (int32 ret, InitResult result);\n+\n+\t/**\n+\t * \\fn start()\n+\t * \\brief Start the IPA\n+\t * \\param[in] controls List of control to handle\n+\t * \\param[out] result Controls to apply and number of dropped frames\n+\t *\n+\t * This function sets the IPA to a started state.\n+\t *\n+\t * The \\a controls provide a list of controls to handle immediately. The\n+\t * actual controls to apply on the sensor and ISP in the pipeline\n+\t * handler are returned in \\a result.\n+\t *\n+\t * The number of convergence frames to be dropped is also returned in\n+\t * \\a result.\n+\t */\n+\tstart(libcamera.ControlList controls) => (StartResult result);\n+\n+\t/**\n+\t * \\fn start()\n+\t * \\brief Stop the IPA\n+\t *\n+\t * This function sets the IPA to a stopped state.\n+\t */\n \tstop();\n \n \t/**\n \t * \\fn configure()\n-\t * \\brief Configure the IPA stream and sensor settings\n-\t * \\param[in] sensorInfo Camera sensor information\n-\t * \\param[in] ipaConfig Pipeline-handler-specific configuration data\n-\t * \\param[out] controls Controls to apply by the pipeline entity\n-\t * \\param[out] result Other results that the pipeline handler may require\n+\t * \\brief Configure the IPA\n+\t * \\param[in] sensorInfo Sensor mode configuration\n+\t * \\param[in] params Platform configuration parameters\n+\t * \\param[out] ret 0 on success or a negative error code otherwise\n+\t * \\param[out] result Results of the configuration operation\n \t *\n-\t * This function shall be called when the camera is configured to inform\n-\t * the IPA of the camera's streams and the sensor settings.\n+\t * This function configures the IPA for a particular camera\n+\t * configuration\n \t *\n-\t * The \\a sensorInfo conveys information about the camera sensor settings that\n-\t * the pipeline handler has selected for the configuration.\n+\t * The \\a params parameter provides a list of available controls for the\n+\t * ISP, sensor and lens devices, and the user requested transform\n+\t * operation. It can also provide platform specific configuration\n+\t * parameters, e.g. the lens shading table memory handle for VC4.\n \t *\n-\t * The \\a ipaConfig and \\a controls parameters carry data passed by the\n-\t * pipeline handler to the IPA and back.\n+\t * The \\a result parameter returns the available controls for the given\n+\t * camera mode, a list of controls to apply to the sensor device, and\n+\t * the requested mode's sensitivity characteristics.\n \t */\n-\tconfigure(libcamera.IPACameraSensorInfo sensorInfo,\n-\t\t  IPAConfig ipaConfig)\n-\t\t=> (int32 ret, libcamera.ControlList controls, IPAConfigResult result);\n+\tconfigure(libcamera.IPACameraSensorInfo sensorInfo, ConfigParams params)\n+\t\t=> (int32 ret, ConfigResult result);\n \n \t/**\n \t * \\fn mapBuffers()\n@@ -99,7 +158,7 @@ interface IPARPiInterface {\n \t * depending on the IPA protocol. Regardless of the protocol, all\n \t * buffers mapped at a given time shall have unique numerical IDs.\n \t *\n-\t * The numerical IDs have no meaning defined by the IPA interface, and \n+\t * The numerical IDs have no meaning defined by the IPA interface, and\n \t * should be treated as opaque handles by IPAs, with the only exception\n \t * that ID zero is invalid.\n \t *\n@@ -119,17 +178,118 @@ interface IPARPiInterface {\n \t */\n \tunmapBuffers(array<uint32> ids);\n \n-\t[async] signalStatReady(uint32 bufferId, uint32 ipaContext);\n-\t[async] signalQueueRequest(libcamera.ControlList controls);\n-\t[async] signalIspPrepare(ISPConfig data);\n+\t/**\n+\t * \\fn prepareIsp()\n+\t * \\brief Prepare the ISP configuration for a frame\n+\t * \\param[in] params Parameter set for the frame to process\n+\t *\n+\t * This function call into all the algorithms in preparation for the\n+\t * frame to be processed by the ISP.\n+\t *\n+\t * The \\a params parameter lists the buffer IDs for the Bayer and\n+\t * embedded data buffers, a ControlList of sensor frame params, and\n+\t * a ControlList of request controls for the current frame.\n+\t *\n+\t * Additionally, \\a params also contains the IPA context (ipaContext) to\n+\t * use as an index location to store control algorithm results, and a\n+\t * historical IPA context (delayContext) that was active when the sensor\n+\t * settings were requested by the IPA.\n+\t */\n+\t[async] prepareIsp(PrepareParams params);\n+\n+\t/**\n+\t * \\fn processStats()\n+\t * \\brief Process the statistics provided by the ISP\n+\t * \\param[in] params Parameter set for the statistics to process\n+\t *\n+\t * This function call into all the algorithms to provide the statistics\n+\t * generated by the ISP for the processed frame.\n+\t *\n+\t * The \\a params parameter lists the buffer ID for the statistics buffer\n+\t * and an IPA context (ipaContext) to use as an index location to store\n+\t * algorithm results.\n+\t */\n+\t[async] processStats(ProcessParams params);\n };\n \n interface IPARPiEventInterface {\n-\tstatsMetadataComplete(uint32 bufferId, libcamera.ControlList controls);\n-\trunIsp(uint32 bufferId);\n-\tembeddedComplete(uint32 bufferId);\n+\t/**\n+\t * \\fn prepareIspComplete()\n+\t * \\brief Signal completion of \\a prepareIsp\n+\t * \\param[in] buffers Bayer and embedded buffers actioned.\n+\t *\n+\t * This asynchronous event is signalled to the pipeline handler once\n+\t * the \\a prepareIsp signal has completed, and the ISP is ready to start\n+\t * processing the frame. The embedded data buffer may be recycled after\n+\t * this event.\n+\t */\n+\tprepareIspComplete(BufferIds buffers);\n+\n+\t/**\n+\t * \\fn processStatsComplete()\n+\t * \\brief Signal completion of \\a processStats\n+\t * \\param[in] buffers Statistics buffers actioned.\n+\t *\n+\t * This asynchronous event is signalled to the pipeline handler once\n+\t * the \\a processStats signal has completed. The statistics buffer may\n+\t * be recycled after this event.\n+\t */\n+\tprocessStatsComplete(BufferIds buffers);\n+\n+\t/**\n+\t * \\fn metadataReady()\n+\t * \\brief Signal request metadata is to be merged\n+\t * \\param[in] metadata Control list of metadata to be merged\n+\t *\n+\t * This asynchronous event is signalled to the pipeline handler once\n+\t * all the frame metadata has been gathered. The pipeline handler will\n+\t * copy or merge this metadata into the \\a Request returned back to the\n+\t * application.\n+\t */\n+\tmetadataReady(libcamera.ControlList metadata);\n+\n+\t/**\n+\t * \\fn setIspControls()\n+\t * \\brief Signal ISP controls to be applied.\n+\t * \\param[in] controls List of controls to be applied.\n+\t *\n+\t * This asynchronous event is signalled to the pipeline handler during\n+\t * the \\a prepareISP signal after all algorithms have been run and the\n+\t * IPA requires ISP controls to be applied for the frame.\n+\t */\n \tsetIspControls(libcamera.ControlList controls);\n+\n+\t/**\n+\t * \\fn setDelayedControls()\n+\t * \\brief Signal Sensor controls to be applied.\n+\t * \\param[in] controls List of controls to be applied.\n+\t * \\param[in] delayContext IPA context index used for this request\n+\t *\n+\t * This asynchronous event is signalled to the pipeline handler when\n+\t * the IPA requires sensor specific controls (e.g. shutter speed, gain,\n+\t * blanking) to be applied.\n+\t */\n \tsetDelayedControls(libcamera.ControlList controls, uint32 delayContext);\n+\n+\t/**\n+\t * \\fn setLensControls()\n+\t * \\brief Signal lens controls to be applied.\n+\t * \\param[in] controls List of controls to be applied.\n+\t *\n+\t * This asynchronous event is signalled to the pipeline handler when\n+\t * the IPA requires a lens movement control to be applied.\n+\t */\n \tsetLensControls(libcamera.ControlList controls);\n+\n+\t/**\n+\t * \\fn setCameraTimeout()\n+\t * \\brief Request a watchdog timeout value to use\n+\t * \\param[in] maxFrameLengthMs Timeout value in ms\n+\t *\n+\t * This asynchronous event is used by the IPA to inform the pipeline\n+\t * handler of an acceptable watchdog timer value to use for the sensor\n+\t * stream. This value is based on the history of frame lengths requested\n+\t * by the IPA.\n+\t */\n \tsetCameraTimeout(uint32 maxFrameLengthMs);\n };\ndiff --git a/src/ipa/rpi/vc4/raspberrypi.cpp b/src/ipa/rpi/vc4/raspberrypi.cpp\nindex 5d3bf4caf3da..17ea5c046f4f 100644\n--- a/src/ipa/rpi/vc4/raspberrypi.cpp\n+++ b/src/ipa/rpi/vc4/raspberrypi.cpp\n@@ -136,30 +136,28 @@ public:\n \t\t\tmunmap(lsTable_, MaxLsGridSize);\n \t}\n \n-\tint init(const IPASettings &settings, bool lensPresent, IPAInitResult *result) override;\n-\tvoid start(const ControlList &controls, StartConfig *startConfig) override;\n+\tint init(const IPASettings &settings, const InitParams &params, InitResult *result) override;\n+\tvoid start(const ControlList &controls, StartResult *result) override;\n \tvoid stop() override {}\n \n-\tint configure(const IPACameraSensorInfo &sensorInfo, const IPAConfig &data,\n-\t\t      ControlList *controls, IPAConfigResult *result) override;\n+\tint configure(const IPACameraSensorInfo &sensorInfo, const ConfigParams &params,\n+\t\t      ConfigResult *result) override;\n \tvoid mapBuffers(const std::vector<IPABuffer> &buffers) override;\n \tvoid unmapBuffers(const std::vector<unsigned int> &ids) override;\n-\tvoid signalStatReady(const uint32_t bufferId, uint32_t ipaContext) override;\n-\tvoid signalQueueRequest(const ControlList &controls) override;\n-\tvoid signalIspPrepare(const ISPConfig &data) override;\n+\tvoid prepareIsp(const PrepareParams &params) override;\n+\tvoid processStats(const ProcessParams &params) override;\n \n private:\n \tvoid setMode(const IPACameraSensorInfo &sensorInfo);\n \tbool validateSensorControls();\n \tbool validateIspControls();\n \tbool validateLensControls();\n-\tvoid queueRequest(const ControlList &controls);\n-\tvoid returnEmbeddedBuffer(unsigned int bufferId);\n-\tvoid prepareISP(const ISPConfig &data);\n+\tvoid applyControls(const ControlList &controls);\n+\tvoid prepare(const PrepareParams &params);\n \tvoid reportMetadata(unsigned int ipaContext);\n \tvoid fillDeviceStatus(const ControlList &sensorControls, unsigned int ipaContext);\n \tRPiController::StatisticsPtr fillStatistics(bcm2835_isp_stats *stats) const;\n-\tvoid processStats(unsigned int bufferId, unsigned int ipaContext);\n+\tvoid process(unsigned int bufferId, unsigned int ipaContext);\n \tvoid setCameraTimeoutValue();\n \tvoid applyFrameDurations(Duration minFrameDuration, Duration maxFrameDuration);\n \tvoid applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls);\n@@ -229,7 +227,7 @@ private:\n \tDuration lastTimeout_;\n };\n \n-int IPARPi::init(const IPASettings &settings, bool lensPresent, IPAInitResult *result)\n+int IPARPi::init(const IPASettings &settings, const InitParams &params, InitResult *result)\n {\n \t/*\n \t * Load the \"helper\" for this sensor. This tells us all the device specific stuff\n@@ -274,7 +272,7 @@ int IPARPi::init(const IPASettings &settings, bool lensPresent, IPAInitResult *r\n \t\treturn -EINVAL;\n \t}\n \n-\tlensPresent_ = lensPresent;\n+\tlensPresent_ = params.lensPresent;\n \n \tcontroller_.initialise();\n \n@@ -287,14 +285,13 @@ int IPARPi::init(const IPASettings &settings, bool lensPresent, IPAInitResult *r\n \treturn 0;\n }\n \n-void IPARPi::start(const ControlList &controls, StartConfig *startConfig)\n+void IPARPi::start(const ControlList &controls, StartResult *result)\n {\n \tRPiController::Metadata metadata;\n \n-\tASSERT(startConfig);\n \tif (!controls.empty()) {\n \t\t/* We have been given some controls to action before start. */\n-\t\tqueueRequest(controls);\n+\t\tapplyControls(controls);\n \t}\n \n \tcontroller_.switchMode(mode_, &metadata);\n@@ -313,7 +310,7 @@ void IPARPi::start(const ControlList &controls, StartConfig *startConfig)\n \tif (agcStatus.shutterTime && agcStatus.analogueGain) {\n \t\tControlList ctrls(sensorCtrls_);\n \t\tapplyAGC(&agcStatus, ctrls);\n-\t\tstartConfig->controls = std::move(ctrls);\n+\t\tresult->controls = std::move(ctrls);\n \t\tsetCameraTimeoutValue();\n \t}\n \n@@ -360,7 +357,7 @@ void IPARPi::start(const ControlList &controls, StartConfig *startConfig)\n \t\tmistrustCount_ = helper_->mistrustFramesModeSwitch();\n \t}\n \n-\tstartConfig->dropFrameCount = dropFrameCount_;\n+\tresult->dropFrameCount = dropFrameCount_;\n \n \tfirstStart_ = false;\n \tlastRunTimestamp_ = 0;\n@@ -435,11 +432,11 @@ void IPARPi::setMode(const IPACameraSensorInfo &sensorInfo)\n \t\t\t     mode_.minFrameDuration, mode_.maxFrameDuration);\n }\n \n-int IPARPi::configure(const IPACameraSensorInfo &sensorInfo, const IPAConfig &ipaConfig,\n-\t\t      ControlList *controls, IPAConfigResult *result)\n+int IPARPi::configure(const IPACameraSensorInfo &sensorInfo, const ConfigParams &params,\n+\t\t      ConfigResult *result)\n {\n-\tsensorCtrls_ = ipaConfig.sensorControls;\n-\tispCtrls_ = ipaConfig.ispControls;\n+\tsensorCtrls_ = params.sensorControls;\n+\tispCtrls_ = params.ispControls;\n \n \tif (!validateSensorControls()) {\n \t\tLOG(IPARPI, Error) << \"Sensor control validation failed.\";\n@@ -452,7 +449,7 @@ int IPARPi::configure(const IPACameraSensorInfo &sensorInfo, const IPAConfig &ip\n \t}\n \n \tif (lensPresent_) {\n-\t\tlensCtrls_ = ipaConfig.lensControls;\n+\t\tlensCtrls_ = params.lensControls;\n \t\tif (!validateLensControls()) {\n \t\t\tLOG(IPARPI, Warning) << \"Lens validation failed, \"\n \t\t\t\t\t     << \"no lens control will be available.\";\n@@ -466,10 +463,10 @@ int IPARPi::configure(const IPACameraSensorInfo &sensorInfo, const IPAConfig &ip\n \t/* Re-assemble camera mode using the sensor info. */\n \tsetMode(sensorInfo);\n \n-\tmode_.transform = static_cast<libcamera::Transform>(ipaConfig.transform);\n+\tmode_.transform = static_cast<libcamera::Transform>(params.transform);\n \n \t/* Store the lens shading table pointer and handle if available. */\n-\tif (ipaConfig.lsTableHandle.isValid()) {\n+\tif (params.lsTableHandle.isValid()) {\n \t\t/* Remove any previous table, if there was one. */\n \t\tif (lsTable_) {\n \t\t\tmunmap(lsTable_, MaxLsGridSize);\n@@ -477,7 +474,7 @@ int IPARPi::configure(const IPACameraSensorInfo &sensorInfo, const IPAConfig &ip\n \t\t}\n \n \t\t/* Map the LS table buffer into user space. */\n-\t\tlsTableHandle_ = std::move(ipaConfig.lsTableHandle);\n+\t\tlsTableHandle_ = std::move(params.lsTableHandle);\n \t\tif (lsTableHandle_.isValid()) {\n \t\t\tlsTable_ = mmap(nullptr, MaxLsGridSize, PROT_READ | PROT_WRITE,\n \t\t\t\t\tMAP_SHARED, lsTableHandle_.get(), 0);\n@@ -512,8 +509,7 @@ int IPARPi::configure(const IPACameraSensorInfo &sensorInfo, const IPAConfig &ip\n \t\tapplyAGC(&agcStatus, ctrls);\n \t}\n \n-\tASSERT(controls);\n-\t*controls = std::move(ctrls);\n+\tresult->controls = std::move(ctrls);\n \n \t/*\n \t * Apply the correct limits to the exposure, gain and frame duration controls\n@@ -560,37 +556,34 @@ void IPARPi::unmapBuffers(const std::vector<unsigned int> &ids)\n \t}\n }\n \n-void IPARPi::signalStatReady(uint32_t bufferId, uint32_t ipaContext)\n+void IPARPi::processStats(const ProcessParams &params)\n {\n-\tunsigned int context = ipaContext % rpiMetadata_.size();\n+\tunsigned int context = params.ipaContext % rpiMetadata_.size();\n \n \tif (++checkCount_ != frameCount_) /* assert here? */\n \t\tLOG(IPARPI, Error) << \"WARNING: Prepare/Process mismatch!!!\";\n \tif (processPending_ && frameCount_ > mistrustCount_)\n-\t\tprocessStats(bufferId, context);\n+\t\tprocess(params.buffers.stats, context);\n \n \treportMetadata(context);\n-\n-\tstatsMetadataComplete.emit(bufferId, libcameraMetadata_);\n+\tprocessStatsComplete.emit(params.buffers);\n }\n \n-void IPARPi::signalQueueRequest(const ControlList &controls)\n-{\n-\tqueueRequest(controls);\n-}\n \n-void IPARPi::signalIspPrepare(const ISPConfig &data)\n+void IPARPi::prepareIsp(const PrepareParams &params)\n {\n+\tapplyControls(params.requestControls);\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(data);\n+\tprepare(params);\n \tframeCount_++;\n \n \t/* Ready to push the input buffer into the ISP. */\n-\trunIsp.emit(data.bayerBufferId);\n+\tprepareIspComplete.emit(params.buffers);\n }\n \n void IPARPi::reportMetadata(unsigned int ipaContext)\n@@ -703,6 +696,8 @@ void IPARPi::reportMetadata(unsigned int ipaContext)\n \t\tlibcameraMetadata_.set(controls::AfState, s);\n \t\tlibcameraMetadata_.set(controls::AfPauseState, p);\n \t}\n+\n+\tmetadataReady.emit(libcameraMetadata_);\n }\n \n bool IPARPi::validateSensorControls()\n@@ -826,7 +821,7 @@ static const std::map<int32_t, RPiController::AfAlgorithm::AfPause> AfPauseTable\n \t{ controls::AfPauseResume, RPiController::AfAlgorithm::AfPauseResume },\n };\n \n-void IPARPi::queueRequest(const ControlList &controls)\n+void IPARPi::applyControls(const ControlList &controls)\n {\n \tusing RPiController::AfAlgorithm;\n \n@@ -1256,27 +1251,22 @@ void IPARPi::queueRequest(const ControlList &controls)\n \t}\n }\n \n-void IPARPi::returnEmbeddedBuffer(unsigned int bufferId)\n+void IPARPi::prepare(const PrepareParams &params)\n {\n-\tembeddedComplete.emit(bufferId);\n-}\n-\n-void IPARPi::prepareISP(const ISPConfig &data)\n-{\n-\tint64_t frameTimestamp = data.controls.get(controls::SensorTimestamp).value_or(0);\n-\tunsigned int ipaContext = data.ipaContext % rpiMetadata_.size();\n+\tint64_t frameTimestamp = params.sensorControls.get(controls::SensorTimestamp).value_or(0);\n+\tunsigned int ipaContext = params.ipaContext % rpiMetadata_.size();\n \tRPiController::Metadata &rpiMetadata = rpiMetadata_[ipaContext];\n \tSpan<uint8_t> embeddedBuffer;\n \n \trpiMetadata.clear();\n-\tfillDeviceStatus(data.controls, ipaContext);\n+\tfillDeviceStatus(params.sensorControls, ipaContext);\n \n-\tif (data.embeddedBufferPresent) {\n+\tif (params.buffers.embedded) {\n \t\t/*\n \t\t * Pipeline handler has supplied us with an embedded data buffer,\n \t\t * we must pass it to the CamHelper for parsing.\n \t\t */\n-\t\tauto it = buffers_.find(data.embeddedBufferId);\n+\t\tauto it = buffers_.find(params.buffers.embedded);\n \t\tASSERT(it != buffers_.end());\n \t\tembeddedBuffer = it->second.planes()[0];\n \t}\n@@ -1288,7 +1278,7 @@ void IPARPi::prepareISP(const ISPConfig &data)\n \t * metadata.\n \t */\n \tAgcStatus agcStatus;\n-\tRPiController::Metadata &delayedMetadata = rpiMetadata_[data.delayContext];\n+\tRPiController::Metadata &delayedMetadata = rpiMetadata_[params.delayContext];\n \tif (!delayedMetadata.get<AgcStatus>(\"agc.status\", agcStatus))\n \t\trpiMetadata.set(\"agc.delayed_status\", agcStatus);\n \n@@ -1298,10 +1288,6 @@ void IPARPi::prepareISP(const ISPConfig &data)\n \t */\n \thelper_->prepare(embeddedBuffer, rpiMetadata);\n \n-\t/* Done with embedded data now, return to pipeline handler asap. */\n-\tif (data.embeddedBufferPresent)\n-\t\treturnEmbeddedBuffer(data.embeddedBufferId);\n-\n \t/* Allow a 10% margin on the comparison below. */\n \tDuration delta = (frameTimestamp - lastRunTimestamp_) * 1.0ns;\n \tif (lastRunTimestamp_ && frameCount_ > dropFrameCount_ &&\n@@ -1445,7 +1431,7 @@ RPiController::StatisticsPtr IPARPi::fillStatistics(bcm2835_isp_stats *stats) co\n \treturn statistics;\n }\n \n-void IPARPi::processStats(unsigned int bufferId, unsigned int ipaContext)\n+void IPARPi::process(unsigned int bufferId, unsigned int ipaContext)\n {\n \tRPiController::Metadata &rpiMetadata = rpiMetadata_[ipaContext];\n \ndiff --git a/src/libcamera/pipeline/rpi/vc4/raspberrypi.cpp b/src/libcamera/pipeline/rpi/vc4/raspberrypi.cpp\nindex 96749c0d1318..27b3bde4dbac 100644\n--- a/src/libcamera/pipeline/rpi/vc4/raspberrypi.cpp\n+++ b/src/libcamera/pipeline/rpi/vc4/raspberrypi.cpp\n@@ -200,15 +200,15 @@ public:\n \tvoid freeBuffers();\n \tvoid frameStarted(uint32_t sequence);\n \n-\tint loadIPA(ipa::RPi::IPAInitResult *result);\n-\tint configureIPA(const CameraConfiguration *config, ipa::RPi::IPAConfigResult *result);\n+\tint loadIPA(ipa::RPi::InitResult *result);\n+\tint configureIPA(const CameraConfiguration *config, ipa::RPi::ConfigResult *result);\n \tint loadPipelineConfiguration();\n \n \tvoid enumerateVideoDevices(MediaLink *link);\n \n-\tvoid statsMetadataComplete(uint32_t bufferId, const ControlList &controls);\n-\tvoid runIsp(uint32_t bufferId);\n-\tvoid embeddedComplete(uint32_t bufferId);\n+\tvoid processStatsComplete(const ipa::RPi::BufferIds &buffers);\n+\tvoid metadataReady(const ControlList &metadata);\n+\tvoid prepareIspComplete(const ipa::RPi::BufferIds &buffers);\n \tvoid setIspControls(const ControlList &controls);\n \tvoid setDelayedControls(const ControlList &controls, uint32_t delayContext);\n \tvoid setLensControls(const ControlList &controls);\n@@ -238,7 +238,7 @@ public:\n \t/* The vector below is just for convenience when iterating over all streams. */\n \tstd::vector<RPi::Stream *> streams_;\n \t/* Stores the ids of the buffers mapped in the IPA. */\n-\tstd::unordered_set<unsigned int> ipaBuffers_;\n+\tstd::unordered_set<unsigned int> bufferIds_;\n \t/*\n \t * Stores a cascade of Video Mux or Bridge devices between the sensor and\n \t * Unicam together with media link across the entities.\n@@ -1000,7 +1000,7 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)\n \n \tdata->isp_[Isp::Input].dev()->setSelection(V4L2_SEL_TGT_CROP, &crop);\n \n-\tipa::RPi::IPAConfigResult result;\n+\tipa::RPi::ConfigResult result;\n \tret = data->configureIPA(config, &result);\n \tif (ret)\n \t\tLOG(RPI, Error) << \"Failed to configure the IPA: \" << ret;\n@@ -1117,17 +1117,17 @@ int PipelineHandlerRPi::start(Camera *camera, const ControlList *controls)\n \t\tdata->applyScalerCrop(*controls);\n \n \t/* Start the IPA. */\n-\tipa::RPi::StartConfig startConfig;\n+\tipa::RPi::StartResult result;\n \tdata->ipa_->start(controls ? *controls : ControlList{ controls::controls },\n-\t\t\t  &startConfig);\n+\t\t\t  &result);\n \n \t/* Apply any gain/exposure settings that the IPA may have passed back. */\n-\tif (!startConfig.controls.empty())\n-\t\tdata->setSensorControls(startConfig.controls);\n+\tif (!result.controls.empty())\n+\t\tdata->setSensorControls(result.controls);\n \n \t/* Configure the number of dropped frames required on startup. */\n \tdata->dropFrameCount_ = data->config_.disableStartupFrameDrops\n-\t\t\t      ? 0 : startConfig.dropFrameCount;\n+\t\t\t\t? 0 : result.dropFrameCount;\n \n \tfor (auto const stream : data->streams_)\n \t\tstream->resetBuffers();\n@@ -1358,7 +1358,7 @@ int PipelineHandlerRPi::registerCamera(MediaDevice *unicam, MediaDevice *isp, Me\n \n \tdata->sensorFormats_ = populateSensorFormats(data->sensor_);\n \n-\tipa::RPi::IPAInitResult result;\n+\tipa::RPi::InitResult result;\n \tif (data->loadIPA(&result)) {\n \t\tLOG(RPI, Error) << \"Failed to load a suitable IPA library\";\n \t\treturn -EINVAL;\n@@ -1599,7 +1599,7 @@ int PipelineHandlerRPi::prepareBuffers(Camera *camera)\n void PipelineHandlerRPi::mapBuffers(Camera *camera, const RPi::BufferMap &buffers, unsigned int mask)\n {\n \tRPiCameraData *data = cameraData(camera);\n-\tstd::vector<IPABuffer> ipaBuffers;\n+\tstd::vector<IPABuffer> bufferIds;\n \t/*\n \t * Link the FrameBuffers with the id (key value) in the map stored in\n \t * the RPi stream object - along with an identifier mask.\n@@ -1608,12 +1608,12 @@ void PipelineHandlerRPi::mapBuffers(Camera *camera, const RPi::BufferMap &buffer\n \t * handler and the IPA.\n \t */\n \tfor (auto const &it : buffers) {\n-\t\tipaBuffers.push_back(IPABuffer(mask | it.first,\n+\t\tbufferIds.push_back(IPABuffer(mask | it.first,\n \t\t\t\t\t       it.second->planes()));\n-\t\tdata->ipaBuffers_.insert(mask | it.first);\n+\t\tdata->bufferIds_.insert(mask | it.first);\n \t}\n \n-\tdata->ipa_->mapBuffers(ipaBuffers);\n+\tdata->ipa_->mapBuffers(bufferIds);\n }\n \n void RPiCameraData::freeBuffers()\n@@ -1623,10 +1623,10 @@ void RPiCameraData::freeBuffers()\n \t\t * Copy the buffer ids from the unordered_set to a vector to\n \t\t * pass to the IPA.\n \t\t */\n-\t\tstd::vector<unsigned int> ipaBuffers(ipaBuffers_.begin(),\n-\t\t\t\t\t\t     ipaBuffers_.end());\n-\t\tipa_->unmapBuffers(ipaBuffers);\n-\t\tipaBuffers_.clear();\n+\t\tstd::vector<unsigned int> bufferIds(bufferIds_.begin(),\n+\t\t\t\t\t\t    bufferIds_.end());\n+\t\tipa_->unmapBuffers(bufferIds);\n+\t\tbufferIds_.clear();\n \t}\n \n \tfor (auto const stream : streams_)\n@@ -1643,16 +1643,16 @@ void RPiCameraData::frameStarted(uint32_t sequence)\n \tdelayedCtrls_->applyControls(sequence);\n }\n \n-int RPiCameraData::loadIPA(ipa::RPi::IPAInitResult *result)\n+int RPiCameraData::loadIPA(ipa::RPi::InitResult *result)\n {\n \tipa_ = IPAManager::createIPA<ipa::RPi::IPAProxyRPi>(pipe(), 1, 1);\n \n \tif (!ipa_)\n \t\treturn -ENOENT;\n \n-\tipa_->statsMetadataComplete.connect(this, &RPiCameraData::statsMetadataComplete);\n-\tipa_->runIsp.connect(this, &RPiCameraData::runIsp);\n-\tipa_->embeddedComplete.connect(this, &RPiCameraData::embeddedComplete);\n+\tipa_->processStatsComplete.connect(this, &RPiCameraData::processStatsComplete);\n+\tipa_->prepareIspComplete.connect(this, &RPiCameraData::prepareIspComplete);\n+\tipa_->metadataReady.connect(this, &RPiCameraData::metadataReady);\n \tipa_->setIspControls.connect(this, &RPiCameraData::setIspControls);\n \tipa_->setDelayedControls.connect(this, &RPiCameraData::setDelayedControls);\n \tipa_->setLensControls.connect(this, &RPiCameraData::setLensControls);\n@@ -1674,23 +1674,25 @@ int RPiCameraData::loadIPA(ipa::RPi::IPAInitResult *result)\n \t}\n \n \tIPASettings settings(configurationFile, sensor_->model());\n+\tipa::RPi::InitParams params;\n \n-\treturn ipa_->init(settings, !!sensor_->focusLens(), result);\n+\tparams.lensPresent = !!sensor_->focusLens();\n+\treturn ipa_->init(settings, params, result);\n }\n \n-int RPiCameraData::configureIPA(const CameraConfiguration *config, ipa::RPi::IPAConfigResult *result)\n+int RPiCameraData::configureIPA(const CameraConfiguration *config, ipa::RPi::ConfigResult *result)\n {\n \tstd::map<unsigned int, ControlInfoMap> entityControls;\n-\tipa::RPi::IPAConfig ipaConfig;\n+\tipa::RPi::ConfigParams params;\n \n \t/* \\todo Move passing of ispControls and lensControls to ipa::init() */\n-\tipaConfig.sensorControls = sensor_->controls();\n-\tipaConfig.ispControls = isp_[Isp::Input].dev()->controls();\n+\tparams.sensorControls = sensor_->controls();\n+\tparams.ispControls = isp_[Isp::Input].dev()->controls();\n \tif (sensor_->focusLens())\n-\t\tipaConfig.lensControls = sensor_->focusLens()->controls();\n+\t\tparams.lensControls = sensor_->focusLens()->controls();\n \n \t/* Always send the user transform to the IPA. */\n-\tipaConfig.transform = static_cast<unsigned int>(config->transform);\n+\tparams.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@@ -1703,7 +1705,7 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config, ipa::RPi::IPA\n \t\t * \\todo Investigate if mapping the lens shading table buffer\n \t\t * could be handled with mapBuffers().\n \t\t */\n-\t\tipaConfig.lsTableHandle = lsTable_;\n+\t\tparams.lsTableHandle = lsTable_;\n \t}\n \n \t/* We store the IPACameraSensorInfo for digital zoom calculations. */\n@@ -1714,15 +1716,14 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config, ipa::RPi::IPA\n \t}\n \n \t/* Ready the IPA - it must know about the sensor resolution. */\n-\tControlList controls;\n-\tret = ipa_->configure(sensorInfo_, ipaConfig, &controls, result);\n+\tret = ipa_->configure(sensorInfo_, params, result);\n \tif (ret < 0) {\n \t\tLOG(RPI, Error) << \"IPA configuration failed!\";\n \t\treturn -EPIPE;\n \t}\n \n-\tif (!controls.empty())\n-\t\tsetSensorControls(controls);\n+\tif (!result->controls.empty())\n+\t\tsetSensorControls(result->controls);\n \n \treturn 0;\n }\n@@ -1883,24 +1884,32 @@ void RPiCameraData::enumerateVideoDevices(MediaLink *link)\n \t}\n }\n \n-void RPiCameraData::statsMetadataComplete(uint32_t bufferId, const ControlList &controls)\n+void RPiCameraData::processStatsComplete(const ipa::RPi::BufferIds &buffers)\n {\n \tif (!isRunning())\n \t\treturn;\n \n-\tFrameBuffer *buffer = isp_[Isp::Stats].getBuffers().at(bufferId & RPi::MaskID);\n+\tFrameBuffer *buffer = isp_[Isp::Stats].getBuffers().at(buffers.stats & RPi::MaskID);\n \n \thandleStreamBuffer(buffer, &isp_[Isp::Stats]);\n+\tstate_ = State::IpaComplete;\n+\thandleState();\n+}\n+\n+void RPiCameraData::metadataReady(const ControlList &metadata)\n+{\n+\tif (!isRunning())\n+\t\treturn;\n \n \t/* Add to the Request metadata buffer what the IPA has provided. */\n \tRequest *request = requestQueue_.front();\n-\trequest->metadata().merge(controls);\n+\trequest->metadata().merge(metadata);\n \n \t/*\n \t * Inform the sensor of the latest colour gains if it has the\n \t * V4L2_CID_NOTIFY_GAINS control (which means notifyGainsUnity_ is set).\n \t */\n-\tconst auto &colourGains = controls.get(libcamera::controls::ColourGains);\n+\tconst auto &colourGains = metadata.get(libcamera::controls::ColourGains);\n \tif (notifyGainsUnity_ && colourGains) {\n \t\t/* The control wants linear gains in the order B, Gb, Gr, R. */\n \t\tControlList ctrls(sensor_->controls());\n@@ -1914,33 +1923,29 @@ void RPiCameraData::statsMetadataComplete(uint32_t bufferId, const ControlList &\n \n \t\tsensor_->setControls(&ctrls);\n \t}\n-\n-\tstate_ = State::IpaComplete;\n-\thandleState();\n }\n \n-void RPiCameraData::runIsp(uint32_t bufferId)\n+void RPiCameraData::prepareIspComplete(const ipa::RPi::BufferIds &buffers)\n {\n+\tunsigned int embeddedId = buffers.embedded & RPi::MaskID;\n+\tunsigned int bayer = buffers.bayer & RPi::MaskID;\n+\tFrameBuffer *buffer;\n+\n \tif (!isRunning())\n \t\treturn;\n \n-\tFrameBuffer *buffer = unicam_[Unicam::Image].getBuffers().at(bufferId & RPi::MaskID);\n-\n-\tLOG(RPI, Debug) << \"Input re-queue to ISP, buffer id \" << (bufferId & RPi::MaskID)\n+\tbuffer = unicam_[Unicam::Image].getBuffers().at(bayer & RPi::MaskID);\n+\tLOG(RPI, Debug) << \"Input re-queue to ISP, buffer id \" << (bayer & RPi::MaskID)\n \t\t\t<< \", timestamp: \" << buffer->metadata().timestamp;\n \n \tisp_[Isp::Input].queueBuffer(buffer);\n \tispOutputCount_ = 0;\n-\thandleState();\n-}\n \n-void RPiCameraData::embeddedComplete(uint32_t bufferId)\n-{\n-\tif (!isRunning())\n-\t\treturn;\n+\tif (sensorMetadata_ && embeddedId) {\n+\t\tbuffer = unicam_[Unicam::Embedded].getBuffers().at(embeddedId & RPi::MaskID);\n+\t\thandleStreamBuffer(buffer, &unicam_[Unicam::Embedded]);\n+\t}\n \n-\tFrameBuffer *buffer = unicam_[Unicam::Embedded].getBuffers().at(bufferId & RPi::MaskID);\n-\thandleStreamBuffer(buffer, &unicam_[Unicam::Embedded]);\n \thandleState();\n }\n \n@@ -2116,8 +2121,10 @@ void RPiCameraData::ispOutputDequeue(FrameBuffer *buffer)\n \t * application until after the IPA signals so.\n \t */\n \tif (stream == &isp_[Isp::Stats]) {\n-\t\tipa_->signalStatReady(RPi::MaskStats | static_cast<unsigned int>(index),\n-\t\t\t\t      requestQueue_.front()->sequence());\n+\t\tipa::RPi::ProcessParams params;\n+\t\tparams.buffers.stats = index | RPi::MaskStats;\n+\t\tparams.ipaContext = requestQueue_.front()->sequence();\n+\t\tipa_->processStats(params);\n \t} else {\n \t\t/* Any other ISP output can be handed back to the application now. */\n \t\thandleStreamBuffer(buffer, stream);\n@@ -2344,38 +2351,30 @@ void RPiCameraData::tryRunPipeline()\n \trequest->metadata().clear();\n \tfillRequestMetadata(bayerFrame.controls, request);\n \n-\t/*\n-\t * Process all the user controls by the IPA. Once this is complete, we\n-\t * queue the ISP output buffer listed in the request to start the HW\n-\t * pipeline.\n-\t */\n-\tipa_->signalQueueRequest(request->controls());\n-\n \t/* Set our state to say the pipeline is active. */\n \tstate_ = State::Busy;\n \n-\tunsigned int bayerId = unicam_[Unicam::Image].getBufferId(bayerFrame.buffer);\n+\tunsigned int bayer = unicam_[Unicam::Image].getBufferId(bayerFrame.buffer);\n \n-\tLOG(RPI, Debug) << \"Signalling signalIspPrepare:\"\n-\t\t\t<< \" Bayer buffer id: \" << bayerId;\n+\tLOG(RPI, Debug) << \"Signalling prepareIsp:\"\n+\t\t\t<< \" Bayer buffer id: \" << bayer;\n \n-\tipa::RPi::ISPConfig ispPrepare;\n-\tispPrepare.bayerBufferId = RPi::MaskBayerData | bayerId;\n-\tispPrepare.controls = std::move(bayerFrame.controls);\n-\tispPrepare.ipaContext = request->sequence();\n-\tispPrepare.delayContext = bayerFrame.delayContext;\n+\tipa::RPi::PrepareParams params;\n+\tparams.buffers.bayer = RPi::MaskBayerData | bayer;\n+\tparams.sensorControls = std::move(bayerFrame.controls);\n+\tparams.requestControls = request->controls();\n+\tparams.ipaContext = request->sequence();\n+\tparams.delayContext = bayerFrame.delayContext;\n \n \tif (embeddedBuffer) {\n \t\tunsigned int embeddedId = unicam_[Unicam::Embedded].getBufferId(embeddedBuffer);\n \n-\t\tispPrepare.embeddedBufferId = RPi::MaskEmbeddedData | embeddedId;\n-\t\tispPrepare.embeddedBufferPresent = true;\n-\n-\t\tLOG(RPI, Debug) << \"Signalling signalIspPrepare:\"\n+\t\tparams.buffers.embedded = RPi::MaskEmbeddedData | embeddedId;\n+\t\tLOG(RPI, Debug) << \"Signalling prepareIsp:\"\n \t\t\t\t<< \" Embedded buffer id: \" << embeddedId;\n \t}\n \n-\tipa_->signalIspPrepare(ispPrepare);\n+\tipa_->prepareIsp(params);\n }\n \n bool RPiCameraData::findMatchingBuffers(BayerFrame &bayerFrame, FrameBuffer *&embeddedBuffer)\n","prefixes":["libcamera-devel","08/13"]}