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