| /* |
| * cl_tonemapping_handler.cpp - CL tonemapping handler |
| * |
| * Copyright (c) 2015 Intel Corporation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * Author: Wu Junkai <[email protected]> |
| */ |
| |
| #include "cl_utils.h" |
| #include "cl_tonemapping_handler.h" |
| |
| namespace XCam { |
| |
| static const XCamKernelInfo kernel_tonemapping_info = { |
| "kernel_tonemapping", |
| #include "kernel_tonemapping.clx" |
| , 0, |
| }; |
| |
| CLTonemappingImageKernel::CLTonemappingImageKernel ( |
| const SmartPtr<CLContext> &context, const char *name) |
| : CLImageKernel (context, name) |
| { |
| } |
| |
| CLTonemappingImageHandler::CLTonemappingImageHandler ( |
| const SmartPtr<CLContext> &context, const char *name) |
| : CLImageHandler (context, name) |
| , _output_format (XCAM_PIX_FMT_SGRBG16_planar) |
| { |
| _wb_config.r_gain = 1.0; |
| _wb_config.gr_gain = 1.0; |
| _wb_config.gb_gain = 1.0; |
| _wb_config.b_gain = 1.0; |
| } |
| |
| bool |
| CLTonemappingImageHandler::set_tonemapping_kernel(SmartPtr<CLTonemappingImageKernel> &kernel) |
| { |
| SmartPtr<CLImageKernel> image_kernel = kernel; |
| add_kernel (image_kernel); |
| _tonemapping_kernel = kernel; |
| return true; |
| } |
| |
| bool |
| CLTonemappingImageHandler::set_wb_config (const XCam3aResultWhiteBalance &wb) |
| { |
| _wb_config.r_gain = (float)wb.r_gain; |
| _wb_config.gr_gain = (float)wb.gr_gain; |
| _wb_config.gb_gain = (float)wb.gb_gain; |
| _wb_config.b_gain = (float)wb.b_gain; |
| return true; |
| } |
| |
| XCamReturn |
| CLTonemappingImageHandler::prepare_buffer_pool_video_info ( |
| const VideoBufferInfo &input, |
| VideoBufferInfo &output) |
| { |
| bool format_inited = output.init (_output_format, input.width, input.height); |
| |
| XCAM_FAIL_RETURN ( |
| WARNING, |
| format_inited, |
| XCAM_RETURN_ERROR_PARAM, |
| "CL image handler(%s) output format(%s) unsupported", |
| XCAM_STR(get_name ()), xcam_fourcc_to_string (_output_format)); |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| XCamReturn |
| CLTonemappingImageHandler::prepare_parameters ( |
| SmartPtr<VideoBuffer> &input, |
| SmartPtr<VideoBuffer> &output) |
| { |
| SmartPtr<CLContext> context = get_context (); |
| float y_max = 0.0f, y_target = 0.0f; |
| CLArgList args; |
| CLWorkSize work_size; |
| XCAM_ASSERT (_tonemapping_kernel.ptr ()); |
| |
| const VideoBufferInfo &video_info = input->get_video_info (); |
| |
| CLImageDesc desc; |
| desc.format.image_channel_order = CL_RGBA; |
| desc.format.image_channel_data_type = CL_UNORM_INT16; |
| desc.width = video_info.aligned_width / 4; |
| desc.height = video_info.aligned_height * 4; |
| desc.row_pitch = video_info.strides[0]; |
| desc.array_size = 4; |
| desc.slice_pitch = video_info.strides [0] * video_info.aligned_height; |
| |
| SmartPtr<CLImage> image_in = convert_to_climage (context, input, desc); |
| SmartPtr<CLImage> image_out = convert_to_climage (context, output, desc); |
| int image_height = video_info.aligned_height; |
| |
| XCAM_FAIL_RETURN ( |
| WARNING, |
| image_in->is_valid () && image_out->is_valid (), |
| XCAM_RETURN_ERROR_MEM, |
| "cl image handler(%s) in/out memory not available", XCAM_STR(get_name ())); |
| |
| SmartPtr<X3aStats> stats; |
| SmartPtr<CLVideoBuffer> cl_buf = input.dynamic_cast_ptr<CLVideoBuffer> (); |
| if (cl_buf.ptr ()) { |
| stats = cl_buf->find_3a_stats (); |
| } |
| #if HAVE_LIBDRM |
| else { |
| SmartPtr<DrmBoBuffer> bo_buf = input.dynamic_cast_ptr<DrmBoBuffer> (); |
| stats = bo_buf->find_3a_stats (); |
| } |
| #endif |
| XCAM_FAIL_RETURN ( |
| ERROR, |
| stats.ptr (), |
| XCAM_RETURN_ERROR_MEM, |
| "CLTonemappingImageKernel find_3a_stats failed"); |
| XCam3AStats *stats_ptr = stats->get_stats (); |
| XCAM_ASSERT (stats_ptr); |
| |
| int pixel_totalnum = stats_ptr->info.aligned_width * stats_ptr->info.aligned_height; |
| int pixel_num = 0; |
| int hist_bin_count = 1 << stats_ptr->info.bit_depth; |
| int64_t cumulative_value = 0; |
| int saturated_thresh = pixel_totalnum * 0.003f; |
| int percent_90_thresh = pixel_totalnum * 0.1f; |
| int medium_thresh = pixel_totalnum * 0.5f; |
| float y_saturated = 0; |
| float y_percent_90 = 0; |
| float y_average = 0; |
| float y_medium = 0; |
| |
| for (int i = (hist_bin_count - 1); i >= 0; i--) |
| { |
| pixel_num += stats_ptr->hist_y[i]; |
| if ((y_saturated == 0) && (pixel_num >= saturated_thresh)) |
| { |
| y_saturated = i; |
| } |
| if ((y_percent_90 == 0) && (pixel_num >= percent_90_thresh)) |
| { |
| y_percent_90 = i; |
| } |
| if ((y_medium == 0) && (pixel_num >= medium_thresh)) |
| { |
| y_medium = i; |
| } |
| cumulative_value += i * stats_ptr->hist_y[i]; |
| } |
| |
| y_average = cumulative_value / pixel_totalnum; |
| |
| if (y_saturated < (hist_bin_count - 1)) { |
| y_saturated = y_saturated + 1; |
| } |
| |
| y_target = (hist_bin_count / y_saturated) * (1.5 * y_medium + 0.5 * y_average) / 2; |
| |
| if (y_target < 4) { |
| y_target = 4; |
| } |
| if ((y_target > y_saturated) || (y_saturated < 4)) { |
| y_target = y_saturated / 4; |
| } |
| |
| y_max = hist_bin_count * (2 * y_saturated + y_target) / y_saturated - y_saturated - y_target; |
| |
| y_target = y_target / pow(2, stats_ptr->info.bit_depth - 8); |
| y_max = y_max / pow(2, stats_ptr->info.bit_depth - 8); |
| |
| //set args; |
| args.push_back (new CLMemArgument (image_in)); |
| args.push_back (new CLMemArgument (image_out)); |
| args.push_back (new CLArgumentT<float> (y_max)); |
| args.push_back (new CLArgumentT<float> (y_target)); |
| args.push_back (new CLArgumentT<int> (image_height)); |
| |
| const CLImageDesc out_info = image_out->get_image_desc (); |
| work_size.dim = XCAM_DEFAULT_IMAGE_DIM; |
| work_size.global[0] = out_info.width; |
| work_size.global[1] = out_info.height / 4; |
| work_size.local[0] = 8; |
| work_size.local[1] = 8; |
| |
| XCAM_ASSERT (_tonemapping_kernel.ptr ()); |
| XCamReturn ret = _tonemapping_kernel->set_arguments (args, work_size); |
| XCAM_FAIL_RETURN ( |
| WARNING, ret == XCAM_RETURN_NO_ERROR, ret, |
| "tone mapping kernel set arguments failed."); |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| |
| SmartPtr<CLImageHandler> |
| create_cl_tonemapping_image_handler (const SmartPtr<CLContext> &context) |
| { |
| SmartPtr<CLTonemappingImageHandler> tonemapping_handler; |
| SmartPtr<CLTonemappingImageKernel> tonemapping_kernel; |
| |
| tonemapping_kernel = new CLTonemappingImageKernel (context, "kernel_tonemapping"); |
| XCAM_ASSERT (tonemapping_kernel.ptr ()); |
| XCAM_FAIL_RETURN ( |
| ERROR, tonemapping_kernel->build_kernel (kernel_tonemapping_info, NULL) == XCAM_RETURN_NO_ERROR, NULL, |
| "build tonemapping kernel(%s) failed", kernel_tonemapping_info.kernel_name); |
| |
| XCAM_ASSERT (tonemapping_kernel->is_valid ()); |
| tonemapping_handler = new CLTonemappingImageHandler(context, "cl_handler_tonemapping"); |
| tonemapping_handler->set_tonemapping_kernel(tonemapping_kernel); |
| |
| return tonemapping_handler; |
| } |
| |
| }; |