summaryrefslogtreecommitdiff
path: root/src/ipa/rkisp1/algorithms/goc.cpp
blob: fc5ad9f9177e98e465c5fbbb57579708bdf0d291 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2024, Ideas On Board
 *
 * RkISP1 Gamma out control
 */
#include "goc.h"

#include <cmath>

#include <libcamera/base/log.h>
#include <libcamera/base/utils.h>

#include <libcamera/control_ids.h>

#include "libcamera/internal/yaml_parser.h"

#include "linux/rkisp1-config.h"

/**
 * \file goc.h
 */

namespace libcamera {

namespace ipa::rkisp1::algorithms {

/**
 * \class GammaOutCorrection
 * \brief RkISP1 Gamma out correction
 *
 * This algorithm implements the gamma out curve for the RkISP1. It defaults to
 * a gamma value of 2.2.
 *
 * As gamma is internally represented as a piecewise linear function with only
 * 17 knots, the difference between gamma=2.2 and sRGB gamma is minimal.
 * Therefore sRGB gamma was not implemented as special case.
 *
 * Useful links:
 * - https://www.cambridgeincolour.com/tutorials/gamma-correction.htm
 * - https://en.wikipedia.org/wiki/SRGB
 */

LOG_DEFINE_CATEGORY(RkISP1Gamma)

const float kDefaultGamma = 2.2f;

/**
 * \copydoc libcamera::ipa::Algorithm::init
 */
int GammaOutCorrection::init([[maybe_unused]] IPAContext &context,
			     [[maybe_unused]] const YamlObject &tuningData)
{
	if (context.hw->numGammaOutSamples !=
	    RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10) {
		LOG(RkISP1Gamma, Error)
			<< "Gamma is not implemented for RkISP1 V12";
		return -EINVAL;
	}

	defaultGamma_ = tuningData["gamma"].get<double>(kDefaultGamma);
	context.ctrlMap[&controls::Gamma] = ControlInfo(0.1f, 10.0f, defaultGamma_);

	return 0;
}

/**
 * \brief Configure the Gamma given a configInfo
 * \param[in] context The shared IPA context
 * \param[in] configInfo The IPA configuration data
 *
 * \return 0
 */
int GammaOutCorrection::configure(IPAContext &context,
				  [[maybe_unused]] const IPACameraSensorInfo &configInfo)
{
	context.activeState.goc.gamma = defaultGamma_;
	return 0;
}

/**
 * \copydoc libcamera::ipa::Algorithm::queueRequest
 */
void GammaOutCorrection::queueRequest([[maybe_unused]] IPAContext &context,
				      [[maybe_unused]] const uint32_t frame,
				      IPAFrameContext &frameContext,
				      const ControlList &controls)
{
	if (frame == 0)
		frameContext.goc.update = true;

	const auto &gamma = controls.get(controls::Gamma);
	if (gamma) {
		context.activeState.goc.gamma = *gamma;
		frameContext.goc.update = true;
		LOG(RkISP1Gamma, Debug) << "Set gamma to " << *gamma;
	}

	frameContext.goc.gamma = context.activeState.goc.gamma;
}

/**
 * \copydoc libcamera::ipa::Algorithm::prepare
 */
void GammaOutCorrection::prepare([[maybe_unused]] IPAContext &context,
				 [[maybe_unused]] const uint32_t frame,
				 [[maybe_unused]] IPAFrameContext &frameContext,
				 rkisp1_params_cfg *params)
{
	ASSERT(context.hw->numGammaOutSamples ==
	       RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10);

	/*
	 * The logarithmic segments as specified in the reference.
	 * Plus an additional 0 to make the loop easier
	 */
	std::array<unsigned, RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10> segments = {
		64, 64, 64, 64, 128, 128, 128, 128, 256,
		256, 256, 512, 512, 512, 512, 512, 0
	};
	auto gamma_y = params->others.goc_config.gamma_y;

	if (!frameContext.goc.update)
		return;

	unsigned x = 0;
	for (const auto [i, size] : utils::enumerate(segments)) {
		gamma_y[i] = std::pow(x / 4096.0, 1.0 / frameContext.goc.gamma) * 1023.0;
		x += size;
	}

	params->others.goc_config.mode = RKISP1_CIF_ISP_GOC_MODE_LOGARITHMIC;
	params->module_cfg_update |= RKISP1_CIF_ISP_MODULE_GOC;
	params->module_en_update |= RKISP1_CIF_ISP_MODULE_GOC;
	params->module_ens |= RKISP1_CIF_ISP_MODULE_GOC;
}

/**
 * \copydoc libcamera::ipa::Algorithm::process
 */
void GammaOutCorrection::process([[maybe_unused]] IPAContext &context,
				 [[maybe_unused]] const uint32_t frame,
				 IPAFrameContext &frameContext,
				 [[maybe_unused]] const rkisp1_stat_buffer *stats,
				 ControlList &metadata)
{
	metadata.set(controls::Gamma, frameContext.goc.gamma);
}

REGISTER_IPA_ALGORITHM(GammaOutCorrection, "GammaOutCorrection")

} /* namespace ipa::rkisp1::algorithms */

} /* namespace libcamera */