/* * cl_gauss_handler.cpp - CL gauss 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_gauss_handler.h" #include <algorithm> #define XCAM_GAUSS_SCALE(radius) ((radius) * 2 + 1) namespace XCam { const static XCamKernelInfo kernel_gauss_info = { "kernel_gauss", #include "kernel_gauss.clx" , 0, }; class CLGaussImageKernelImpl : public CLGaussImageKernel { public: CLGaussImageKernelImpl ( SmartPtr<CLGaussImageHandler> &handler, const SmartPtr<CLContext> &context, uint32_t radius, float sigma); virtual SmartPtr<VideoBuffer> get_input_buf (); virtual SmartPtr<VideoBuffer> get_output_buf (); private: SmartPtr<CLGaussImageHandler> _handler; }; CLGaussImageKernelImpl::CLGaussImageKernelImpl ( SmartPtr<CLGaussImageHandler> &handler, const SmartPtr<CLContext> &context, uint32_t radius, float sigma ) : CLGaussImageKernel (context, radius, sigma) , _handler (handler) { } SmartPtr<VideoBuffer> CLGaussImageKernelImpl::get_input_buf () { return _handler->get_input_buf (); } SmartPtr<VideoBuffer> CLGaussImageKernelImpl::get_output_buf () { return _handler->get_output_buf ();; } CLGaussImageKernel::CLGaussImageKernel ( const SmartPtr<CLContext> &context, uint32_t radius, float sigma) : CLImageKernel (context, "kernel_gauss") , _g_radius (radius) , _g_table (NULL) { set_gaussian(radius, sigma); } CLGaussImageKernel::~CLGaussImageKernel () { xcam_free (_g_table); } bool CLGaussImageKernel::set_gaussian (uint32_t radius, float sigma) { uint32_t i, j; uint32_t scale = XCAM_GAUSS_SCALE (radius); float dis = 0.0f, sum = 0.0f; uint32_t scale_size = scale * scale * sizeof (_g_table[0]); xcam_free (_g_table); _g_table_buffer.release (); _g_radius = radius; _g_table = (float*) xcam_malloc0 (scale_size); XCAM_ASSERT (_g_table); for(i = 0; i < scale; i++) { for(j = 0; j < scale; j++) { dis = ((float)i - radius) * ((float)i - radius) + ((float)j - radius) * ((float)j - radius); _g_table[i * scale + j] = exp(-dis / (2.0f * sigma * sigma)); sum += _g_table[i * scale + j]; } } for(i = 0; i < scale * scale; i++) { _g_table[i] = _g_table[i] / sum; } _g_table_buffer = new CLBuffer( get_context (), scale_size, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR , _g_table); return true; } XCamReturn CLGaussImageKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) { SmartPtr<CLContext> context = get_context (); SmartPtr<VideoBuffer> input = get_input_buf (); SmartPtr<VideoBuffer> output = get_output_buf (); XCAM_FAIL_RETURN ( WARNING, input.ptr () && output.ptr (), XCAM_RETURN_ERROR_MEM, "cl image kernel(%s) get input/output buffer failed", get_kernel_name ()); const VideoBufferInfo & video_info_in = input->get_video_info (); const VideoBufferInfo & video_info_out = output->get_video_info (); CLImageDesc cl_desc_in, cl_desc_out; cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8; cl_desc_in.format.image_channel_order = CL_R; cl_desc_in.width = video_info_in.width; cl_desc_in.height = video_info_in.height; cl_desc_in.row_pitch = video_info_in.strides[0]; SmartPtr<CLImage> image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[0]); cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8; cl_desc_out.format.image_channel_order = CL_RGBA; cl_desc_out.width = video_info_out.width / 4; cl_desc_out.height = video_info_out.height; cl_desc_out.row_pitch = video_info_out.strides[0]; SmartPtr<CLImage> image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[0]); 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 ()); //set args; args.push_back (new CLMemArgument (image_in)); args.push_back (new CLMemArgument (image_out)); args.push_back (new CLMemArgument (_g_table_buffer)); work_size.dim = XCAM_DEFAULT_IMAGE_DIM; work_size.global[0] = XCAM_ALIGN_UP(cl_desc_out.width, 8); work_size.global[1] = XCAM_ALIGN_UP (cl_desc_out.height / 2, 4); work_size.local[0] = 8; work_size.local[1] = 4; return XCAM_RETURN_NO_ERROR; } CLGaussImageHandler::CLGaussImageHandler (const SmartPtr<CLContext> &context, const char *name) : CLImageHandler (context, name) { } bool CLGaussImageHandler::set_gaussian_table (int size, float sigma) { _gauss_kernel->set_gaussian (size, sigma); return true; } bool CLGaussImageHandler::set_gauss_kernel(SmartPtr<CLGaussImageKernel> &kernel) { SmartPtr<CLImageKernel> image_kernel = kernel; add_kernel (image_kernel); _gauss_kernel = kernel; return true; } SmartPtr<CLImageHandler> create_cl_gauss_image_handler (const SmartPtr<CLContext> &context, uint32_t radius, float sigma) { SmartPtr<CLGaussImageHandler> gauss_handler; SmartPtr<CLGaussImageKernel> gauss_kernel; char build_options[1024]; xcam_mem_clear (build_options); snprintf (build_options, sizeof (build_options), " -DGAUSS_RADIUS=%d ", radius); gauss_handler = new CLGaussImageHandler (context, "cl_handler_gauss"); gauss_kernel = new CLGaussImageKernelImpl (gauss_handler, context, radius, sigma); XCAM_ASSERT (gauss_kernel.ptr ()); XCAM_FAIL_RETURN ( ERROR, gauss_kernel->build_kernel (kernel_gauss_info, build_options) == XCAM_RETURN_NO_ERROR, NULL, "build gaussian kernel(%s) failed", kernel_gauss_info.kernel_name); XCAM_ASSERT (gauss_kernel->is_valid ()); gauss_handler->set_gauss_kernel (gauss_kernel); return gauss_handler; } }