From 9b441cf198ab7344885620de0291978c26b03a5e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 30 Sep 2025 17:04:27 +0200 Subject: [PATCH] libcamera: software_isp: Add valid flag to struct SwIspStats Generating statistics for every single frame is not really necessary. However a roundtrip through ipa_->processStats() still need to be done every frame, even if there are no stats to make the IPA generate metadata for every frame. Add a valid flag to the statistics struct to let the IPA know when there are no statistics for the frame being processed and modify the IPA to only generate metadata for frames without valid statistics. This is a preparation patch for skipping statistics generation for some frames. Reviewed-by: Kieran Bingham Reviewed-by: Milan Zamazal Tested-by: Milan Zamazal Tested-by: Kieran Bingham Signed-off-by: Hans de Goede Signed-off-by: Kieran Bingham --- .../internal/software_isp/swisp_stats.h | 5 ++++ src/ipa/simple/algorithms/agc.cpp | 24 ++++++++++++++++++- src/ipa/simple/algorithms/awb.cpp | 3 +++ src/ipa/simple/algorithms/blc.cpp | 3 +++ src/ipa/simple/ipa_context.h | 5 ++++ src/libcamera/software_isp/swstats_cpu.cpp | 1 + 6 files changed, 40 insertions(+), 1 deletion(-) diff --git a/include/libcamera/internal/software_isp/swisp_stats.h b/include/libcamera/internal/software_isp/swisp_stats.h index ae11f112..3c986018 100644 --- a/include/libcamera/internal/software_isp/swisp_stats.h +++ b/include/libcamera/internal/software_isp/swisp_stats.h @@ -20,6 +20,11 @@ namespace libcamera { * wrap around. */ struct SwIspStats { + /** + * \brief True if the statistics buffer contains valid data, false if + * no statistics were generated for this frame + */ + bool valid; /** * \brief Holds the sum of all sampled red pixels */ diff --git a/src/ipa/simple/algorithms/agc.cpp b/src/ipa/simple/algorithms/agc.cpp index 3471cc88..e0447cbd 100644 --- a/src/ipa/simple/algorithms/agc.cpp +++ b/src/ipa/simple/algorithms/agc.cpp @@ -91,13 +91,16 @@ void Agc::updateExposure(IPAContext &context, IPAFrameContext &frameContext, dou again = std::clamp(again, context.configuration.agc.againMin, context.configuration.agc.againMax); + context.activeState.agc.exposure = exposure; + context.activeState.agc.again = again; + LOG(IPASoftExposure, Debug) << "exposureMSV " << exposureMSV << " exp " << exposure << " again " << again; } void Agc::process(IPAContext &context, - [[maybe_unused]] const uint32_t frame, + const uint32_t frame, IPAFrameContext &frameContext, const SwIspStats *stats, ControlList &metadata) @@ -107,6 +110,25 @@ void Agc::process(IPAContext &context, metadata.set(controls::ExposureTime, exposureTime.get()); metadata.set(controls::AnalogueGain, frameContext.sensor.gain); + if (frame == 0) { + /* + * Init active-state from sensor values in case updateExposure() + * does not run for the first frame. + */ + context.activeState.agc.exposure = frameContext.sensor.exposure; + context.activeState.agc.again = frameContext.sensor.gain; + } + + if (!stats->valid) { + /* + * Use the new exposure and gain values calculated the last time + * there were valid stats. + */ + frameContext.sensor.exposure = context.activeState.agc.exposure; + frameContext.sensor.gain = context.activeState.agc.again; + return; + } + /* * Calculate Mean Sample Value (MSV) according to formula from: * https://www.araa.asn.au/acra/acra2007/papers/paper84final.pdf diff --git a/src/ipa/simple/algorithms/awb.cpp b/src/ipa/simple/algorithms/awb.cpp index cf567e89..ddd0b791 100644 --- a/src/ipa/simple/algorithms/awb.cpp +++ b/src/ipa/simple/algorithms/awb.cpp @@ -61,6 +61,9 @@ void Awb::process(IPAContext &context, }; metadata.set(controls::ColourGains, mdGains); + if (!stats->valid) + return; + /* * Black level must be subtracted to get the correct AWB ratios, they * would be off if they were computed from the whole brightness range diff --git a/src/ipa/simple/algorithms/blc.cpp b/src/ipa/simple/algorithms/blc.cpp index 8c1e9ed0..616da0ee 100644 --- a/src/ipa/simple/algorithms/blc.cpp +++ b/src/ipa/simple/algorithms/blc.cpp @@ -60,6 +60,9 @@ void BlackLevel::process(IPAContext &context, }; metadata.set(controls::SensorBlackLevels, blackLevels); + if (!stats->valid) + return; + if (context.configuration.black.level.has_value()) return; diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h index 468fccab..c3081e30 100644 --- a/src/ipa/simple/ipa_context.h +++ b/src/ipa/simple/ipa_context.h @@ -37,6 +37,11 @@ struct IPASessionConfiguration { }; struct IPAActiveState { + struct { + int32_t exposure; + double again; + } agc; + struct { uint8_t level; int32_t lastExposure; diff --git a/src/libcamera/software_isp/swstats_cpu.cpp b/src/libcamera/software_isp/swstats_cpu.cpp index 4b77b360..eb416dfd 100644 --- a/src/libcamera/software_isp/swstats_cpu.cpp +++ b/src/libcamera/software_isp/swstats_cpu.cpp @@ -318,6 +318,7 @@ void SwStatsCpu::startFrame(void) */ void SwStatsCpu::finishFrame(uint32_t frame, uint32_t bufferId) { + stats_.valid = true; *sharedStats_ = stats_; statsReady.emit(frame, bufferId); }