ipa: mali-c55: Introduce MaliC55Params

Implement MaliC55Params to derive from V4L2Params and use the new
helpers in the Mali C55 IPA algorithms implementation.

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Tested-by: Antoine Bouyer <antoine.bouyer@nxp.com>
Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
Jacopo Mondi
2025-08-28 15:28:06 +02:00
parent bd7b54876d
commit 99e35cc9ec
11 changed files with 189 additions and 172 deletions
+34 -52
View File
@@ -241,8 +241,8 @@ void Agc::queueRequest(IPAContext &context, const uint32_t frame,
}
}
size_t Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContext,
mali_c55_params_block block)
void Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContext,
MaliC55Params *params)
{
IPAActiveState &activeState = context.activeState;
double gain;
@@ -252,52 +252,49 @@ size_t Agc::fillGainParamBlock(IPAContext &context, IPAFrameContext &frameContex
else
gain = activeState.agc.manual.ispGain;
block.header->type = MALI_C55_PARAM_BLOCK_DIGITAL_GAIN;
block.header->flags = 0;
block.header->size = sizeof(struct mali_c55_params_digital_gain);
auto block = params->block<MaliC55Blocks::Dgain>();
block->gain = floatingToFixedPoint<5, 8, uint16_t, double>(gain);
block.digital_gain->gain = floatingToFixedPoint<5, 8, uint16_t, double>(gain);
frameContext.agc.ispGain = gain;
return block.header->size;
}
size_t Agc::fillParamsBuffer(mali_c55_params_block block,
enum mali_c55_param_block_type type)
void Agc::fillParamsBuffer(MaliC55Params *params, enum MaliC55Blocks type)
{
block.header->type = type;
block.header->flags = 0;
block.header->size = sizeof(struct mali_c55_params_aexp_hist);
assert(type == MaliC55Blocks::AexpHist || type == MaliC55Blocks::AexpIhist);
auto block = type == MaliC55Blocks::AexpHist ?
params->block<MaliC55Blocks::AexpHist>() :
params->block<MaliC55Blocks::AexpIhist>();
/* Collect every 3rd pixel horizontally */
block.aexp_hist->skip_x = 1;
block->skip_x = 1;
/* Start from first column */
block.aexp_hist->offset_x = 0;
block->offset_x = 0;
/* Collect every pixel vertically */
block.aexp_hist->skip_y = 0;
block->skip_y = 0;
/* Start from the first row */
block.aexp_hist->offset_y = 0;
block->offset_y = 0;
/* 1x scaling (i.e. none) */
block.aexp_hist->scale_bottom = 0;
block.aexp_hist->scale_top = 0;
block->scale_bottom = 0;
block->scale_top = 0;
/* Collect all Bayer planes into 4 separate histograms */
block.aexp_hist->plane_mode = 1;
block->plane_mode = 1;
/* Tap the data immediately after the digital gain block */
block.aexp_hist->tap_point = MALI_C55_AEXP_HIST_TAP_FS;
return block.header->size;
block->tap_point = MALI_C55_AEXP_HIST_TAP_FS;
}
size_t Agc::fillWeightsArrayBuffer(mali_c55_params_block block,
enum mali_c55_param_block_type type)
void Agc::fillWeightsArrayBuffer(MaliC55Params *params, const enum MaliC55Blocks type)
{
block.header->type = type;
block.header->flags = 0;
block.header->size = sizeof(struct mali_c55_params_aexp_weights);
assert(type == MaliC55Blocks::AexpHistWeights ||
type == MaliC55Blocks::AexpIhistWeights);
auto block = type == MaliC55Blocks::AexpHistWeights ?
params->block<MaliC55Blocks::AexpHistWeights>() :
params->block<MaliC55Blocks::AexpIhistWeights>();
/* We use every zone - a 15x15 grid */
block.aexp_weights->nodes_used_horiz = 15;
block.aexp_weights->nodes_used_vert = 15;
block->nodes_used_horiz = 15;
block->nodes_used_vert = 15;
/*
* We uniformly weight the zones to 1 - this results in the collected
@@ -305,40 +302,25 @@ size_t Agc::fillWeightsArrayBuffer(mali_c55_params_block block,
* approximate colour channel averages for the image.
*/
Span<uint8_t> weights{
block.aexp_weights->zone_weights,
block->zone_weights,
MALI_C55_MAX_ZONES
};
std::fill(weights.begin(), weights.end(), 1);
return block.header->size;
}
void Agc::prepare(IPAContext &context, const uint32_t frame,
IPAFrameContext &frameContext, v4l2_isp_params_buffer *params)
IPAFrameContext &frameContext, MaliC55Params *params)
{
mali_c55_params_block block;
block.data = &params->data[params->data_size];
params->data_size += fillGainParamBlock(context, frameContext, block);
fillGainParamBlock(context, frameContext, params);
if (frame > 0)
return;
block.data = &params->data[params->data_size];
params->data_size += fillParamsBuffer(block,
MALI_C55_PARAM_BLOCK_AEXP_HIST);
fillParamsBuffer(params, MaliC55Blocks::AexpHist);
fillWeightsArrayBuffer(params, MaliC55Blocks::AexpHistWeights);
block.data = &params->data[params->data_size];
params->data_size += fillWeightsArrayBuffer(block,
MALI_C55_PARAM_BLOCK_AEXP_HIST_WEIGHTS);
block.data = &params->data[params->data_size];
params->data_size += fillParamsBuffer(block,
MALI_C55_PARAM_BLOCK_AEXP_IHIST);
block.data = &params->data[params->data_size];
params->data_size += fillWeightsArrayBuffer(block,
MALI_C55_PARAM_BLOCK_AEXP_IHIST_WEIGHTS);
fillParamsBuffer(params, MaliC55Blocks::AexpIhist);
fillWeightsArrayBuffer(params, MaliC55Blocks::AexpIhistWeights);
}
double Agc::estimateLuminance(const double gain) const
+6 -8
View File
@@ -57,7 +57,7 @@ public:
const ControlList &controls) override;
void prepare(IPAContext &context, const uint32_t frame,
IPAFrameContext &frameContext,
v4l2_isp_params_buffer *params) override;
MaliC55Params *params) override;
void process(IPAContext &context, const uint32_t frame,
IPAFrameContext &frameContext,
const mali_c55_stats_buffer *stats,
@@ -65,13 +65,11 @@ public:
private:
double estimateLuminance(const double gain) const override;
size_t fillGainParamBlock(IPAContext &context,
IPAFrameContext &frameContext,
mali_c55_params_block block);
size_t fillParamsBuffer(mali_c55_params_block block,
enum mali_c55_param_block_type type);
size_t fillWeightsArrayBuffer(mali_c55_params_block block,
enum mali_c55_param_block_type type);
void fillGainParamBlock(IPAContext &context,
IPAFrameContext &frameContext,
MaliC55Params *params);
void fillParamsBuffer(MaliC55Params *params, enum MaliC55Blocks type);
void fillWeightsArrayBuffer(MaliC55Params *params, enum MaliC55Blocks type);
AgcStatistics statistics_;
};
+26 -38
View File
@@ -43,13 +43,9 @@ int Awb::configure([[maybe_unused]] IPAContext &context,
return 0;
}
size_t Awb::fillGainsParamBlock(mali_c55_params_block block, IPAContext &context,
void Awb::fillGainsParamBlock(MaliC55Params *params, IPAContext &context,
IPAFrameContext &frameContext)
{
block.header->type = MALI_C55_PARAM_BLOCK_AWB_GAINS;
block.header->flags = 0;
block.header->size = sizeof(struct mali_c55_params_awb_gains);
double rGain = context.activeState.awb.rGain;
double bGain = context.activeState.awb.bGain;
@@ -63,34 +59,32 @@ size_t Awb::fillGainsParamBlock(mali_c55_params_block block, IPAContext &context
* This holds true regardless of the bayer order of the input data, as
* the mapping is done internally in the ISP.
*/
block.awb_gains->gain00 = floatingToFixedPoint<4, 8, uint16_t, double>(rGain);
block.awb_gains->gain01 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0);
block.awb_gains->gain10 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0);
block.awb_gains->gain11 = floatingToFixedPoint<4, 8, uint16_t, double>(bGain);
auto block = params->block<MaliC55Blocks::AwbGains>();
block->gain00 = floatingToFixedPoint<4, 8, uint16_t, double>(rGain);
block->gain01 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0);
block->gain10 = floatingToFixedPoint<4, 8, uint16_t, double>(1.0);
block->gain11 = floatingToFixedPoint<4, 8, uint16_t, double>(bGain);
frameContext.awb.rGain = rGain;
frameContext.awb.bGain = bGain;
return sizeof(struct mali_c55_params_awb_gains);
}
size_t Awb::fillConfigParamBlock(mali_c55_params_block block)
void Awb::fillConfigParamBlock(MaliC55Params *params)
{
block.header->type = MALI_C55_PARAM_BLOCK_AWB_CONFIG;
block.header->flags = 0;
block.header->size = sizeof(struct mali_c55_params_awb_config);
auto block = params->block<MaliC55Blocks::AwbConfig>();
/* Tap the stats after the purple fringe block */
block.awb_config->tap_point = MALI_C55_AWB_STATS_TAP_PF;
block->tap_point = MALI_C55_AWB_STATS_TAP_PF;
/* Get R/G and B/G ratios as statistics */
block.awb_config->stats_mode = MALI_C55_AWB_MODE_RGBG;
block->stats_mode = MALI_C55_AWB_MODE_RGBG;
/* Default white level */
block.awb_config->white_level = 1023;
block->white_level = 1023;
/* Default black level */
block.awb_config->black_level = 0;
block->black_level = 0;
/*
* By default pixels are included who's colour ratios are bounded in a
@@ -104,40 +98,34 @@ size_t Awb::fillConfigParamBlock(mali_c55_params_block block)
*
* \todo should these perhaps be tunable?
*/
block.awb_config->cr_max = 511;
block.awb_config->cr_min = 64;
block.awb_config->cb_max = 511;
block.awb_config->cb_min = 64;
block->cr_max = 511;
block->cr_min = 64;
block->cb_max = 511;
block->cb_min = 64;
/* We use the full 15x15 zoning scheme */
block.awb_config->nodes_used_horiz = 15;
block.awb_config->nodes_used_vert = 15;
block->nodes_used_horiz = 15;
block->nodes_used_vert = 15;
/*
* We set the trimming boundaries equivalent to the main boundaries. In
* other words; no trimming.
*/
block.awb_config->cr_high = 511;
block.awb_config->cr_low = 64;
block.awb_config->cb_high = 511;
block.awb_config->cb_low = 64;
return sizeof(struct mali_c55_params_awb_config);
block->cr_high = 511;
block->cr_low = 64;
block->cb_high = 511;
block->cb_low = 64;
}
void Awb::prepare(IPAContext &context, const uint32_t frame,
IPAFrameContext &frameContext, v4l2_isp_params_buffer *params)
IPAFrameContext &frameContext, MaliC55Params *params)
{
mali_c55_params_block block;
block.data = &params->data[params->data_size];
params->data_size += fillGainsParamBlock(block, context, frameContext);
fillGainsParamBlock(params, context, frameContext);
if (frame > 0)
return;
block.data = &params->data[params->data_size];
params->data_size += fillConfigParamBlock(block);
fillConfigParamBlock(params);
}
void Awb::process(IPAContext &context, const uint32_t frame,
+5 -5
View File
@@ -22,17 +22,17 @@ public:
const IPACameraSensorInfo &configInfo) override;
void prepare(IPAContext &context, const uint32_t frame,
IPAFrameContext &frameContext,
v4l2_isp_params_buffer *params) override;
MaliC55Params *params) override;
void process(IPAContext &context, const uint32_t frame,
IPAFrameContext &frameContext,
const mali_c55_stats_buffer *stats,
ControlList &metadata) override;
private:
size_t fillGainsParamBlock(mali_c55_params_block block,
IPAContext &context,
IPAFrameContext &frameContext);
size_t fillConfigParamBlock(mali_c55_params_block block);
void fillGainsParamBlock(MaliC55Params *params,
IPAContext &context,
IPAFrameContext &frameContext);
void fillConfigParamBlock(MaliC55Params *params);
};
} /* namespace ipa::mali_c55::algorithms */
+6 -14
View File
@@ -85,27 +85,19 @@ int BlackLevelCorrection::configure(IPAContext &context,
void BlackLevelCorrection::prepare([[maybe_unused]] IPAContext &context,
const uint32_t frame,
[[maybe_unused]] IPAFrameContext &frameContext,
v4l2_isp_params_buffer *params)
MaliC55Params *params)
{
mali_c55_params_block block;
block.data = &params->data[params->data_size];
if (frame > 0)
return;
if (!tuningParameters_)
return;
block.header->type = MALI_C55_PARAM_BLOCK_SENSOR_OFFS;
block.header->flags = 0;
block.header->size = sizeof(mali_c55_params_sensor_off_preshading);
block.sensor_offs->chan00 = offset00;
block.sensor_offs->chan01 = offset01;
block.sensor_offs->chan10 = offset10;
block.sensor_offs->chan11 = offset11;
params->data_size += block.header->size;
auto block = params->block<MaliC55Blocks::Bls>();
block->chan00 = offset00;
block->chan01 = offset01;
block->chan10 = offset10;
block->chan11 = offset11;
}
void BlackLevelCorrection::process([[maybe_unused]] IPAContext &context,
+2 -1
View File
@@ -6,6 +6,7 @@
*/
#include "algorithm.h"
#include "params.h"
namespace libcamera {
@@ -22,7 +23,7 @@ public:
const IPACameraSensorInfo &configInfo) override;
void prepare(IPAContext &context, const uint32_t frame,
IPAFrameContext &frameContext,
v4l2_isp_params_buffer *params) override;
MaliC55Params *params) override;
void process(IPAContext &context, const uint32_t frame,
IPAFrameContext &frameContext,
const mali_c55_stats_buffer *stats,
+22 -34
View File
@@ -108,41 +108,33 @@ int Lsc::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData
return 0;
}
size_t Lsc::fillConfigParamsBlock(mali_c55_params_block block) const
void Lsc::fillConfigParamsBlock(MaliC55Params *params) const
{
block.header->type = MALI_C55_PARAM_MESH_SHADING_CONFIG;
block.header->flags = 0;
block.header->size = sizeof(struct mali_c55_params_mesh_shading_config);
auto block = params->block<MaliC55Blocks::MeshShadingConfig>();
block.shading_config->mesh_show = false;
block.shading_config->mesh_scale = meshScale_;
block.shading_config->mesh_page_r = 0;
block.shading_config->mesh_page_g = 1;
block.shading_config->mesh_page_b = 2;
block.shading_config->mesh_width = meshSize_;
block.shading_config->mesh_height = meshSize_;
block->mesh_show = false;
block->mesh_scale = meshScale_;
block->mesh_page_r = 0;
block->mesh_page_g = 1;
block->mesh_page_b = 2;
block->mesh_width = meshSize_;
block->mesh_height = meshSize_;
std::copy(mesh_.begin(), mesh_.end(), block.shading_config->mesh);
return block.header->size;
std::copy(mesh_.begin(), mesh_.end(), block->mesh);
}
size_t Lsc::fillSelectionParamsBlock(mali_c55_params_block block, uint8_t bank,
void Lsc::fillSelectionParamsBlock(MaliC55Params *params, uint8_t bank,
uint8_t alpha) const
{
block.header->type = MALI_C55_PARAM_MESH_SHADING_SELECTION;
block.header->flags = 0;
block.header->size = sizeof(struct mali_c55_params_mesh_shading_selection);
auto block = params->block<MaliC55Blocks::MeshShadingSel>();
block.shading_selection->mesh_alpha_bank_r = bank;
block.shading_selection->mesh_alpha_bank_g = bank;
block.shading_selection->mesh_alpha_bank_b = bank;
block.shading_selection->mesh_alpha_r = alpha;
block.shading_selection->mesh_alpha_g = alpha;
block.shading_selection->mesh_alpha_b = alpha;
block.shading_selection->mesh_strength = 0x1000; /* Otherwise known as 1.0 */
return block.header->size;
block->mesh_alpha_bank_r = bank;
block->mesh_alpha_bank_g = bank;
block->mesh_alpha_bank_b = bank;
block->mesh_alpha_r = alpha;
block->mesh_alpha_g = alpha;
block->mesh_alpha_b = alpha;
block->mesh_strength = 0x1000; /* Otherwise known as 1.0 */
}
std::tuple<uint8_t, uint8_t> Lsc::findBankAndAlpha(uint32_t ct) const
@@ -170,7 +162,7 @@ std::tuple<uint8_t, uint8_t> Lsc::findBankAndAlpha(uint32_t ct) const
void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,
[[maybe_unused]] IPAFrameContext &frameContext,
v4l2_isp_params_buffer *params)
MaliC55Params *params)
{
/*
* For each frame we assess the colour temperature of the **last** frame
@@ -193,10 +185,7 @@ void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,
std::tie(bank, alpha) = findBankAndAlpha(temperatureK);
}
mali_c55_params_block block;
block.data = &params->data[params->data_size];
params->data_size += fillSelectionParamsBlock(block, bank, alpha);
fillSelectionParamsBlock(params, bank, alpha);
if (frame > 0)
return;
@@ -205,8 +194,7 @@ void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,
* If this is the first frame, we need to load the parsed coefficient
* tables from tuning data to the ISP.
*/
block.data = &params->data[params->data_size];
params->data_size += fillConfigParamsBlock(block);
fillConfigParamsBlock(params);
}
REGISTER_IPA_ALGORITHM(Lsc, "Lsc")
+4 -4
View File
@@ -23,15 +23,15 @@ public:
int init(IPAContext &context, const YamlObject &tuningData) override;
void prepare(IPAContext &context, const uint32_t frame,
IPAFrameContext &frameContext,
v4l2_isp_params_buffer *params) override;
MaliC55Params *params) override;
private:
static constexpr unsigned int kRedOffset = 0;
static constexpr unsigned int kGreenOffset = 1024;
static constexpr unsigned int kBlueOffset = 2048;
size_t fillConfigParamsBlock(mali_c55_params_block block) const;
size_t fillSelectionParamsBlock(mali_c55_params_block block,
uint8_t bank, uint8_t alpha) const;
void fillConfigParamsBlock(MaliC55Params *params) const;
void fillSelectionParamsBlock(MaliC55Params *params,
uint8_t bank, uint8_t alpha) const;
std::tuple<uint8_t, uint8_t> findBankAndAlpha(uint32_t ct) const;
std::vector<uint32_t> mesh_ = std::vector<uint32_t>(3072);
+5 -15
View File
@@ -30,6 +30,7 @@
#include "libipa/camera_sensor_helper.h"
#include "ipa_context.h"
#include "params.h"
namespace libcamera {
@@ -333,24 +334,13 @@ void IPAMaliC55::queueRequest(const uint32_t request, const ControlList &control
void IPAMaliC55::fillParams(unsigned int request,
[[maybe_unused]] uint32_t bufferId)
{
struct v4l2_isp_params_buffer *params;
IPAFrameContext &frameContext = context_.frameContexts.get(request);
MaliC55Params params(buffers_.at(bufferId).planes()[0]);
params = reinterpret_cast<v4l2_isp_params_buffer *>(
buffers_.at(bufferId).planes()[0].data());
memset(params, 0,
buffers_.at(bufferId).planes()[0].size());
for (auto const &algo : algorithms())
algo->prepare(context_, request, frameContext, &params);
params->version = V4L2_ISP_PARAMS_VERSION_V1;
for (auto const &algo : algorithms()) {
algo->prepare(context_, request, frameContext, params);
ASSERT(params->data_size <= MALI_C55_PARAMS_MAX_SIZE);
}
size_t bytesused = offsetof(struct v4l2_isp_params_buffer, data) + params->data_size;
paramsComputed.emit(request, bytesused);
paramsComputed.emit(request, params.bytesused());
}
void IPAMaliC55::processStats(unsigned int request, unsigned int bufferId,
+2 -1
View File
@@ -14,13 +14,14 @@
#include <libipa/module.h>
#include "ipa_context.h"
#include "params.h"
namespace libcamera {
namespace ipa::mali_c55 {
using Module = ipa::Module<IPAContext, IPAFrameContext, IPACameraSensorInfo,
v4l2_isp_params_buffer, mali_c55_stats_buffer>;
MaliC55Params, mali_c55_stats_buffer>;
} /* namespace ipa::mali_c55 */
+77
View File
@@ -0,0 +1,77 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2025, Ideas On Board
*
* Mali C55 ISP Parameters
*/
#pragma once
#include <linux/mali-c55-config.h>
#include <linux/videodev2.h>
#include <libipa/v4l2_params.h>
namespace libcamera {
namespace ipa::mali_c55 {
enum class MaliC55Blocks {
Bls,
AexpHist,
AexpHistWeights,
AexpIhist,
AexpIhistWeights,
Dgain,
AwbGains,
AwbConfig,
MeshShadingConfig,
MeshShadingSel,
};
namespace details {
template<MaliC55Blocks B>
struct block_type {
};
#define MALI_C55_DEFINE_BLOCK_TYPE(id, cfgType, blkType) \
template<> \
struct block_type<MaliC55Blocks::id> { \
using type = struct mali_c55_params_##cfgType; \
static constexpr mali_c55_param_block_type blockType = \
mali_c55_param_block_type::MALI_C55_PARAM_##blkType; \
}
MALI_C55_DEFINE_BLOCK_TYPE(Bls, sensor_off_preshading, BLOCK_SENSOR_OFFS);
MALI_C55_DEFINE_BLOCK_TYPE(AexpHist, aexp_hist, BLOCK_AEXP_HIST);
MALI_C55_DEFINE_BLOCK_TYPE(AexpHistWeights, aexp_weights, BLOCK_AEXP_HIST_WEIGHTS);
MALI_C55_DEFINE_BLOCK_TYPE(AexpIhist, aexp_hist, BLOCK_AEXP_IHIST);
MALI_C55_DEFINE_BLOCK_TYPE(AexpIhistWeights, aexp_weights, BLOCK_AEXP_IHIST_WEIGHTS);
MALI_C55_DEFINE_BLOCK_TYPE(Dgain, digital_gain, BLOCK_DIGITAL_GAIN);
MALI_C55_DEFINE_BLOCK_TYPE(AwbGains, awb_gains, BLOCK_AWB_GAINS);
MALI_C55_DEFINE_BLOCK_TYPE(AwbConfig, awb_config, BLOCK_AWB_CONFIG);
MALI_C55_DEFINE_BLOCK_TYPE(MeshShadingConfig, mesh_shading_config, MESH_SHADING_CONFIG);
MALI_C55_DEFINE_BLOCK_TYPE(MeshShadingSel, mesh_shading_selection, MESH_SHADING_SELECTION);
struct param_traits {
using id_type = MaliC55Blocks;
template<id_type Id>
using id_to_details = block_type<Id>;
};
} /* namespace details */
class MaliC55Params : public V4L2Params<details::param_traits>
{
public:
MaliC55Params(Span<uint8_t> data)
: V4L2Params(data, V4L2_ISP_PARAMS_VERSION_V1)
{
}
};
} /* namespace ipa::mali_c55 */
} /* namespace libcamera */