new file mode 100644
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2026, Ideas On Board
+ *
+ * MaliC55 RGB Gamma control
+ */
+
+#include "gamma.h"
+
+#include <algorithm>
+
+#include <libcamera/controls.h>
+
+#include <libipa/fixedpoint.h>
+
+namespace libcamera {
+
+namespace ipa::mali_c55::algorithms {
+
+/**
+ * \class RGBGamma
+ * \brief MaliC55 Gamma out correction
+ *
+ * This algorithm implements the output gamma correction using the libipa
+ * GammaAlgorithm class.
+ *
+ * The hardware uses 129 evenly spaced points for its lookup table, and
+ * applies linear interpolation between them.
+ *
+ * The same module is also capable of applying an offset and gain to each channel.
+ * \todo Implement support for global contrast adjustments.
+ */
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::init
+ */
+int RGBGamma::init(IPAContext &context, const ValueNode &tuningData)
+{
+ return gamma_.init(context.ctrlMap, tuningData);
+}
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::configure
+ */
+int RGBGamma::configure(IPAContext &context,
+ [[maybe_unused]] const IPACameraSensorInfo &configInfo)
+{
+ gamma_.configure(context.activeState.gamma);
+
+ return 0;
+}
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::queueRequest
+ */
+void RGBGamma::queueRequest(IPAContext &context, const uint32_t frame,
+ IPAFrameContext &frameContext,
+ const ControlList &controls)
+{
+ gamma_.queueRequest(context.activeState.gamma, frame, frameContext.gamma, controls);
+}
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::prepare
+ */
+void RGBGamma::prepare([[maybe_unused]] IPAContext &context,
+ [[maybe_unused]] const uint32_t frame,
+ IPAFrameContext &frameContext,
+ MaliC55Params *params)
+{
+ if (!frameContext.gamma.update)
+ return;
+
+ auto frConfig = params->block<MaliC55Blocks::GammaFr>();
+ frConfig.setEnabled(true);
+
+ gamma_.prepare(frameContext.gamma, std::span(frConfig->lut));
+
+ /*
+ * Fixed offsets and gains: 0 and 1x.
+ * \todo Implement global contrast adjustment using offsets and gains.
+ */
+ std::fill(frConfig->gains, std::end(frConfig->gains), UQ<4, 8>(1.f).quantized());
+ std::fill(frConfig->offs, std::end(frConfig->offs), UQ<0, 12>(0.f).quantized());
+
+ /* Enable the same gamma correction on the "downscale" pipeline as well. */
+ auto dsConfig = params->block<MaliC55Blocks::GammaDs>();
+ dsConfig.setEnabled(true);
+
+ std::copy(frConfig->gains, std::end(frConfig->gains), dsConfig->gains);
+ std::copy(frConfig->offs, std::end(frConfig->offs), dsConfig->offs);
+ std::copy(frConfig->lut, std::end(frConfig->lut), dsConfig->lut);
+}
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::process
+ */
+void RGBGamma::process([[maybe_unused]] IPAContext &context,
+ [[maybe_unused]] const uint32_t frame,
+ IPAFrameContext &frameContext,
+ [[maybe_unused]] const mali_c55_stats_buffer *stats,
+ ControlList &metadata)
+{
+ gamma_.process(frameContext.gamma, metadata);
+}
+
+REGISTER_IPA_ALGORITHM(RGBGamma, "RGBGamma")
+
+} /* namespace ipa::mali_c55::algorithms */
+
+} /* namespace libcamera */
new file mode 100644
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2026, Ideas On Board
+ *
+ * MaliC55 RGB Gamma control
+ */
+
+#pragma once
+
+#include <libipa/fixedpoint.h>
+#include <libipa/gamma.h>
+
+#include "algorithm.h"
+
+namespace libcamera {
+
+namespace ipa::mali_c55::algorithms {
+
+class RGBGamma : public Algorithm
+{
+public:
+ int init(IPAContext &context, const ValueNode &tuningData) override;
+ int configure(IPAContext &context,
+ const IPACameraSensorInfo &configInfo) override;
+ void queueRequest(IPAContext &context,
+ const uint32_t frame,
+ IPAFrameContext &frameContext,
+ const ControlList &controls) override;
+ void prepare(IPAContext &context, const uint32_t frame,
+ IPAFrameContext &frameContext,
+ MaliC55Params *params) override;
+ void process(IPAContext &context, const uint32_t frame,
+ IPAFrameContext &frameContext,
+ const mali_c55_stats_buffer *stats,
+ ControlList &metadata) override;
+
+private:
+ GammaAlgorithm<129, UQ<0, 12>> gamma_;
+};
+
+} /* namespace ipa::mali_c55::algorithms */
+} /* namespace libcamera */
@@ -5,5 +5,6 @@ mali_c55_ipa_algorithms = files([
'awb.cpp',
'blc.cpp',
'ccm.cpp',
+ 'gamma.cpp',
'lsc.cpp',
])
@@ -7,4 +7,5 @@ algorithms:
- Awb:
- BlackLevelCorrection:
- Ccm:
+ - RGBGamma:
...
@@ -21,6 +21,7 @@
#include "libipa/awb.h"
#include "libipa/ccm.h"
#include "libipa/fixedpoint.h"
+#include "libipa/gamma.h"
#include "libipa/lsc.h"
namespace libcamera {
@@ -43,6 +44,7 @@ struct IPAActiveState {
ipa::awb::ActiveState awb;
ipa::ccm::ActiveState ccm;
+ ipa::gamma::ActiveState gamma;
ipa::lsc::ActiveState lsc;
};
@@ -56,6 +58,7 @@ struct IPAFrameContext : public FrameContext {
ipa::awb::FrameContext awb;
ipa::ccm::FrameContext ccm;
+ ipa::gamma::FrameContext gamma;
ipa::lsc::FrameContext lsc;
};
@@ -30,6 +30,8 @@ enum class MaliC55Blocks : uint16_t {
MeshShadingConfig,
MeshShadingSel,
Ccm,
+ GammaFr,
+ GammaDs,
};
namespace details {
@@ -57,6 +59,8 @@ 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);
MALI_C55_DEFINE_BLOCK_TYPE(Ccm, ccm, BLOCK_CCM);
+MALI_C55_DEFINE_BLOCK_TYPE(GammaFr, gamma, BLOCK_GAMMA_FR);
+MALI_C55_DEFINE_BLOCK_TYPE(GammaDs, gamma, BLOCK_GAMMA_DS);
struct param_traits {
using id_type = MaliC55Blocks;