1 /*
2 * rk_aiq_algo_aldch_itf.c
3 *
4 * Copyright (c) 2019 Rockchip Corporation
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20 #include "aldch/rk_aiq_algo_aldch_itf.h"
21 #include "aldch/rk_aiq_types_aldch_algo_prvt.h"
22 #include "rk_aiq_algo_types.h"
23 #include "RkAiqCalibDbV2Helper.h"
24 #include "xcam_log.h"
25 #include "rk_aiq_ldch_generate_mesh.h"
26
27 RKAIQ_BEGIN_DECLARE
28
29
30 static XCamReturn
updateCalibConfig(RkAiqAlgoCom * params)31 updateCalibConfig(RkAiqAlgoCom* params)
32 {
33 LDCHHandle_t hLDCH = (LDCHHandle_t)params->ctx->hLDCH;
34 LDCHContext_t* ldchCtx = (LDCHContext_t*)hLDCH;
35 RkAiqAlgoConfigAldch* rkaiqAldchConfig = (RkAiqAlgoConfigAldch*)params;
36
37 CalibDbV2_LDCH_t* calib_ldch_db =
38 (CalibDbV2_LDCH_t*)(CALIBDBV2_GET_MODULE_PTR(rkaiqAldchConfig->com.u.prepare.calibv2, aldch));
39 CalibDbV2_Ldch_Param_t* calib_ldch = &calib_ldch_db->param;
40
41 ldchCtx->camCoeff.cx = calib_ldch->light_center[0];
42 ldchCtx->camCoeff.cy = calib_ldch->light_center[1];
43 ldchCtx->camCoeff.a0 = calib_ldch->coefficient[0];
44 ldchCtx->camCoeff.a2 = calib_ldch->coefficient[1];
45 ldchCtx->camCoeff.a3 = calib_ldch->coefficient[2];
46 ldchCtx->camCoeff.a4 = calib_ldch->coefficient[3];
47
48 if (calib_ldch->ldch_en) {
49 if (!ldchCtx->ldch_en || calib_ldch->correct_level != hLDCH->correct_level) {
50 aiqGenLdchMeshInit(hLDCH);
51 bool success = aiqGenMesh(hLDCH, calib_ldch->correct_level);
52 if (!success) {
53 LOGE_ALDCH("lut is not exist");
54 put_ldch_buf(hLDCH);
55 return XCAM_RETURN_ERROR_PARAM;
56 }
57 }
58 }
59
60 ldchCtx->ldch_en = calib_ldch->ldch_en;
61 memcpy(ldchCtx->meshfile, calib_ldch->meshfile, sizeof(ldchCtx->meshfile));
62 ldchCtx->correct_level = calib_ldch->correct_level;
63 ldchCtx->correct_level_max = calib_ldch->correct_level_max;
64
65 ldchCtx->isAttribUpdated = true;
66
67 LOGI_ALDCH("en(%d), level(%d-%d), coeff(%f, %f, %f, %f, %f, %f)",
68 calib_ldch->ldch_en,
69 calib_ldch->correct_level,
70 calib_ldch->correct_level_max,
71 calib_ldch->light_center[0],
72 calib_ldch->light_center[1],
73 calib_ldch->coefficient[0],
74 calib_ldch->coefficient[1],
75 calib_ldch->coefficient[2],
76 calib_ldch->coefficient[3]);
77
78 return XCAM_RETURN_NO_ERROR;
79 }
80
81 static XCamReturn
create_context(RkAiqAlgoContext ** context,const AlgoCtxInstanceCfg * cfg)82 create_context(RkAiqAlgoContext **context, const AlgoCtxInstanceCfg* cfg)
83 {
84 XCamReturn result = XCAM_RETURN_NO_ERROR;
85
86 LOG1_ALDCH("%s: (enter)\n", __FUNCTION__ );
87 RkAiqAlgoContext *ctx = new RkAiqAlgoContext();
88 if (ctx == NULL) {
89 LOGE_ALDCH( "%s: create aldch context fail!\n", __FUNCTION__);
90 return XCAM_RETURN_ERROR_MEM;
91 }
92 ctx->hLDCH = new LDCHContext_t;
93 if (ctx->hLDCH == NULL) {
94 LOGE_ALDCH( "%s: create aldch handle fail!\n", __FUNCTION__);
95 return XCAM_RETURN_ERROR_MEM;
96 }
97 /* setup config */
98 memset((void *)(ctx->hLDCH), 0, sizeof(LDCHContext_t) );
99
100 /* return handle */
101 *context = ctx;
102
103 #if GENMESH_ONLINE
104 ctx->hLDCH->isAttribUpdated = false;
105 ctx->hLDCH->aldchReadMeshThread = new RKAiqAldchThread(ctx->hLDCH);
106 /* ctx->hLDCH->aldchReadMeshThread->triger_start(); */
107 /* ctx->hLDCH->aldchReadMeshThread->start(); */
108 #endif
109
110 LDCHHandle_t ldchCtx = ctx->hLDCH;
111 CalibDbV2_LDCH_t* calib_ldch_db =
112 (CalibDbV2_LDCH_t*)(CALIBDBV2_GET_MODULE_PTR(cfg->calibv2, aldch));
113 CalibDbV2_Ldch_Param_t* calib_ldch = &calib_ldch_db->param;
114
115 ldchCtx->ldch_en = calib_ldch->ldch_en;
116 memcpy(ldchCtx->meshfile, calib_ldch->meshfile, sizeof(ldchCtx->meshfile));
117 #if GENMESH_ONLINE
118 ldchCtx->camCoeff.cx = calib_ldch->light_center[0];
119 ldchCtx->camCoeff.cy = calib_ldch->light_center[1];
120 ldchCtx->camCoeff.a0 = calib_ldch->coefficient[0];
121 ldchCtx->camCoeff.a2 = calib_ldch->coefficient[1];
122 ldchCtx->camCoeff.a3 = calib_ldch->coefficient[2];
123 ldchCtx->camCoeff.a4 = calib_ldch->coefficient[3];
124 LOGI_ALDCH("(%s) len light center(%.16f, %.16f)\n",
125 __FUNCTION__,
126 ldchCtx->camCoeff.cx, ldchCtx->camCoeff.cy);
127 LOGI_ALDCH("(%s) len coefficient(%.16f, %.16f, %.16f, %.16f)\n",
128 __FUNCTION__,
129 ldchCtx->camCoeff.a0, ldchCtx->camCoeff.a2,
130 ldchCtx->camCoeff.a3, ldchCtx->camCoeff.a4);
131 #endif
132 ldchCtx->correct_level = calib_ldch->correct_level;
133 ldchCtx->correct_level_max = calib_ldch->correct_level_max;
134
135 LOGI_ALDCH("ldch en %d, meshfile: %s, correct_level-max: %d-%d from xml file",
136 calib_ldch->ldch_en,
137 ldchCtx->meshfile,
138 ldchCtx->correct_level,
139 ldchCtx->correct_level_max);
140
141 return XCAM_RETURN_NO_ERROR;
142 }
143
144 static XCamReturn
destroy_context(RkAiqAlgoContext * context)145 destroy_context(RkAiqAlgoContext *context)
146 {
147 LDCHHandle_t hLDCH = (LDCHHandle_t)context->hLDCH;
148 LDCHContext_t* ldchCtx = (LDCHContext_t*)hLDCH;
149
150 #if GENMESH_ONLINE
151 if (!hLDCH->aldchReadMeshThread->is_empty())
152 hLDCH->aldchReadMeshThread->clear_attr();
153 ldchCtx->aldchReadMeshThread->triger_stop();
154 ldchCtx->aldchReadMeshThread->stop();
155 #endif
156
157 #if GENMESH_ONLINE
158 genLdchMeshDeInit(ldchCtx->ldchParams);
159 #endif
160 release_ldch_buf(ldchCtx);
161 delete context->hLDCH;
162 context->hLDCH = NULL;
163 delete context;
164 context = NULL;
165 return XCAM_RETURN_NO_ERROR;
166 }
167
168 static XCamReturn
prepare(RkAiqAlgoCom * params)169 prepare(RkAiqAlgoCom* params)
170 {
171 LDCHHandle_t hLDCH = (LDCHHandle_t)params->ctx->hLDCH;
172 LDCHContext_t* ldchCtx = (LDCHContext_t*)hLDCH;
173 RkAiqAlgoConfigAldch* rkaiqAldchConfig = (RkAiqAlgoConfigAldch*)params;
174
175 ldchCtx->src_width = params->u.prepare.sns_op_width;
176 ldchCtx->src_height = params->u.prepare.sns_op_height;
177 ldchCtx->dst_width = params->u.prepare.sns_op_width;
178 ldchCtx->dst_height = params->u.prepare.sns_op_height;
179 ldchCtx->resource_path = rkaiqAldchConfig->resource_path;
180 ldchCtx->share_mem_ops = rkaiqAldchConfig->mem_ops_ptr;
181
182 bool config_calib = !!(params->u.prepare.conf_type & RK_AIQ_ALGO_CONFTYPE_UPDATECALIB);
183 if (config_calib) {
184 updateCalibConfig(params);
185 return XCAM_RETURN_NO_ERROR;
186 }
187
188 #if GENMESH_ONLINE
189 // process the new attrib set before prepare
190 hLDCH->aldchReadMeshThread->triger_stop();
191 hLDCH->aldchReadMeshThread->stop();
192 if (!hLDCH->aldchReadMeshThread->is_empty()) {
193 hLDCH->aldchReadMeshThread->clear_attr();
194 ldchCtx->isAttribUpdated = true;
195 }
196
197 if (ldchCtx->isAttribUpdated) {
198 ldchCtx->ldch_en = ldchCtx->user_config.en;
199 ldchCtx->correct_level = ldchCtx->user_config.correct_level;
200 ldchCtx->isAttribUpdated = false;
201 } else {
202 ldchCtx->user_config.en = ldchCtx->ldch_en;
203 ldchCtx->user_config.correct_level = ldchCtx->correct_level;
204 }
205
206 hLDCH->aldchReadMeshThread->triger_start();
207 hLDCH->aldchReadMeshThread->start();
208 if (!ldchCtx->ldch_en)
209 return XCAM_RETURN_NO_ERROR;
210
211 if (aiqGenLdchMeshInit(ldchCtx) == XCAM_RETURN_NO_ERROR) {
212 bool success = aiqGenMesh(hLDCH, ldchCtx->correct_level);
213 if (!success) {
214 LOGW_ALDCH("lut is not exist");
215 put_ldch_buf(hLDCH);
216 ldchCtx->ldch_en = 0;
217 }
218 }
219 #else
220 if (!ldchCtx->ldch_en)
221 return XCAM_RETURN_NO_ERROR;
222
223 char filename[512];
224 sprintf(filename, "%s/%s/mesh_level%d.bin",
225 ldchCtx->resource_path,
226 ldchCtx->meshfile,
227 ldchCtx->correct_level);
228 bool ret = read_mesh_from_file(ldchCtx, filename);
229 if (!ret)
230 ldchCtx->ldch_en = 0;
231 #endif
232
233 return XCAM_RETURN_NO_ERROR;
234 }
235
236 static XCamReturn
pre_process(const RkAiqAlgoCom * inparams,RkAiqAlgoResCom * outparams)237 pre_process(const RkAiqAlgoCom* inparams, RkAiqAlgoResCom* outparams)
238 {
239 return XCAM_RETURN_NO_ERROR;
240 }
241
242 static XCamReturn
processing(const RkAiqAlgoCom * inparams,RkAiqAlgoResCom * outparams)243 processing(const RkAiqAlgoCom* inparams, RkAiqAlgoResCom* outparams)
244 {
245 LDCHHandle_t hLDCH = (LDCHHandle_t)inparams->ctx->hLDCH;
246 LDCHContext_t* ldchCtx = (LDCHContext_t*)hLDCH;
247 RkAiqAlgoProcResAldch* ldchPreOut = (RkAiqAlgoProcResAldch*)outparams;
248
249 bool update_params = false;
250 if (inparams->u.proc.init) {
251 update_params = true;
252 } else {
253 if (ldchCtx->isAttribUpdated) {
254 ldchCtx->isAttribUpdated = false;
255 update_params = true;
256 } else {
257 update_params = false;
258 }
259
260 LOGV_ALDCH("(%s) en(%d), level(%d), user en(%d), level(%d), result update(%d)\n",
261 __FUNCTION__,
262 ldchCtx->ldch_en,
263 ldchCtx->correct_level,
264 ldchCtx->user_config.en,
265 ldchCtx->user_config.correct_level,
266 update_params);
267 }
268
269 if (update_params) {
270 ldchPreOut->ldch_result->sw_ldch_en = ldchCtx->ldch_en;
271 ldchPreOut->ldch_result->lut_h_size = ldchCtx->lut_h_size;
272 ldchPreOut->ldch_result->lut_v_size = ldchCtx->lut_v_size;
273 ldchPreOut->ldch_result->lut_map_size = ldchCtx->lut_mapxy_size;
274 if (ldchCtx->ldch_en) {
275 if (!ldchCtx->ldch_mem_info) {
276 LOGE_ALDCH("no available ldch buf, ldch_mem_info: %p", ldchCtx->ldch_mem_info);
277 outparams->cfg_update = false;
278 return XCAM_RETURN_NO_ERROR;
279 }
280
281 ldchPreOut->ldch_result->lut_mapxy_buf_fd = ldchCtx->ldch_mem_info->fd;
282 }
283 }
284 outparams->cfg_update = update_params;
285
286 return XCAM_RETURN_NO_ERROR;
287 }
288
289 static XCamReturn
post_process(const RkAiqAlgoCom * inparams,RkAiqAlgoResCom * outparams)290 post_process(const RkAiqAlgoCom* inparams, RkAiqAlgoResCom* outparams)
291 {
292 return XCAM_RETURN_NO_ERROR;
293 }
294
295 RkAiqAlgoDescription g_RkIspAlgoDescAldch = {
296 .common = {
297 .version = RKISP_ALGO_ALDCH_VERSION,
298 .vendor = RKISP_ALGO_ALDCH_VENDOR,
299 .description = RKISP_ALGO_ALDCH_DESCRIPTION,
300 .type = RK_AIQ_ALGO_TYPE_ALDCH,
301 .id = 0,
302 .create_context = create_context,
303 .destroy_context = destroy_context,
304 },
305 .prepare = prepare,
306 .pre_process = NULL,
307 .processing = processing,
308 .post_process = NULL,
309 };
310
311 RKAIQ_END_DECLARE
312
313
loop()314 bool RKAiqAldchThread::loop()
315 {
316 XCamReturn ret = XCAM_RETURN_NO_ERROR;
317 ENTER_ANALYZER_FUNCTION();
318
319 const static int32_t timeout = -1;
320 SmartPtr<rk_aiq_ldch_cfg_t> attrib = mAttrQueue.pop (timeout);
321
322 if (!attrib.ptr()) {
323 LOGW_ALDCH("RKAiqAldchThread got empty attrib, stop thread");
324 return false;
325 }
326 #if GENMESH_ONLINE
327 if (attrib->en) {
328 if (!hLDCH->ldch_en || attrib->correct_level != hLDCH->correct_level) {
329 aiqGenLdchMeshInit(hLDCH);
330 bool success = aiqGenMesh(hLDCH, attrib->correct_level);
331 if (!success) {
332 LOGW_ALDCH("lut is not exist");
333 put_ldch_buf(hLDCH);
334 }
335 }
336 }
337
338 hLDCH->ldch_en = hLDCH->user_config.en;
339 hLDCH->correct_level = hLDCH->user_config.correct_level;
340 #endif
341 if (ret == XCAM_RETURN_NO_ERROR) {
342 hLDCH->isAttribUpdated = true;
343 LOGV_ALDCH("ldch en(%d), level(%d)\n", hLDCH->ldch_en, hLDCH->correct_level);
344 return true;
345 }
346
347 LOGE_ALDCH("RKAiqAldchThread failed to read mesh table!");
348
349 EXIT_ANALYZER_FUNCTION();
350
351 return false;
352 }
353