summaryrefslogtreecommitdiff
path: root/src/ipa/rkisp1/algorithms/goc.cpp
blob: a82cee3bbf61087006a9c183d3470cab9c8684be (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
/* 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(IPAContext &context, 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;
}

/**
 * \copydoc libcamera::ipa::Algorithm::configure
 */
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(IPAContext &context, 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(IPAContext &context,
				 [[maybe_unused]] const uint32_t frame,
				 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
	 */
	static constexpr std::array<unsigned int, 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
	};
	__u16 *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 */