Patch Detail
Show a patch.
GET /api/patches/24419/?format=api
{ "id": 24419, "url": "https://patchwork.libcamera.org/api/patches/24419/?format=api", "web_url": "https://patchwork.libcamera.org/patch/24419/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20250919094041.183031-11-stefan.klug@ideasonboard.com>", "date": "2025-09-19T09:40:25", "name": "[v5,10/19] ipa: rkisp1: agc: Add correction for exposure quantization", "commit_ref": "ef830669d0ca5a9d27ed09729126c137cde86f82", "pull_url": null, "state": "accepted", "archived": false, "hash": "fe4e2caa081a378d8251987f2c2087e9efb0bf6b", "submitter": { "id": 184, "url": "https://patchwork.libcamera.org/api/people/184/?format=api", "name": "Stefan Klug", "email": "stefan.klug@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/24419/mbox/", "series": [ { "id": 5450, "url": "https://patchwork.libcamera.org/api/series/5450/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5450", "date": "2025-09-19T09:40:15", "name": "Implement WDR algorithm", "version": 5, "mbox": "https://patchwork.libcamera.org/series/5450/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/24419/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/24419/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 03B63C328C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 19 Sep 2025 09:41:25 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 685856B5B9;\n\tFri, 19 Sep 2025 11:41:25 +0200 (CEST)", "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 962856B5A9\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 19 Sep 2025 11:41:22 +0200 (CEST)", "from ideasonboard.com (unknown\n\t[IPv6:2a00:6020:448c:6c00:4d54:eab8:98ca:163b])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 6598E842;\n\tFri, 19 Sep 2025 11:40:02 +0200 (CEST)" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"m8HgF/r0\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1758274802;\n\tbh=8NrnZ1Svug0IEpVFOG2l9atAlmoOVvrNZc39ea8krp4=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=m8HgF/r02W8YnKsziYOK9UkKBJAEd9mdL7su4BKnu6PRuKx/AHQgvT/L5+xJ62x55\n\tp7aXM6bVuQI4LT3JAqsPNQ/fAb/HB4DvJh+tUeoUpIS2bPKlT6Nw03toS/MxJI0wQz\n\t1lmsfaVLpx85TkUPaxfIggRGfyrgbhqGA4YYYORU=", "From": "Stefan Klug <stefan.klug@ideasonboard.com>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "Stefan Klug <stefan.klug@ideasonboard.com>,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>,\n\tDaniel Scally <dan.scally@ideasonboard.com>,\n\tPaul Elder <paul.elder@ideasonboard.com>", "Subject": "[PATCH v5 10/19] ipa: rkisp1: agc: Add correction for exposure\n\tquantization", "Date": "Fri, 19 Sep 2025 11:40:25 +0200", "Message-ID": "<20250919094041.183031-11-stefan.klug@ideasonboard.com>", "X-Mailer": "git-send-email 2.48.1", "In-Reply-To": "<20250919094041.183031-1-stefan.klug@ideasonboard.com>", "References": "<20250919094041.183031-1-stefan.klug@ideasonboard.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "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>", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "There are several occasions where quantization can lead to visible\neffects.\n\nIn WDR mode it can happen that exposure times get set to very low values\n(Sometimes 2-3 lines). This intentionally introduced underexposure is\ncorrected by the GWDR module. As exposure time is quantized by lines,\nthe smallest possible change in exposure time now results in a quite\nvisible change in perceived brightness.\n\nOn some sensors the possible gain steps are also quite large leading to\nvisible jumps if e.g. if the exposure time is fixed.\n\nMitigate that by applying a global gain to account for the error\nintroduced by the exposure quantization.\n\nToDo: This needs perfect frame synchronous control of the sensor to work\nproperly which is not guaranteed in all cases. It still improves the\nbehavior with the current regulation and can easily be skipped, be\nremoving the compress algorithm from the tuning file.\n\nSigned-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\nReviewed-by: Daniel Scally <dan.scally@ideasonboard.com>\nReviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n\n---\n\nChanges in v4:\n- Include quantization gain in effective exposure value\n- Correctly initialize quantizationGain in frameContext\n- Collected tags\n\nChanges in v3:\n- Collected tags\n---\n src/ipa/rkisp1/algorithms/agc.cpp | 33 ++++++++++++++++++++++++++++---\n src/ipa/rkisp1/ipa_context.h | 2 ++\n 2 files changed, 32 insertions(+), 3 deletions(-)", "diff": "diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp\nindex 0a29326841fb..fe2f66cf6ee4 100644\n--- a/src/ipa/rkisp1/algorithms/agc.cpp\n+++ b/src/ipa/rkisp1/algorithms/agc.cpp\n@@ -176,6 +176,7 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)\n \tcontext.activeState.agc.automatic.gain = context.configuration.sensor.minAnalogueGain;\n \tcontext.activeState.agc.automatic.exposure =\n \t\t10ms / context.configuration.sensor.lineDuration;\n+\tcontext.activeState.agc.automatic.quantizationGain = 1.0;\n \tcontext.activeState.agc.manual.gain = context.activeState.agc.automatic.gain;\n \tcontext.activeState.agc.manual.exposure = context.activeState.agc.automatic.exposure;\n \tcontext.activeState.agc.autoExposureEnabled = !context.configuration.raw;\n@@ -199,6 +200,9 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)\n \tcontext.configuration.agc.measureWindow.h_size = configInfo.outputSize.width;\n \tcontext.configuration.agc.measureWindow.v_size = configInfo.outputSize.height;\n \n+\tAgcMeanLuminance::configure(context.configuration.sensor.lineDuration,\n+\t\t\t\t context.camHelper.get());\n+\n \tsetLimits(context.configuration.sensor.minExposureTime,\n \t\t context.configuration.sensor.maxExposureTime,\n \t\t context.configuration.sensor.minAnalogueGain,\n@@ -283,6 +287,10 @@ void Agc::queueRequest(IPAContext &context,\n \tif (!frameContext.agc.autoGainEnabled)\n \t\tframeContext.agc.gain = agc.manual.gain;\n \n+\tif (!frameContext.agc.autoExposureEnabled &&\n+\t !frameContext.agc.autoGainEnabled)\n+\t\tframeContext.agc.quantizationGain = 1.0;\n+\n \tconst auto &meteringMode = controls.get(controls::AeMeteringMode);\n \tif (meteringMode) {\n \t\tframeContext.agc.updateMetering = agc.meteringMode != *meteringMode;\n@@ -336,12 +344,17 @@ void Agc::prepare(IPAContext &context, const uint32_t frame,\n {\n \tuint32_t activeAutoExposure = context.activeState.agc.automatic.exposure;\n \tdouble activeAutoGain = context.activeState.agc.automatic.gain;\n+\tdouble activeAutoQGain = context.activeState.agc.automatic.quantizationGain;\n \n \t/* Populate exposure and gain in auto mode */\n-\tif (frameContext.agc.autoExposureEnabled)\n+\tif (frameContext.agc.autoExposureEnabled) {\n \t\tframeContext.agc.exposure = activeAutoExposure;\n-\tif (frameContext.agc.autoGainEnabled)\n+\t\tframeContext.agc.quantizationGain = activeAutoQGain;\n+\t}\n+\tif (frameContext.agc.autoGainEnabled) {\n \t\tframeContext.agc.gain = activeAutoGain;\n+\t\tframeContext.agc.quantizationGain = activeAutoQGain;\n+\t}\n \n \t/*\n \t * Populate manual exposure and gain from the active auto values when\n@@ -354,6 +367,12 @@ void Agc::prepare(IPAContext &context, const uint32_t frame,\n \tif (!frameContext.agc.autoGainEnabled && frameContext.agc.autoGainModeChange) {\n \t\tcontext.activeState.agc.manual.gain = activeAutoGain;\n \t\tframeContext.agc.gain = activeAutoGain;\n+\t\tframeContext.agc.quantizationGain = activeAutoQGain;\n+\t}\n+\n+\tif (context.configuration.compress.supported) {\n+\t\tframeContext.compress.enable = true;\n+\t\tframeContext.compress.gain = frameContext.agc.quantizationGain;\n \t}\n \n \tif (frame > 0 && !frameContext.agc.updateMetering)\n@@ -564,6 +583,14 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n \tdouble analogueGain = frameContext.sensor.gain;\n \tutils::Duration effectiveExposureValue = exposureTime * analogueGain;\n \n+\t/*\n+\t * Include the quantization gain if it was applied. Do not use\n+\t * compress.gain because it will include gains that shall not be\n+\t * reported to the user when HDR is implemented.\n+\t */\n+\tif (frameContext.compress.enable)\n+\t\teffectiveExposureValue *= frameContext.agc.quantizationGain;\n+\n \tsetExposureCompensation(pow(2.0, frameContext.agc.exposureValue));\n \n \tutils::Duration newExposureTime;\n@@ -582,7 +609,7 @@ void Agc::process(IPAContext &context, [[maybe_unused]] const uint32_t frame,\n \t/* Update the estimated exposure and gain. */\n \tactiveState.agc.automatic.exposure = newExposureTime / lineDuration;\n \tactiveState.agc.automatic.gain = aGain;\n-\n+\tactiveState.agc.automatic.quantizationGain = qGain;\n \t/*\n \t * Expand the target frame duration so that we do not run faster than\n \t * the minimum frame duration when we have short exposures.\ndiff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h\nindex a723c79b04d9..35d25d555e65 100644\n--- a/src/ipa/rkisp1/ipa_context.h\n+++ b/src/ipa/rkisp1/ipa_context.h\n@@ -81,6 +81,7 @@ struct IPAActiveState {\n \t\tstruct {\n \t\t\tuint32_t exposure;\n \t\t\tdouble gain;\n+\t\t\tdouble quantizationGain;\n \t\t} automatic;\n \n \t\tbool autoExposureEnabled;\n@@ -135,6 +136,7 @@ struct IPAFrameContext : public FrameContext {\n \t\tuint32_t exposure;\n \t\tdouble gain;\n \t\tdouble exposureValue;\n+\t\tdouble quantizationGain;\n \t\tuint32_t vblank;\n \t\tbool autoExposureEnabled;\n \t\tbool autoGainEnabled;\n", "prefixes": [ "v5", "10/19" ] }