/* * cl_3d_denoise_handler.cpp - CL 3D noise reduction 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: Wei Zong <wei.zong@intel.com> */ #include "cl_utils.h" #include "cl_3d_denoise_handler.h" namespace XCam { #define CL_3D_DENOISE_MAX_REFERENCE_FRAME_COUNT 3 #define CL_3D_DENOISE_REFERENCE_FRAME_COUNT 3 #define CL_3D_DENOISE_WG_WIDTH 4 #define CL_3D_DENOISE_WG_HEIGHT 16 #define CL_3D_DENOISE_ENABLE_SUBGROUP 1 #define CL_3D_DENOISE_IIR_FILTERING 1 #if CL_3D_DENOISE_ENABLE_SUBGROUP #define KERNEL_3D_DENOISE_NAME "kernel_3d_denoise" #else #define KERNEL_3D_DENOISE_NAME "kernel_3d_denoise_slm" #endif enum { Kernel3DDenoise, Kernel3DDenoiseSLM, }; const XCamKernelInfo kernel_3d_denoise_info[] = { { "kernel_3d_denoise", #include "kernel_3d_denoise.clx" , 0, }, { "kernel_3d_denoise_slm", #include "kernel_3d_denoise_slm.clx" , 0, }, }; CL3DDenoiseImageKernel::CL3DDenoiseImageKernel ( const SmartPtr<CLContext> &context, const char *name, uint32_t channel, SmartPtr<CL3DDenoiseImageHandler> &handler) : CLImageKernel (context, name) , _channel (channel) , _ref_count (CL_3D_DENOISE_REFERENCE_FRAME_COUNT) , _handler (handler) { } XCamReturn CL3DDenoiseImageKernel::prepare_arguments ( CLArgList &args, CLWorkSize &work_size) { SmartPtr<CLContext> context = get_context (); SmartPtr<VideoBuffer> input = _handler->get_input_buf (); SmartPtr<VideoBuffer> output = _handler->get_output_buf (); const VideoBufferInfo & video_info_in = input->get_video_info (); const VideoBufferInfo & video_info_out = output->get_video_info (); uint32_t info_index = 0; if (_channel == CL_IMAGE_CHANNEL_Y) { info_index = 0; } else if (_channel == CL_IMAGE_CHANNEL_UV) { info_index = 1; } CLImageDesc cl_desc_in, cl_desc_out; cl_desc_in.format.image_channel_order = CL_RGBA; #if CL_3D_DENOISE_ENABLE_SUBGROUP cl_desc_in.format.image_channel_data_type = CL_UNSIGNED_INT16; cl_desc_in.width = XCAM_ALIGN_UP (video_info_in.width, 8) / 8; #else cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8; cl_desc_in.width = XCAM_ALIGN_UP (video_info_in.width, 4) / 4; #endif cl_desc_in.height = video_info_in.height >> info_index; cl_desc_in.row_pitch = video_info_in.strides[info_index]; cl_desc_out.format.image_channel_order = CL_RGBA; #if CL_3D_DENOISE_ENABLE_SUBGROUP cl_desc_out.format.image_channel_data_type = CL_UNSIGNED_INT16; cl_desc_out.width = XCAM_ALIGN_UP (video_info_out.width, 8) / 8; #else cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8; cl_desc_out.width = XCAM_ALIGN_UP (video_info_out.width, 4) / 4; #endif cl_desc_out.height = video_info_out.height >> info_index; cl_desc_out.row_pitch = video_info_out.strides[info_index]; _ref_count = _handler->get_ref_framecount (); float gain = 5.0f / (_handler->get_denoise_config ().gain + 0.0001f); float threshold = 2.0f * _handler->get_denoise_config ().threshold[info_index]; SmartPtr<CLImage> image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[info_index]); SmartPtr<CLImage> image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[info_index]); XCAM_ASSERT (image_in->is_valid () && image_out->is_valid ()); XCAM_FAIL_RETURN ( WARNING, image_in->is_valid () && image_out->is_valid (), XCAM_RETURN_ERROR_MEM, "cl image kernel(%s) in/out memory not available", get_kernel_name ()); if (_image_in_list.size () < _ref_count) { while (_image_in_list.size () < _ref_count) { _image_in_list.push_back (image_in); } } else { _image_in_list.pop_back (); _image_in_list.push_front (image_in); } if (!_image_out_prev.ptr ()) { _image_out_prev = image_in; } //set args; args.push_back (new CLArgumentT<float> (gain)); args.push_back (new CLArgumentT<float> (threshold)); args.push_back (new CLMemArgument (_image_out_prev)); args.push_back (new CLMemArgument (image_out)); uint8_t image_list_count = _image_in_list.size (); for (std::list<SmartPtr<CLImage>>::iterator it = _image_in_list.begin (); it != _image_in_list.end (); it++) { args.push_back (new CLMemArgument (*it)); } //backup enough buffers for kernel for (; image_list_count < CL_3D_DENOISE_MAX_REFERENCE_FRAME_COUNT; ++image_list_count) { args.push_back (new CLMemArgument (image_in)); } //set worksize work_size.dim = XCAM_DEFAULT_IMAGE_DIM; #if CL_3D_DENOISE_ENABLE_SUBGROUP work_size.local[0] = CL_3D_DENOISE_WG_WIDTH; work_size.local[1] = CL_3D_DENOISE_WG_HEIGHT; work_size.global[0] = XCAM_ALIGN_UP (cl_desc_in.width, work_size.local[0]); work_size.global[1] = (cl_desc_in.height + work_size.local[1] - 1) / work_size.local[1] * work_size.local[1]; #else work_size.local[0] = 8; work_size.local[1] = 1; work_size.global[0] = XCAM_ALIGN_UP (cl_desc_in.width, work_size.local[0]); work_size.global[1] = XCAM_ALIGN_UP(cl_desc_in.height / 8, 8 * work_size.local[1]); #endif _image_out_prev = image_out; return XCAM_RETURN_NO_ERROR; } CL3DDenoiseImageHandler::CL3DDenoiseImageHandler (const SmartPtr<CLContext> &context, const char *name) : CLImageHandler (context, name) , _ref_count (CL_3D_DENOISE_REFERENCE_FRAME_COUNT - 2) { _config.gain = 1.0f; _config.threshold[0] = 0.05f; _config.threshold[1] = 0.05f; } bool CL3DDenoiseImageHandler::set_ref_framecount (const uint8_t count) { _ref_count = count; return true; } bool CL3DDenoiseImageHandler::set_denoise_config (const XCam3aResultTemporalNoiseReduction& config) { _config = config; return true; } XCamReturn CL3DDenoiseImageHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) { _input_buf = input; _output_buf = output; return XCAM_RETURN_NO_ERROR; } static SmartPtr<CLImageKernel> create_3d_denoise_kernel ( const SmartPtr<CLContext> &context, SmartPtr<CL3DDenoiseImageHandler> handler, uint32_t channel, uint8_t ref_count) { char build_options[1024]; xcam_mem_clear (build_options); snprintf (build_options, sizeof (build_options), " -DREFERENCE_FRAME_COUNT=%d" " -DWORKGROUP_WIDTH=%d" " -DWORKGROUP_HEIGHT=%d" " -DENABLE_IIR_FILERING=%d", ref_count, CL_3D_DENOISE_WG_WIDTH, CL_3D_DENOISE_WG_HEIGHT, CL_3D_DENOISE_IIR_FILTERING); #if CL_3D_DENOISE_ENABLE_SUBGROUP int kernel_index = Kernel3DDenoise; #else int kernel_index = Kernel3DDenoiseSLM; #endif SmartPtr<CLImageKernel> kernel = new CL3DDenoiseImageKernel (context, KERNEL_3D_DENOISE_NAME, channel, handler); XCAM_ASSERT (kernel.ptr ()); XCAM_FAIL_RETURN ( ERROR, kernel->build_kernel (kernel_3d_denoise_info[kernel_index], build_options) == XCAM_RETURN_NO_ERROR, NULL, "build 3d denoise kernel failed"); return kernel; } SmartPtr<CLImageHandler> create_cl_3d_denoise_image_handler ( const SmartPtr<CLContext> &context, uint32_t channel, uint8_t ref_count) { SmartPtr<CL3DDenoiseImageHandler> denoise_handler; SmartPtr<CLImageKernel> denoise_kernel; denoise_handler = new CL3DDenoiseImageHandler (context, "cl_3d_denoise_handler"); XCAM_ASSERT (denoise_handler.ptr ()); denoise_handler->set_ref_framecount (ref_count); if (channel & CL_IMAGE_CHANNEL_Y) { denoise_kernel = create_3d_denoise_kernel (context, denoise_handler, CL_IMAGE_CHANNEL_Y, ref_count); XCAM_FAIL_RETURN ( ERROR, denoise_kernel.ptr (), NULL, "3D denoise handler create Y channel kernel failed."); denoise_handler->add_kernel (denoise_kernel); } if (channel & CL_IMAGE_CHANNEL_UV) { denoise_kernel = create_3d_denoise_kernel (context, denoise_handler, CL_IMAGE_CHANNEL_UV, ref_count); XCAM_FAIL_RETURN ( ERROR, denoise_kernel.ptr (), NULL, "3D denoise handler create UV channel kernel failed."); denoise_handler->add_kernel (denoise_kernel); } return denoise_handler; } };