1 /*
2  * cl_gauss_handler.cpp - CL gauss handler
3  *
4  *  Copyright (c) 2016 Intel Corporation
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * Author: wangfei <feix.w.wang@intel.com>
19  *             Wind Yuan <feng.yuan@intel.com>
20  */
21 
22 #include "cl_utils.h"
23 #include "cl_gauss_handler.h"
24 #include <algorithm>
25 
26 #define XCAM_GAUSS_SCALE(radius) ((radius) * 2 + 1)
27 
28 namespace XCam {
29 
30 const static XCamKernelInfo kernel_gauss_info = {
31     "kernel_gauss",
32 #include "kernel_gauss.clx"
33     , 0,
34 };
35 
36 class CLGaussImageKernelImpl
37     : public CLGaussImageKernel
38 {
39 public:
40     CLGaussImageKernelImpl (
41         SmartPtr<CLGaussImageHandler> &handler,
42         const SmartPtr<CLContext> &context, uint32_t radius, float sigma);
43 
44     virtual SmartPtr<VideoBuffer> get_input_buf ();
45     virtual SmartPtr<VideoBuffer> get_output_buf ();
46 private:
47     SmartPtr<CLGaussImageHandler> _handler;
48 };
49 
CLGaussImageKernelImpl(SmartPtr<CLGaussImageHandler> & handler,const SmartPtr<CLContext> & context,uint32_t radius,float sigma)50 CLGaussImageKernelImpl::CLGaussImageKernelImpl (
51     SmartPtr<CLGaussImageHandler> &handler,
52     const SmartPtr<CLContext> &context,
53     uint32_t radius,
54     float sigma
55 )
56     : CLGaussImageKernel (context, radius, sigma)
57     , _handler (handler)
58 {
59 }
60 
61 SmartPtr<VideoBuffer>
get_input_buf()62 CLGaussImageKernelImpl::get_input_buf ()
63 {
64     return _handler->get_input_buf ();
65 }
66 SmartPtr<VideoBuffer>
get_output_buf()67 CLGaussImageKernelImpl::get_output_buf ()
68 {
69     return _handler->get_output_buf ();;
70 }
71 
CLGaussImageKernel(const SmartPtr<CLContext> & context,uint32_t radius,float sigma)72 CLGaussImageKernel::CLGaussImageKernel (
73     const SmartPtr<CLContext> &context, uint32_t radius, float sigma)
74     : CLImageKernel (context, "kernel_gauss")
75     , _g_radius (radius)
76     , _g_table (NULL)
77 {
78     set_gaussian(radius, sigma);
79 }
80 
~CLGaussImageKernel()81 CLGaussImageKernel::~CLGaussImageKernel ()
82 {
83     xcam_free (_g_table);
84 }
85 
86 bool
set_gaussian(uint32_t radius,float sigma)87 CLGaussImageKernel::set_gaussian (uint32_t radius, float sigma)
88 {
89     uint32_t i, j;
90     uint32_t scale = XCAM_GAUSS_SCALE (radius);
91     float dis = 0.0f, sum = 0.0f;
92     uint32_t scale_size = scale * scale * sizeof (_g_table[0]);
93 
94     xcam_free (_g_table);
95     _g_table_buffer.release ();
96     _g_radius = radius;
97     _g_table = (float*) xcam_malloc0 (scale_size);
98     XCAM_ASSERT (_g_table);
99 
100     for(i = 0; i < scale; i++)  {
101         for(j = 0; j < scale; j++) {
102             dis = ((float)i - radius) * ((float)i - radius) + ((float)j - radius) * ((float)j - radius);
103             _g_table[i * scale + j] = exp(-dis / (2.0f * sigma * sigma));
104             sum += _g_table[i * scale + j];
105         }
106     }
107 
108     for(i = 0; i < scale * scale; i++) {
109         _g_table[i] = _g_table[i] / sum;
110     }
111 
112     _g_table_buffer = new CLBuffer(
113         get_context (), scale_size,
114         CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR , _g_table);
115 
116     return true;
117 }
118 
119 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)120 CLGaussImageKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size)
121 {
122     SmartPtr<CLContext> context = get_context ();
123     SmartPtr<VideoBuffer> input = get_input_buf ();
124     SmartPtr<VideoBuffer> output = get_output_buf ();
125 
126     XCAM_FAIL_RETURN (
127         WARNING,
128         input.ptr () && output.ptr (),
129         XCAM_RETURN_ERROR_MEM,
130         "cl image kernel(%s) get input/output buffer failed", get_kernel_name ());
131 
132     const VideoBufferInfo & video_info_in = input->get_video_info ();
133     const VideoBufferInfo & video_info_out = output->get_video_info ();
134     CLImageDesc cl_desc_in, cl_desc_out;
135 
136     cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8;
137     cl_desc_in.format.image_channel_order = CL_R;
138     cl_desc_in.width = video_info_in.width;
139     cl_desc_in.height = video_info_in.height;
140     cl_desc_in.row_pitch = video_info_in.strides[0];
141     SmartPtr<CLImage> image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[0]);
142 
143     cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8;
144     cl_desc_out.format.image_channel_order = CL_RGBA;
145     cl_desc_out.width = video_info_out.width / 4;
146     cl_desc_out.height = video_info_out.height;
147     cl_desc_out.row_pitch = video_info_out.strides[0];
148     SmartPtr<CLImage> image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[0]);
149 
150     XCAM_FAIL_RETURN (
151         WARNING,
152         image_in->is_valid () && image_out->is_valid (),
153         XCAM_RETURN_ERROR_MEM,
154         "cl image kernel(%s) in/out memory not available", get_kernel_name ());
155 
156     //set args;
157     args.push_back (new CLMemArgument (image_in));
158     args.push_back (new CLMemArgument (image_out));
159     args.push_back (new CLMemArgument (_g_table_buffer));
160 
161     work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
162     work_size.global[0] = XCAM_ALIGN_UP(cl_desc_out.width, 8);
163     work_size.global[1] = XCAM_ALIGN_UP (cl_desc_out.height / 2, 4);
164     work_size.local[0] = 8;
165     work_size.local[1] = 4;
166 
167     return XCAM_RETURN_NO_ERROR;
168 }
169 
CLGaussImageHandler(const SmartPtr<CLContext> & context,const char * name)170 CLGaussImageHandler::CLGaussImageHandler (const SmartPtr<CLContext> &context, const char *name)
171     : CLImageHandler (context, name)
172 {
173 }
174 
175 bool
set_gaussian_table(int size,float sigma)176 CLGaussImageHandler::set_gaussian_table (int size, float sigma)
177 {
178     _gauss_kernel->set_gaussian (size, sigma);
179     return true;
180 }
181 
182 bool
set_gauss_kernel(SmartPtr<CLGaussImageKernel> & kernel)183 CLGaussImageHandler::set_gauss_kernel(SmartPtr<CLGaussImageKernel> &kernel)
184 {
185     SmartPtr<CLImageKernel> image_kernel = kernel;
186     add_kernel (image_kernel);
187     _gauss_kernel = kernel;
188     return true;
189 }
190 
191 SmartPtr<CLImageHandler>
create_cl_gauss_image_handler(const SmartPtr<CLContext> & context,uint32_t radius,float sigma)192 create_cl_gauss_image_handler (const SmartPtr<CLContext> &context, uint32_t radius, float sigma)
193 {
194     SmartPtr<CLGaussImageHandler> gauss_handler;
195     SmartPtr<CLGaussImageKernel> gauss_kernel;
196     char build_options[1024];
197 
198     xcam_mem_clear (build_options);
199     snprintf (build_options, sizeof (build_options), " -DGAUSS_RADIUS=%d ", radius);
200 
201     gauss_handler = new CLGaussImageHandler (context, "cl_handler_gauss");
202     gauss_kernel = new CLGaussImageKernelImpl (gauss_handler, context, radius, sigma);
203     XCAM_ASSERT (gauss_kernel.ptr ());
204     XCAM_FAIL_RETURN (
205         ERROR, gauss_kernel->build_kernel (kernel_gauss_info, build_options) == XCAM_RETURN_NO_ERROR, NULL,
206         "build gaussian kernel(%s) failed", kernel_gauss_info.kernel_name);
207 
208     XCAM_ASSERT (gauss_kernel->is_valid ());
209     gauss_handler->set_gauss_kernel (gauss_kernel);
210 
211     return gauss_handler;
212 }
213 
214 }
215