new file mode 100644
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2026, Ideas On Board
+ *
+ * RPP-X1 Gamma out control
+ */
+
+#include "goc.h"
+
+/**
+ * \file goc.h
+ */
+
+namespace libcamera {
+
+namespace ipa::rppx1::algorithms {
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::init
+ */
+int GammaOutCorrection::init(IPAContext &context, const ValueNode &tuningData)
+{
+ /* The logarithmic segments as specified in the reference. */
+ static constexpr unsigned int segments[] = {
+ 64, 64, 64, 64, 128, 128, 128, 128,
+ 256, 256, 256, 512, 512, 512, 512, 512,
+ };
+
+ return gamma_.init(context.ctrlMap, tuningData, segments);
+}
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::configure
+ */
+int GammaOutCorrection::configure(IPAContext &context,
+ [[maybe_unused]] const IPACameraSensorInfo &configInfo)
+{
+ gamma_.configure(context.activeState.goc);
+ return 0;
+}
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::queueRequest
+ */
+void GammaOutCorrection::queueRequest(IPAContext &context, const uint32_t frame,
+ IPAFrameContext &frameContext,
+ const ControlList &controls)
+{
+ gamma_.queueRequest(context.activeState.goc, frame, frameContext.goc, controls);
+}
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::prepare
+ */
+void GammaOutCorrection::prepare([[maybe_unused]] IPAContext &context,
+ [[maybe_unused]] const uint32_t frame,
+ IPAFrameContext &frameContext,
+ RppX1Params *params)
+{
+ if (!frameContext.goc.update)
+ return;
+
+ auto config = params->block<BlockType::GaHv>();
+ config.setEnabled(true);
+
+ config->mode = RPPX1_GA_SEG_MODE_LOGARITHMIC;
+ gamma_.prepare(frameContext.goc, std::span(config->gamma_y));
+}
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::process
+ */
+void GammaOutCorrection::process([[maybe_unused]] IPAContext &context,
+ [[maybe_unused]] const uint32_t frame,
+ IPAFrameContext &frameContext,
+ [[maybe_unused]] const RppX1Stats *stats,
+ ControlList &metadata)
+{
+ metadata.set(controls::Gamma, frameContext.goc.gamma);
+}
+
+REGISTER_IPA_ALGORITHM(GammaOutCorrection, "GammaOutCorrection")
+
+} /* namespace ipa::rppx1::algorithms */
+
+} /* namespace libcamera */
new file mode 100644
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2026, Ideas On Board
+ *
+ * RPP-X1 Gamma out control
+ */
+
+#pragma once
+
+#include <libipa/gamma.h>
+
+#include "algorithm.h"
+
+namespace libcamera {
+
+namespace ipa::rppx1::algorithms {
+
+class GammaOutCorrection : 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,
+ RppX1Params *params) override;
+ void process(IPAContext &context, const uint32_t frame,
+ IPAFrameContext &frameContext,
+ const RppX1Stats *stats,
+ ControlList &metadata) override;
+
+private:
+ /* RPP_OUT ("human vision") pipeline with 12-bit gamma values */
+ GammaAlgorithm<RPPX1_GA_MAX_SAMPLES, UQ<0, 12>> gamma_;
+};
+
+} /* namespace ipa::rppx1::algorithms */
+
+} /* namespace libcamera */
@@ -5,5 +5,6 @@ rppx1_ipa_algorithms = files([
'awb.cpp',
'blc.cpp',
'ccm.cpp',
+ 'goc.cpp',
'lux.cpp',
])
@@ -21,6 +21,7 @@
#include <libipa/ccm.h>
#include <libipa/camera_sensor_helper.h>
#include <libipa/fc_queue.h>
+#include <libipa/gamma.h>
namespace libcamera {
@@ -46,6 +47,8 @@ struct IPAActiveState {
ipa::ccm::ActiveState ccm;
+ ipa::gamma::ActiveState goc;
+
struct {
double lux;
} lux;
@@ -66,6 +69,8 @@ struct IPAFrameContext : public FrameContext {
ipa::ccm::FrameContext ccm;
+ ipa::gamma::FrameContext goc;
+
struct {
double lux;
} lux;
@@ -20,6 +20,7 @@ enum class BlockType : uint16_t {
BlsPre1,
CcorPost,
ExmPre1,
+ GaHv,
HistPost,
WbMeasPost,
};
@@ -42,6 +43,7 @@ RPPX1_DEFINE_BLOCK_TYPE(AwbGPre1, awbg, AWBG_PRE1)
RPPX1_DEFINE_BLOCK_TYPE(BlsPre1, bls, BLS_PRE1)
RPPX1_DEFINE_BLOCK_TYPE(CcorPost, ccor, CCOR_POST)
RPPX1_DEFINE_BLOCK_TYPE(ExmPre1, exm, EXM_PRE1)
+RPPX1_DEFINE_BLOCK_TYPE(GaHv, ga, GA_HV)
RPPX1_DEFINE_BLOCK_TYPE(HistPost, hist, HIST_POST)
RPPX1_DEFINE_BLOCK_TYPE(WbMeasPost, wbmeas, WBMEAS_POST)