Home | History | Annotate | Download | only in ocl
      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 (at) 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 
     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
     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 
    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
    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 
    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
    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 
    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
    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
    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 
    289 CLDefogDcpImageHandler::CLDefogDcpImageHandler (
    290     const SmartPtr<CLContext> &context, const char *name)
    291     : CLImageHandler (context, name)
    292 {
    293 }
    294 
    295 XCamReturn
    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
    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
    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
    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>
    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>
    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>
    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>
    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>
    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