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