From patchwork Thu Feb 27 10:57:26 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keke Li X-Patchwork-Id: 22887 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 7DC08BF415 for ; Thu, 27 Feb 2025 10:57:51 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0B3396875B; Thu, 27 Feb 2025 11:57:50 +0100 (CET) Received: from mail-sh.amlogic.com (unknown [58.32.228.46]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A513C686E7 for ; Thu, 27 Feb 2025 11:57:42 +0100 (CET) Received: from droid10.amlogic.com (10.18.11.213) by mail-sh.amlogic.com (10.18.11.5) with Microsoft SMTP Server id 15.1.2507.39; Thu, 27 Feb 2025 18:57:38 +0800 From: Keke Li To: CC: , , , Keke Li Subject: [PATCH v3 04/11] ipa: c3-isp: Add C3 ISP IPA module Date: Thu, 27 Feb 2025 18:57:26 +0800 Message-ID: <20250227105733.187611-5-keke.li@amlogic.com> X-Mailer: git-send-email 2.29.0 In-Reply-To: <20250227105733.187611-1-keke.li@amlogic.com> References: <20250227105733.187611-1-keke.li@amlogic.com> MIME-Version: 1.0 X-Originating-IP: [10.18.11.213] 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" Add a barebones IPA module for the C3 ISP. In this initial implementation only basic interfaces are implemented. Signed-off-by: Keke Li --- meson_options.txt | 2 +- src/ipa/c3-isp/algorithms/algorithm.h | 28 ++ src/ipa/c3-isp/algorithms/meson.build | 5 + src/ipa/c3-isp/c3-isp.cpp | 370 ++++++++++++++++++++++++++ src/ipa/c3-isp/data/meson.build | 9 + src/ipa/c3-isp/ipa_context.cpp | 101 +++++++ src/ipa/c3-isp/ipa_context.h | 87 ++++++ src/ipa/c3-isp/meson.build | 32 +++ src/ipa/c3-isp/module.h | 28 ++ src/ipa/c3-isp/params.cpp | 127 +++++++++ src/ipa/c3-isp/params.h | 133 +++++++++ 11 files changed, 921 insertions(+), 1 deletion(-) create mode 100644 src/ipa/c3-isp/algorithms/algorithm.h create mode 100644 src/ipa/c3-isp/algorithms/meson.build create mode 100644 src/ipa/c3-isp/c3-isp.cpp create mode 100644 src/ipa/c3-isp/data/meson.build create mode 100644 src/ipa/c3-isp/ipa_context.cpp create mode 100644 src/ipa/c3-isp/ipa_context.h create mode 100644 src/ipa/c3-isp/meson.build create mode 100644 src/ipa/c3-isp/module.h create mode 100644 src/ipa/c3-isp/params.cpp create mode 100644 src/ipa/c3-isp/params.h diff --git a/meson_options.txt b/meson_options.txt index 998a4463..7c666d34 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -32,7 +32,7 @@ option('gstreamer', option('ipas', type : 'array', - choices : ['ipu3', 'mali-c55', 'rkisp1', 'rpi/vc4', 'simple', 'vimc'], + choices : ['c3-isp', 'ipu3', 'mali-c55', 'rkisp1', 'rpi/vc4', 'simple', 'vimc'], description : 'Select which IPA modules to build') option('lc-compliance', diff --git a/src/ipa/c3-isp/algorithms/algorithm.h b/src/ipa/c3-isp/algorithms/algorithm.h new file mode 100644 index 00000000..68c311d7 --- /dev/null +++ b/src/ipa/c3-isp/algorithms/algorithm.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Amlogic + * + * C3ISP control algorithm interface + */ + +#pragma once + +#include + +#include "module.h" + +namespace libcamera { + +namespace ipa::c3isp { + +class Algorithm : public libcamera::ipa::Algorithm +{ +public: + Algorithm() + { + } +}; + +} /* namespace ipa::c3isp */ + +} /* namespace libcamera */ diff --git a/src/ipa/c3-isp/algorithms/meson.build b/src/ipa/c3-isp/algorithms/meson.build new file mode 100644 index 00000000..1e00af33 --- /dev/null +++ b/src/ipa/c3-isp/algorithms/meson.build @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: CC0-1.0 + +c3isp_ipa_algorithms = files([ + +]) diff --git a/src/ipa/c3-isp/c3-isp.cpp b/src/ipa/c3-isp/c3-isp.cpp new file mode 100644 index 00000000..abb56d15 --- /dev/null +++ b/src/ipa/c3-isp/c3-isp.cpp @@ -0,0 +1,370 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Amlogic Inc. + * + * c3-isp.cpp - Amlogic Image Processing Algorithms + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "libcamera/internal/formats.h" +#include "libcamera/internal/mapped_framebuffer.h" +#include "libcamera/internal/yaml_parser.h" + +#include "algorithms/algorithm.h" +#include "libipa/camera_sensor_helper.h" + +#include "ipa_context.h" +#include "params.h" + +namespace libcamera { + +LOG_DEFINE_CATEGORY(IPAC3ISP) + +using namespace std::literals::chrono_literals; + +namespace ipa::c3isp { + +static constexpr uint32_t kMaxFrameContexts = 16; + +class IPAC3ISP : public IPAC3ISPInterface, public Module +{ +public: + IPAC3ISP(); + + int init(const IPASettings &settings, const IPAConfigInfo &ipaConfig, + ControlInfoMap *ipaControls) override; + int start() override; + void stop() override; + + int configure(const IPAConfigInfo &ipaConfig, + ControlInfoMap *ipaControls) override; + void mapBuffers(const std::vector &buffers, bool readOnly) override; + void unmapBuffers(const std::vector &buffers) override; + + void queueRequest(const uint32_t request, const ControlList &controls) override; + void computeParams(const uint32_t request, const uint32_t bufferId) override; + void processStats(const uint32_t request, const uint32_t bufferId, + const ControlList &sensorControls) override; + +protected: + std::string logPrefix() const override; + +private: + void updateSessionConfiguration(const IPACameraSensorInfo &info, + const ControlInfoMap &sensorControls); + void updateControls(const IPACameraSensorInfo &sensorInfo, + const ControlInfoMap &sensorControls, + ControlInfoMap *ipaControls); + void setControls(); + + std::map buffers_; + + ControlInfoMap sensorControls_; + + /* Interface to the Camera Helper */ + std::unique_ptr camHelper_; + + /* Local parameter storage */ + struct IPAContext context_; +}; + +IPAC3ISP::IPAC3ISP() + : context_(kMaxFrameContexts) +{ +} + +std::string IPAC3ISP::logPrefix() const +{ + return "c3isp"; +} + +int IPAC3ISP::init(const IPASettings &settings, const IPAConfigInfo &ipaConfig, + ControlInfoMap *ipaControls) +{ + camHelper_ = CameraSensorHelperFactoryBase::create(settings.sensorModel); + if (!camHelper_) { + LOG(IPAC3ISP, Error) + << "Failed to create camera sensor helper for " + << settings.sensorModel; + return -ENODEV; + } + + File file(settings.configurationFile); + if (!file.open(File::OpenModeFlag::ReadOnly)) { + int ret = file.error(); + LOG(IPAC3ISP, Error) + << "Failed to open configuration file " + << settings.configurationFile << ": " << strerror(-ret); + return ret; + } + + std::unique_ptr data = YamlParser::parse(file); + if (!data) + return -EINVAL; + + if (!data->contains("algorithms")) { + LOG(IPAC3ISP, Error) + << "Tuning file doesn't contain any algorithm"; + return -EINVAL; + } + + int ret = createAlgorithms(context_, (*data)["algorithms"]); + if (ret) + return ret; + + updateControls(ipaConfig.sensorInfo, ipaConfig.sensorControls, ipaControls); + + return 0; +} + +int IPAC3ISP::start() +{ + return 0; +} + +void IPAC3ISP::stop() +{ + context_.frameContexts.clear(); +} + +void IPAC3ISP::updateSessionConfiguration(const IPACameraSensorInfo &info, + const ControlInfoMap &sensorControls) +{ + const ControlInfo &v4l2Exposure = sensorControls.find(V4L2_CID_EXPOSURE)->second; + int32_t minExposure = v4l2Exposure.min().get(); + int32_t maxExposure = v4l2Exposure.max().get(); + int32_t defExposure = v4l2Exposure.def().get(); + + const ControlInfo &v4l2Gain = sensorControls.find(V4L2_CID_ANALOGUE_GAIN)->second; + int32_t minGain = v4l2Gain.min().get(); + int32_t maxGain = v4l2Gain.max().get(); + + context_.configuration.sensor.lineDuration = info.minLineLength * 1.0s / info.pixelRate; + context_.configuration.agc.minShutterSpeed = minExposure * context_.configuration.sensor.lineDuration; + context_.configuration.agc.maxShutterSpeed = maxExposure * context_.configuration.sensor.lineDuration; + context_.configuration.agc.defaultExposure = defExposure; + context_.configuration.agc.minAnalogueGain = camHelper_->gain(minGain); + context_.configuration.agc.maxAnalogueGain = camHelper_->gain(maxGain); + + context_.configuration.sensor.size = info.outputSize; + + if (camHelper_->blackLevel().has_value()) + /* + * The black level from CameraSensorHelper is a 16-bit value. + * The C3 ISP expects 20-bit settings, so we shift it to the + * appropriate width + */ + context_.configuration.sensor.blackLevel = camHelper_->blackLevel().value() << 4; +} + +void IPAC3ISP::updateControls(const IPACameraSensorInfo &sensorInfo, + const ControlInfoMap &sensorControls, + ControlInfoMap *ipaControls) +{ + ControlInfoMap::Map ctrlMap; + + /* Compute the frame duration limits. */ + const ControlInfo &v4l2HBlank = sensorControls.find(V4L2_CID_HBLANK)->second; + uint32_t hblank = v4l2HBlank.def().get(); + uint32_t lineLength = sensorInfo.outputSize.width + hblank; + + const ControlInfo &v4l2VBlank = sensorControls.find(V4L2_CID_VBLANK)->second; + std::array frameHeights{ + v4l2VBlank.min().get() + sensorInfo.outputSize.height, + v4l2VBlank.max().get() + sensorInfo.outputSize.height, + v4l2VBlank.def().get() + sensorInfo.outputSize.height, + }; + + std::array frameDurations; + for (unsigned int i = 0; i < frameHeights.size(); ++i) { + uint64_t frameSize = lineLength * frameHeights[i]; + frameDurations[i] = frameSize / (sensorInfo.pixelRate / 1000000U); + } + + ctrlMap[&controls::FrameDurationLimits] = ControlInfo(frameDurations[0], + frameDurations[1], + frameDurations[2]); + + /* Compute the exposure time limits */ + double lineDuration = context_.configuration.sensor.lineDuration.get(); + const ControlInfo &v4l2Exposure = sensorControls.find(V4L2_CID_EXPOSURE)->second; + int32_t minExposure = v4l2Exposure.min().get() * lineDuration; + int32_t maxExposure = v4l2Exposure.max().get() * lineDuration; + int32_t defExposure = v4l2Exposure.def().get() * lineDuration; + ctrlMap[&controls::ExposureTime] = ControlInfo(minExposure, maxExposure, defExposure); + + /* Compute the analogue gain limits. */ + const ControlInfo &v4l2Gain = sensorControls.find(V4L2_CID_ANALOGUE_GAIN)->second; + float minGain = camHelper_->gain(v4l2Gain.min().get()); + float maxGain = camHelper_->gain(v4l2Gain.max().get()); + float defGain = camHelper_->gain(v4l2Gain.def().get()); + ctrlMap[&controls::AnalogueGain] = ControlInfo(minGain, maxGain, defGain); + + /* Merge the cotrols */ + ctrlMap.merge(context_.ctrlMap); + + *ipaControls = ControlInfoMap(std::move(ctrlMap), controls::controls); +} + +int IPAC3ISP::configure(const IPAConfigInfo &ipaConfig, + ControlInfoMap *ipaControls) +{ + sensorControls_ = ipaConfig.sensorControls; + + context_.configuration = {}; + context_.activeState = {}; + context_.frameContexts.clear(); + + const IPACameraSensorInfo &info = ipaConfig.sensorInfo; + + updateSessionConfiguration(info, ipaConfig.sensorControls); + + updateControls(info, ipaConfig.sensorControls, ipaControls); + + for (auto const &a : algorithms()) { + Algorithm *algo = static_cast(a.get()); + + int ret = algo->configure(context_, info); + if (ret) + return ret; + } + + return 0; +} + +void IPAC3ISP::mapBuffers(const std::vector &buffers, bool readOnly) +{ + for (const IPABuffer &buffer : buffers) { + const FrameBuffer fb(buffer.planes); + buffers_.emplace( + buffer.id, + MappedFrameBuffer( + &fb, + readOnly ? MappedFrameBuffer::MapFlag::Read + : MappedFrameBuffer::MapFlag::ReadWrite)); + } +} + +void IPAC3ISP::unmapBuffers(const std::vector &buffers) +{ + for (const IPABuffer &buffer : buffers) { + auto it = buffers_.find(buffer.id); + if (it == buffers_.end()) + continue; + + buffers_.erase(buffer.id); + } +} + +void IPAC3ISP::queueRequest(const uint32_t request, const ControlList &controls) +{ + IPAFrameContext &frameContext = context_.frameContexts.alloc(request); + + for (auto const &a : algorithms()) { + Algorithm *algo = static_cast(a.get()); + + algo->queueRequest(context_, request, frameContext, controls); + } +} + +void IPAC3ISP::computeParams(const uint32_t request, const uint32_t bufferId) +{ + IPAFrameContext &frameContext = context_.frameContexts.get(request); + + C3ISPParams params(buffers_.at(bufferId).planes()[0]); + + for (auto const &algo : algorithms()) + algo->prepare(context_, request, frameContext, ¶ms); + + paramsComputed.emit(request, params.size()); +} + +void IPAC3ISP::processStats(const uint32_t request, const uint32_t bufferId, + const ControlList &sensorControls) +{ + IPAFrameContext &frameContext = context_.frameContexts.get(request); + const c3_isp_stats_info *stats = nullptr; + + stats = reinterpret_cast( + buffers_.at(bufferId).planes()[0].data()); + + frameContext.agc.exposure = + sensorControls.get(V4L2_CID_EXPOSURE).get(); + frameContext.agc.sensorGain = + camHelper_->gain(sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get()); + + ControlList metadata(controls::controls); + + for (auto const &a : algorithms()) { + Algorithm *algo = static_cast(a.get()); + + algo->process(context_, request, frameContext, stats, metadata); + } + + setControls(); + + statsProcessed.emit(request, metadata); +} + +void IPAC3ISP::setControls() +{ + IPAActiveState &activeState = context_.activeState; + uint32_t exposure; + uint32_t gain; + + if (activeState.agc.autoEnabled) { + exposure = activeState.agc.automatic.exposure; + gain = camHelper_->gainCode(activeState.agc.automatic.sensorGain); + } else { + exposure = activeState.agc.manual.exposure; + gain = camHelper_->gainCode(activeState.agc.manual.sensorGain); + } + + ControlList ctrls(sensorControls_); + ctrls.set(V4L2_CID_EXPOSURE, static_cast(exposure)); + ctrls.set(V4L2_CID_ANALOGUE_GAIN, static_cast(gain)); + + setSensorControls.emit(ctrls); +} + +} /* namespace ipa::c3isp */ + +/* + * External IPA module interface + */ + +extern "C" { +const struct IPAModuleInfo ipaModuleInfo = { + IPA_MODULE_API_VERSION, + 1, + "c3isp", + "c3isp", +}; + +IPAInterface *ipaCreate() +{ + return new ipa::c3isp::IPAC3ISP(); +} +} + +} /* namespace libcamera */ diff --git a/src/ipa/c3-isp/data/meson.build b/src/ipa/c3-isp/data/meson.build new file mode 100644 index 00000000..75e44bac --- /dev/null +++ b/src/ipa/c3-isp/data/meson.build @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: CC0-1.0 + +conf_files = files([ + +]) + +install_data(conf_files, + install_dir : ipa_data_dir / 'c3isp', + install_tag : 'runtime') diff --git a/src/ipa/c3-isp/ipa_context.cpp b/src/ipa/c3-isp/ipa_context.cpp new file mode 100644 index 00000000..8f69bbfb --- /dev/null +++ b/src/ipa/c3-isp/ipa_context.cpp @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Amlogic Inc. + * + * C3ISP IPA Context + */ + +#include "ipa_context.h" + +/** + * \file ipa_context.h + * \brief Context and state information shared between the algorithms + */ + +namespace libcamera::ipa::c3isp { + +/** + * \struct IPASessionConfiguration + * \brief Session configuration for the IPA module + * + * The session configuration contains all IPA configuration parameters that + * remain constant during the capture session, from IPA module start to stop. + * It is typically set during the configure() operation of the IPA module, but + * may also be updated in the start() operation. + */ + +/** + * \struct IPAActiveState + * \brief Active state for algorithms + * + * The active state contains all algorithm-specific data that needs to be + * maintained by algorithms across frames. Unlike the session configuration, + * the active state is mutable and constantly updated by algorithms. The active + * state is accessible through the IPAContext structure. + * + * The active state stores two distinct categories of information: + * + * - The consolidated value of all algorithm controls. Requests passed to + * the queueRequest() function store values for controls that the + * application wants to modify for that particular frame, and the + * queueRequest() function updates the active state with those values. + * The active state thus contains a consolidated view of the value of all + * controls handled by the algorithm. + * + * - The value of parameters computed by the algorithm when running in auto + * mode. Algorithms running in auto mode compute new parameters every + * time statistics buffers are received (either synchronously, or + * possibly in a background thread). The latest computed value of those + * parameters is stored in the active state in the process() function. + * + * Each of the members in the active state belongs to a specific algorithm. A + * member may be read by any algorithm, but shall only be written by its owner. + */ + +/** + * \struct IPAFrameContext + * \brief Per-frame context for algorithms + * + * The frame context stores two distinct categories of information: + * + * - The value of the controls to be applied to the frame. These values are + * typically set in the queueRequest() function, from the consolidated + * control values stored in the active state. The frame context thus stores + * values for all controls related to the algorithm, not limited to the + * controls specified in the corresponding request, but consolidated from all + * requests that have been queued so far. + * + * For controls that can be set manually or computed by an algorithm + * (depending on the algorithm operation mode), such as for instance the + * colour gains for the AWB algorithm, the control value will be stored in + * the frame context in the queueRequest() function only when operating in + * manual mode. When operating in auto mode, the values are computed by the + * algorithm in process(), stored in the active state, and copied to the + * frame context in prepare(), just before being stored in the ISP parameters + * buffer. + * + * The queueRequest() function can also store ancillary data in the frame + * context, such as flags to indicate if (and what) control values have + * changed compared to the previous request. + * + * - Status information computed by the algorithm for a frame. For instance, + * the colour temperature estimated by the AWB algorithm from ISP statistics + * calculated on a frame is stored in the frame context for that frame in + * the process() function. + */ + +/** + * \struct IPAContext + * \brief Global IPA context data shared between all algorithms + * + * \var IPAContext::configuration + * \brief The IPA session configuration, immutable during the session + * + * \var IPAContext::activeState + * \brief The IPA active state, storing the latest state for all algorithms + * + * \var IPAContext::frameContexts + * \brief Ring buffer of per-frame contexts + */ + +} /* namespace libcamera::ipa::c3isp */ diff --git a/src/ipa/c3-isp/ipa_context.h b/src/ipa/c3-isp/ipa_context.h new file mode 100644 index 00000000..227d657a --- /dev/null +++ b/src/ipa/c3-isp/ipa_context.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Amlogic Inc. + * + * C3ISP IPA Context + */ + +#pragma once + +#include +#include + +#include + +namespace libcamera { + +namespace ipa::c3isp { + +struct IPASessionConfiguration { + struct { + utils::Duration minShutterSpeed; + utils::Duration maxShutterSpeed; + uint32_t defaultExposure; + double minAnalogueGain; + double maxAnalogueGain; + } agc; + + struct { + utils::Duration lineDuration; + uint32_t blackLevel; + Size size; + } sensor; +}; + +struct IPAActiveState { + struct { + struct { + uint32_t exposure; + double sensorGain; + double ispGain; + } automatic; + struct { + uint32_t exposure; + double sensorGain; + double ispGain; + } manual; + bool autoEnabled; + uint32_t constraintMode; + uint32_t exposureMode; + } agc; + + struct { + double rGain; + double bGain; + uint32_t temperatureK; + } awb; +}; + +struct IPAFrameContext : public FrameContext { + struct { + uint32_t exposure; + double sensorGain; + } agc; + + struct { + double rGain; + double bGain; + } awb; +}; + +struct IPAContext { + IPAContext(unsigned int frameContextSize) + : frameContexts(frameContextSize) + { + } + + IPASessionConfiguration configuration; + IPAActiveState activeState; + + FCQueue frameContexts; + + ControlInfoMap::Map ctrlMap; +}; + +} /* namespace ipa::c3isp */ + +} /* namespace libcamera*/ diff --git a/src/ipa/c3-isp/meson.build b/src/ipa/c3-isp/meson.build new file mode 100644 index 00000000..fa5c6be0 --- /dev/null +++ b/src/ipa/c3-isp/meson.build @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: CC0-1.0 + +subdir('algorithms') +subdir('data') + +ipa_name = 'ipa_c3isp' + +c3isp_ipa_sources = files([ + 'ipa_context.cpp', + 'params.cpp', + 'c3-isp.cpp', +]) + +c3isp_ipa_sources += c3isp_ipa_algorithms + +mod = shared_module(ipa_name, c3isp_ipa_sources, + name_prefix : '', + include_directories : [ipa_includes], + dependencies : [libcamera_private, libipa_dep], + install : true, + install_dir : ipa_install_dir) + +if ipa_sign_module + custom_target(ipa_name + '.so.sign', + input : mod, + output : ipa_name + '.so.sign', + command : [ipa_sign, ipa_priv_key, '@INPUT@', '@OUTPUT@'], + install : false, + build_by_default : true) +endif + +ipa_names += ipa_name diff --git a/src/ipa/c3-isp/module.h b/src/ipa/c3-isp/module.h new file mode 100644 index 00000000..a1116396 --- /dev/null +++ b/src/ipa/c3-isp/module.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Amlogic + * + * C3ISP IPA Module + */ + +#pragma once + +#include + +#include + +#include + +#include "ipa_context.h" +#include "params.h" + +namespace libcamera { + +namespace ipa::c3isp { + +using Module = ipa::Module; + +} /* namespace ipa::c3isp */ + +} /* namespace libcamera*/ diff --git a/src/ipa/c3-isp/params.cpp b/src/ipa/c3-isp/params.cpp new file mode 100644 index 00000000..d5c57da3 --- /dev/null +++ b/src/ipa/c3-isp/params.cpp @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Amlogic Inc. + * + * C3ISP ISP Parameters + */ + +#include "params.h" + +#include +#include +#include + +#include +#include + +#include +#include + +namespace libcamera { + +LOG_DEFINE_CATEGORY(C3ISPParams) + +namespace ipa::c3isp { + +namespace { + +struct BlockTypeInfo { + enum c3_isp_params_block_type type; + size_t size; +}; + +#define C3ISP_BLOCK_TYPE_ENTRY(block, id, type) \ + { \ + BlockType::block, \ + { \ + C3_ISP_PARAMS_BLOCK_##id, \ + sizeof(struct c3_isp_params_##type), \ + } \ + } + +const std::map kBlockTypeInfo = { + C3ISP_BLOCK_TYPE_ENTRY(AWBGains, AWB_GAINS, awb_gains), + C3ISP_BLOCK_TYPE_ENTRY(AWBConfig, AWB_CONFIG, awb_config), + C3ISP_BLOCK_TYPE_ENTRY(AEConfig, AE_CONFIG, ae_config), + C3ISP_BLOCK_TYPE_ENTRY(AFConfig, AF_CONFIG, af_config), + C3ISP_BLOCK_TYPE_ENTRY(PostGamma, PST_GAMMA, pst_gamma), + C3ISP_BLOCK_TYPE_ENTRY(Ccm, CCM, ccm), + C3ISP_BLOCK_TYPE_ENTRY(Csc, CSC, csc), + C3ISP_BLOCK_TYPE_ENTRY(Blc, BLC, blc), +}; + +} /* namespace */ + +C3ISPParamsBlockBase::C3ISPParamsBlockBase(BlockType type, + const Span &data) + : type_(type), data_(data) +{ + header_ = data.subspan(0, sizeof(c3_isp_params_block_header)); +} + +void C3ISPParamsBlockBase::setEnabled(uint16_t flags) +{ + struct c3_isp_params_block_header *header = + reinterpret_cast(header_.data()); + + header->flags = flags; +} + +C3ISPParams::C3ISPParams(Span data) + : data_(data), used_(0) +{ + struct c3_isp_params_cfg *buffer = + reinterpret_cast(data.data()); + + buffer->version = C3_ISP_PARAMS_BUFFER_V0; + buffer->data_size = 0; + + used_ += offsetof(struct c3_isp_params_cfg, data); +} + +Span C3ISPParams::block(BlockType type) +{ + auto infoIt = kBlockTypeInfo.find(type); + if (infoIt == kBlockTypeInfo.end()) { + LOG(C3ISPParams, Error) + << "Invalid parameters type " + << utils::to_underlying(type); + return {}; + } + + const BlockTypeInfo &info = infoIt->second; + + auto cacheIt = blocks_.find(type); + if (cacheIt != blocks_.end()) + return cacheIt->second; + + size_t size = info.size; + if (size > data_.size() - used_) { + LOG(C3ISPParams, Error) + << "No enough remaining space " + << utils::to_underlying(type); + return {}; + } + + Span block = data_.subspan(used_, info.size); + used_ += block.size(); + + struct c3_isp_params_cfg *buffer = + reinterpret_cast(data_.data()); + buffer->data_size += block.size(); + + memset(block.data(), 0, block.size()); + + struct c3_isp_params_block_header *header = + reinterpret_cast(block.data()); + header->type = info.type; + header->size = block.size(); + + blocks_[type] = block; + + return block; +} + +} /* namespace ipa::c3isp */ + +} /* namespace libcamera */ diff --git a/src/ipa/c3-isp/params.h b/src/ipa/c3-isp/params.h new file mode 100644 index 00000000..9bb3877b --- /dev/null +++ b/src/ipa/c3-isp/params.h @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Amlogic Inc. + * + * C3ISP ISP Parameters + */ + +#pragma once + +#include +#include + +#include + +#include +#include + +namespace libcamera { + +namespace ipa::c3isp { + +enum class BlockType { + AWBGains, + AWBConfig, + AEConfig, + AFConfig, + PostGamma, + Ccm, + Csc, + Blc, +}; + +namespace details { + +template +struct block_type { +}; + +#define C3ISP_DEFINE_BLOCK_TYPE(blocktype, blockStruct) \ + template<> \ + struct block_type { \ + using type = struct c3_isp_params_##blockStruct; \ + }; + +C3ISP_DEFINE_BLOCK_TYPE(AWBGains, awb_gains) +C3ISP_DEFINE_BLOCK_TYPE(AWBConfig, awb_config) +C3ISP_DEFINE_BLOCK_TYPE(AEConfig, ae_config) +C3ISP_DEFINE_BLOCK_TYPE(AFConfig, af_config) +C3ISP_DEFINE_BLOCK_TYPE(PostGamma, pst_gamma) +C3ISP_DEFINE_BLOCK_TYPE(Ccm, ccm) +C3ISP_DEFINE_BLOCK_TYPE(Csc, csc) +C3ISP_DEFINE_BLOCK_TYPE(Blc, blc) + +} /* namespace details */ + +class C3ISPParams; + +class C3ISPParamsBlockBase +{ +public: + C3ISPParamsBlockBase(BlockType type, const Span &data); + + Span data() const { return data_; } + + void setEnabled(uint16_t flags); + +private: + LIBCAMERA_DISABLE_COPY(C3ISPParamsBlockBase) + + BlockType type_; + Span header_; + Span data_; +}; + +template +class C3ISPParamsBlock : public C3ISPParamsBlockBase +{ +public: + using Type = typename details::block_type::type; + + C3ISPParamsBlock(const Span &data) + : C3ISPParamsBlockBase(B, data) + { + } + + const Type *operator->() const + { + return reinterpret_cast(data().data()); + } + + Type *operator->() + { + return reinterpret_cast(data().data()); + } + + const Type &operator*() const & + { + return *reinterpret_cast(data().data()); + } + + const Type &operator*() & + { + return *reinterpret_cast(data().data()); + } +}; + +class C3ISPParams +{ +public: + C3ISPParams(Span data); + + template + C3ISPParamsBlock block() + { + return C3ISPParamsBlock(block(B)); + } + + size_t size() const { return used_; } + +private: + friend class C3ISPParamsBlockBase; + + Span block(BlockType type); + + Span data_; + size_t used_; + + std::map> blocks_; +}; + +} /* namespace ipa::c3isp */ + +} /* namespace libcamera */