1 /*
2 * cl_image_scaler.cpp - CL image scaler
3 *
4 * Copyright (c) 2015 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: Zong Wei <wei.zong@intel.com>
19 */
20
21 #include "cl_utils.h"
22 #include "cl_image_scaler.h"
23
24 namespace XCam {
25
26 static const XCamKernelInfo kernel_scale_info = {
27 "kernel_image_scaler",
28 #include "kernel_image_scaler.clx"
29 , 0,
30 };
31
CLScalerKernel(const SmartPtr<CLContext> & context,CLImageScalerMemoryLayout mem_layout)32 CLScalerKernel::CLScalerKernel (
33 const SmartPtr<CLContext> &context,
34 CLImageScalerMemoryLayout mem_layout
35 )
36 : CLImageKernel (context, "kernel_image_scaler")
37 , _mem_layout (mem_layout)
38 {
39 }
40
41 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)42 CLScalerKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size)
43 {
44 XCamReturn ret = XCAM_RETURN_NO_ERROR;
45 SmartPtr<CLContext> context = get_context ();
46
47 SmartPtr<VideoBuffer> input = get_input_buffer ();
48 SmartPtr<VideoBuffer> output = get_output_buffer ();
49 SmartPtr<CLImage> image_in, image_out;
50
51 XCAM_FAIL_RETURN (
52 WARNING,
53 input.ptr () && output.ptr (),
54 XCAM_RETURN_ERROR_MEM,
55 "cl image kernel(%s) get input/output buffer failed", XCAM_STR(get_kernel_name ()));
56
57 const VideoBufferInfo &input_info = input->get_video_info ();
58 const VideoBufferInfo &output_info = output->get_video_info ();
59
60 uint32_t output_width = 0, output_height = 0;
61 CLImageDesc output_imageDesc;
62
63 uint32_t channel_bits = XCAM_ALIGN_UP (output_info.color_bits, 8);
64 if (channel_bits == 8)
65 output_imageDesc.format.image_channel_data_type = CL_UNSIGNED_INT8;
66 else if (channel_bits == 16)
67 output_imageDesc.format.image_channel_data_type = CL_UNSIGNED_INT16;
68
69 if ((CL_IMAGE_SCALER_NV12_UV == get_mem_layout ()) && (V4L2_PIX_FMT_NV12 == input_info.format)) {
70 output_imageDesc.format.image_channel_order = CL_RG;
71 output_imageDesc.width = output_info.width / 2;
72 output_imageDesc.height = output_info.height / 2;
73 output_imageDesc.row_pitch = output_info.strides[1];
74
75 image_out = convert_to_climage (context, output, output_imageDesc, output_info.offsets[1]);
76 output_width = output_info.width / 2;
77 output_height = output_info.height / 2;
78 } else {
79 output_imageDesc.format.image_channel_order = CL_R;
80 output_imageDesc.width = output_info.width;
81 output_imageDesc.height = output_info.height;
82 output_imageDesc.row_pitch = output_info.strides[0];
83
84 image_out = convert_to_climage (context, output, output_imageDesc, output_info.offsets[0]);
85 output_width = output_info.width;
86 output_height = output_info.height;
87 }
88
89 CLImageDesc input_imageDesc;
90 channel_bits = XCAM_ALIGN_UP (input_info.color_bits, 8);
91 if (channel_bits == 8)
92 input_imageDesc.format.image_channel_data_type = CL_UNSIGNED_INT8;
93 else if (channel_bits == 16)
94 input_imageDesc.format.image_channel_data_type = CL_UNSIGNED_INT16;
95
96 if ((CL_IMAGE_SCALER_NV12_UV == get_mem_layout ()) && (V4L2_PIX_FMT_NV12 == input_info.format)) {
97 input_imageDesc.format.image_channel_order = CL_RG;
98 input_imageDesc.width = input_info.width / 2;
99 input_imageDesc.height = input_info.height / 2;
100 input_imageDesc.row_pitch = input_info.strides[1];
101
102 image_in = convert_to_climage (context, input, input_imageDesc, input_info.offsets[1]);
103 } else {
104 input_imageDesc.format.image_channel_order = CL_R;
105 input_imageDesc.width = input_info.width;
106 input_imageDesc.height = input_info.height;
107 input_imageDesc.row_pitch = input_info.strides[0];
108
109 image_in = convert_to_climage (context, input, input_imageDesc, input_info.offsets[0]);
110 }
111
112 //set args;
113 args.push_back (new CLMemArgument (image_in));
114 args.push_back (new CLMemArgument (image_out));
115 args.push_back (new CLArgumentT<uint32_t> (output_width));
116 args.push_back (new CLArgumentT<uint32_t> (output_height));
117
118 work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
119 work_size.global[0] = XCAM_ALIGN_UP (output_width, XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE0);
120 work_size.global[1] = XCAM_ALIGN_UP (output_height, XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE1);
121 work_size.local[0] = XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE0;
122 work_size.local[1] = XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE1;
123
124 return ret;
125 }
126
CLImageScalerKernel(const SmartPtr<CLContext> & context,CLImageScalerMemoryLayout mem_layout,SmartPtr<CLImageScaler> & scaler)127 CLImageScalerKernel::CLImageScalerKernel (
128 const SmartPtr<CLContext> &context,
129 CLImageScalerMemoryLayout mem_layout,
130 SmartPtr<CLImageScaler> &scaler
131 )
132 : CLScalerKernel (context, mem_layout)
133 , _scaler (scaler)
134 {
135 }
136
137 SmartPtr<VideoBuffer>
get_input_buffer()138 CLImageScalerKernel::get_input_buffer ()
139 {
140 return _scaler->get_input_buf ();
141 }
142
143 SmartPtr<VideoBuffer>
get_output_buffer()144 CLImageScalerKernel::get_output_buffer ()
145 {
146 return _scaler->get_scaler_buf ();
147 }
148
CLImageScaler(const SmartPtr<CLContext> & context)149 CLImageScaler::CLImageScaler (const SmartPtr<CLContext> &context)
150 : CLImageHandler (context, "CLImageScaler")
151 , _h_scaler_factor (0.5)
152 , _v_scaler_factor (0.5)
153 {
154 }
155
156 void
emit_stop()157 CLImageScaler::emit_stop ()
158 {
159 if (_scaler_buf_pool.ptr ())
160 _scaler_buf_pool->stop ();
161 }
162
163 bool
set_scaler_factor(const double h_factor,const double v_factor)164 CLImageScaler::set_scaler_factor (const double h_factor, const double v_factor)
165 {
166 _h_scaler_factor = h_factor;
167 _v_scaler_factor = v_factor;
168
169 return true;
170 }
171
172 bool
get_scaler_factor(double & h_factor,double & v_factor) const173 CLImageScaler::get_scaler_factor (double &h_factor, double &v_factor) const
174 {
175 h_factor = _h_scaler_factor;
176 v_factor = _v_scaler_factor;
177
178 return true;
179 };
180
181 XCamReturn
prepare_output_buf(SmartPtr<VideoBuffer> & input,SmartPtr<VideoBuffer> & output)182 CLImageScaler::prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output)
183 {
184 XCamReturn ret = XCAM_RETURN_NO_ERROR;
185 output = input;
186
187 ret = prepare_scaler_buf (input->get_video_info (), _scaler_buf);
188 XCAM_FAIL_RETURN(
189 WARNING,
190 ret == XCAM_RETURN_NO_ERROR,
191 ret,
192 "CLImageScalerKernel prepare scaled video buf failed");
193
194 _scaler_buf->set_timestamp (input->get_timestamp ());
195
196 return ret;
197 }
198
199 XCamReturn
execute_done(SmartPtr<VideoBuffer> & output)200 CLImageScaler::execute_done (SmartPtr<VideoBuffer> &output)
201 {
202 XCAM_UNUSED (output);
203 get_context ()->finish();
204 XCAM_ASSERT (_scaler_buf.ptr ());
205
206 //post buffer out
207 return post_buffer (_scaler_buf);
208 }
209
210 XCamReturn
prepare_scaler_buf(const VideoBufferInfo & video_info,SmartPtr<VideoBuffer> & output)211 CLImageScaler::prepare_scaler_buf (const VideoBufferInfo &video_info, SmartPtr<VideoBuffer> &output)
212 {
213 if (!_scaler_buf_pool.ptr ()) {
214 VideoBufferInfo scaler_video_info;
215 uint32_t new_width = XCAM_ALIGN_UP ((uint32_t)(video_info.width * _h_scaler_factor),
216 2 * XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE0);
217 uint32_t new_height = XCAM_ALIGN_UP ((uint32_t)(video_info.height * _v_scaler_factor),
218 2 * XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE1);
219
220 scaler_video_info.init (video_info.format, new_width, new_height);
221
222 _scaler_buf_pool = new CLVideoBufferPool ();
223 XCAM_ASSERT (_scaler_buf_pool.ptr ());
224 _scaler_buf_pool->set_video_info (scaler_video_info);
225 _scaler_buf_pool->reserve (6);
226 }
227
228 output = _scaler_buf_pool->get_buffer (_scaler_buf_pool);
229 XCAM_ASSERT (output.ptr ());
230
231 return XCAM_RETURN_NO_ERROR;
232 }
233
234 XCamReturn
post_buffer(const SmartPtr<VideoBuffer> & buffer)235 CLImageScaler::post_buffer (const SmartPtr<VideoBuffer> &buffer)
236 {
237 if (_scaler_callback.ptr ())
238 return _scaler_callback->scaled_image_ready (buffer);
239
240 return XCAM_RETURN_NO_ERROR;
241 }
242
243 static SmartPtr<CLImageKernel>
create_scale_kernel(const SmartPtr<CLContext> & context,SmartPtr<CLImageScaler> & handler,CLImageScalerMemoryLayout layout)244 create_scale_kernel (
245 const SmartPtr<CLContext> &context, SmartPtr<CLImageScaler> &handler, CLImageScalerMemoryLayout layout)
246 {
247 SmartPtr<CLImageKernel> kernel;
248 kernel = new CLImageScalerKernel (context, layout, handler);
249 XCAM_ASSERT (kernel.ptr ());
250 XCAM_FAIL_RETURN (
251 ERROR, kernel->build_kernel (kernel_scale_info, NULL) == XCAM_RETURN_NO_ERROR, NULL,
252 "build scaler kernel(%s) failed", kernel_scale_info.kernel_name);
253 XCAM_ASSERT (kernel->is_valid ());
254 return kernel;
255 }
256
257 SmartPtr<CLImageHandler>
create_cl_image_scaler_handler(const SmartPtr<CLContext> & context,const uint32_t format)258 create_cl_image_scaler_handler (const SmartPtr<CLContext> &context, const uint32_t format)
259 {
260 SmartPtr<CLImageScaler> scaler_handler;
261 SmartPtr<CLImageKernel> scaler_kernel;
262
263 scaler_handler = new CLImageScaler (context);
264 XCAM_ASSERT (scaler_handler.ptr ());
265
266 if (V4L2_PIX_FMT_NV12 == format) {
267 //Y
268 scaler_kernel = create_scale_kernel (context, scaler_handler, CL_IMAGE_SCALER_NV12_Y);
269 XCAM_FAIL_RETURN (ERROR, scaler_kernel.ptr (), NULL, "build CL_IMAGE_SCALER_NV12_Y kernel failed");
270 scaler_handler->add_kernel (scaler_kernel);
271 //UV
272 scaler_kernel = create_scale_kernel (context, scaler_handler, CL_IMAGE_SCALER_NV12_UV);
273 XCAM_FAIL_RETURN (ERROR, scaler_kernel.ptr (), NULL, "build CL_IMAGE_SCALER_NV12_UV kernel failed");
274 scaler_handler->add_kernel (scaler_kernel);
275 } else if (XCAM_PIX_FMT_RGBA64 == format) {
276 scaler_kernel = create_scale_kernel (context, scaler_handler, CL_IMAGE_SCALER_RGBA);
277 XCAM_FAIL_RETURN (ERROR, scaler_kernel.ptr (), NULL, "build CL_IMAGE_SCALER_RGBA kernel failed");
278 scaler_handler->add_kernel (scaler_kernel);
279 } else {
280 XCAM_LOG_ERROR ("create cl image scaler failed, unknown format:0x%08x", format);
281 return NULL;
282 }
283
284 return scaler_handler;
285 }
286
287 };
288