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