Home | History | Annotate | Download | only in ocl
      1 /*
      2  * cl_retinex_handler.cpp - CL retinex 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: wangfei <feix.w.wang (at) intel.com>
     19  *             Wind Yuan <feng.yuan (at) intel.com>
     20  */
     21 
     22 #include "cl_utils.h"
     23 #include "cl_retinex_handler.h"
     24 #include <algorithm>
     25 #include "cl_device.h"
     26 
     27 namespace XCam {
     28 
     29 static uint32_t retinex_gauss_scale [3] = {2, 8, 20}; //{20, 60, 150};
     30 static float retinex_gauss_sigma [3] = {2.0f, 8.0f, 20.0f}; //{12.0f, 40.0f, 120.0f};
     31 static float retinex_config_log_min = -0.12f; // -0.18f
     32 static float retinex_config_log_max = 0.18f;  //0.2f
     33 
     34 enum {
     35     KernelScaler = 0,
     36     KernelGaussian,
     37     KernelRetinex,
     38 };
     39 
     40 const static XCamKernelInfo kernel_retinex_info [] = {
     41     {
     42         "kernel_image_scaler",
     43 #include "kernel_image_scaler.clx"
     44         , 0,
     45     },
     46     {
     47         "kernel_gauss",
     48 #include "kernel_gauss.clx"
     49         , 0,
     50     },
     51     {
     52         "kernel_retinex",
     53 #include "kernel_retinex.clx"
     54         , 0,
     55     },
     56 };
     57 
     58 CLRetinexScalerImageKernel::CLRetinexScalerImageKernel (
     59     const SmartPtr<CLContext> &context,
     60     const CLImageScalerMemoryLayout mem_layout,
     61     SmartPtr<CLRetinexImageHandler> &retinex)
     62     : CLScalerKernel (context, mem_layout)
     63     , _retinex(retinex)
     64 {
     65 }
     66 
     67 SmartPtr<VideoBuffer>
     68 CLRetinexScalerImageKernel::get_input_buffer ()
     69 {
     70     return _retinex->get_input_buf ();
     71 }
     72 
     73 SmartPtr<VideoBuffer>
     74 CLRetinexScalerImageKernel::get_output_buffer ()
     75 {
     76     return _retinex->get_scaler_buf1 ();
     77 }
     78 
     79 CLRetinexGaussImageKernel::CLRetinexGaussImageKernel (
     80     const SmartPtr<CLContext> &context,
     81     SmartPtr<CLRetinexImageHandler> &retinex,
     82     uint32_t index,
     83     uint32_t radius, float sigma)
     84     : CLGaussImageKernel (context, radius, sigma)
     85     , _retinex (retinex)
     86     , _index (index)
     87 {
     88 }
     89 
     90 SmartPtr<VideoBuffer>
     91 CLRetinexGaussImageKernel::get_input_buf ()
     92 {
     93     return _retinex->get_scaler_buf1 ();
     94 }
     95 
     96 SmartPtr<VideoBuffer>
     97 CLRetinexGaussImageKernel::get_output_buf ()
     98 {
     99     return _retinex->get_gaussian_buf (_index);
    100 }
    101 
    102 CLRetinexImageKernel::CLRetinexImageKernel (const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> &retinex)
    103     : CLImageKernel (context, "kernel_retinex"),
    104       _retinex (retinex)
    105 {
    106 }
    107 
    108 XCamReturn
    109 CLRetinexImageKernel::prepare_arguments (
    110     CLArgList &args, CLWorkSize &work_size)
    111 {
    112     SmartPtr<CLContext> context = get_context ();
    113     SmartPtr<VideoBuffer> input = _retinex->get_input_buf ();
    114     SmartPtr<VideoBuffer> output = _retinex->get_output_buf ();
    115 
    116     const VideoBufferInfo & video_info_in = input->get_video_info ();
    117     const VideoBufferInfo & video_info_out = output->get_video_info ();
    118     SmartPtr<CLImage> image_in, image_in_uv;
    119     SmartPtr<CLImage> image_out, image_out_uv;
    120     SmartPtr<CLImage> image_in_ga[XCAM_RETINEX_MAX_SCALE];
    121 
    122     CLImageDesc cl_desc_in, cl_desc_out, cl_desc_ga;
    123 
    124     cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8; //CL_UNSIGNED_INT32;
    125     cl_desc_in.format.image_channel_order = CL_RGBA;
    126     cl_desc_in.width = video_info_in.width / 4; // 16;
    127     cl_desc_in.height = video_info_in.height;
    128     cl_desc_in.row_pitch = video_info_in.strides[0];
    129     image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[0]);
    130 
    131     cl_desc_in.height = video_info_in.height / 2;
    132     cl_desc_in.row_pitch = video_info_in.strides[1];
    133     image_in_uv = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[1]);
    134 
    135     cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8; //CL_UNSIGNED_INT32;
    136     cl_desc_out.format.image_channel_order = CL_RGBA;
    137     cl_desc_out.width = video_info_out.width / 4; // 16;
    138     cl_desc_out.height = video_info_out.height;
    139     cl_desc_out.row_pitch = video_info_out.strides[0];
    140     image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[0]);
    141 
    142     cl_desc_out.height = video_info_out.height / 2;
    143     cl_desc_out.row_pitch = video_info_out.strides[1];
    144     image_out_uv = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[1]);
    145 
    146     XCAM_FAIL_RETURN (
    147         WARNING,
    148         image_in->is_valid () && image_in_uv->is_valid () &&
    149         image_out->is_valid () && image_out_uv->is_valid(),
    150         XCAM_RETURN_ERROR_MEM,
    151         "cl image kernel(%s) in/out memory not available", get_kernel_name ());
    152 
    153     for (uint32_t i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) {
    154         SmartPtr<VideoBuffer> gaussian_buf = _retinex->get_gaussian_buf (i);
    155         XCAM_ASSERT (gaussian_buf.ptr ());
    156 
    157         const VideoBufferInfo & video_info_gauss = gaussian_buf->get_video_info ();
    158 
    159         cl_desc_ga.format.image_channel_data_type = CL_UNORM_INT8;
    160         cl_desc_ga.format.image_channel_order = CL_R;
    161         cl_desc_ga.width = video_info_gauss.width;
    162         cl_desc_ga.height = video_info_gauss.height;
    163         cl_desc_ga.row_pitch = video_info_gauss.strides[0];
    164         image_in_ga[i] = convert_to_climage (context, gaussian_buf, cl_desc_ga, video_info_gauss.offsets[0]);
    165 
    166         XCAM_FAIL_RETURN (
    167             WARNING,
    168             image_in_ga[i]->is_valid (),
    169             XCAM_RETURN_ERROR_MEM,
    170             "cl image kernel(%s) gauss memory[%d] is invalid", get_kernel_name (), i);
    171     }
    172     CLRetinexConfig retinex_config;
    173     retinex_config.log_min = retinex_config_log_min;
    174     retinex_config.log_max = retinex_config_log_max;
    175     retinex_config.gain = 1.0f / (retinex_config.log_max - retinex_config.log_min);
    176     retinex_config.width = (float)video_info_in.width;
    177     retinex_config.height = (float)video_info_in.height;
    178 
    179     //set args;
    180     args.push_back (new CLMemArgument (image_in));
    181     args.push_back (new CLMemArgument (image_in_uv));
    182     for (uint32_t i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) {
    183         args.push_back (new CLMemArgument (image_in_ga[i]));
    184     }
    185     args.push_back (new CLMemArgument (image_out));
    186     args.push_back (new CLMemArgument (image_out_uv));
    187     args.push_back (new CLArgumentT<CLRetinexConfig> (retinex_config));
    188 
    189     work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
    190     work_size.global[0] = video_info_out.width / 4;
    191     work_size.global[1] = video_info_out.height;
    192     work_size.local[0] = 16;
    193     work_size.local[1] = 2;
    194 
    195     return XCAM_RETURN_NO_ERROR;
    196 }
    197 
    198 CLRetinexImageHandler::CLRetinexImageHandler (const SmartPtr<CLContext> &context, const char *name)
    199     : CLImageHandler (context, name)
    200     , _scaler_factor(XCAM_RETINEX_SCALER_FACTOR)
    201 {
    202 }
    203 
    204 void
    205 CLRetinexImageHandler::emit_stop ()
    206 {
    207     if (_scaler_buf_pool.ptr ())
    208         _scaler_buf_pool->stop ();
    209 }
    210 
    211 XCamReturn
    212 CLRetinexImageHandler::prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output)
    213 {
    214     CLImageHandler::prepare_output_buf(input, output);
    215     XCamReturn ret = XCAM_RETURN_NO_ERROR;
    216     ret = prepare_scaler_buf (input->get_video_info ());
    217     XCAM_FAIL_RETURN(
    218         WARNING,
    219         ret == XCAM_RETURN_NO_ERROR,
    220         ret,
    221         "CLRetinexImageHandler prepare scaled video buf failed");
    222 
    223     return XCAM_RETURN_NO_ERROR;
    224 }
    225 
    226 XCamReturn
    227 CLRetinexImageHandler::prepare_scaler_buf (const VideoBufferInfo &video_info)
    228 {
    229     if (!_scaler_buf_pool.ptr ()) {
    230         SmartPtr<CLContext> context = get_context ();
    231         VideoBufferInfo scaler_video_info;
    232         uint32_t new_width = XCAM_ALIGN_UP ((uint32_t)(video_info.width * _scaler_factor), 8);
    233         uint32_t new_height = XCAM_ALIGN_UP ((uint32_t)(video_info.height * _scaler_factor), 4);
    234 
    235         scaler_video_info.init (video_info.format, new_width, new_height);
    236 
    237         _scaler_buf_pool = new CLVideoBufferPool ();
    238         XCAM_ASSERT (_scaler_buf_pool.ptr ());
    239         _scaler_buf_pool->set_video_info (scaler_video_info);
    240         _scaler_buf_pool->reserve (XCAM_RETINEX_MAX_SCALE + 1);
    241 
    242         _scaler_buf1 = _scaler_buf_pool->get_buffer (_scaler_buf_pool);
    243         XCAM_ASSERT (_scaler_buf1.ptr ());
    244 
    245         for (int i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) {
    246             _gaussian_buf[i] = _scaler_buf_pool->get_buffer (_scaler_buf_pool);
    247             XCAM_ASSERT (_gaussian_buf[i].ptr ());
    248         }
    249     }
    250 
    251     return XCAM_RETURN_NO_ERROR;
    252 }
    253 
    254 bool
    255 CLRetinexImageHandler::set_retinex_kernel(SmartPtr<CLRetinexImageKernel> &kernel)
    256 {
    257     SmartPtr<CLImageKernel> image_kernel = kernel;
    258     add_kernel (image_kernel);
    259     _retinex_kernel = kernel;
    260     return true;
    261 }
    262 
    263 bool
    264 CLRetinexImageHandler::set_retinex_scaler_kernel(SmartPtr<CLRetinexScalerImageKernel> &kernel)
    265 {
    266     SmartPtr<CLImageKernel> image_kernel = kernel;
    267     add_kernel (image_kernel);
    268     _retinex_scaler_kernel = kernel;
    269     return true;
    270 }
    271 
    272 static SmartPtr<CLRetinexScalerImageKernel>
    273 create_kernel_retinex_scaler (
    274     const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> handler)
    275 {
    276     SmartPtr<CLRetinexScalerImageKernel> kernel;
    277 
    278     kernel = new CLRetinexScalerImageKernel (context, CL_IMAGE_SCALER_NV12_Y, handler);
    279     XCAM_ASSERT (kernel.ptr ());
    280     XCAM_FAIL_RETURN (
    281         ERROR, kernel->build_kernel (kernel_retinex_info[KernelScaler], NULL) == XCAM_RETURN_NO_ERROR, NULL,
    282         "build retinex scaler kernel(%s) failed", kernel_retinex_info[KernelScaler].kernel_name);
    283 
    284     XCAM_ASSERT (kernel->is_valid ());
    285     return kernel;
    286 }
    287 
    288 static SmartPtr<CLRetinexGaussImageKernel>
    289 create_kernel_retinex_gaussian (
    290     const SmartPtr<CLContext> &context,
    291     SmartPtr<CLRetinexImageHandler> handler,
    292     uint32_t index,
    293     uint32_t radius, float sigma)
    294 {
    295     SmartPtr<CLRetinexGaussImageKernel> kernel;
    296     char build_options[1024];
    297 
    298     xcam_mem_clear (build_options);
    299     snprintf (build_options, sizeof (build_options), " -DGAUSS_RADIUS=%d ", radius);
    300 
    301     kernel = new CLRetinexGaussImageKernel (context, handler, index, radius, sigma);
    302     XCAM_ASSERT (kernel.ptr ());
    303     XCAM_FAIL_RETURN (
    304         ERROR, kernel->build_kernel (kernel_retinex_info[KernelGaussian], build_options) == XCAM_RETURN_NO_ERROR, NULL,
    305         "build retinex gaussian kernel(%s) failed", kernel_retinex_info[KernelGaussian].kernel_name);
    306 
    307     XCAM_ASSERT (kernel->is_valid ());
    308 
    309     return kernel;
    310 }
    311 
    312 static SmartPtr<CLRetinexImageKernel>
    313 create_kernel_retinex (const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> handler)
    314 {
    315     SmartPtr<CLRetinexImageKernel> kernel;
    316     char build_options[1024];
    317 
    318     xcam_mem_clear (build_options);
    319     snprintf (build_options, sizeof (build_options), " -DRETINEX_SCALE_SIZE=%d ", XCAM_RETINEX_MAX_SCALE);
    320 
    321     kernel = new CLRetinexImageKernel (context, handler);
    322     XCAM_ASSERT (kernel.ptr ());
    323     XCAM_FAIL_RETURN (
    324         ERROR, kernel->build_kernel (kernel_retinex_info[KernelRetinex], build_options) == XCAM_RETURN_NO_ERROR, NULL,
    325         "build retinex kernel(%s) failed", kernel_retinex_info[KernelRetinex].kernel_name);
    326 
    327     XCAM_ASSERT (kernel->is_valid ());
    328     return kernel;
    329 }
    330 
    331 SmartPtr<CLImageHandler>
    332 create_cl_retinex_image_handler (const SmartPtr<CLContext> &context)
    333 {
    334     SmartPtr<CLRetinexImageHandler> retinex_handler;
    335 
    336     SmartPtr<CLRetinexScalerImageKernel> retinex_scaler_kernel;
    337     SmartPtr<CLRetinexImageKernel> retinex_kernel;
    338 
    339     retinex_handler = new CLRetinexImageHandler (context, "cl_handler_retinex");
    340     retinex_scaler_kernel = create_kernel_retinex_scaler (context, retinex_handler);
    341     XCAM_FAIL_RETURN (
    342         ERROR,
    343         retinex_scaler_kernel.ptr () && retinex_scaler_kernel->is_valid (),
    344         NULL,
    345         "Retinex handler create scaler kernel failed");
    346     retinex_handler->set_retinex_scaler_kernel (retinex_scaler_kernel);
    347 
    348     for (uint32_t i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) {
    349         SmartPtr<CLImageKernel> retinex_gauss_kernel;
    350         retinex_gauss_kernel = create_kernel_retinex_gaussian (
    351                                    context, retinex_handler, i, retinex_gauss_scale [i], retinex_gauss_sigma [i]);
    352         XCAM_FAIL_RETURN (
    353             ERROR,
    354             retinex_gauss_kernel.ptr () && retinex_gauss_kernel->is_valid (),
    355             NULL,
    356             "Retinex handler create gaussian kernel failed");
    357         retinex_handler->add_kernel (retinex_gauss_kernel);
    358     }
    359 
    360     retinex_kernel = create_kernel_retinex (context, retinex_handler);
    361     XCAM_FAIL_RETURN (
    362         ERROR,
    363         retinex_kernel.ptr () && retinex_kernel->is_valid (),
    364         NULL,
    365         "Retinex handler create retinex kernel failed");
    366     retinex_handler->set_retinex_kernel (retinex_kernel);
    367 
    368     return retinex_handler;
    369 }
    370 
    371 }
    372