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