1 /*
2 * cl_image_warp_handler.cpp - CL image warping 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: Zong Wei <wei.zong@intel.com>
19 */
20
21 #include "cl_utils.h"
22 #include "cl_image_warp_handler.h"
23
24 namespace XCam {
25
26 #define CL_IMAGE_WARP_WG_WIDTH 8
27 #define CL_IMAGE_WARP_WG_HEIGHT 4
28
29
30 static const XCamKernelInfo kernel_image_warp_info [] = {
31 {
32 "kernel_image_warp_8_pixel",
33 #include "kernel_image_warp.clx"
34 , 0,
35 },
36 {
37 "kernel_image_warp_1_pixel",
38 #include "kernel_image_warp.clx"
39 , 0,
40 }
41 };
42
CLImageWarpKernel(const SmartPtr<CLContext> & context,const char * name,uint32_t channel,SmartPtr<CLImageHandler> & handler)43 CLImageWarpKernel::CLImageWarpKernel (
44 const SmartPtr<CLContext> &context,
45 const char *name,
46 uint32_t channel,
47 SmartPtr<CLImageHandler> &handler)
48 : CLImageKernel (context, name)
49 , _channel (channel)
50 {
51 _handler = handler.dynamic_cast_ptr<CLImageWarpHandler> ();
52 }
53
54 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)55 CLImageWarpKernel::prepare_arguments (
56 CLArgList &args, CLWorkSize &work_size)
57 {
58 SmartPtr<CLContext> context = get_context ();
59 SmartPtr<VideoBuffer> input = _handler->get_warp_input_buf ();
60 SmartPtr<VideoBuffer> output = _handler->get_output_buf ();
61
62 const VideoBufferInfo & video_info_in = input->get_video_info ();
63 const VideoBufferInfo & video_info_out = output->get_video_info ();
64
65 uint32_t info_index = 0;
66 if (_channel == CL_IMAGE_CHANNEL_Y) {
67 info_index = 0;
68 } else if (_channel == CL_IMAGE_CHANNEL_UV) {
69 info_index = 1;
70 }
71
72 CLImageDesc cl_desc_in, cl_desc_out;
73 cl_desc_in.format.image_channel_order = info_index == 0 ? CL_R : CL_RG;
74 cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8;
75 cl_desc_in.width = video_info_in.width >> info_index;
76 cl_desc_in.height = video_info_in.height >> info_index;
77 cl_desc_in.row_pitch = video_info_in.strides[info_index];
78
79 #if CL_IMAGE_WARP_WRITE_UINT
80 cl_desc_out.format.image_channel_data_type = info_index == 0 ? CL_UNSIGNED_INT16 : CL_UNSIGNED_INT32;
81 cl_desc_out.format.image_channel_order = CL_RGBA;
82 cl_desc_out.width = XCAM_ALIGN_DOWN (video_info_out.width >> info_index, 8) / 8;
83 cl_desc_out.height = video_info_out.height >> info_index;
84 #else
85 cl_desc_out.format.image_channel_order = info_index == 0 ? CL_R : CL_RG;
86 cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8;
87 cl_desc_out.width = video_info_out.width >> info_index;
88 cl_desc_out.height = video_info_out.height >> info_index;
89 #endif
90
91 cl_desc_out.row_pitch = video_info_out.strides[info_index];
92 SmartPtr<CLImage> image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[info_index]);
93
94 CLWarpConfig warp_config = _handler->get_warp_config ();
95 if ((warp_config.trim_ratio > 0.5f) || (warp_config.trim_ratio < 0.0f)) {
96 warp_config.trim_ratio = 0.0f;
97 }
98
99 float sample_rate_x = (float)warp_config.width / (float)video_info_in.width;
100 float sample_rate_y = (float)warp_config.height / (float)video_info_in.height;
101 XCAM_LOG_DEBUG ("warp analyze image sample rate(%fx%f)", sample_rate_x, sample_rate_y);
102 warp_config.proj_mat[2] = warp_config.proj_mat[2] / sample_rate_x;
103 warp_config.proj_mat[5] = warp_config.proj_mat[5] / sample_rate_y;
104 warp_config.proj_mat[6] = warp_config.proj_mat[6] * sample_rate_x;
105 warp_config.proj_mat[7] = warp_config.proj_mat[7] * sample_rate_y;
106
107 /*
108 For NV12 image (YUV420), UV plane has half horizontal & vertical coordinate size of Y plane,
109 need to adjust the projection matrix as:
110 H(uv) = [0.5, 0, 0; 0, 0.5, 0; 0, 0, 1] * H(y) * [2, 0, 0; 0, 2, 0; 0, 0, 1]
111 */
112 if (_channel == CL_IMAGE_CHANNEL_UV) {
113 warp_config.proj_mat[2] = 0.5 * warp_config.proj_mat[2];
114 warp_config.proj_mat[5] = 0.5 * warp_config.proj_mat[5];
115 warp_config.proj_mat[6] = 2.0 * warp_config.proj_mat[6];
116 warp_config.proj_mat[7] = 2.0 * warp_config.proj_mat[7];
117 }
118
119 /*
120 Trim image: shift toward origin then scale up
121 Trim Matrix (TMat)
122 TMat = [ scale_x, 0.0f, shift_x;
123 0.0f, scale_y, shift_y;
124 1.0f, 1.0f, 1.0f; ]
125
126 Warp Perspective Matrix = TMat * HMat
127 */
128 #if CL_IMAGE_WARP_WRITE_UINT
129 float shift_x = warp_config.trim_ratio * cl_desc_out.width * 8.0f;
130 #else
131 float shift_x = warp_config.trim_ratio * cl_desc_out.width;
132 #endif
133 float shift_y = warp_config.trim_ratio * cl_desc_out.height;
134 float scale_x = 1.0f - 2.0f * warp_config.trim_ratio;
135 float scale_y = 1.0f - 2.0f * warp_config.trim_ratio;
136
137 warp_config.proj_mat[0] = scale_x * warp_config.proj_mat[0] + shift_x * warp_config.proj_mat[6];
138 warp_config.proj_mat[1] = scale_x * warp_config.proj_mat[1] + shift_x * warp_config.proj_mat[7];
139 warp_config.proj_mat[2] = scale_x * warp_config.proj_mat[2] + shift_x * warp_config.proj_mat[8];
140 warp_config.proj_mat[3] = scale_y * warp_config.proj_mat[3] + shift_y * warp_config.proj_mat[6];
141 warp_config.proj_mat[4] = scale_y * warp_config.proj_mat[4] + shift_y * warp_config.proj_mat[7];
142 warp_config.proj_mat[5] = scale_y * warp_config.proj_mat[5] + shift_y * warp_config.proj_mat[8];
143
144 XCAM_LOG_DEBUG ("warp config image size(%dx%d)", warp_config.width, warp_config.height);
145 XCAM_LOG_DEBUG ("proj_mat[%d]=(%f, %f, %f, %f, %f, %f, %f, %f, %f);", warp_config.frame_id,
146 warp_config.proj_mat[0], warp_config.proj_mat[1], warp_config.proj_mat[2],
147 warp_config.proj_mat[3], warp_config.proj_mat[4], warp_config.proj_mat[5],
148 warp_config.proj_mat[6], warp_config.proj_mat[7], warp_config.proj_mat[8]);
149
150 SmartPtr<CLImage> image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[info_index]);
151 XCAM_FAIL_RETURN (
152 WARNING,
153 image_in->is_valid () && image_out->is_valid (),
154 XCAM_RETURN_ERROR_MEM,
155 "cl image kernel(%s) in/out memory not available", get_kernel_name ());
156
157 //set args;
158 work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
159 work_size.local[0] = CL_IMAGE_WARP_WG_WIDTH;
160 work_size.local[1] = CL_IMAGE_WARP_WG_HEIGHT;
161 work_size.global[0] = XCAM_ALIGN_UP (cl_desc_out.width, work_size.local[0]);
162 work_size.global[1] = XCAM_ALIGN_UP(cl_desc_out.height, work_size.local[1]);
163
164 args.push_back (new CLMemArgument (image_in));
165 args.push_back (new CLMemArgument (image_out));
166 args.push_back (new CLArgumentT<CLWarpConfig> (warp_config));
167
168 return XCAM_RETURN_NO_ERROR;
169 }
170
CLImageWarpHandler(const SmartPtr<CLContext> & context,const char * name)171 CLImageWarpHandler::CLImageWarpHandler (const SmartPtr<CLContext> &context, const char *name)
172 : CLImageHandler (context, name)
173 {
174 }
175
176 bool
is_ready()177 CLImageWarpHandler::is_ready ()
178 {
179 bool ret = !_warp_config_list.empty ();
180 return ret && CLImageHandler::is_ready ();
181 }
182
183 XCamReturn
execute_done(SmartPtr<VideoBuffer> & output)184 CLImageWarpHandler::execute_done (SmartPtr<VideoBuffer> &output)
185 {
186 XCAM_UNUSED (output);
187 if (!_warp_config_list.empty ()) {
188 _warp_config_list.pop_front ();
189 }
190
191 return XCAM_RETURN_NO_ERROR;
192 }
193
194 SmartPtr<VideoBuffer>
get_warp_input_buf()195 CLImageWarpHandler::get_warp_input_buf ()
196 {
197 return CLImageHandler::get_input_buf ();
198 }
199
200 bool
set_warp_config(const XCamDVSResult & config)201 CLImageWarpHandler::set_warp_config (const XCamDVSResult& config)
202 {
203 CLWarpConfig warp_config;
204 warp_config.frame_id = config.frame_id;
205 warp_config.width = config.frame_width;
206 warp_config.height = config.frame_height;
207 for( int i = 0; i < 9; i++ ) {
208 warp_config.proj_mat[i] = config.proj_mat[i];
209 }
210 XCAM_LOG_DEBUG ("warp_mat{%d}=[%f, %f, %f; %f, %f, %f; %f, %f, %f]", warp_config.frame_id + 1,
211 warp_config.proj_mat[0], warp_config.proj_mat[1], warp_config.proj_mat[2],
212 warp_config.proj_mat[3], warp_config.proj_mat[4], warp_config.proj_mat[5],
213 warp_config.proj_mat[6], warp_config.proj_mat[7], warp_config.proj_mat[8]);
214 #if 0
215 printf ("warp_mat{%d}=[%f, %f, %f; %f, %f, %f; %f, %f, %f]; \n", warp_config.frame_id + 1,
216 warp_config.proj_mat[0], warp_config.proj_mat[1], warp_config.proj_mat[2],
217 warp_config.proj_mat[3], warp_config.proj_mat[4], warp_config.proj_mat[5],
218 warp_config.proj_mat[6], warp_config.proj_mat[7], warp_config.proj_mat[8]);
219 #endif
220 _warp_config_list.push_back (warp_config);
221
222 return true;
223 }
224
225 CLWarpConfig
get_warp_config()226 CLImageWarpHandler::get_warp_config ()
227 {
228 CLWarpConfig warp_config;
229
230 if (_warp_config_list.size () > 0) {
231 warp_config = *(_warp_config_list.begin ());
232 } else {
233 warp_config.frame_id = -1;
234 warp_config.proj_mat[0] = 1.0f;
235 warp_config.proj_mat[1] = 0.0f;
236 warp_config.proj_mat[2] = 0.0f;
237 warp_config.proj_mat[3] = 0.0f;
238 warp_config.proj_mat[4] = 1.0f;
239 warp_config.proj_mat[5] = 0.0f;
240 warp_config.proj_mat[6] = 0.0f;
241 warp_config.proj_mat[7] = 0.0f;
242 warp_config.proj_mat[8] = 1.0f;
243 }
244
245 return warp_config;
246 }
247
248 static SmartPtr<CLImageWarpKernel>
create_kernel_image_warp(const SmartPtr<CLContext> & context,uint32_t channel,SmartPtr<CLImageHandler> handler)249 create_kernel_image_warp (
250 const SmartPtr<CLContext> &context,
251 uint32_t channel,
252 SmartPtr<CLImageHandler> handler)
253 {
254 SmartPtr<CLImageWarpKernel> warp_kernel;
255
256 const char *name = (channel == CL_IMAGE_CHANNEL_Y ? "kernel_image_warp_y" : "kernel_image_warp_uv");
257 char build_options[1024];
258 xcam_mem_clear (build_options);
259
260 snprintf (build_options, sizeof (build_options),
261 " -DWARP_Y=%d ",
262 (channel == CL_IMAGE_CHANNEL_Y ? 1 : 0));
263
264 warp_kernel = new CLImageWarpKernel (context, name, channel, handler);
265 XCAM_ASSERT (warp_kernel.ptr ());
266 XCAM_FAIL_RETURN (
267 ERROR, warp_kernel->build_kernel (kernel_image_warp_info[KernelImageWarp], build_options) == XCAM_RETURN_NO_ERROR,
268 NULL, "build image warp kernel failed");
269 XCAM_ASSERT (warp_kernel->is_valid ());
270
271 return warp_kernel;
272 }
273
274 SmartPtr<CLImageHandler>
create_cl_image_warp_handler(const SmartPtr<CLContext> & context)275 create_cl_image_warp_handler (const SmartPtr<CLContext> &context)
276 {
277 SmartPtr<CLImageWarpHandler> warp_handler;
278 SmartPtr<CLImageKernel> warp_kernel;
279
280 warp_handler = new CLImageWarpHandler (context);
281 XCAM_ASSERT (warp_handler.ptr ());
282
283 warp_kernel = create_kernel_image_warp (context, CL_IMAGE_CHANNEL_Y, warp_handler);
284 XCAM_ASSERT (warp_kernel.ptr ());
285 warp_handler->add_kernel (warp_kernel);
286
287 warp_kernel = create_kernel_image_warp (context, CL_IMAGE_CHANNEL_UV, warp_handler);
288 XCAM_ASSERT (warp_kernel.ptr ());
289 warp_handler->add_kernel (warp_kernel);
290
291 return warp_handler;
292 }
293
294 };
295