From patchwork Thu Dec 4 21:37:43 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 25368 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 B8618BD80A for ; Thu, 4 Dec 2025 21:38:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6B01461160; Thu, 4 Dec 2025 22:38:16 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="S2pw6EpB"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2D5FB61145 for ; Thu, 4 Dec 2025 22:38:15 +0100 (CET) Received: from localhost.localdomain (unknown [209.216.103.65]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 25428EB7; Thu, 4 Dec 2025 22:35:59 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1764884159; bh=quwt/48HxC7Htnr5cBdEcfIhMofqWnP5niiLki4iZGk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=S2pw6EpBMc6Tijhp7x58X5yyN4t91Usj4E1rcnZwmG/fBECF8BD0FN3NpVUoza48c ZLSYwrqMnOP1rfGvW0jc5NgTCfSubYmGVMtSmFTpX+57/yhpn0uLnLN80oT2mvFHUF auHSwcPC5KpmuJ+wAGkxrVoMO+Re03rI0Cl+N93U= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v3 1/2] ipa/rkisp1: refactory DPF parsing and initialization Date: Thu, 4 Dec 2025 16:37:43 -0500 Message-ID: <20251204213744.1110922-2-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251204213744.1110922-1-rui.wang@ideasonboard.com> References: <20251204213744.1110922-1-rui.wang@ideasonboard.com> MIME-Version: 1.0 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" Split DPF configuration parsing and initialization into clearer, self-contained helpers and modernized initialization patterns. Add parseConfig, parseModes and loadReductionConfig to factor parsing logic and mode lookups. Introduce ModeConfig and store mode entries in noiseReductionModes_ to decouple parsing from runtime selection. Move sentinel member initializers into the constructor initializer list (runningMode_) and declare vectors without in-class initializers for default construction. Replace ad-hoc string handling with value_or and const auto where appropriate for clearer and safer parsing. Replace domain/range/strength YAML keys mapping and error returns (use filter, nll, strength keys and return false from parse helpers instead of -EINVAL). Add loadReductionConfig to centralize loading of DPF configs for reduction modes and preserve logging and failure behavior. Adjust queueRequest, prepare, and helpers to use the new parsing/initialization flow while preserving existing behavior. This refactor improves separation of concerns, makes parsing easier to maintain, and reduces duplicated logic. No functional behaviour is intended to be changed. Signed-off-by: Rui Wang --- changelog : 1. fix config issue and some format --- Makefile | 125 +++++++++++ src/ipa/rkisp1/algorithms/dpf.cpp | 359 +++++++++++++++++++++++------- src/ipa/rkisp1/algorithms/dpf.h | 22 ++ 3 files changed, 420 insertions(+), 86 deletions(-) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..07f8f0fb --- /dev/null +++ b/Makefile @@ -0,0 +1,125 @@ +# Support execution in a docker environment + +define run-in-docker + # CONTAINER=$1 + # COMMAND=$2 + # OPTIONS=$3 + docker run \ + -v "${PWD}":"${PWD}" \ + -w "${PWD}" \ + ${3} \ + --rm -i ${1} ${2} + + #--privileged=true \ + #--cap-add=SYS_PTRACE \ + #--security-opt seccomp=unconfined \ + #-v "${HOME}":"${HOME}" \ + #-v /var/run/docker.sock:/var/run/docker.sock \ + +endef + +define git-uk-bookworm-arm64-cross + $(call run-in-docker,git.uk.ideasonboard.com/camera/containers:debian-bookworm-cross-arm64,$1,$2) +endef + +define bookworm-arm64 + $(call run-in-docker,debian-bookworm-cross-arm64,$1,$2) +endef + +# Helper function to run clang-tidy with proper setup +# $1 = git command to list files +# $2 = output log file +define run-tidy + @echo "Running clang-tidy and saving to $(2)..." + @$(1) > /tmp/tidy-files.txt + @if [ -s /tmp/tidy-files.txt ]; then \ + echo "Checking files:"; cat /tmp/tidy-files.txt; \ + cat /tmp/tidy-files.txt | docker run -v "${PWD}":"${PWD}" -w "${PWD}" --rm -i debian-bookworm-cross-arm64 sh -c "mkdir -p $(RESULTS_DIR) && chmod 777 $(RESULTS_DIR) && xargs -r -I{} clang-tidy {} -p $(BUILD) || true" > $(2) 2>&1 || touch $(2); \ + echo "Done. Output saved to $(2)"; \ + python3 utils/log_to_html.py $(2) $(basename $(2)).html || true; \ + else \ + echo "No files to check"; \ + touch $(2); \ + fi + @rm -f /tmp/tidy-files.txt +endef + +BUILD=build/bookworm-arm64 +RESULTS_DIR=$(BUILD)/clang-tidy-results + +libcamera: $(BUILD)/build.ninja + $(call bookworm-arm64,ninja -C $(BUILD)) + +# /usr/share/meson/arm64-cross is provided by the debian-bookworm-cross-arm64 container +configure $(BUILD)/build.ninja: + $(call bookworm-arm64,meson setup $(BUILD) \ + $(RECONFIGURE) \ + --cross-file /usr/share/meson/arm64-cross \ + -Dprefix=/usr \ + -Dpycamera=enabled \ + -Ddocumentation=disabled \ + -Dlibdir=/lib/aarch64-linux-gnu \ + ) + +reconfigure: RECONFIGURE=--reconfigure +reconfigure: configure + +PYTHON_DIST=usr/lib/python3.11/dist-packages +PACKAGE_TGZ=libcamera-aarch64.tgz +.PHONY: package +package: + $(call bookworm-arm64,rm -rf $(BUILD)/install) + $(call bookworm-arm64,mkdir -p $(BUILD)/install) + $(call bookworm-arm64,ninja -C $(BUILD) install,--env DESTDIR=install) + $(call bookworm-arm64,mkdir -p $(BUILD)/install/$(PYTHON_DIST)) +# $(call bookworm-arm64,mv \ +# $(BUILD)/install/usr/lib/python3/dist-packages/libcamera \ +# $(BUILD)/install/$(PYTHON_DIST)) + tar -C $(BUILD)/install -czf $(PACKAGE_TGZ) ./ + +.PHONY: tmp_install +tmp_install: + $(call bookworm-arm64,rm -rf $(BUILD)/install) + $(call bookworm-arm64,mkdir -p $(BUILD)/install) + $(call bookworm-arm64,ninja -C $(BUILD) install,--env DESTDIR=install) + $(call bookworm-arm64,mkdir -p $(BUILD)/install/$(PYTHON_DIST)) + $(call bookworm-arm64,mv \ + $(BUILD)/install/usr/lib/python3/dist-packages/libcamera \ + $(BUILD)/install/$(PYTHON_DIST)) + +# Directly install on a target +kastor kakip debix-som debix-model-A: libcamera tmp_install + rsync --keep-dirlinks -rav --progress build/bookworm-arm64/install/ rui@192.168.31.73:~/libcamera-install/ + + +beehive: package + scp $(PACKAGE_TGZ) rui@192.168.31.73:~/python3-disp/ + ssh $@ -tC "cd / && sudo tar --keep-directory-symlink --no-same-owner -vxhf ~/python3-disp/$(PACKAGE_TGZ)" +rui: package + scp $(PACKAGE_TGZ) rui@192.168.31.73:/tmp/ + ssh rui@192.168.31.73 -tC "cd / && sudo tar --keep-directory-symlink --no-same-owner -vxhf /tmp/$(PACKAGE_TGZ)" + +.PHONY: tidy-diff +tidy-diff: + $(call run-tidy,git diff --name-only -- '*.c' '*.cpp' '*.cc' '*.h',$(RESULTS_DIR)/tidy-diff.log) + +.PHONY: tidy +tidy: + $(call run-tidy,git ls-files -- '*.c' '*.cpp' '*.cc' '*.h',$(RESULTS_DIR)/tidy.log) + +.PHONY: tidy-last-commit +tidy-last-commit: + $(call run-tidy,git diff --name-only HEAD~1 HEAD -- '*.c' '*.cpp' '*.cc' '*.h',$(RESULTS_DIR)/tidy-last-commit.log) + +.PHONY: tidy-branch +tidy-branch: + $(call run-tidy,git diff --name-only master...HEAD -- '*.c' '*.cpp' '*.cc' '*.h',$(RESULTS_DIR)/tidy-branch.log) + +.PHONY: tidy-staged +tidy-staged: + $(call run-tidy,git diff --name-only --cached -- '*.c' '*.cpp' '*.cc' '*.h',$(RESULTS_DIR)/tidy-staged.log) + +.PHONY: build-and-check-branch +build-and-check-branch: + git diff master...HEAD + diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp index 39f3e461..7e2da7b1 100644 --- a/src/ipa/rkisp1/algorithms/dpf.cpp +++ b/src/ipa/rkisp1/algorithms/dpf.cpp @@ -37,7 +37,8 @@ namespace ipa::rkisp1::algorithms { LOG_DEFINE_CATEGORY(RkISP1Dpf) Dpf::Dpf() - : config_({}), strengthConfig_({}) + : config_({}), strengthConfig_({}), + runningMode_(controls::draft::NoiseReductionModeOff) { } @@ -46,6 +47,69 @@ Dpf::Dpf() */ int Dpf::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) +{ + /* Parse tuning block. */ + if (!parseConfig(tuningData)) { + return -EINVAL; + } + + return 0; +} +bool Dpf::parseConfig(const YamlObject &tuningData) +{ + /* Parse base config. */ + if (!parseSingleConfig(tuningData, config_, strengthConfig_)) { + return false; + } + if (!parseModes(tuningData)) { + return false; + } + return true; +} + +bool Dpf::parseModes(const YamlObject &tuningData) +{ + /* Parse noise reduction modes. */ + if (!tuningData.contains("modes")) { + return true; + } + + noiseReductionModes_.clear(); + for (const auto &entry : tuningData["modes"].asList()) { + std::optional typeOpt = + entry["type"].get(); + if (!typeOpt) { + LOG(RkISP1Dpf, Error) << "Modes entry missing type"; + return false; + } + + int32_t modeValue = controls::draft::NoiseReductionModeOff; + if (*typeOpt == "minimal") { + modeValue = controls::draft::NoiseReductionModeMinimal; + } else if (*typeOpt == "fast") { + modeValue = controls::draft::NoiseReductionModeFast; + } else if (*typeOpt == "highquality") { + modeValue = controls::draft::NoiseReductionModeHighQuality; + } else if (*typeOpt == "zsl") { + modeValue = controls::draft::NoiseReductionModeZSL; + } else { + LOG(RkISP1Dpf, Error) << "Unknown mode type: " << *typeOpt; + return false; + } + + ModeConfig mode{}; + mode.modeValue = modeValue; + if (!parseSingleConfig(entry, mode.dpf, mode.strength)) { + return false; + } + noiseReductionModes_.push_back(mode); + } + + return true; +} +bool Dpf::parseSingleConfig(const YamlObject &tuningData, + rkisp1_cif_isp_dpf_config &config, + rkisp1_cif_isp_dpf_strength_config &strengthConfig) { std::vector values; @@ -53,7 +117,11 @@ int Dpf::init([[maybe_unused]] IPAContext &context, * The domain kernel is configured with a 9x9 kernel for the green * pixels, and a 13x9 or 9x9 kernel for red and blue pixels. */ - const YamlObject &dFObject = tuningData["DomainFilter"]; + const YamlObject &dFObject = tuningData["filter"]; + if (!dFObject) { + LOG(RkISP1Dpf, Error) << "filter section missing"; + return false; + } /* * For the green component, we have the 9x9 kernel specified @@ -75,17 +143,17 @@ int Dpf::init([[maybe_unused]] IPAContext &context, values = dFObject["g"].getList().value_or(std::vector{}); if (values.size() != RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS) { LOG(RkISP1Dpf, Error) - << "Invalid 'DomainFilter:g': expected " + << "Invalid 'filter:g': expected " << RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS << " elements, got " << values.size(); - return -EINVAL; + return false; } std::copy_n(values.begin(), values.size(), - std::begin(config_.g_flt.spatial_coeff)); + std::begin(config.g_flt.spatial_coeff)); - config_.g_flt.gr_enable = true; - config_.g_flt.gb_enable = true; + config.g_flt.gr_enable = true; + config.g_flt.gb_enable = true; /* * For the red and blue components, we have the 13x9 kernel specified @@ -112,65 +180,155 @@ int Dpf::init([[maybe_unused]] IPAContext &context, if (values.size() != RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS && values.size() != RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS - 1) { LOG(RkISP1Dpf, Error) - << "Invalid 'DomainFilter:rb': expected " + << "Invalid 'filter:rb': expected " << RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS - 1 << " or " << RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS << " elements, got " << values.size(); - return -EINVAL; + return false; } - config_.rb_flt.fltsize = values.size() == RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS - ? RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9 - : RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9; + config.rb_flt.fltsize = values.size() == RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS + ? RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9 + : RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_9x9; std::copy_n(values.begin(), values.size(), - std::begin(config_.rb_flt.spatial_coeff)); + std::begin(config.rb_flt.spatial_coeff)); - config_.rb_flt.r_enable = true; - config_.rb_flt.b_enable = true; + config.rb_flt.r_enable = true; + config.rb_flt.b_enable = true; /* * The range kernel is configured with a noise level lookup table (NLL) * which stores a piecewise linear function that characterizes the * sensor noise profile as a noise level function curve (NLF). */ - const YamlObject &rFObject = tuningData["NoiseLevelFunction"]; + const YamlObject &rFObject = tuningData["nll"]; + if (!rFObject) { + LOG(RkISP1Dpf, Error) << "nll section missing"; + return false; + } - std::vector nllValues; - nllValues = rFObject["coeff"].getList().value_or(std::vector{}); + const auto nllValues = + rFObject["coeff"].getList().value_or(std::vector{}); if (nllValues.size() != RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS) { LOG(RkISP1Dpf, Error) - << "Invalid 'RangeFilter:coeff': expected " + << "Invalid 'nll:coeff': expected " << RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS << " elements, got " << nllValues.size(); - return -EINVAL; + return false; } std::copy_n(nllValues.begin(), nllValues.size(), - std::begin(config_.nll.coeff)); + std::begin(config.nll.coeff)); - std::string scaleMode = rFObject["scale-mode"].get(""); + const auto scaleMode = rFObject["scale-mode"].get(""); if (scaleMode == "linear") { - config_.nll.scale_mode = RKISP1_CIF_ISP_NLL_SCALE_LINEAR; + config.nll.scale_mode = RKISP1_CIF_ISP_NLL_SCALE_LINEAR; } else if (scaleMode == "logarithmic") { - config_.nll.scale_mode = RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC; + config.nll.scale_mode = RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC; } else { LOG(RkISP1Dpf, Error) - << "Invalid 'RangeFilter:scale-mode': expected " + << "Invalid 'nll:scale-mode': expected " << "'linear' or 'logarithmic' value, got " << scaleMode; - return -EINVAL; + return false; } - const YamlObject &fSObject = tuningData["FilterStrength"]; + const YamlObject &gObject = tuningData["gain"]; + if (!gObject) { + LOG(RkISP1Dpf, Error) << "gain section missing"; + return false; + } - strengthConfig_.r = fSObject["r"].get(64); - strengthConfig_.g = fSObject["g"].get(64); - strengthConfig_.b = fSObject["b"].get(64); + config.gain.mode = + gObject["gain_mode"].get().value_or( + RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS); + config.gain.nf_r_gain = gObject["r"].get().value_or(256); + config.gain.nf_b_gain = gObject["b"].get().value_or(256); + config.gain.nf_gr_gain = gObject["gr"].get().value_or(256); + config.gain.nf_gb_gain = gObject["gb"].get().value_or(256); + + const YamlObject &fSObject = tuningData["strength"]; + if (!fSObject) { + LOG(RkISP1Dpf, Error) << "strength section missing"; + return false; + } - return 0; + strengthConfig.r = fSObject["r"].get().value_or(64); + strengthConfig.g = fSObject["g"].get().value_or(64); + strengthConfig.b = fSObject["b"].get().value_or(64); + return true; +} + +bool Dpf::loadReductionConfig(int32_t mode) +{ + auto it = std::find_if(noiseReductionModes_.begin(), noiseReductionModes_.end(), + [mode](const ModeConfig &m) { + return m.modeValue == mode; + }); + if (it == noiseReductionModes_.end()) { + LOG(RkISP1Dpf, Warning) + << "No DPF config for reduction mode " + << static_cast(mode); + return false; + } + + config_ = it->dpf; + strengthConfig_ = it->strength; + + LOG(RkISP1Dpf, Info) + << "DPF mode=Reduction (config loaded)" + << " mode=" << static_cast(mode); + + return true; } +void Dpf::logConfigIfChanged(const IPAFrameContext &frameContext) +{ + if (!frameContext.dpf.update) { + return; + } + + std::ostringstream ss; + + ss << "DPF config update: "; + ss << ", control mode=" << static_cast(runningMode_); + ss << ", denoise=" << (frameContext.dpf.denoise ? "enabled" : "disabled, "); + + ss << "rb_fltsize=" + << (config_.rb_flt.fltsize == RKISP1_CIF_ISP_DPF_RB_FILTERSIZE_13x9 ? "13x9" : "9x9"); + ss << ", nll_scale=" + << (config_.nll.scale_mode == RKISP1_CIF_ISP_NLL_SCALE_LOGARITHMIC ? "log" : "linear"); + ss << ", gain_mode=" << config_.gain.mode; + ss << ", strength=" << int(strengthConfig_.r) << ',' << int(strengthConfig_.g) << ',' << int(strengthConfig_.b); + + ss << ", g=["; + for (size_t i = 0; i < RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS; ++i) { + if (i) { + ss << ','; + } + ss << int(config_.g_flt.spatial_coeff[i]); + } + ss << "]"; + ss << ", rb=["; + for (size_t i = 0; i < RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS; ++i) { + if (i) { + ss << ','; + } + ss << int(config_.rb_flt.spatial_coeff[i]); + } + ss << "]"; + + ss << ", nll=["; + for (size_t i = 0; i < RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS; ++i) { + if (i) { + ss << ','; + } + ss << int(config_.nll.coeff[i]); + } + ss << "]"; + LOG(RkISP1Dpf, Info) << ss.str(); +} /** * \copydoc libcamera::ipa::Algorithm::queueRequest */ @@ -183,30 +341,34 @@ void Dpf::queueRequest(IPAContext &context, bool update = false; const auto &denoise = controls.get(controls::draft::NoiseReductionMode); - if (denoise) { - LOG(RkISP1Dpf, Debug) << "Set denoise to " << *denoise; - - switch (*denoise) { - case controls::draft::NoiseReductionModeOff: - if (dpf.denoise) { - dpf.denoise = false; - update = true; - } - break; - case controls::draft::NoiseReductionModeMinimal: - case controls::draft::NoiseReductionModeHighQuality: - case controls::draft::NoiseReductionModeFast: - if (!dpf.denoise) { - dpf.denoise = true; - update = true; - } - break; - default: - LOG(RkISP1Dpf, Error) - << "Unsupported denoise value " - << *denoise; - break; + if (!denoise) { + return; + } + runningMode_ = *denoise; + switch (runningMode_) { + case controls::draft::NoiseReductionModeOff: + if (dpf.denoise) { + dpf.denoise = false; + update = true; + } + break; + case controls::draft::NoiseReductionModeMinimal: + case controls::draft::NoiseReductionModeHighQuality: + case controls::draft::NoiseReductionModeFast: + case controls::draft::NoiseReductionModeZSL: + if (loadReductionConfig(runningMode_)) { + update = true; + dpf.denoise = true; + } else { + dpf.denoise = false; + update = true; } + break; + default: + LOG(RkISP1Dpf, Error) + << "Unsupported denoise value " + << *denoise; + break; } frameContext.dpf.denoise = dpf.denoise; @@ -219,41 +381,66 @@ void Dpf::queueRequest(IPAContext &context, void Dpf::prepare(IPAContext &context, const uint32_t frame, IPAFrameContext &frameContext, RkISP1Params *params) { - if (!frameContext.dpf.update && frame > 0) + if (!frameContext.dpf.update && frame > 0) { return; + } + + if (!frameContext.dpf.denoise) { + prepareDisabledMode(context, frame, frameContext, params); + return; + } + + prepareEnabledMode(context, frame, frameContext, params); +} + +void Dpf::prepareDisabledMode([[maybe_unused]] IPAContext &context, + [[maybe_unused]] const uint32_t frame, + [[maybe_unused]] IPAFrameContext &frameContext, + RkISP1Params *params) +{ + frameContext.dpf.denoise = false; + auto dpfConfig = params->block(); + dpfConfig.setEnabled(false); + auto dpfStrength = params->block(); + dpfStrength.setEnabled(false); +} + +void Dpf::prepareEnabledMode(IPAContext &context, [[maybe_unused]] const uint32_t frame, + [[maybe_unused]] IPAFrameContext &frameContext, RkISP1Params *params) +{ + auto dpfConfig = params->block(); + dpfConfig.setEnabled(true); + *dpfConfig = config_; - auto config = params->block(); - config.setEnabled(frameContext.dpf.denoise); - - auto strengthConfig = params->block(); - strengthConfig.setEnabled(frameContext.dpf.denoise); - - if (frameContext.dpf.denoise) { - *config = config_; - *strengthConfig = strengthConfig_; - - const auto &awb = context.configuration.awb; - const auto &lsc = context.configuration.lsc; - - auto &mode = config->gain.mode; - - /* - * The DPF needs to take into account the total amount of - * digital gain, which comes from the AWB and LSC modules. The - * DPF hardware can be programmed with a digital gain value - * manually, but can also use the gains supplied by the AWB and - * LSC modules automatically when they are enabled. Use that - * mode of operation as it simplifies control of the DPF. - */ - if (awb.enabled && lsc.enabled) - mode = RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS; - else if (awb.enabled) - mode = RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS; - else if (lsc.enabled) - mode = RKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS; - else - mode = RKISP1_CIF_ISP_DPF_GAIN_USAGE_DISABLED; + /* + * The DPF needs to take into account the total amount of + * digital gain, which comes from the AWB and LSC modules. The + * DPF hardware can be programmed with a digital gain value + * manually, but can also use the gains supplied by the AWB and + * LSC modules automatically when they are enabled. Use that + * mode of operation as it simplifies control of the DPF. + */ + const auto &awb = context.configuration.awb; + const auto &lsc = context.configuration.lsc; + auto &mode = dpfConfig->gain.mode; + + if (awb.enabled && lsc.enabled) { + mode = RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_LSC_GAINS; + } else if (awb.enabled) { + mode = RKISP1_CIF_ISP_DPF_GAIN_USAGE_AWB_GAINS; + } else if (lsc.enabled) { + mode = RKISP1_CIF_ISP_DPF_GAIN_USAGE_LSC_GAINS; + } else { + mode = RKISP1_CIF_ISP_DPF_GAIN_USAGE_DISABLED; } + config_.gain.mode = mode; + + auto dpfStrength = params->block(); + dpfStrength.setEnabled(true); + + *dpfStrength = strengthConfig_; + + logConfigIfChanged(frameContext); } REGISTER_IPA_ALGORITHM(Dpf, "Dpf") diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h index 2dd8cd36..d4bfb2dc 100644 --- a/src/ipa/rkisp1/algorithms/dpf.h +++ b/src/ipa/rkisp1/algorithms/dpf.h @@ -30,8 +30,30 @@ public: RkISP1Params *params) override; private: + struct ModeConfig { + int32_t modeValue; + rkisp1_cif_isp_dpf_config dpf; + rkisp1_cif_isp_dpf_strength_config strength; + }; + bool parseConfig(const YamlObject &tuningData); + bool parseModes(const YamlObject &tuningData); + bool parseSingleConfig(const YamlObject &tuningData, + rkisp1_cif_isp_dpf_config &config, + rkisp1_cif_isp_dpf_strength_config &strengthConfig); + + bool loadReductionConfig(int32_t mode); + void logConfigIfChanged(const IPAFrameContext &frameContext); + + void prepareDisabledMode(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, + RkISP1Params *params); + void prepareEnabledMode(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, RkISP1Params *params); + struct rkisp1_cif_isp_dpf_config config_; struct rkisp1_cif_isp_dpf_strength_config strengthConfig_; + std::vector noiseReductionModes_; + int32_t runningMode_; }; } /* namespace ipa::rkisp1::algorithms */ From patchwork Thu Dec 4 21:37:44 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rui Wang X-Patchwork-Id: 25369 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 3F5D0BD80A for ; Thu, 4 Dec 2025 21:38:19 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E800D611BA; Thu, 4 Dec 2025 22:38:18 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="lgdq9Mhk"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D14ED61186 for ; Thu, 4 Dec 2025 22:38:16 +0100 (CET) Received: from localhost.localdomain (unknown [209.216.103.65]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B37E4D7; Thu, 4 Dec 2025 22:36:00 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1764884161; bh=rZ0qMrC4Rjs2hrokDqG2Mp93Ahv3kwm8DiQNIEzqrM0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lgdq9MhkgELacQ+/3LqJdbH2cTK8NVo7Tlj1Flt0kIeurtwXY7O4o8exY/hKWCvX8 qKjymMCKChSouZsvqZd07J1IisX/huUmcrAlXzlsJjH3miN7ax4mgKdbH2cv3bV5fZ cio3GG2+VkTJQDiLfDJyHW3VTY+jYwDztc6PudAY= From: Rui Wang To: libcamera-devel@lists.libcamera.org Cc: Rui Wang Subject: [PATCH v3 2/2] imx219: enable DPF tuning for IMX219 sensor Date: Thu, 4 Dec 2025 16:37:44 -0500 Message-ID: <20251204213744.1110922-3-rui.wang@ideasonboard.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251204213744.1110922-1-rui.wang@ideasonboard.com> References: <20251204213744.1110922-1-rui.wang@ideasonboard.com> MIME-Version: 1.0 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" Enable the RkISP1 denoise pre-filter (DPF) for the IMX219 sensor by adding the required DPF tuning block to imx219.yaml. Signed-off-by: Rui Wang --- src/ipa/rkisp1/data/imx219.yaml | 90 +++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/src/ipa/rkisp1/data/imx219.yaml b/src/ipa/rkisp1/data/imx219.yaml index 0d99cb52..5b0b2771 100644 --- a/src/ipa/rkisp1/data/imx219.yaml +++ b/src/ipa/rkisp1/data/imx219.yaml @@ -111,4 +111,94 @@ algorithms: 1438, 1226, 1059, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1025, 1054, 1185, 1326, 1334, 1334, ] + - Dpf: + filter: + g: [ 18, 13, 9, 5, 3, 1 ] + rb: [ 18, 15, 12, 8, 5, 2 ] + nll: + coeff: [ + 0, 14, 28, 42, 58, 76, 96, 120, + 148, 180, 216, 256, 300, 348, 400, 456, + 520 + ] + scale-mode: "linear" + strength: + r: 80 + g: 80 + b: 80 + gain: + gain_mode: 5 + r: 256 + b: 256 + gr: 256 + gb: 256 + modes: + - type: "minimal" + filter: + g: [ 14, 10, 7, 4, 2, 1 ] + rb: [ 14, 11, 8, 4, 2, 1 ] + nll: + coeff: [ 0, 10, 20, 30, 42, 56, 72, 90, 112, 138, 168, 200, 236, 276, 320, 368, 420 ] + scale-mode: "linear" + strength: + r: 60 + g: 60 + b: 60 + gain: + gain_mode: 5 + r: 256 + b: 256 + gr: 256 + gb: 256 + - type: "highquality" + filter: + g: [ 22, 18, 13, 8, 5, 2 ] + rb: [ 20, 18, 16, 11, 7, 3 ] + nll: + coeff: [ 0, 26, 52, 78, 106, 138, 172, 208, 248, 292, 340, 392, 448, 508, 572, 640, 712 ] + scale-mode: "linear" + strength: + r: 130 + g: 130 + b: 130 + gain: + gain_mode: 5 + r: 256 + b: 256 + gr: 256 + gb: 256 + - type: "fast" + filter: + g: [ 16, 12, 9, 5, 3, 1 ] + rb: [ 16, 13, 10, 6, 4, 2 ] + nll: + coeff: [ 0, 16, 32, 48, 66, 86, 108, 132, 160, 192, 228, 268, 312, 360, 412, 468, 528 ] + scale-mode: "linear" + strength: + r: 90 + g: 90 + b: 90 + gain: + gain_mode: 5 + r: 256 + b: 256 + gr: 256 + gb: 256 + - type: "zsl" + filter: + g: [ 18, 14, 10, 6, 3, 1 ] + rb: [ 18, 16, 13, 9, 5, 3 ] + nll: + coeff: [ 0, 20, 40, 60, 82, 106, 132, 160, 192, 228, 268, 312, 360, 412, 468, 528, 592 ] + scale-mode: "linear" + strength: + r: 110 + g: 110 + b: 110 + gain: + gain_mode: 5 + r: 256 + b: 256 + gr: 256 + gb: 256 ...