/*
* 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;
}
}