summaryrefslogtreecommitdiff
path: root/src/ipa/rkisp1/algorithms/gsl.cpp
blob: b9f8791246338f4d2da90f2eef0e8618c1fad94a (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
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2021-2022, Ideas On Board
 *
 * gsl.cpp - RkISP1 Gamma Sensor Linearization control
 */

#include "gsl.h"

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

#include "libcamera/internal/yaml_parser.h"

#include "linux/rkisp1-config.h"

/**
 * \file gsl.h
 */

namespace libcamera {

namespace ipa::rkisp1::algorithms {

/**
 * \class GammaSensorLinearization
 * \brief RkISP1 Gamma Sensor Linearization control
 *
 * This algorithm linearizes the sensor output to compensate the sensor
 * non-linearities by applying piecewise linear functions to the red, green and
 * blue channels.
 *
 * The curves are specified in the tuning data and defined using 17 points.
 *
 * - The X coordinates are expressed using 16 intervals, with the first point
 *   at X coordinate 0. Each interval is expressed as a 2-bit value DX (from
 *   GAMMA_DX_1 to GAMMA_DX_16), stored in the RKISP1_CIF_ISP_GAMMA_DX_LO and
 *   RKISP1_CIF_ISP_GAMMA_DX_HI registers. The real interval is equal to
 *   \f$2^{dx+4}\f$. X coordinates are shared between the red, green and blue
 *   curves.
 *
 * - The Y coordinates are specified as 17 values separately for the
 *   red, green and blue channels, with a 12-bit resolution. Each value must be
 *   in the [-2048, 2047] range compared to the previous value.
 */

LOG_DEFINE_CATEGORY(RkISP1Gsl)

static constexpr unsigned int kDegammaXIntervals = 16;

GammaSensorLinearization::GammaSensorLinearization()
{
}

/**
 * \copydoc libcamera::ipa::Algorithm::init
 */
int GammaSensorLinearization::init([[maybe_unused]] IPAContext &context,
				   const YamlObject &tuningData)
{
	std::vector<uint16_t> xIntervals =
		tuningData["x-intervals"].getList<uint16_t>().value_or(std::vector<uint16_t>{});
	if (xIntervals.size() != kDegammaXIntervals) {
		LOG(RkISP1Gsl, Error)
			<< "Invalid 'x' coordinates: expected "
			<< kDegammaXIntervals << " elements, got "
			<< xIntervals.size();

		return -EINVAL;
	}

	/* Compute gammaDx_ intervals from xIntervals values */
	gammaDx_[0] = 0;
	gammaDx_[1] = 0;
	for (unsigned int i = 0; i < kDegammaXIntervals; ++i)
		gammaDx_[i / 8] |= (xIntervals[i] & 0x07) << ((i % 8) * 4);

	const YamlObject &yObject = tuningData["y"];
	if (!yObject.isDictionary()) {
		LOG(RkISP1Gsl, Error)
			<< "Issue while parsing 'y' in tuning file: "
			<< "entry must be a dictionary";
		return -EINVAL;
	}

	curveYr_ = yObject["red"].getList<uint16_t>().value_or(std::vector<uint16_t>{});
	if (curveYr_.size() != RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE) {
		LOG(RkISP1Gsl, Error)
			<< "Invalid 'y:red' coordinates: expected "
			<< RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE
			<< " elements, got " << curveYr_.size();
		return -EINVAL;
	}

	curveYg_ = yObject["green"].getList<uint16_t>().value_or(std::vector<uint16_t>{});
	if (curveYg_.size() != RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE) {
		LOG(RkISP1Gsl, Error)
			<< "Invalid 'y:green' coordinates: expected "
			<< RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE
			<< " elements, got " << curveYg_.size();
		return -EINVAL;
	}

	curveYb_ = yObject["blue"].getList<uint16_t>().value_or(std::vector<uint16_t>{});
	if (curveYb_.size() != RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE) {
		LOG(RkISP1Gsl, Error)
			<< "Invalid 'y:blue' coordinates: expected "
			<< RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE
			<< " elements, got " << curveYb_.size();
		return -EINVAL;
	}

	return 0;
}

/**
 * \copydoc libcamera::ipa::Algorithm::prepare
 */
void GammaSensorLinearization::prepare([[maybe_unused]] IPAContext &context,
				       const uint32_t frame,
				       [[maybe_unused]] IPAFrameContext &frameContext,
				       rkisp1_params_cfg *params)
{
	if (frame > 0)
		return;

	params->others.sdg_config.xa_pnts.gamma_dx0 = gammaDx_[0];
	params->others.sdg_config.xa_pnts.gamma_dx1 = gammaDx_[1];

	std::copy(curveYr_.begin(), curveYr_.end(),
		  params->others.sdg_config.curve_r.gamma_y);
	std::copy(curveYg_.begin(), curveYg_.end(),
		  params->others.sdg_config.curve_g.gamma_y);
	std::copy(curveYb_.begin(), curveYb_.end(),
		  params->others.sdg_config.curve_b.gamma_y);

	params->module_en_update |= RKISP1_CIF_ISP_MODULE_SDG;
	params->module_ens |= RKISP1_CIF_ISP_MODULE_SDG;
	params->module_cfg_update |= RKISP1_CIF_ISP_MODULE_SDG;
}

REGISTER_IPA_ALGORITHM(GammaSensorLinearization, "GammaSensorLinearization")

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

} /* namespace libcamera */