1 /*
2 * cl_defog_dcp_handler.cpp - CL defog dark channel prior handler
3 *
4 * Copyright (c) 2016 Intel 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 * Author: Wind Yuan <feng.yuan@intel.com>
19 */
20
21 #include "cl_utils.h"
22 #include "cl_defog_dcp_handler.h"
23 #include <algorithm>
24 #include "cl_device.h"
25
26 enum {
27 KernelDarkChannel = 0,
28 KernelMinFilter,
29 KernelBiFilter,
30 KernelDefogRecover,
31 };
32
33 const static XCamKernelInfo kernels_info [] = {
34 {
35 "kernel_dark_channel",
36 #include "kernel_defog_dcp.clx"
37 , 0,
38 },
39 {
40 "kernel_min_filter",
41 #include "kernel_min_filter.clx"
42 , 0,
43 },
44 {
45 "kernel_bi_filter",
46 #include "kernel_bi_filter.clx"
47 , 0,
48 },
49 {
50 "kernel_defog_recover",
51 #include "kernel_defog_dcp.clx"
52 , 0,
53 },
54 };
55
56 namespace XCam {
57
CLDarkChannelKernel(const SmartPtr<CLContext> & context,SmartPtr<CLDefogDcpImageHandler> & defog_handler)58 CLDarkChannelKernel::CLDarkChannelKernel (
59 const SmartPtr<CLContext> &context,
60 SmartPtr<CLDefogDcpImageHandler> &defog_handler)
61 : CLImageKernel (context)
62 , _defog_handler (defog_handler)
63 {
64 }
65
66 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)67 CLDarkChannelKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size)
68 {
69 SmartPtr<CLContext> context = get_context ();
70 SmartPtr<VideoBuffer> &input = _defog_handler->get_input_buf ();
71
72 const VideoBufferInfo & video_info_in = input->get_video_info ();
73
74 CLImageDesc cl_desc_in;
75
76 cl_desc_in.format.image_channel_data_type = CL_UNSIGNED_INT16;
77 cl_desc_in.format.image_channel_order = CL_RGBA;
78 cl_desc_in.width = video_info_in.width / 8;
79 cl_desc_in.height = video_info_in.height;
80 cl_desc_in.row_pitch = video_info_in.strides[0];
81 SmartPtr<CLImage> image_in_y = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[0]);
82
83 cl_desc_in.height = video_info_in.height / 2;
84 cl_desc_in.row_pitch = video_info_in.strides[1];
85 SmartPtr<CLImage> image_in_uv = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[1]);
86
87 args.push_back (new CLMemArgument (image_in_y));
88 args.push_back (new CLMemArgument (image_in_uv));
89
90 SmartPtr<CLImage> &dark_channel = _defog_handler->get_dark_map (XCAM_DEFOG_DC_ORIGINAL);
91 args.push_back (new CLMemArgument (dark_channel));
92
93 // R, G, B channel
94 for (uint32_t i = 0; i < XCAM_DEFOG_MAX_CHANNELS; ++i) {
95 SmartPtr<CLImage> &rgb_image = _defog_handler->get_rgb_channel (i);
96 args.push_back (new CLMemArgument (rgb_image));
97 }
98
99 work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
100 work_size.local[0] = 16;
101 work_size.local[1] = 2;
102 work_size.global[0] = XCAM_ALIGN_UP (cl_desc_in.width, work_size.local[0]);
103 work_size.global[1] = XCAM_ALIGN_UP (cl_desc_in.height, work_size.local[1]);
104
105 return XCAM_RETURN_NO_ERROR;
106 }
107
CLMinFilterKernel(const SmartPtr<CLContext> & context,SmartPtr<CLDefogDcpImageHandler> & defog_handler,int index)108 CLMinFilterKernel::CLMinFilterKernel (
109 const SmartPtr<CLContext> &context,
110 SmartPtr<CLDefogDcpImageHandler> &defog_handler,
111 int index)
112 : CLImageKernel (context)
113 , _defog_handler (defog_handler)
114 , _buf_index (index)
115 {
116 XCAM_ASSERT (XCAM_DEFOG_DC_MIN_FILTER_V == _buf_index || XCAM_DEFOG_DC_MIN_FILTER_H == _buf_index);
117 }
118
119 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)120 CLMinFilterKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size)
121 {
122 SmartPtr<CLImage> &dark_channel_in = _defog_handler->get_dark_map (_buf_index - 1);
123 SmartPtr<CLImage> &dark_channel_out = _defog_handler->get_dark_map (_buf_index);
124
125 args.push_back (new CLMemArgument (dark_channel_in));
126 args.push_back (new CLMemArgument (dark_channel_out));
127
128 const CLImageDesc &cl_desc = dark_channel_in->get_image_desc ();
129
130 work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
131 if (XCAM_DEFOG_DC_MIN_FILTER_V == _buf_index) {
132 work_size.local[0] = 16;
133 work_size.local[1] = 4;
134 work_size.global[0] = XCAM_ALIGN_UP (cl_desc.width, work_size.local[0]);
135 work_size.global[1] = XCAM_ALIGN_UP (cl_desc.height / 2, work_size.local[1]);
136 } else {
137 work_size.local[0] = 16;
138 work_size.local[1] = 4;
139 work_size.global[0] = XCAM_ALIGN_UP (cl_desc.width, work_size.local[0]);
140 work_size.global[1] = XCAM_ALIGN_UP (cl_desc.height, work_size.local[1]);
141 }
142
143 return XCAM_RETURN_NO_ERROR;
144 }
145
CLBiFilterKernel(const SmartPtr<CLContext> & context,SmartPtr<CLDefogDcpImageHandler> & defog_handler)146 CLBiFilterKernel::CLBiFilterKernel (
147 const SmartPtr<CLContext> &context,
148 SmartPtr<CLDefogDcpImageHandler> &defog_handler)
149 : CLImageKernel (context)
150 , _defog_handler (defog_handler)
151 {
152 }
153
154 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)155 CLBiFilterKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size)
156 {
157 SmartPtr<CLContext> context = get_context ();
158 SmartPtr<VideoBuffer> &input = _defog_handler->get_input_buf ();
159 const VideoBufferInfo & video_info_in = input->get_video_info ();
160
161 CLImageDesc cl_desc_in;
162 cl_desc_in.format.image_channel_data_type = CL_UNSIGNED_INT16;
163 cl_desc_in.format.image_channel_order = CL_RGBA;
164 cl_desc_in.width = video_info_in.width / 8;
165 cl_desc_in.height = video_info_in.height;
166 cl_desc_in.row_pitch = video_info_in.strides[0];
167 SmartPtr<CLImage> image_in_y = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[0]);
168
169 SmartPtr<CLImage> &dark_channel_in = _defog_handler->get_dark_map (XCAM_DEFOG_DC_ORIGINAL);
170 SmartPtr<CLImage> &dark_channel_out = _defog_handler->get_dark_map (XCAM_DEFOG_DC_BI_FILTER);
171
172 args.push_back (new CLMemArgument (image_in_y));
173 args.push_back (new CLMemArgument (dark_channel_in));
174 args.push_back (new CLMemArgument (dark_channel_out));
175
176 work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
177 work_size.local[0] = 16;
178 work_size.local[1] = 2;
179 work_size.global[0] = XCAM_ALIGN_UP (cl_desc_in.width, work_size.local[0]);
180 work_size.global[1] = XCAM_ALIGN_UP (cl_desc_in.height, work_size.local[1]);
181
182 return XCAM_RETURN_NO_ERROR;
183 }
184
CLDefogRecoverKernel(const SmartPtr<CLContext> & context,SmartPtr<CLDefogDcpImageHandler> & defog_handler)185 CLDefogRecoverKernel::CLDefogRecoverKernel (
186 const SmartPtr<CLContext> &context, SmartPtr<CLDefogDcpImageHandler> &defog_handler)
187 : CLImageKernel (context)
188 , _defog_handler (defog_handler)
189 , _max_r (255.0f)
190 , _max_g (255.0f)
191 , _max_b (255.0f)
192 , _max_i (255.0f)
193 {
194 }
195
196 float
get_max_value(SmartPtr<VideoBuffer> & buf)197 CLDefogRecoverKernel::get_max_value (SmartPtr<VideoBuffer> &buf)
198 {
199 float ret = 255.0f;
200 const float max_percent = 1.0f;
201
202 SmartPtr<X3aStats> stats;
203 SmartPtr<CLVideoBuffer> cl_buf = buf.dynamic_cast_ptr<CLVideoBuffer> ();
204 if (cl_buf.ptr ()) {
205 stats = cl_buf->find_3a_stats ();
206 }
207 #if HAVE_LIBDRM
208 else {
209 SmartPtr<DrmBoBuffer> bo_buf = buf.dynamic_cast_ptr<DrmBoBuffer> ();
210 stats = bo_buf->find_3a_stats ();
211 }
212 #endif
213
214 _max_r = 230.0f;
215 _max_g = 230.0f;
216 _max_b = 230.0f;
217 _max_i = XCAM_MAX (_max_r, _max_g);
218 _max_i = XCAM_MAX (_max_i, _max_b);
219 if (!stats.ptr ())
220 return ret;
221
222 XCam3AStats *stats_ptr = stats->get_stats ();
223 if (!stats_ptr || !stats_ptr->hist_y)
224 return ret;
225
226 uint32_t his_bins = stats_ptr->info.histogram_bins;
227 uint32_t pixel_count = stats_ptr->info.width * stats_ptr->info.height;
228 uint32_t max_expect_count = (uint32_t)(max_percent * pixel_count / 100.0f);
229 uint32_t sum_count = 0;
230 int32_t i = (int32_t)(his_bins - 1);
231
232 for (; i >= 0; --i) {
233 sum_count += stats_ptr->hist_y[i];
234 if (sum_count >= max_expect_count)
235 break;
236 }
237 ret = (float)i * 256.0f / (1 << stats_ptr->info.bit_depth);
238 ret = XCAM_MAX (ret, 1.0f);
239 return ret;
240 }
241
242 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)243 CLDefogRecoverKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size)
244 {
245 SmartPtr<CLContext> context = get_context ();
246 SmartPtr<VideoBuffer> &input = _defog_handler->get_input_buf ();
247 SmartPtr<VideoBuffer> &output = _defog_handler->get_output_buf ();
248 SmartPtr<CLImage> &dark_map = _defog_handler->get_dark_map (XCAM_DEFOG_DC_BI_FILTER);
249 get_max_value (input);
250
251 args.push_back (new CLMemArgument (dark_map));
252 args.push_back (new CLArgumentT<float> (_max_i));
253 args.push_back (new CLArgumentT<float> (_max_r));
254 args.push_back (new CLArgumentT<float> (_max_g));
255 args.push_back (new CLArgumentT<float> (_max_b));
256
257 for (int i = 0; i < XCAM_DEFOG_MAX_CHANNELS; ++i) {
258 SmartPtr<CLImage> &input_color = _defog_handler->get_rgb_channel (i);
259 args.push_back (new CLMemArgument (input_color));
260 }
261
262 const VideoBufferInfo & video_info_out = output->get_video_info ();
263
264 CLImageDesc cl_desc_out;
265 cl_desc_out.format.image_channel_data_type = CL_UNSIGNED_INT16;
266 cl_desc_out.format.image_channel_order = CL_RGBA;
267 cl_desc_out.width = video_info_out.width / 8;
268 cl_desc_out.height = video_info_out.height;
269 cl_desc_out.row_pitch = video_info_out.strides[0];
270 SmartPtr<CLImage> image_out_y = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[0]);
271
272 cl_desc_out.height = video_info_out.height / 2;
273 cl_desc_out.row_pitch = video_info_out.strides[1];
274 SmartPtr<CLImage> image_out_uv = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[1]);
275
276 args.push_back (new CLMemArgument (image_out_y));
277 args.push_back (new CLMemArgument (image_out_uv));
278
279 work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
280 work_size.local[0] = 16;
281 work_size.local[1] = 8;
282
283 work_size.global[0] = XCAM_ALIGN_UP (cl_desc_out.width, work_size.local[0]);
284 work_size.global[1] = XCAM_ALIGN_UP (cl_desc_out.height, work_size.local[1]); // uv height
285
286 return XCAM_RETURN_NO_ERROR;
287 }
288
CLDefogDcpImageHandler(const SmartPtr<CLContext> & context,const char * name)289 CLDefogDcpImageHandler::CLDefogDcpImageHandler (
290 const SmartPtr<CLContext> &context, const char *name)
291 : CLImageHandler (context, name)
292 {
293 }
294
295 XCamReturn
prepare_parameters(SmartPtr<VideoBuffer> & input,SmartPtr<VideoBuffer> & output)296 CLDefogDcpImageHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output)
297 {
298 XCAM_UNUSED (output);
299 XCamReturn ret = allocate_transmit_bufs (input->get_video_info ());
300 XCAM_FAIL_RETURN(
301 WARNING,
302 ret == XCAM_RETURN_NO_ERROR,
303 ret,
304 "CLDefogDcpImageHandler allocate transmit buffers failed");
305
306 return XCAM_RETURN_NO_ERROR;
307 }
308
309 XCamReturn
execute_done(SmartPtr<VideoBuffer> & output)310 CLDefogDcpImageHandler::execute_done (SmartPtr<VideoBuffer> &output)
311 {
312 XCAM_UNUSED (output);
313 #if 0
314 dump_buffer ();
315 #endif
316
317 return XCAM_RETURN_NO_ERROR;
318 }
319
320 XCamReturn
allocate_transmit_bufs(const VideoBufferInfo & video_info)321 CLDefogDcpImageHandler::allocate_transmit_bufs (const VideoBufferInfo &video_info)
322 {
323 int i;
324 CLImageDesc cl_rgb_desc, cl_dark_desc;
325 SmartPtr<CLContext> context = get_context ();
326
327 cl_rgb_desc.format.image_channel_data_type = CL_UNSIGNED_INT16;
328 cl_rgb_desc.format.image_channel_order = CL_RGBA;
329 cl_rgb_desc.width = video_info.width / 8;
330 cl_rgb_desc.height = video_info.height;
331
332 for (i = 0; i < XCAM_DEFOG_MAX_CHANNELS; ++i) {
333 _rgb_buf[i] = new CLImage2D (context, cl_rgb_desc);
334 XCAM_FAIL_RETURN(
335 WARNING,
336 _rgb_buf[i]->is_valid (),
337 XCAM_RETURN_ERROR_MEM,
338 "CLDefogDcpImageHandler allocate RGB buffers failed");
339 }
340
341 cl_dark_desc.format.image_channel_data_type = CL_UNSIGNED_INT16;
342 cl_dark_desc.format.image_channel_order = CL_RGBA;
343 cl_dark_desc.width = video_info.width / 8;
344 cl_dark_desc.height = video_info.height;
345
346 for (i = 0; i < XCAM_DEFOG_DC_MAX_BUF; ++i) {
347 _dark_channel_buf[i] = new CLImage2D (context, cl_dark_desc);
348 XCAM_FAIL_RETURN(
349 WARNING,
350 _dark_channel_buf[i]->is_valid (),
351 XCAM_RETURN_ERROR_MEM,
352 "CLDefogDcpImageHandler allocate dark channel buffers failed");
353 }
354
355 return XCAM_RETURN_NO_ERROR;
356 }
357
358 void
dump_buffer()359 CLDefogDcpImageHandler::dump_buffer ()
360 {
361 SmartPtr<CLImage> image;
362 CLImageDesc desc;
363 uint32_t width, height;
364 char file_name[1024];
365
366 // dump dark channel bi-filtered map
367 image = _dark_channel_buf[XCAM_DEFOG_DC_BI_FILTER];
368 desc = image->get_image_desc ();
369 width = image->get_pixel_bytes () * desc.width;
370 height = desc.height;
371
372 snprintf (file_name, 1024, "dark-channel-map_%dx%d.y", width, height);
373 dump_image (image, file_name);
374 }
375
376 static SmartPtr<CLDarkChannelKernel>
create_kernel_dark_channel(const SmartPtr<CLContext> & context,SmartPtr<CLDefogDcpImageHandler> handler)377 create_kernel_dark_channel (const SmartPtr<CLContext> &context, SmartPtr<CLDefogDcpImageHandler> handler)
378 {
379 SmartPtr<CLDarkChannelKernel> kernel;
380
381 kernel = new CLDarkChannelKernel (context, handler);
382 XCAM_FAIL_RETURN (
383 WARNING,
384 kernel->build_kernel (kernels_info[KernelDarkChannel], NULL) == XCAM_RETURN_NO_ERROR,
385 NULL,
386 "Defog build kernel(%s) failed", kernels_info[KernelDarkChannel].kernel_name);
387 return kernel;
388 }
389
390 static SmartPtr<CLMinFilterKernel>
create_kernel_min_filter(const SmartPtr<CLContext> & context,SmartPtr<CLDefogDcpImageHandler> handler,int index)391 create_kernel_min_filter (
392 const SmartPtr<CLContext> &context,
393 SmartPtr<CLDefogDcpImageHandler> handler,
394 int index)
395 {
396 SmartPtr<CLMinFilterKernel> kernel;
397
398 char build_options[1024];
399 xcam_mem_clear (build_options);
400 snprintf (
401 build_options, sizeof (build_options),
402 " -DVERTICAL_MIN_KERNEL=%d ", (XCAM_DEFOG_DC_MIN_FILTER_V == index ? 1 : 0));
403
404 kernel = new CLMinFilterKernel (context, handler, index);
405 XCAM_FAIL_RETURN (
406 WARNING,
407 kernel->build_kernel (kernels_info[KernelMinFilter], build_options) == XCAM_RETURN_NO_ERROR,
408 NULL,
409 "Defog build kernel(%s) failed", kernels_info[KernelMinFilter].kernel_name);
410
411 return kernel;
412 }
413
414 static SmartPtr<CLBiFilterKernel>
create_kernel_bi_filter(const SmartPtr<CLContext> & context,SmartPtr<CLDefogDcpImageHandler> handler)415 create_kernel_bi_filter (
416 const SmartPtr<CLContext> &context, SmartPtr<CLDefogDcpImageHandler> handler)
417 {
418 SmartPtr<CLBiFilterKernel> kernel;
419
420 kernel = new CLBiFilterKernel (context, handler);
421 XCAM_FAIL_RETURN (
422 WARNING,
423 kernel->build_kernel (kernels_info[KernelBiFilter], NULL) == XCAM_RETURN_NO_ERROR,
424 NULL,
425 "Defog build kernel(%s) failed", kernels_info[KernelBiFilter].kernel_name);
426
427 return kernel;
428 }
429
430 static SmartPtr<CLDefogRecoverKernel>
create_kernel_defog_recover(const SmartPtr<CLContext> & context,SmartPtr<CLDefogDcpImageHandler> handler)431 create_kernel_defog_recover (
432 const SmartPtr<CLContext> &context, SmartPtr<CLDefogDcpImageHandler> handler)
433 {
434 SmartPtr<CLDefogRecoverKernel> kernel;
435
436 kernel = new CLDefogRecoverKernel (context, handler);
437 XCAM_FAIL_RETURN (
438 WARNING,
439 kernel->build_kernel (kernels_info[KernelDefogRecover], NULL) == XCAM_RETURN_NO_ERROR,
440 NULL,
441 "Defog build kernel(%s) failed", kernels_info[KernelDefogRecover].kernel_name);
442 return kernel;
443 }
444
445 SmartPtr<CLImageHandler>
create_cl_defog_dcp_image_handler(const SmartPtr<CLContext> & context)446 create_cl_defog_dcp_image_handler (const SmartPtr<CLContext> &context)
447 {
448 SmartPtr<CLDefogDcpImageHandler> defog_handler;
449
450 SmartPtr<CLImageKernel> kernel;
451
452 defog_handler = new CLDefogDcpImageHandler (context, "cl_handler_defog_dcp");
453 kernel = create_kernel_dark_channel (context, defog_handler);
454 XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "defog handler create dark channel kernel failed");
455 defog_handler->add_kernel (kernel);
456
457 #if 0
458 for (int i = XCAM_DEFOG_DC_MIN_FILTER_V; i <= XCAM_DEFOG_DC_MIN_FILTER_H; ++i) {
459 SmartPtr<CLImageKernel> min_kernel;
460 min_kernel = create_kernel_min_filter (context, defog_handler, i);
461 XCAM_FAIL_RETURN (ERROR, min_kernel.ptr (), NULL, "defog handler create min filter kernel failed");
462 defog_handler->add_kernel (min_kernel);
463 }
464 #endif
465
466 kernel = create_kernel_bi_filter (context, defog_handler);
467 XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "defog handler create bilateral filter kernel failed");
468 defog_handler->add_kernel (kernel);
469
470 kernel = create_kernel_defog_recover (context, defog_handler);
471 XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "defog handler create defog recover kernel failed");
472 defog_handler->add_kernel (kernel);
473
474 return defog_handler;
475 }
476
477 }
478