Home | History | Annotate | Download | only in ocl
      1 /*
      2  * cl_3d_denoise_handler.cpp - CL 3D noise reduction handler
      3  *
      4  *  Copyright (c) 2015 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: Wei Zong <wei.zong (at) intel.com>
     19  */
     20 
     21 #include "cl_utils.h"
     22 #include "cl_3d_denoise_handler.h"
     23 
     24 namespace XCam {
     25 
     26 #define CL_3D_DENOISE_MAX_REFERENCE_FRAME_COUNT  3
     27 #define CL_3D_DENOISE_REFERENCE_FRAME_COUNT      3
     28 #define CL_3D_DENOISE_WG_WIDTH   4
     29 #define CL_3D_DENOISE_WG_HEIGHT  16
     30 
     31 #define CL_3D_DENOISE_ENABLE_SUBGROUP 1
     32 #define CL_3D_DENOISE_IIR_FILTERING   1
     33 
     34 #if CL_3D_DENOISE_ENABLE_SUBGROUP
     35 #define KERNEL_3D_DENOISE_NAME "kernel_3d_denoise"
     36 #else
     37 #define KERNEL_3D_DENOISE_NAME "kernel_3d_denoise_slm"
     38 #endif
     39 
     40 enum {
     41     Kernel3DDenoise,
     42     Kernel3DDenoiseSLM,
     43 };
     44 
     45 const XCamKernelInfo kernel_3d_denoise_info[] = {
     46     {
     47         "kernel_3d_denoise",
     48 #include "kernel_3d_denoise.clx"
     49         , 0,
     50     },
     51 
     52     {
     53         "kernel_3d_denoise_slm",
     54 #include "kernel_3d_denoise_slm.clx"
     55         , 0,
     56     },
     57 };
     58 
     59 CL3DDenoiseImageKernel::CL3DDenoiseImageKernel (
     60     const SmartPtr<CLContext> &context,
     61     const char *name,
     62     uint32_t channel,
     63     SmartPtr<CL3DDenoiseImageHandler> &handler)
     64     : CLImageKernel (context, name)
     65     , _channel (channel)
     66     , _ref_count (CL_3D_DENOISE_REFERENCE_FRAME_COUNT)
     67     , _handler (handler)
     68 {
     69 }
     70 
     71 XCamReturn
     72 CL3DDenoiseImageKernel::prepare_arguments (
     73     CLArgList &args, CLWorkSize &work_size)
     74 {
     75     SmartPtr<CLContext> context = get_context ();
     76 
     77     SmartPtr<VideoBuffer> input = _handler->get_input_buf ();
     78     SmartPtr<VideoBuffer> output = _handler->get_output_buf ();
     79 
     80     const VideoBufferInfo & video_info_in = input->get_video_info ();
     81     const VideoBufferInfo & video_info_out = output->get_video_info ();
     82 
     83     uint32_t info_index = 0;
     84     if (_channel == CL_IMAGE_CHANNEL_Y) {
     85         info_index = 0;
     86     } else if (_channel == CL_IMAGE_CHANNEL_UV) {
     87         info_index = 1;
     88     }
     89 
     90     CLImageDesc cl_desc_in, cl_desc_out;
     91     cl_desc_in.format.image_channel_order = CL_RGBA;
     92 #if CL_3D_DENOISE_ENABLE_SUBGROUP
     93     cl_desc_in.format.image_channel_data_type = CL_UNSIGNED_INT16;
     94     cl_desc_in.width = XCAM_ALIGN_UP (video_info_in.width, 8) / 8;
     95 #else
     96     cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8;
     97     cl_desc_in.width = XCAM_ALIGN_UP (video_info_in.width, 4) / 4;
     98 #endif
     99     cl_desc_in.height = video_info_in.height >> info_index;
    100     cl_desc_in.row_pitch = video_info_in.strides[info_index];
    101 
    102     cl_desc_out.format.image_channel_order = CL_RGBA;
    103 #if CL_3D_DENOISE_ENABLE_SUBGROUP
    104     cl_desc_out.format.image_channel_data_type = CL_UNSIGNED_INT16;
    105     cl_desc_out.width = XCAM_ALIGN_UP (video_info_out.width, 8) / 8;
    106 #else
    107     cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8;
    108     cl_desc_out.width = XCAM_ALIGN_UP (video_info_out.width, 4) / 4;
    109 #endif
    110     cl_desc_out.height = video_info_out.height >> info_index;
    111     cl_desc_out.row_pitch = video_info_out.strides[info_index];
    112 
    113     _ref_count = _handler->get_ref_framecount ();
    114     float gain = 5.0f / (_handler->get_denoise_config ().gain + 0.0001f);
    115     float threshold = 2.0f * _handler->get_denoise_config ().threshold[info_index];
    116 
    117     SmartPtr<CLImage> image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[info_index]);
    118     SmartPtr<CLImage> image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[info_index]);
    119     XCAM_ASSERT (image_in->is_valid () && image_out->is_valid ());
    120     XCAM_FAIL_RETURN (
    121         WARNING,
    122         image_in->is_valid () && image_out->is_valid (),
    123         XCAM_RETURN_ERROR_MEM,
    124         "cl image kernel(%s) in/out memory not available", get_kernel_name ());
    125 
    126     if (_image_in_list.size () < _ref_count) {
    127         while (_image_in_list.size () < _ref_count) {
    128             _image_in_list.push_back (image_in);
    129         }
    130     } else {
    131         _image_in_list.pop_back ();
    132         _image_in_list.push_front (image_in);
    133     }
    134 
    135     if (!_image_out_prev.ptr ()) {
    136         _image_out_prev = image_in;
    137     }
    138 
    139     //set args;
    140     args.push_back (new CLArgumentT<float> (gain));
    141     args.push_back (new CLArgumentT<float> (threshold));
    142     args.push_back (new CLMemArgument (_image_out_prev));
    143     args.push_back (new CLMemArgument (image_out));
    144 
    145     uint8_t image_list_count = _image_in_list.size ();
    146     for (std::list<SmartPtr<CLImage>>::iterator it = _image_in_list.begin (); it != _image_in_list.end (); it++) {
    147         args.push_back (new CLMemArgument (*it));
    148     }
    149 
    150     //backup enough buffers for kernel
    151     for (; image_list_count < CL_3D_DENOISE_MAX_REFERENCE_FRAME_COUNT; ++image_list_count) {
    152         args.push_back (new CLMemArgument (image_in));
    153     }
    154 
    155     //set worksize
    156     work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
    157 #if CL_3D_DENOISE_ENABLE_SUBGROUP
    158     work_size.local[0] = CL_3D_DENOISE_WG_WIDTH;
    159     work_size.local[1] = CL_3D_DENOISE_WG_HEIGHT;
    160     work_size.global[0] = XCAM_ALIGN_UP (cl_desc_in.width, work_size.local[0]);
    161     work_size.global[1] = (cl_desc_in.height +  work_size.local[1] - 1) / work_size.local[1] * work_size.local[1];
    162 #else
    163     work_size.local[0] = 8;
    164     work_size.local[1] = 1;
    165     work_size.global[0] = XCAM_ALIGN_UP (cl_desc_in.width, work_size.local[0]);
    166     work_size.global[1] = XCAM_ALIGN_UP(cl_desc_in.height / 8, 8 * work_size.local[1]);
    167 #endif
    168 
    169     _image_out_prev = image_out;
    170 
    171     return XCAM_RETURN_NO_ERROR;
    172 }
    173 
    174 CL3DDenoiseImageHandler::CL3DDenoiseImageHandler (const SmartPtr<CLContext> &context, const char *name)
    175     : CLImageHandler (context, name)
    176     , _ref_count (CL_3D_DENOISE_REFERENCE_FRAME_COUNT - 2)
    177 {
    178     _config.gain = 1.0f;
    179     _config.threshold[0] = 0.05f;
    180     _config.threshold[1] = 0.05f;
    181 }
    182 
    183 bool
    184 CL3DDenoiseImageHandler::set_ref_framecount (const uint8_t count)
    185 {
    186     _ref_count = count;
    187 
    188     return true;
    189 }
    190 
    191 bool
    192 CL3DDenoiseImageHandler::set_denoise_config (const XCam3aResultTemporalNoiseReduction& config)
    193 {
    194     _config = config;
    195 
    196     return true;
    197 }
    198 
    199 XCamReturn
    200 CL3DDenoiseImageHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output)
    201 {
    202     _input_buf = input;
    203     _output_buf = output;
    204     return XCAM_RETURN_NO_ERROR;
    205 }
    206 
    207 static SmartPtr<CLImageKernel>
    208 create_3d_denoise_kernel (
    209     const SmartPtr<CLContext> &context, SmartPtr<CL3DDenoiseImageHandler> handler,
    210     uint32_t channel, uint8_t ref_count)
    211 {
    212     char build_options[1024];
    213     xcam_mem_clear (build_options);
    214 
    215     snprintf (build_options, sizeof (build_options),
    216               " -DREFERENCE_FRAME_COUNT=%d"
    217               " -DWORKGROUP_WIDTH=%d"
    218               " -DWORKGROUP_HEIGHT=%d"
    219               " -DENABLE_IIR_FILERING=%d",
    220               ref_count,
    221               CL_3D_DENOISE_WG_WIDTH,
    222               CL_3D_DENOISE_WG_HEIGHT,
    223               CL_3D_DENOISE_IIR_FILTERING);
    224 
    225 #if CL_3D_DENOISE_ENABLE_SUBGROUP
    226     int kernel_index = Kernel3DDenoise;
    227 #else
    228     int kernel_index = Kernel3DDenoiseSLM;
    229 #endif
    230 
    231     SmartPtr<CLImageKernel> kernel =
    232         new CL3DDenoiseImageKernel (context, KERNEL_3D_DENOISE_NAME, channel, handler);
    233     XCAM_ASSERT (kernel.ptr ());
    234     XCAM_FAIL_RETURN (
    235         ERROR, kernel->build_kernel (kernel_3d_denoise_info[kernel_index], build_options) == XCAM_RETURN_NO_ERROR,
    236         NULL, "build 3d denoise kernel failed");
    237     return kernel;
    238 }
    239 
    240 SmartPtr<CLImageHandler>
    241 create_cl_3d_denoise_image_handler (
    242     const SmartPtr<CLContext> &context, uint32_t channel, uint8_t ref_count)
    243 {
    244     SmartPtr<CL3DDenoiseImageHandler> denoise_handler;
    245     SmartPtr<CLImageKernel> denoise_kernel;
    246 
    247     denoise_handler = new CL3DDenoiseImageHandler (context, "cl_3d_denoise_handler");
    248     XCAM_ASSERT (denoise_handler.ptr ());
    249     denoise_handler->set_ref_framecount (ref_count);
    250 
    251     if (channel & CL_IMAGE_CHANNEL_Y) {
    252         denoise_kernel = create_3d_denoise_kernel (context, denoise_handler, CL_IMAGE_CHANNEL_Y, ref_count);
    253         XCAM_FAIL_RETURN (
    254             ERROR, denoise_kernel.ptr (), NULL, "3D denoise handler create Y channel kernel failed.");
    255 
    256         denoise_handler->add_kernel (denoise_kernel);
    257     }
    258 
    259     if (channel & CL_IMAGE_CHANNEL_UV) {
    260         denoise_kernel = create_3d_denoise_kernel (context, denoise_handler, CL_IMAGE_CHANNEL_UV, ref_count);
    261         XCAM_FAIL_RETURN (
    262             ERROR, denoise_kernel.ptr (), NULL, "3D denoise handler create UV channel kernel failed.");
    263 
    264         denoise_handler->add_kernel (denoise_kernel);
    265     }
    266 
    267     return denoise_handler;
    268 }
    269 };
    270