/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2021-2022, Ideas On Board * * dpcc.cpp - RkISP1 Defect Pixel Cluster Correction control */ #include "dpcc.h" #include #include "libcamera/internal/yaml_parser.h" #include "linux/rkisp1-config.h" /** * \file dpcc.h */ namespace libcamera { namespace ipa::rkisp1::algorithms { /** * \class DefectPixelClusterCorrection * \brief RkISP1 Defect Pixel Cluster Correction control * * Depending of the sensor quality, some pixels can be defective and then * appear significantly brighter or darker than the other pixels. * * The Defect Pixel Cluster Correction algorithms is responsible to minimize * the impact of the pixels. This can be done with algorithms applied at run * time (on-the-fly method) or with a table of defective pixels. Only the first * method is supported for the moment. */ LOG_DEFINE_CATEGORY(RkISP1Dpcc) namespace { using MethodParamExtract = uint32_t &(*)(struct rkisp1_cif_isp_dpcc_config &config, struct rkisp1_cif_isp_dpcc_methods_config &set); struct MethodParam { std::string name; unsigned int indexShift; unsigned int redBlueShift; MethodParamExtract param; }; struct Method { std::string name; uint32_t enableGreen; uint32_t enableRedBlue; std::vector params; }; static const Method methods[] = { { "pg", /* Peak Gradient */ RKISP1_CIF_ISP_DPCC_METHODS_SET_PG_GREEN_ENABLE, RKISP1_CIF_ISP_DPCC_METHODS_SET_PG_RED_BLUE_ENABLE, { { "", 0, 8, []([[maybe_unused]] struct rkisp1_cif_isp_dpcc_config &config, struct rkisp1_cif_isp_dpcc_methods_config &set) -> uint32_t & { return set.pg_fac; }, }, }, }, { "lc", /* Line Check */ RKISP1_CIF_ISP_DPCC_METHODS_SET_LC_GREEN_ENABLE, RKISP1_CIF_ISP_DPCC_METHODS_SET_LC_RED_BLUE_ENABLE, { { "threshold", 0, 8, []([[maybe_unused]] struct rkisp1_cif_isp_dpcc_config &config, struct rkisp1_cif_isp_dpcc_methods_config &set) -> uint32_t & { return set.line_thresh; }, }, { "mad-factor", 0, 8, []([[maybe_unused]] struct rkisp1_cif_isp_dpcc_config &config, struct rkisp1_cif_isp_dpcc_methods_config &set) -> uint32_t & { return set.line_mad_fac; }, }, }, }, { "ro", /* Rank Order */ RKISP1_CIF_ISP_DPCC_METHODS_SET_RO_GREEN_ENABLE, RKISP1_CIF_ISP_DPCC_METHODS_SET_RO_RED_BLUE_ENABLE, { { "", 4, 2, [](struct rkisp1_cif_isp_dpcc_config &config, [[maybe_unused]] struct rkisp1_cif_isp_dpcc_methods_config &set) -> uint32_t & { return config.ro_limits; }, }, }, }, { "rnd", /* Rank Neighbour Difference */ RKISP1_CIF_ISP_DPCC_METHODS_SET_RND_GREEN_ENABLE, RKISP1_CIF_ISP_DPCC_METHODS_SET_RND_RED_BLUE_ENABLE, { { "threshold", 0, 8, []([[maybe_unused]] struct rkisp1_cif_isp_dpcc_config &config, struct rkisp1_cif_isp_dpcc_methods_config &set) -> uint32_t & { return set.rnd_thresh; }, }, { "offset", 4, 2, [](struct rkisp1_cif_isp_dpcc_config &config, [[maybe_unused]] struct rkisp1_cif_isp_dpcc_methods_config &set) -> uint32_t & { return config.rnd_offs; }, }, }, }, { "rg", /* Rank Gradient */ RKISP1_CIF_ISP_DPCC_METHODS_SET_RG_GREEN_ENABLE, RKISP1_CIF_ISP_DPCC_METHODS_SET_RG_RED_BLUE_ENABLE, { { "", 0, 8, []([[maybe_unused]] struct rkisp1_cif_isp_dpcc_config &config, struct rkisp1_cif_isp_dpcc_methods_config &set) -> uint32_t & { return set.rg_fac; }, }, }, }, }; bool parseMethodParam(const YamlObject &data, unsigned int setIndex, bool redBlue, const MethodParam ¶m, struct rkisp1_cif_isp_dpcc_config &config, struct rkisp1_cif_isp_dpcc_methods_config &set) { uint32_t value; if (!param.name.empty()) { if (!data.contains(param.name)) return false; value = data[param.name].get(0); } else { value = data.get(0); } uint32_t &field = param.param(config, set); unsigned int shift = param.indexShift * setIndex + (redBlue ? param.redBlueShift : 0); field |= value << shift; return true; } bool parseMethod(const YamlObject &yamlMethod, const Method &method, unsigned int setIndex, bool redBlue, struct rkisp1_cif_isp_dpcc_config &config, struct rkisp1_cif_isp_dpcc_methods_config &set) { const char *color = redBlue ? "red-blue" : "green"; if (!yamlMethod.contains(color)) return true; const YamlObject &yamlParams = yamlMethod[color]; for (const MethodParam ¶m : method.params) { if (!parseMethodParam(yamlParams, setIndex, redBlue, param, config, set)) { LOG(RkISP1Dpcc, Error) << "Failed to parse " << color << " values for " << method.name << "." << param.name << " in set " << setIndex; return false; } } set.method |= method.enableGreen; return true; } } /* namespace */ DefectPixelClusterCorrection::DefectPixelClusterCorrection() : config_({}) { } /** * \copydoc libcamera::ipa::Algorithm::init */ int DefectPixelClusterCorrection::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) { config_.mode = RKISP1_CIF_ISP_DPCC_MODE_STAGE1_ENABLE; config_.output_mode = RKISP1_CIF_ISP_DPCC_OUTPUT_MODE_STAGE1_INCL_G_CENTER | RKISP1_CIF_ISP_DPCC_OUTPUT_MODE_STAGE1_INCL_RB_CENTER; config_.set_use = tuningData["fixed-set"].get(false) ? RKISP1_CIF_ISP_DPCC_SET_USE_STAGE1_USE_FIX_SET : 0; /* Get all defined sets to apply (up to 3). */ const YamlObject &yamlSets = tuningData["sets"]; if (!yamlSets.isList()) { LOG(RkISP1Dpcc, Error) << "'sets' parameter not found in tuning file"; return -EINVAL; } if (yamlSets.size() > RKISP1_CIF_ISP_DPCC_METHODS_MAX) { LOG(RkISP1Dpcc, Error) << "'sets' size in tuning file (" << yamlSets.size() << ") exceeds the maximum hardware capacity (3)"; return -EINVAL; } for (std::size_t i = 0; i < yamlSets.size(); ++i) { struct rkisp1_cif_isp_dpcc_methods_config &set = config_.methods[i]; const YamlObject &yamlSet = yamlSets[i]; /* Enable set if described in YAML tuning file. */ config_.set_use |= 1 << i; /* Parse the methods contained in the set. */ for (const Method &method : methods) { if (!yamlSet.contains(method.name)) continue; const YamlObject &yamlMethod = yamlSet[method.name]; /* Parse the green and red-blue params. */ if (!parseMethod(yamlMethod, method, i, false, config_, set)) return -EINVAL; if (!parseMethod(yamlMethod, method, i, true, config_, set)) return -EINVAL; } if (!set.method) { LOG(RkISP1Dpcc, Error) << "No valid method specified in set " << i; return -EINVAL; } } return 0; } /** * \copydoc libcamera::ipa::Algorithm::prepare */ void DefectPixelClusterCorrection::prepare([[maybe_unused]] IPAContext &context, const uint32_t frame, [[maybe_unused]] IPAFrameContext &frameContext, rkisp1_params_cfg *params) { if (frame > 0) return; params->others.dpcc_config = config_; params->module_en_update |= RKISP1_CIF_ISP_MODULE_DPCC; params->module_ens |= RKISP1_CIF_ISP_MODULE_DPCC; params->module_cfg_update |= RKISP1_CIF_ISP_MODULE_DPCC; } REGISTER_IPA_ALGORITHM(DefectPixelClusterCorrection, "DefectPixelClusterCorrection") } /* namespace ipa::rkisp1::algorithms */ } /* namespace libcamera */