/* * cl_retinex_handler.cpp - CL retinex handler * * Copyright (c) 2016 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: wangfei <feix.w.wang@intel.com> * Wind Yuan <feng.yuan@intel.com> */ #include "cl_utils.h" #include "cl_retinex_handler.h" #include <algorithm> #include "cl_device.h" namespace XCam { static uint32_t retinex_gauss_scale [3] = {2, 8, 20}; //{20, 60, 150}; static float retinex_gauss_sigma [3] = {2.0f, 8.0f, 20.0f}; //{12.0f, 40.0f, 120.0f}; static float retinex_config_log_min = -0.12f; // -0.18f static float retinex_config_log_max = 0.18f; //0.2f enum { KernelScaler = 0, KernelGaussian, KernelRetinex, }; const static XCamKernelInfo kernel_retinex_info [] = { { "kernel_image_scaler", #include "kernel_image_scaler.clx" , 0, }, { "kernel_gauss", #include "kernel_gauss.clx" , 0, }, { "kernel_retinex", #include "kernel_retinex.clx" , 0, }, }; CLRetinexScalerImageKernel::CLRetinexScalerImageKernel ( const SmartPtr<CLContext> &context, const CLImageScalerMemoryLayout mem_layout, SmartPtr<CLRetinexImageHandler> &retinex) : CLScalerKernel (context, mem_layout) , _retinex(retinex) { } SmartPtr<VideoBuffer> CLRetinexScalerImageKernel::get_input_buffer () { return _retinex->get_input_buf (); } SmartPtr<VideoBuffer> CLRetinexScalerImageKernel::get_output_buffer () { return _retinex->get_scaler_buf1 (); } CLRetinexGaussImageKernel::CLRetinexGaussImageKernel ( const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> &retinex, uint32_t index, uint32_t radius, float sigma) : CLGaussImageKernel (context, radius, sigma) , _retinex (retinex) , _index (index) { } SmartPtr<VideoBuffer> CLRetinexGaussImageKernel::get_input_buf () { return _retinex->get_scaler_buf1 (); } SmartPtr<VideoBuffer> CLRetinexGaussImageKernel::get_output_buf () { return _retinex->get_gaussian_buf (_index); } CLRetinexImageKernel::CLRetinexImageKernel (const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> &retinex) : CLImageKernel (context, "kernel_retinex"), _retinex (retinex) { } XCamReturn CLRetinexImageKernel::prepare_arguments ( CLArgList &args, CLWorkSize &work_size) { SmartPtr<CLContext> context = get_context (); SmartPtr<VideoBuffer> input = _retinex->get_input_buf (); SmartPtr<VideoBuffer> output = _retinex->get_output_buf (); const VideoBufferInfo & video_info_in = input->get_video_info (); const VideoBufferInfo & video_info_out = output->get_video_info (); SmartPtr<CLImage> image_in, image_in_uv; SmartPtr<CLImage> image_out, image_out_uv; SmartPtr<CLImage> image_in_ga[XCAM_RETINEX_MAX_SCALE]; CLImageDesc cl_desc_in, cl_desc_out, cl_desc_ga; cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8; //CL_UNSIGNED_INT32; cl_desc_in.format.image_channel_order = CL_RGBA; cl_desc_in.width = video_info_in.width / 4; // 16; cl_desc_in.height = video_info_in.height; cl_desc_in.row_pitch = video_info_in.strides[0]; image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[0]); cl_desc_in.height = video_info_in.height / 2; cl_desc_in.row_pitch = video_info_in.strides[1]; image_in_uv = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[1]); cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8; //CL_UNSIGNED_INT32; cl_desc_out.format.image_channel_order = CL_RGBA; cl_desc_out.width = video_info_out.width / 4; // 16; cl_desc_out.height = video_info_out.height; cl_desc_out.row_pitch = video_info_out.strides[0]; image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[0]); cl_desc_out.height = video_info_out.height / 2; cl_desc_out.row_pitch = video_info_out.strides[1]; image_out_uv = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[1]); XCAM_FAIL_RETURN ( WARNING, image_in->is_valid () && image_in_uv->is_valid () && image_out->is_valid () && image_out_uv->is_valid(), XCAM_RETURN_ERROR_MEM, "cl image kernel(%s) in/out memory not available", get_kernel_name ()); for (uint32_t i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) { SmartPtr<VideoBuffer> gaussian_buf = _retinex->get_gaussian_buf (i); XCAM_ASSERT (gaussian_buf.ptr ()); const VideoBufferInfo & video_info_gauss = gaussian_buf->get_video_info (); cl_desc_ga.format.image_channel_data_type = CL_UNORM_INT8; cl_desc_ga.format.image_channel_order = CL_R; cl_desc_ga.width = video_info_gauss.width; cl_desc_ga.height = video_info_gauss.height; cl_desc_ga.row_pitch = video_info_gauss.strides[0]; image_in_ga[i] = convert_to_climage (context, gaussian_buf, cl_desc_ga, video_info_gauss.offsets[0]); XCAM_FAIL_RETURN ( WARNING, image_in_ga[i]->is_valid (), XCAM_RETURN_ERROR_MEM, "cl image kernel(%s) gauss memory[%d] is invalid", get_kernel_name (), i); } CLRetinexConfig retinex_config; retinex_config.log_min = retinex_config_log_min; retinex_config.log_max = retinex_config_log_max; retinex_config.gain = 1.0f / (retinex_config.log_max - retinex_config.log_min); retinex_config.width = (float)video_info_in.width; retinex_config.height = (float)video_info_in.height; //set args; args.push_back (new CLMemArgument (image_in)); args.push_back (new CLMemArgument (image_in_uv)); for (uint32_t i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) { args.push_back (new CLMemArgument (image_in_ga[i])); } args.push_back (new CLMemArgument (image_out)); args.push_back (new CLMemArgument (image_out_uv)); args.push_back (new CLArgumentT<CLRetinexConfig> (retinex_config)); work_size.dim = XCAM_DEFAULT_IMAGE_DIM; work_size.global[0] = video_info_out.width / 4; work_size.global[1] = video_info_out.height; work_size.local[0] = 16; work_size.local[1] = 2; return XCAM_RETURN_NO_ERROR; } CLRetinexImageHandler::CLRetinexImageHandler (const SmartPtr<CLContext> &context, const char *name) : CLImageHandler (context, name) , _scaler_factor(XCAM_RETINEX_SCALER_FACTOR) { } void CLRetinexImageHandler::emit_stop () { if (_scaler_buf_pool.ptr ()) _scaler_buf_pool->stop (); } XCamReturn CLRetinexImageHandler::prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) { CLImageHandler::prepare_output_buf(input, output); XCamReturn ret = XCAM_RETURN_NO_ERROR; ret = prepare_scaler_buf (input->get_video_info ()); XCAM_FAIL_RETURN( WARNING, ret == XCAM_RETURN_NO_ERROR, ret, "CLRetinexImageHandler prepare scaled video buf failed"); return XCAM_RETURN_NO_ERROR; } XCamReturn CLRetinexImageHandler::prepare_scaler_buf (const VideoBufferInfo &video_info) { if (!_scaler_buf_pool.ptr ()) { SmartPtr<CLContext> context = get_context (); VideoBufferInfo scaler_video_info; uint32_t new_width = XCAM_ALIGN_UP ((uint32_t)(video_info.width * _scaler_factor), 8); uint32_t new_height = XCAM_ALIGN_UP ((uint32_t)(video_info.height * _scaler_factor), 4); scaler_video_info.init (video_info.format, new_width, new_height); _scaler_buf_pool = new CLVideoBufferPool (); XCAM_ASSERT (_scaler_buf_pool.ptr ()); _scaler_buf_pool->set_video_info (scaler_video_info); _scaler_buf_pool->reserve (XCAM_RETINEX_MAX_SCALE + 1); _scaler_buf1 = _scaler_buf_pool->get_buffer (_scaler_buf_pool); XCAM_ASSERT (_scaler_buf1.ptr ()); for (int i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) { _gaussian_buf[i] = _scaler_buf_pool->get_buffer (_scaler_buf_pool); XCAM_ASSERT (_gaussian_buf[i].ptr ()); } } return XCAM_RETURN_NO_ERROR; } bool CLRetinexImageHandler::set_retinex_kernel(SmartPtr<CLRetinexImageKernel> &kernel) { SmartPtr<CLImageKernel> image_kernel = kernel; add_kernel (image_kernel); _retinex_kernel = kernel; return true; } bool CLRetinexImageHandler::set_retinex_scaler_kernel(SmartPtr<CLRetinexScalerImageKernel> &kernel) { SmartPtr<CLImageKernel> image_kernel = kernel; add_kernel (image_kernel); _retinex_scaler_kernel = kernel; return true; } static SmartPtr<CLRetinexScalerImageKernel> create_kernel_retinex_scaler ( const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> handler) { SmartPtr<CLRetinexScalerImageKernel> kernel; kernel = new CLRetinexScalerImageKernel (context, CL_IMAGE_SCALER_NV12_Y, handler); XCAM_ASSERT (kernel.ptr ()); XCAM_FAIL_RETURN ( ERROR, kernel->build_kernel (kernel_retinex_info[KernelScaler], NULL) == XCAM_RETURN_NO_ERROR, NULL, "build retinex scaler kernel(%s) failed", kernel_retinex_info[KernelScaler].kernel_name); XCAM_ASSERT (kernel->is_valid ()); return kernel; } static SmartPtr<CLRetinexGaussImageKernel> create_kernel_retinex_gaussian ( const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> handler, uint32_t index, uint32_t radius, float sigma) { SmartPtr<CLRetinexGaussImageKernel> kernel; char build_options[1024]; xcam_mem_clear (build_options); snprintf (build_options, sizeof (build_options), " -DGAUSS_RADIUS=%d ", radius); kernel = new CLRetinexGaussImageKernel (context, handler, index, radius, sigma); XCAM_ASSERT (kernel.ptr ()); XCAM_FAIL_RETURN ( ERROR, kernel->build_kernel (kernel_retinex_info[KernelGaussian], build_options) == XCAM_RETURN_NO_ERROR, NULL, "build retinex gaussian kernel(%s) failed", kernel_retinex_info[KernelGaussian].kernel_name); XCAM_ASSERT (kernel->is_valid ()); return kernel; } static SmartPtr<CLRetinexImageKernel> create_kernel_retinex (const SmartPtr<CLContext> &context, SmartPtr<CLRetinexImageHandler> handler) { SmartPtr<CLRetinexImageKernel> kernel; char build_options[1024]; xcam_mem_clear (build_options); snprintf (build_options, sizeof (build_options), " -DRETINEX_SCALE_SIZE=%d ", XCAM_RETINEX_MAX_SCALE); kernel = new CLRetinexImageKernel (context, handler); XCAM_ASSERT (kernel.ptr ()); XCAM_FAIL_RETURN ( ERROR, kernel->build_kernel (kernel_retinex_info[KernelRetinex], build_options) == XCAM_RETURN_NO_ERROR, NULL, "build retinex kernel(%s) failed", kernel_retinex_info[KernelRetinex].kernel_name); XCAM_ASSERT (kernel->is_valid ()); return kernel; } SmartPtr<CLImageHandler> create_cl_retinex_image_handler (const SmartPtr<CLContext> &context) { SmartPtr<CLRetinexImageHandler> retinex_handler; SmartPtr<CLRetinexScalerImageKernel> retinex_scaler_kernel; SmartPtr<CLRetinexImageKernel> retinex_kernel; retinex_handler = new CLRetinexImageHandler (context, "cl_handler_retinex"); retinex_scaler_kernel = create_kernel_retinex_scaler (context, retinex_handler); XCAM_FAIL_RETURN ( ERROR, retinex_scaler_kernel.ptr () && retinex_scaler_kernel->is_valid (), NULL, "Retinex handler create scaler kernel failed"); retinex_handler->set_retinex_scaler_kernel (retinex_scaler_kernel); for (uint32_t i = 0; i < XCAM_RETINEX_MAX_SCALE; ++i) { SmartPtr<CLImageKernel> retinex_gauss_kernel; retinex_gauss_kernel = create_kernel_retinex_gaussian ( context, retinex_handler, i, retinex_gauss_scale [i], retinex_gauss_sigma [i]); XCAM_FAIL_RETURN ( ERROR, retinex_gauss_kernel.ptr () && retinex_gauss_kernel->is_valid (), NULL, "Retinex handler create gaussian kernel failed"); retinex_handler->add_kernel (retinex_gauss_kernel); } retinex_kernel = create_kernel_retinex (context, retinex_handler); XCAM_FAIL_RETURN ( ERROR, retinex_kernel.ptr () && retinex_kernel->is_valid (), NULL, "Retinex handler create retinex kernel failed"); retinex_handler->set_retinex_kernel (retinex_kernel); return retinex_handler; } }