From patchwork Wed Sep 16 14:39:43 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jai Luthra X-Patchwork-Id: 28307 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id C6647BDE6B for ; Wed, 16 Sep 2026 14:40:48 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7AB4D68700; Wed, 16 Sep 2026 16:40:48 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="v1jIF/Fg"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0BF1E68700 for ; Wed, 16 Sep 2026 16:40:47 +0200 (CEST) Received: from mail.ideasonboard.com (unknown [IPv6:2401:4900:1c69:85de:a3c9:9357:b164:bf0b]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 0B532558; Wed, 16 Sep 2026 16:39:04 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1789569545; bh=/VeaHiORXTitMSGsB1tZsfYr5Q88+ZNwS1g2kzTGhC4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=v1jIF/Fg89af+3RQFMKDPxVBkt3mTNWmHo3jffmQGmx0GvkUGO4YFd4ECTSJPvCq8 pBmHhvtiYgt0CZ8JWb0F5q2rNszrWIOdDyLQHlWQ2EZBHnDZMIaCDS6R4l+YnJQDsJ pym8YAy6tv7ONmerX6ysrMNfJeCLgh7FDEjqi7hE= From: Jai Luthra Date: Wed, 16 Sep 2026 20:09:43 +0530 Subject: [PATCH v3 7/8] pipeline/ipa: rpi: vc4: Switch configuration from controls to param buffer MIME-Version: 1.0 Message-Id: <20260916-pi4-upstream-v3-7-4666708d8829@ideasonboard.com> References: <20260916-pi4-upstream-v3-0-4666708d8829@ideasonboard.com> In-Reply-To: <20260916-pi4-upstream-v3-0-4666708d8829@ideasonboard.com> To: libcamera-devel@lists.libcamera.org Cc: Naushir Patuck , David Plowman , Laurent Pinchart , Kieran Bingham , Paul Elder , Jai Luthra X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=25112; i=jai.luthra@ideasonboard.com; h=from:subject:message-id; bh=/VeaHiORXTitMSGsB1tZsfYr5Q88+ZNwS1g2kzTGhC4=; b=owEBbQKS/ZANAwAKAUPekfkkmnFFAcsmYgBqqqpD/kK0pHYd5tjdf0b+DGOZ5jYl8YlWiH1aZ LIVaKWVU/+JAjMEAAEKAB0WIQRN4NgY5dV16NRar8VD3pH5JJpxRQUCaqqqQwAKCRBD3pH5JJpx RTMaEACfHMnZJ7Xc7+HAdUNQrofOvkZoXspD/ASmkAR2suDum1f9t35qQCDcpZ2brteUDRf+Fw2 5iEL9MPYqhyghqE+MqEHfEIwb3A4o7VQVLVkz+piKg1eSIkTK3WEgvqmtvIs1SXj9Jup2OqIf8b 6jvLlLU/crT1JIiiUwfodabV5KnuHwEJI67xNpV6AsGA0kP3tEd4sFdQCZFhWqI+JDzQNAI9MGi X+XOF6/LZ+tVGqeOBHZXAd/mCuDcr0vl9Jjhx0AKhSxw8uAXu12EIpGyQUQyBcAo/AUoV307cdP 859GI9OBMrrH8BuhqsibnWokQq8ji/lyYrwI8oI/CW7evHr7yuPvXWNPb/u19Bg6c9X557Mg5JZ wVaW9RI+Qz2I9BcThPzZONQNbyKypl+9xkbE04Jqa5j+BRpUVxPOYQxLCVLNxWuNuc1NVLYrIBh 2MN2zh/hyj/AKesWgZ3HOH/dsDqETSjDqsQ9/cfbeJosl4ecCleahHwI3mvGWSac76N1ZfGyOVC ni4Qk+JXkvXTzqhNSWIJpcbJRl1GjHZ/5nbZ8r86m4/52OEexItSOvakcaMGJ84qQl2G4imyZOs p70xha9u5Jbl/2qAi6U7lFkpWNn9+uIhVcebHtn/chAdaGbdXNKX8KcOjtEjQs99pacMcYkzTbP 8t9eP7iTugmsJ9Q== X-Developer-Key: i=jai.luthra@ideasonboard.com; a=openpgp; fpr=4DE0D818E5D575E8D45AAFC543DE91F9249A7145 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Let each algorithm write directly into typed parameter blocks using the Bcm2835Params helper. Acquire a parameter buffer in tryRunPipeline(), pass it to the IPA through BufferIds::params, and queue it back to the ISP once the IPA reports how many bytes it filled. Also patch the lens-shading dmabuf fd in the params buffer, similar to what setIspControls() did before. Finally, drop the dead-code that was used to configure the custom V4L2 controls for ISP configuration. Reviewed-by: Paul Elder Tested-by: Paul Elder Signed-off-by: Jai Luthra --- include/libcamera/ipa/raspberrypi.mojom | 12 -- src/ipa/rpi/vc4/vc4.cpp | 215 ++++++++++++++------------------ src/libcamera/pipeline/rpi/vc4/vc4.cpp | 89 +++++++++---- 3 files changed, 158 insertions(+), 158 deletions(-) diff --git a/include/libcamera/ipa/raspberrypi.mojom b/include/libcamera/ipa/raspberrypi.mojom index 84566648d213..255811fd6302 100644 --- a/include/libcamera/ipa/raspberrypi.mojom +++ b/include/libcamera/ipa/raspberrypi.mojom @@ -39,7 +39,6 @@ struct BufferIds { struct ConfigParams { uint32 transform; libcamera.ControlInfoMap sensorControls; - libcamera.ControlInfoMap ispControls; libcamera.ControlInfoMap lensControls; /* VC4 specific */ libcamera.SharedFD lsTableHandle; @@ -254,17 +253,6 @@ interface IPARPiEventInterface { */ metadataReady(libcamera.ControlList metadata); - /** - * \fn setIspControls() - * \brief Signal ISP controls to be applied. - * \param[in] controls List of controls to be applied. - * - * This asynchronous event is signalled to the pipeline handler during - * the \a prepareISP signal after all algorithms have been run and the - * IPA requires ISP controls to be applied for the frame. - */ - setIspControls(libcamera.ControlList controls); - /** * \fn setDelayedControls() * \brief Signal Sensor controls to be applied. diff --git a/src/ipa/rpi/vc4/vc4.cpp b/src/ipa/rpi/vc4/vc4.cpp index 298cf8829258..e1075235f663 100644 --- a/src/ipa/rpi/vc4/vc4.cpp +++ b/src/ipa/rpi/vc4/vc4.cpp @@ -5,6 +5,7 @@ * Raspberry Pi VC4/BCM2835 ISP IPA. */ +#include #include #include #include @@ -30,6 +31,7 @@ #include "controller/lux_status.h" #include "controller/noise_status.h" #include "controller/sharpen_status.h" +#include "params.h" namespace libcamera { @@ -59,34 +61,38 @@ private: int32_t platformStart(const ControlList &controls, StartResult *result) override; int32_t platformConfigure(const ConfigParams ¶ms, ConfigResult *result) override; + void platformParamsBufferInit(std::span paramsBuffer) override; void platformPrepareIsp(RPiController::Metadata &rpiMetadata) override; void platformPrepareAgc([[maybe_unused]] RPiController::Metadata &rpiMetadata) override; RPiController::StatisticsPtr platformProcessStats(std::span mem) override; void handleControls(const ControlList &controls) override; - bool validateIspControls(); - void applyAWB(const struct AwbStatus *awbStatus, ControlList &ctrls); - void applyDG(double digitalGain, const struct AwbStatus *awbStatus, ControlList &ctrls); - void applyCCM(const struct CcmStatus *ccmStatus, ControlList &ctrls); - void applyBlackLevel(const struct BlackLevelStatus *blackLevelStatus, ControlList &ctrls); - void applyGamma(const struct ContrastStatus *contrastStatus, ControlList &ctrls); - void applyGEQ(const struct GeqStatus *geqStatus, ControlList &ctrls); - void applyDenoise(const struct DenoiseStatus *denoiseStatus, ControlList &ctrls); - void applySharpen(const struct SharpenStatus *sharpenStatus, ControlList &ctrls); - void applyDPC(const struct DpcStatus *dpcStatus, ControlList &ctrls); - void applyLS(const struct AlscStatus *lsStatus, ControlList &ctrls); + void applyAWB(const struct AwbStatus *awbStatus, Bcm2835Params ¶ms); + void applyDG(double digitalGain, const struct AwbStatus *awbStatus, Bcm2835Params ¶ms); + void applyCCM(const struct CcmStatus *ccmStatus, Bcm2835Params ¶ms); + void applyBlackLevel(const struct BlackLevelStatus *blackLevelStatus, Bcm2835Params ¶ms); + void applyGamma(const struct ContrastStatus *contrastStatus, Bcm2835Params ¶ms); + void applyGEQ(const struct GeqStatus *geqStatus, Bcm2835Params ¶ms); + void applyDenoise(const struct DenoiseStatus *denoiseStatus, Bcm2835Params ¶ms); + void applySharpen(const struct SharpenStatus *sharpenStatus, Bcm2835Params ¶ms); + void applyDPC(const struct DpcStatus *dpcStatus, Bcm2835Params ¶ms); + void applyLS(const struct AlscStatus *lsStatus, Bcm2835Params ¶ms); void applyAF(const struct AfStatus *afStatus, ControlList &lensCtrls); void resampleTable(uint16_t dest[], const std::vector &src, int destW, int destH); - /* VC4 ISP controls. */ - ControlInfoMap ispCtrls_; - ControlList ctrls_; + size_t platformParamsBytesUsed() const override + { + return (ispParams_.has_value()) ? ispParams_->bytesused() : 0; + } /* LS table allocation passed in from the pipeline handler. */ SharedFD lsTableHandle_; void *lsTable_; + /* Params buffer for the current frame. */ + std::optional ispParams_; + /* Remember the most recent AWB values. */ AwbStatus lastAwbStatus_; }; @@ -113,13 +119,6 @@ int32_t IpaVc4::platformStart([[maybe_unused]] const ControlList &controls, int32_t IpaVc4::platformConfigure(const ConfigParams ¶ms, [[maybe_unused]] ConfigResult *result) { - ispCtrls_ = params.ispControls; - ctrls_ = ControlList(ispCtrls_); - if (!validateIspControls()) { - LOG(IPARPI, Error) << "ISP control validation failed."; - return -1; - } - /* Store the lens shading table pointer and handle if available. */ if (params.lsTableHandle.isValid()) { /* Remove any previous table, if there was one. */ @@ -144,50 +143,54 @@ int32_t IpaVc4::platformConfigure(const ConfigParams ¶ms, [[maybe_unused]] C return 0; } +void IpaVc4::platformParamsBufferInit(std::span paramsBuffer) +{ + /* Initialize the extensible parameter buffer */ + ispParams_.emplace(paramsBuffer); +} + void IpaVc4::platformPrepareIsp(RPiController::Metadata &rpiMetadata) { - ControlList &ctrls = ctrls_; - /* Lock the metadata buffer to avoid constant locks/unlocks. */ std::unique_lock lock(rpiMetadata); AwbStatus *awbStatus = rpiMetadata.getLocked("awb.status"); if (awbStatus) { - applyAWB(awbStatus, ctrls); + applyAWB(awbStatus, *ispParams_); lastAwbStatus_ = *awbStatus; } CcmStatus *ccmStatus = rpiMetadata.getLocked("ccm.status"); if (ccmStatus) - applyCCM(ccmStatus, ctrls); + applyCCM(ccmStatus, *ispParams_); AlscStatus *lsStatus = rpiMetadata.getLocked("alsc.status"); if (lsStatus) - applyLS(lsStatus, ctrls); + applyLS(lsStatus, *ispParams_); ContrastStatus *contrastStatus = rpiMetadata.getLocked("contrast.status"); if (contrastStatus) - applyGamma(contrastStatus, ctrls); + applyGamma(contrastStatus, *ispParams_); BlackLevelStatus *blackLevelStatus = rpiMetadata.getLocked("black_level.status"); if (blackLevelStatus) - applyBlackLevel(blackLevelStatus, ctrls); + applyBlackLevel(blackLevelStatus, *ispParams_); GeqStatus *geqStatus = rpiMetadata.getLocked("geq.status"); if (geqStatus) - applyGEQ(geqStatus, ctrls); + applyGEQ(geqStatus, *ispParams_); DenoiseStatus *denoiseStatus = rpiMetadata.getLocked("denoise.status"); if (denoiseStatus) - applyDenoise(denoiseStatus, ctrls); + applyDenoise(denoiseStatus, *ispParams_); SharpenStatus *sharpenStatus = rpiMetadata.getLocked("sharpen.status"); if (sharpenStatus) - applySharpen(sharpenStatus, ctrls); + applySharpen(sharpenStatus, *ispParams_); DpcStatus *dpcStatus = rpiMetadata.getLocked("dpc.status"); if (dpcStatus) - applyDPC(dpcStatus, ctrls); + applyDPC(dpcStatus, *ispParams_); const AfStatus *afStatus = rpiMetadata.getLocked("af.status"); if (afStatus) { @@ -204,10 +207,7 @@ void IpaVc4::platformPrepareAgc(RPiController::Metadata &rpiMetadata) double digitalGain = delayedAgcStatus ? delayedAgcStatus->digitalGain : agcStatus_.digitalGain; AwbStatus *awbStatus = rpiMetadata.getLocked("awb.status"); - applyDG(digitalGain, awbStatus, ctrls_); - - setIspControls.emit(ctrls_); - ctrls_ = ControlList(ispCtrls_); + applyDG(digitalGain, awbStatus, *ispParams_); } RPiController::StatisticsPtr IpaVc4::platformProcessStats(std::span mem) @@ -324,48 +324,26 @@ void IpaVc4::handleControls(const ControlList &controls) } } -bool IpaVc4::validateIspControls() +void IpaVc4::applyAWB(const struct AwbStatus *awbStatus, Bcm2835Params ¶ms) { - static const uint32_t ctrls[] = { - V4L2_CID_RED_BALANCE, - V4L2_CID_BLUE_BALANCE, - V4L2_CID_DIGITAL_GAIN, - V4L2_CID_USER_BCM2835_ISP_CC_MATRIX, - V4L2_CID_USER_BCM2835_ISP_GAMMA, - V4L2_CID_USER_BCM2835_ISP_BLACK_LEVEL, - V4L2_CID_USER_BCM2835_ISP_GEQ, - V4L2_CID_USER_BCM2835_ISP_DENOISE, - V4L2_CID_USER_BCM2835_ISP_SHARPEN, - V4L2_CID_USER_BCM2835_ISP_DPC, - V4L2_CID_USER_BCM2835_ISP_LENS_SHADING, - V4L2_CID_USER_BCM2835_ISP_CDN, - }; + auto block = params.block(); - for (auto c : ctrls) { - if (ispCtrls_.find(c) == ispCtrls_.end()) { - LOG(IPARPI, Error) << "Unable to find ISP control " - << utils::hex(c); - return false; - } - } - - return true; -} - -void IpaVc4::applyAWB(const struct AwbStatus *awbStatus, ControlList &ctrls) -{ LOG(IPARPI, Debug) << "Applying WB R: " << awbStatus->gainR << " B: " << awbStatus->gainB; - ctrls.set(V4L2_CID_RED_BALANCE, - static_cast(awbStatus->gainR * 1000)); - ctrls.set(V4L2_CID_BLUE_BALANCE, - static_cast(awbStatus->gainB * 1000)); + block->awb_gains.r_gain.num = static_cast(awbStatus->gainR * 1000); + block->awb_gains.r_gain.den = 1000; + block->awb_gains.b_gain.num = static_cast(awbStatus->gainB * 1000); + block->awb_gains.b_gain.den = 1000; + + block.setEnabled(true); } void IpaVc4::applyDG(double digitalGain, - const struct AwbStatus *awbStatus, ControlList &ctrls) + const struct AwbStatus *awbStatus, Bcm2835Params ¶ms) { + auto block = params.block(); + if (awbStatus) { /* * We must apply sufficient extra digital gain to stop any of the channel gains being @@ -379,13 +357,16 @@ void IpaVc4::applyDG(double digitalGain, digitalGain *= extraGain; } - ctrls.set(V4L2_CID_DIGITAL_GAIN, - static_cast(digitalGain * 1000)); + block->digital_gain.gain.num = static_cast(digitalGain * 1000); + block->digital_gain.gain.den = 1000; + + block.setEnabled(true); } -void IpaVc4::applyCCM(const struct CcmStatus *ccmStatus, ControlList &ctrls) +void IpaVc4::applyCCM(const struct CcmStatus *ccmStatus, Bcm2835Params ¶ms) { - bcm2835_isp_custom_ccm ccm; + auto block = params.block(); + bcm2835_isp_custom_ccm &ccm = block->ccm; for (int i = 0; i < 9; i++) { ccm.ccm.ccm[i / 3][i % 3].den = 1000; @@ -395,29 +376,29 @@ void IpaVc4::applyCCM(const struct CcmStatus *ccmStatus, ControlList &ctrls) ccm.enabled = 1; ccm.ccm.offsets[0] = ccm.ccm.offsets[1] = ccm.ccm.offsets[2] = 0; - ControlValue c(std::span{ reinterpret_cast(&ccm), - sizeof(ccm) }); - ctrls.set(V4L2_CID_USER_BCM2835_ISP_CC_MATRIX, c); + block.setEnabled(true); } -void IpaVc4::applyBlackLevel(const struct BlackLevelStatus *blackLevelStatus, ControlList &ctrls) +void IpaVc4::applyBlackLevel(const struct BlackLevelStatus *blackLevelStatus, + Bcm2835Params ¶ms) { - bcm2835_isp_black_level blackLevel; + auto block = params.block(); + bcm2835_isp_black_level &blackLevel = block->black_level; blackLevel.enabled = 1; blackLevel.black_level_r = blackLevelStatus->blackLevelR; blackLevel.black_level_g = blackLevelStatus->blackLevelG; blackLevel.black_level_b = blackLevelStatus->blackLevelB; - ControlValue c(std::span{ reinterpret_cast(&blackLevel), - sizeof(blackLevel) }); - ctrls.set(V4L2_CID_USER_BCM2835_ISP_BLACK_LEVEL, c); + block.setEnabled(true); } -void IpaVc4::applyGamma(const struct ContrastStatus *contrastStatus, ControlList &ctrls) +void IpaVc4::applyGamma(const struct ContrastStatus *contrastStatus, + Bcm2835Params ¶ms) { const unsigned int numGammaPoints = controller_.getHardwareConfig().numGammaPoints; - struct bcm2835_isp_gamma gamma; + auto block = params.block(); + struct bcm2835_isp_gamma &gamma = block->gamma; for (unsigned int i = 0; i < numGammaPoints - 1; i++) { int x = i < 16 ? i * 1024 @@ -431,30 +412,28 @@ void IpaVc4::applyGamma(const struct ContrastStatus *contrastStatus, ControlList gamma.y[numGammaPoints - 1] = 65535; gamma.enabled = 1; - ControlValue c(std::span{ reinterpret_cast(&gamma), - sizeof(gamma) }); - ctrls.set(V4L2_CID_USER_BCM2835_ISP_GAMMA, c); + block.setEnabled(true); } -void IpaVc4::applyGEQ(const struct GeqStatus *geqStatus, ControlList &ctrls) +void IpaVc4::applyGEQ(const struct GeqStatus *geqStatus, Bcm2835Params ¶ms) { - bcm2835_isp_geq geq; + auto block = params.block(); + bcm2835_isp_geq &geq = block->geq; geq.enabled = 1; geq.offset = geqStatus->offset; geq.slope.den = 1000; geq.slope.num = 1000 * geqStatus->slope; - ControlValue c(std::span{ reinterpret_cast(&geq), - sizeof(geq) }); - ctrls.set(V4L2_CID_USER_BCM2835_ISP_GEQ, c); + block.setEnabled(true); } -void IpaVc4::applyDenoise(const struct DenoiseStatus *denoiseStatus, ControlList &ctrls) +void IpaVc4::applyDenoise(const struct DenoiseStatus *denoiseStatus, Bcm2835Params ¶ms) { + auto blockDenoise = params.block(); using RPiController::DenoiseMode; - bcm2835_isp_denoise denoise; + bcm2835_isp_denoise &denoise = blockDenoise->denoise; DenoiseMode mode = static_cast(denoiseStatus->mode); denoise.enabled = mode != DenoiseMode::Off; @@ -463,9 +442,11 @@ void IpaVc4::applyDenoise(const struct DenoiseStatus *denoiseStatus, ControlList denoise.slope.den = 1000; denoise.strength.num = 1000 * denoiseStatus->strength; denoise.strength.den = 1000; + blockDenoise.setEnabled(denoise.enabled); /* Set the CDN mode to match the SDN operating mode. */ - bcm2835_isp_cdn cdn; + auto blockCdn = params.block(); + bcm2835_isp_cdn &cdn = blockCdn->cdn; switch (mode) { case DenoiseMode::ColourFast: cdn.enabled = 1; @@ -479,18 +460,13 @@ void IpaVc4::applyDenoise(const struct DenoiseStatus *denoiseStatus, ControlList cdn.enabled = 0; } - ControlValue c(std::span{ reinterpret_cast(&denoise), - sizeof(denoise) }); - ctrls.set(V4L2_CID_USER_BCM2835_ISP_DENOISE, c); - - c = ControlValue(std::span{ reinterpret_cast(&cdn), - sizeof(cdn) }); - ctrls.set(V4L2_CID_USER_BCM2835_ISP_CDN, c); + blockCdn.setEnabled(cdn.enabled); } -void IpaVc4::applySharpen(const struct SharpenStatus *sharpenStatus, ControlList &ctrls) +void IpaVc4::applySharpen(const struct SharpenStatus *sharpenStatus, Bcm2835Params ¶ms) { - bcm2835_isp_sharpen sharpen; + auto block = params.block(); + bcm2835_isp_sharpen &sharpen = block->sharpen; sharpen.enabled = 1; sharpen.threshold.num = 1000 * sharpenStatus->threshold; @@ -500,24 +476,21 @@ void IpaVc4::applySharpen(const struct SharpenStatus *sharpenStatus, ControlList sharpen.limit.num = 1000 * sharpenStatus->limit; sharpen.limit.den = 1000; - ControlValue c(std::span{ reinterpret_cast(&sharpen), - sizeof(sharpen) }); - ctrls.set(V4L2_CID_USER_BCM2835_ISP_SHARPEN, c); + block.setEnabled(true); } -void IpaVc4::applyDPC(const struct DpcStatus *dpcStatus, ControlList &ctrls) +void IpaVc4::applyDPC(const struct DpcStatus *dpcStatus, Bcm2835Params ¶ms) { - bcm2835_isp_dpc dpc; + auto block = params.block(); + bcm2835_isp_dpc &dpc = block->dpc; dpc.enabled = 1; dpc.strength = dpcStatus->strength; - ControlValue c(std::span{ reinterpret_cast(&dpc), - sizeof(dpc) }); - ctrls.set(V4L2_CID_USER_BCM2835_ISP_DPC, c); + block.setEnabled(true); } -void IpaVc4::applyLS(const struct AlscStatus *lsStatus, ControlList &ctrls) +void IpaVc4::applyLS(const struct AlscStatus *lsStatus, Bcm2835Params ¶ms) { /* * Program lens shading tables into pipeline. @@ -541,7 +514,14 @@ void IpaVc4::applyLS(const struct AlscStatus *lsStatus, ControlList &ctrls) /* We're going to supply corner sampled tables, 16 bit samples. */ w++, h++; - bcm2835_isp_lens_shading ls = { + + if (!lsTableHandle_.isValid() || !lsTable_ || w * h * 4 * sizeof(uint16_t) > MaxLsGridSize) { + LOG(IPARPI, Error) << "Do not have a correctly allocated lens shading table!"; + return; + } + + auto block = params.block(); + block->ls = { .enabled = 1, .grid_cell_size = cellSize, .grid_width = w, @@ -554,11 +534,6 @@ void IpaVc4::applyLS(const struct AlscStatus *lsStatus, ControlList &ctrls) .gain_format = GAIN_FORMAT_U4P10 }; - if (!lsTable_ || w * h * 4 * sizeof(uint16_t) > MaxLsGridSize) { - LOG(IPARPI, Error) << "Do not have a correctly allocate lens shading table!"; - return; - } - if (lsStatus) { /* Format will be u4.10 */ uint16_t *grid = static_cast(lsTable_); @@ -569,9 +544,7 @@ void IpaVc4::applyLS(const struct AlscStatus *lsStatus, ControlList &ctrls) resampleTable(grid + 3 * w * h, lsStatus->b, w, h); } - ControlValue c(std::span{ reinterpret_cast(&ls), - sizeof(ls) }); - ctrls.set(V4L2_CID_USER_BCM2835_ISP_LENS_SHADING, c); + block.setEnabled(true); } void IpaVc4::applyAF(const struct AfStatus *afStatus, ControlList &lensCtrls) diff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp index d242157d58c5..12384f53dc6c 100644 --- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp +++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp @@ -86,7 +86,6 @@ public: void processStatsComplete(const ipa::RPi::BufferIds &buffers); void prepareIspComplete(const ipa::RPi::BufferIds &buffers, bool stitchSwapBuffers, unsigned int paramsBytesUsed); - void setIspControls(const ControlList &controls); void setCameraTimeout(uint32_t maxFrameLengthMs); std::unique_ptr unicamSubdev_; @@ -142,6 +141,8 @@ private: void tryRunPipeline() override; bool findMatchingBuffers(BayerFrame &bayerFrame, FrameBuffer *&embeddedBuffer); + void populateLensShadingFD(const RPi::BufferObject ¶msBufObj); + std::queue bayerQueue_; std::queue embeddedQueue_; }; @@ -412,7 +413,6 @@ int PipelineHandlerVc4::platformRegister(std::unique_ptr &camer /* Write up all the IPA connections. */ data->ipa_->processStatsComplete.connect(data, &Vc4CameraData::processStatsComplete); data->ipa_->prepareIspComplete.connect(data, &Vc4CameraData::prepareIspComplete); - data->ipa_->setIspControls.connect(data, &Vc4CameraData::setIspControls); data->ipa_->setCameraTimeout.connect(data, &Vc4CameraData::setCameraTimeout); /* @@ -824,8 +824,6 @@ int Vc4CameraData::platformConfigure(const RPi::RPiCameraConfiguration *rpiConfi int Vc4CameraData::platformConfigureIpa(ipa::RPi::ConfigParams ¶ms) { - params.ispControls = isp_[Isp::Input].dev()->controls(); - /* Allocate the lens shading table via dmaHeap and pass to the IPA. */ if (!lsTable_.isValid()) { lsTable_ = SharedFD(dmaHeap_.alloc("ls_grid", ipa::RPi::MaxLsGridSize)); @@ -968,17 +966,65 @@ void Vc4CameraData::processStatsComplete(const ipa::RPi::BufferIds &buffers) handleState(); } +/* + * Populate the lens shading table's dmabuf descriptor inside the params buffer. + * + * While the IPA fills the lens shading table, it may run in an isolated + * process context, so it does not populate the dmabuf file descriptor. + * + * Do that here. + */ +void Vc4CameraData::populateLensShadingFD(const RPi::BufferObject ¶msBufObj) +{ + std::span plane = paramsBufObj.mapped->planes()[0]; + auto *paramsBuffer = + reinterpret_cast(plane.data()); + uint8_t *data = paramsBuffer->data; + uint32_t offset = 0; + + while (offset < paramsBuffer->data_size) { + auto *blockHeader = + reinterpret_cast(data + offset); + + if (blockHeader->type == BCM2835_ISP_PARAM_BLOCK_LENS_SHADING) { + auto *lsBlock = + reinterpret_cast(blockHeader); + lsBlock->ls.dmabuf = lsTable_.get(); + return; + } + + offset += blockHeader->size; + } + + LOG(RPI, Error) << "Unable to populate lens-shading dmabuf fd"; +} + void Vc4CameraData::prepareIspComplete(const ipa::RPi::BufferIds &buffers, [[maybe_unused]] bool stitchSwapBuffers, - [[maybe_unused]] unsigned int paramsBytesUsed) + unsigned int paramsBytesUsed) { unsigned int embeddedId = buffers.embedded & RPi::MaskID; + unsigned int paramsId = buffers.params & RPi::MaskID; unsigned int bayer = buffers.bayer & RPi::MaskID; FrameBuffer *buffer; if (!isRunning()) return; + /* Queue params buffer */ + const RPi::BufferObject ¶msBufObj = isp_[Isp::Params].getBuffers().at(paramsId); + ASSERT(paramsBufObj.mapped); + populateLensShadingFD(paramsBufObj); + buffer = paramsBufObj.buffer; + buffer->_d()->metadata().planes()[0].bytesused = paramsBytesUsed; + + LOG(RPI, Debug) << "Queue params to ISP, buffer id " << paramsId + << ", timestamp: " << buffer->metadata().timestamp + << ", bytes used: " << paramsBytesUsed; + + isp_[Isp::Params].queueBuffer(buffer); + + /* Queue input buffer */ buffer = unicam_[Unicam::Image].getBuffers().at(bayer & RPi::MaskID).buffer; LOG(RPI, Debug) << "Input re-queue to ISP, buffer id " << (bayer & RPi::MaskID) << ", timestamp: " << buffer->metadata().timestamp; @@ -993,23 +1039,6 @@ void Vc4CameraData::prepareIspComplete(const ipa::RPi::BufferIds &buffers, handleState(); } -void Vc4CameraData::setIspControls(const ControlList &controls) -{ - ControlList ctrls = controls; - - if (ctrls.contains(V4L2_CID_USER_BCM2835_ISP_LENS_SHADING)) { - ControlValue &value = - const_cast(ctrls.get(V4L2_CID_USER_BCM2835_ISP_LENS_SHADING)); - std::span s = value.data(); - bcm2835_isp_lens_shading *ls = - reinterpret_cast(s.data()); - ls->dmabuf = lsTable_.get(); - } - - isp_[Isp::Input].dev()->setControls(&ctrls); - handleState(); -} - void Vc4CameraData::setCameraTimeout(uint32_t maxFrameLengthMs) { /* @@ -1037,6 +1066,11 @@ void Vc4CameraData::tryRunPipeline() if (!findMatchingBuffers(bayerFrame, embeddedBuffer)) return; + /* Request a parameter buffer, will be released by ispOutputDequeue */ + const RPi::BufferObject ¶mBufObj = isp_[Isp::Params].acquireBuffer(); + if (!paramBufObj.buffer || !paramBufObj.mapped) + return; + /* Take the first request from the queue and action the IPA. */ Request *request = requestQueue_.front(); ASSERT(request->metadata().empty()); @@ -1048,9 +1082,6 @@ void Vc4CameraData::tryRunPipeline() unsigned int bayer = unicam_[Unicam::Image].getBufferId(bayerFrame.buffer); - LOG(RPI, Debug) << "Signalling prepareIsp:" - << " Bayer buffer id: " << bayer; - ipa::RPi::PrepareParams params; params.buffers.bayer = RPi::MaskBayerData | bayer; params.sensorControls = std::move(bayerFrame.controls); @@ -1065,6 +1096,14 @@ void Vc4CameraData::tryRunPipeline() /* Set our state to say the pipeline is active. */ state_ = State::Busy; + unsigned int paramId = isp_[Isp::Params].getBufferId(paramBufObj.buffer); + ASSERT(paramId); + params.buffers.params = RPi::MaskParams | paramId; + + LOG(RPI, Debug) << "Signalling prepareIsp:" + << " Bayer buffer id: " << bayer + << " Param buffer id: " << paramId; + if (embeddedBuffer) { unsigned int embeddedId = unicam_[Unicam::Embedded].getBufferId(embeddedBuffer);