77
88#include " lsc.h"
99
10+ #include < libcamera/base/log.h>
1011#include < libcamera/base/utils.h>
1112
12- #include " libcamera/internal/value_node.h"
13-
1413namespace libcamera {
1514
1615namespace ipa ::mali_c55::algorithms {
1716
1817LOG_DEFINE_CATEGORY (MaliC55Lsc)
1918
20- int Lsc::init ([[maybe_unused]] IPAContext &context, const ValueNode &tuningData)
19+ /* Gain values in [1, 5] range */
20+ static constexpr unsigned int kMeshScale = 6 ;
21+
22+ /* Mali-C55 hw supports configurable mesh sizes; we fix it to 32. */
23+ static constexpr unsigned int kMeshSize = 32 ;
24+ static constexpr unsigned int kGridSize = kMeshSize * kMeshSize ;
25+
26+ /* Per-colour component page offsets in the mesh table. */
27+ static constexpr unsigned int kRedOffset = 0 ;
28+ static constexpr unsigned int kGreenOffset = 1024 ;
29+ static constexpr unsigned int kBlueOffset = 2048 ;
30+
31+ /*
32+ * \todo Clarify if Mali-C55 can support up to 4 colour temperatures.
33+ *
34+ * The uAPI only expose MALI_C55_NUM_MESH_SHADING_ELEMENTS (3072) gain elements,
35+ * which correspond to three pages of 1024 (32x32) entries.
36+ */
37+ static constexpr unsigned int kMaxColourTemperatures = 3 ;
38+
39+ /*
40+ * The LSC algorithm implementation only supports 32x32 grids. Create a list of
41+ * positions from the grid size.
42+ */
43+ std::vector<double > Lsc::segmentsToPosition () const
2144{
22- if (!tuningData.contains (" meshScale" )) {
23- LOG (MaliC55Lsc, Error) << " meshScale missing from tuningData" ;
24- return -EINVAL ;
25- }
45+ std::vector<double > positions (kMeshSize );
46+ for (double i = 0.0 ; i < kMeshSize ; ++i)
47+ positions[i] = i / (kMeshSize - 1 );
2648
27- meshScale_ = tuningData[" meshScale" ].get <uint32_t >(0 );
49+ return positions;
50+ }
2851
29- const ValueNode &sets = tuningData[" sets" ];
30- if (!sets.isList ()) {
31- LOG (MaliC55Lsc, Error) << " LSC tables missing or invalid" ;
32- return -EINVAL ;
33- }
52+ int Lsc::init (IPAContext &context, const ValueNode &tuningData)
53+ {
54+ gridPos_ = segmentsToPosition ();
55+
56+ return lscAlgo_.init (tuningData, context.ctrlMap , {
57+ .keys = { " r" , " g" , " b" },
58+ .numHSamples = kMeshSize ,
59+ .numVSamples = kMeshSize ,
60+ .sensorSize = context.sensorInfo .activeAreaSize
61+ });
62+ }
3463
35- size_t tableSize = 0 ;
36- for (const auto &set : sets.asList ()) {
37- uint32_t ct = set[" ct" ].get <uint32_t >(0 );
64+ int Lsc::configure (IPAContext &context, const IPACameraSensorInfo &configInfo)
65+ {
66+ int ret = lscAlgo_.configure (context.activeState .lsc , configInfo.analogCrop ,
67+ gridPos_, gridPos_);
68+ if (ret)
69+ return ret;
3870
39- if (!ct) {
40- LOG (MaliC55Lsc, Error) << " Invalid colour temperature" ;
41- return -EINVAL ;
42- }
71+ /* Re-initialize the mesh tables and reserve space for enough entries. */
72+ mesh_ = std::vector<uint32_t >(kGridSize * kMaxColourTemperatures );
73+ colourTemperatures_.clear ();
4374
75+ /*
76+ * Get the lsc tables per colour components and populate mesh_ with
77+ * their content.
78+ */
79+ auto &components = lscAlgo_.getComponents ();
80+ for (auto const &[ct, component] : components) {
4481 if (std::count (colourTemperatures_.begin (),
4582 colourTemperatures_.end (), ct)) {
4683 LOG (MaliC55Lsc, Error)
4784 << " Multiple sets found for colour temperature" ;
4885 return -EINVAL ;
4986 }
5087
51- std::vector<uint8_t > rTable =
52- set[" r" ].get <std::vector<uint8_t >>().value_or (utils::defopt);
53- std::vector<uint8_t > gTable =
54- set[" g" ].get <std::vector<uint8_t >>().value_or (utils::defopt);
55- std::vector<uint8_t > bTable =
56- set[" b" ].get <std::vector<uint8_t >>().value_or (utils::defopt);
88+ const std::vector<uint8_t > &rTable = component.at (" r" );
89+ const std::vector<uint8_t > &gTable = component.at (" g" );
90+ const std::vector<uint8_t > &bTable = component.at (" b" );
5791
58- /*
59- * Some validation to do; only 16x16 and 32x32 tables of
60- * coefficients are acceptable, and all tables across all of the
61- * sets must be the same size. The first time we encounter a
62- * table we check that it is an acceptable size and if so make
63- * sure all other tables are of equal size.
64- */
65- if (!tableSize) {
66- if (rTable.size () != 256 && rTable.size () != 1024 ) {
67- LOG (MaliC55Lsc, Error)
68- << " Invalid table size for colour temperature " << ct;
69- return -EINVAL ;
70- }
71- tableSize = rTable.size ();
72- }
73-
74- if (rTable.size () != tableSize ||
75- gTable .size () != tableSize ||
76- bTable.size () != tableSize) {
77- LOG (MaliC55Lsc, Error)
78- << " Invalid or mismatched table size for colour temperature " << ct;
79- return -EINVAL ;
80- }
92+ /* Only 32x32 tables of coefficients are accepted. */
93+ ASSERT (rTable.size () == kGridSize &&
94+ gTable .size () == kGridSize &&
95+ bTable.size () != kGridSize );
8196
82- if (colourTemperatures_.size () >= 3 ) {
97+ if (colourTemperatures_.size () >= kMaxColourTemperatures ) {
8398 LOG (MaliC55Lsc, Error)
8499 << " A maximum of 3 colour temperatures are supported" ;
85100 return -EINVAL ;
86101 }
87102
88- for (unsigned int i = 0 ; i < tableSize; i++) {
103+ /*
104+ * Create the mesh table entries by assembling up to 3 gains per
105+ * colour temperature in a u32 word.
106+ */
107+ for (unsigned int i = 0 ; i < kGridSize ; i++) {
89108 mesh_[kRedOffset + i] |=
90109 (rTable[i] << (colourTemperatures_.size () * 8 ));
91110 mesh_[kGreenOffset + i] |=
@@ -97,35 +116,36 @@ int Lsc::init([[maybe_unused]] IPAContext &context, const ValueNode &tuningData)
97116 colourTemperatures_.push_back (ct);
98117 }
99118
100- /*
101- * The mesh has either 16x16 or 32x32 nodes, we tell the driver which it
102- * is based on the number of values in the tuning data's table.
103- */
104- if (tableSize == 256 )
105- meshSize_ = 15 ;
106- else
107- meshSize_ = 31 ;
108-
109119 return 0 ;
110120}
111121
122+ /* *
123+ * \copydoc libcamera::ipa::Algorithm::queueRequest
124+ */
125+ void Lsc::queueRequest (IPAContext &context, [[maybe_unused]] const uint32_t frame,
126+ IPAFrameContext &frameContext, const ControlList &controls)
127+ {
128+ lscAlgo_.queueRequest (context.activeState .lsc , frameContext.lsc ,
129+ controls);
130+ }
131+
112132void Lsc::fillConfigParamsBlock (MaliC55Params *params) const
113133{
114134 auto block = params->block <MaliC55Blocks::MeshShadingConfig>();
115135
116136 block->mesh_show = false ;
117- block->mesh_scale = meshScale_ ;
137+ block->mesh_scale = kMeshScale ;
118138 block->mesh_page_r = 0 ;
119139 block->mesh_page_g = 1 ;
120140 block->mesh_page_b = 2 ;
121- block->mesh_width = meshSize_ ;
122- block->mesh_height = meshSize_ ;
141+ block->mesh_width = kMeshSize - 1 ;
142+ block->mesh_height = kMeshSize - 1 ;
123143
124144 std::copy (mesh_.begin (), mesh_.end (), block->mesh );
125145}
126146
127147void Lsc::fillSelectionParamsBlock (MaliC55Params *params, uint8_t bank,
128- uint8_t alpha) const
148+ uint8_t alpha) const
129149{
130150 auto block = params->block <MaliC55Blocks::MeshShadingSel>();
131151
@@ -198,6 +218,18 @@ void Lsc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,
198218 fillConfigParamsBlock (params);
199219}
200220
221+ /* *
222+ * \copydoc libcamera::ipa::Algorithm::process
223+ */
224+ void Lsc::process ([[maybe_unused]] IPAContext &context,
225+ [[maybe_unused]] const uint32_t frame,
226+ IPAFrameContext &frameContext,
227+ [[maybe_unused]] const mali_c55_stats_buffer *stats,
228+ ControlList &metadata)
229+ {
230+ lscAlgo_.process (frameContext.lsc , metadata);
231+ }
232+
201233REGISTER_IPA_ALGORITHM (Lsc, " Lsc" )
202234
203235} /* namespace ipa::mali_c55::algorithms */
0 commit comments