1 /*
2  * cl_geo_map_handler.cpp - CL geometry map 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: Wind Yuan <feng.yuan@intel.com>
19  */
20 
21 #include "cl_utils.h"
22 #include "cl_geo_map_handler.h"
23 #include "cl_device.h"
24 
25 namespace XCam {
26 
27 static const XCamKernelInfo kernel_geo_map_info = {
28     "kernel_geo_map",
29 #include "kernel_geo_map.clx"
30     , 0,
31 };
32 
33 // GEO_MAP_CHANNEL for CL_RGBA channel
34 #define GEO_MAP_CHANNEL 4  /* only use channel_0, channel_1 */
35 
CLGeoMapKernel(const SmartPtr<CLContext> & context,const SmartPtr<GeoKernelParamCallback> handler,bool need_lsc)36 CLGeoMapKernel::CLGeoMapKernel (
37     const SmartPtr<CLContext> &context, const SmartPtr<GeoKernelParamCallback> handler, bool need_lsc)
38     : CLImageKernel (context)
39     , _handler (handler)
40     , _need_lsc (need_lsc)
41 {
42     XCAM_ASSERT (handler.ptr ());
43 }
44 
45 XCamReturn
prepare_arguments(CLArgList & args,CLWorkSize & work_size)46 CLGeoMapKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size)
47 {
48     SmartPtr<CLImage> input_y = _handler->get_geo_input_image (NV12PlaneYIdx);
49     SmartPtr<CLImage> input_uv = _handler->get_geo_input_image (NV12PlaneUVIdx);
50     SmartPtr<CLImage> output_y = _handler->get_geo_output_image (NV12PlaneYIdx);
51     SmartPtr<CLImage> output_uv = _handler->get_geo_output_image (NV12PlaneUVIdx);
52     const CLImageDesc &outuv_desc = output_uv->get_image_desc ();
53     SmartPtr<CLImage> geo_image = _handler->get_geo_map_table ();
54 
55     float geo_scale_size[2]; //width/height
56     float out_size[2];
57     _handler->get_geo_equivalent_out_size (geo_scale_size[0], geo_scale_size[1]);
58     _handler->get_geo_pixel_out_size (out_size[0], out_size[1]);
59 
60     args.push_back (new CLMemArgument (input_y));
61     args.push_back (new CLMemArgument (input_uv));
62     args.push_back (new CLMemArgument (geo_image));
63     args.push_back (new CLArgumentTArray<float, 2> (geo_scale_size));
64 
65     if (_need_lsc) {
66         SmartPtr<CLImage> lsc_image = _handler->get_lsc_table ();
67         float *gray_threshold = _handler->get_lsc_gray_threshold ();
68         XCAM_FAIL_RETURN (
69             ERROR,
70             lsc_image.ptr() && lsc_image->is_valid () && gray_threshold,
71             XCAM_RETURN_ERROR_PARAM,
72             "CLGeoMapHandler::lsc table or gray threshold was not found");
73         args.push_back (new CLMemArgument (lsc_image));
74         args.push_back (new CLArgumentTArray<float, 2> (gray_threshold));
75     }
76     args.push_back (new CLMemArgument (output_y));
77     args.push_back (new CLMemArgument (output_uv));
78     args.push_back (new CLArgumentTArray<float, 2> (out_size));
79 
80     work_size.dim = XCAM_DEFAULT_IMAGE_DIM;
81     work_size.local[0] = 16;
82     work_size.local[1] = 4;
83     work_size.global[0] = XCAM_ALIGN_UP (outuv_desc.width, work_size.local[0]);
84     work_size.global[1] = XCAM_ALIGN_UP (outuv_desc.height, work_size.local[1]);
85 
86     return XCAM_RETURN_NO_ERROR;
87 }
88 
CLGeoMapHandler(const SmartPtr<CLContext> & context)89 CLGeoMapHandler::CLGeoMapHandler (const SmartPtr<CLContext> &context)
90     : CLImageHandler (context, "CLGeoMapHandler")
91     , _output_width (0)
92     , _output_height (0)
93     , _map_width (0)
94     , _map_height (0)
95     , _map_aligned_width (0)
96     , _uint_x (0.0f)
97     , _uint_y (0.0f)
98     , _geo_map_normalized (false)
99 {
100 }
101 
102 void
get_geo_equivalent_out_size(float & width,float & height)103 CLGeoMapHandler::get_geo_equivalent_out_size (float &width, float &height)
104 {
105     width = _map_width * _uint_x;
106     height = _map_height * _uint_y;
107 }
108 
109 void
get_geo_pixel_out_size(float & width,float & height)110 CLGeoMapHandler::get_geo_pixel_out_size (float &width, float &height)
111 {
112     width = _output_width;
113     height = _output_height;
114 }
115 
116 bool
set_map_uint(float uint_x,float uint_y)117 CLGeoMapHandler::set_map_uint (float uint_x, float uint_y)
118 {
119     _uint_x = uint_x;
120     _uint_y = uint_y;
121     return true;
122 }
123 
124 bool
set_map_data(GeoPos * data,uint32_t width,uint32_t height)125 CLGeoMapHandler::set_map_data (GeoPos *data, uint32_t width, uint32_t height)
126 {
127     uint32_t size = width * height * GEO_MAP_CHANNEL * sizeof (float); // 4 for CL_RGBA,
128     float *map_ptr = NULL;
129 
130     XCAM_FAIL_RETURN (
131         ERROR, check_geo_map_buf (width, height), false,
132         "CLGeoMapKernel check geo map buffer failed");
133 
134     XCamReturn ret = _geo_map->enqueue_map ((void *&)map_ptr, 0, size);
135     XCAM_FAIL_RETURN (
136         WARNING, ret == XCAM_RETURN_NO_ERROR, false,
137         "CLGeoMapKernel map buffer failed");
138 
139     uint32_t start, idx;
140     for (uint32_t h = 0; h < height; ++h) {
141         for (uint32_t w = 0; w < width; ++w) {
142             start = (h * _map_aligned_width + w) * GEO_MAP_CHANNEL;
143             idx = h * width + w;
144 
145             map_ptr [start] = data [idx].x;
146             map_ptr [start + 1] = data [idx].y;
147         }
148     }
149     _geo_map->enqueue_unmap ((void *&)map_ptr);
150     _geo_map_normalized = false;
151     return true;
152 }
153 
154 bool
check_geo_map_buf(uint32_t width,uint32_t height)155 CLGeoMapHandler::check_geo_map_buf (uint32_t width, uint32_t height)
156 {
157     XCAM_ASSERT (width && height);
158     if (width == _map_width && height == _map_height && _geo_map.ptr ()) {
159         return true; // geo memory already created
160     }
161 
162     uint32_t aligned_width = XCAM_ALIGN_UP (width, XCAM_CL_IMAGE_ALIGNMENT_X);  // 4 channel for CL_RGBA, but only use RG
163     uint32_t row_pitch = aligned_width * GEO_MAP_CHANNEL * sizeof (float);
164     uint32_t size = row_pitch * height;
165     SmartPtr<CLContext> context = get_context ();
166     XCAM_ASSERT (context.ptr ());
167     _geo_map = new CLBuffer (context, size);
168 
169     if (!_geo_map.ptr () || !_geo_map->is_valid ()) {
170         XCAM_LOG_ERROR ("CLGeoMapKernel create geo map buffer failed.");
171         _geo_map.release ();
172         return false;
173     }
174 
175     CLImageDesc cl_geo_desc;
176     cl_geo_desc.format.image_channel_data_type = CL_FLOAT;
177     cl_geo_desc.format.image_channel_order = CL_RGBA; // CL_FLOAT need co-work with CL_RGBA
178     cl_geo_desc.width = width;
179     cl_geo_desc.height = height;
180     cl_geo_desc.row_pitch = row_pitch;
181     _geo_image = new CLImage2D (context, cl_geo_desc, 0, _geo_map);
182     if (!_geo_image.ptr () || !_geo_image->is_valid ()) {
183         XCAM_LOG_ERROR ("CLGeoMapKernel convert geo map buffer to image2d failed.");
184         _geo_map.release ();
185         _geo_image.release ();
186         return false;
187     }
188 
189     _map_width = width;
190     _map_height = height;
191     _map_aligned_width = aligned_width;
192     return true;
193 }
194 
195 
196 bool
normalize_geo_map(uint32_t image_w,uint32_t image_h)197 CLGeoMapHandler::normalize_geo_map (uint32_t image_w, uint32_t image_h)
198 {
199     XCamReturn ret = XCAM_RETURN_NO_ERROR;
200 
201     uint32_t row_pitch = _map_aligned_width * GEO_MAP_CHANNEL * sizeof (float);  // 4 channel for CL_RGBA, but only use RG
202     uint32_t size = row_pitch * _map_height;
203     float *map_ptr = NULL;
204 
205     XCAM_ASSERT (image_w && image_h);
206     XCAM_FAIL_RETURN (
207         ERROR, _geo_map.ptr () && _geo_map->is_valid (),
208         false, "CLGeoMapKernel geo_map was not initialized");
209 
210     ret = _geo_map->enqueue_map ((void *&)map_ptr, 0, size);
211     XCAM_FAIL_RETURN (WARNING, ret == XCAM_RETURN_NO_ERROR, false, "CLGeoMapKernel map buffer failed");
212     uint32_t idx = 0;
213     for (uint32_t h = 0; h < _map_height; ++h) {
214         for (uint32_t w = 0; w < _map_width; ++w) {
215             idx = (h * _map_aligned_width + w) * GEO_MAP_CHANNEL;
216 
217             map_ptr [idx] /= image_w;
218             map_ptr [idx + 1] /= image_h;
219         }
220     }
221     _geo_map->enqueue_unmap ((void *&)map_ptr);
222 
223     return true;
224 }
225 
226 XCamReturn
prepare_buffer_pool_video_info(const VideoBufferInfo & input,VideoBufferInfo & output)227 CLGeoMapHandler::prepare_buffer_pool_video_info (
228     const VideoBufferInfo &input, VideoBufferInfo &output)
229 {
230     XCAM_FAIL_RETURN (
231         WARNING, input.format == V4L2_PIX_FMT_NV12, XCAM_RETURN_ERROR_PARAM,
232         "CLGeoMapHandler(%s) input buffer format(%s) not NV12", get_name (), xcam_fourcc_to_string (input.format));
233 
234     if (!_output_width || !_output_height) {
235         _output_width = input.width;
236         _output_height = input.height;
237     }
238     output.init (
239         input.format, _output_width, _output_height,
240         XCAM_ALIGN_UP (_output_width, 16), XCAM_ALIGN_UP (_output_height, 16));
241     return XCAM_RETURN_NO_ERROR;
242 }
243 
244 XCamReturn
prepare_parameters(SmartPtr<VideoBuffer> & input,SmartPtr<VideoBuffer> & output)245 CLGeoMapHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output)
246 {
247     const VideoBufferInfo &in_info = input->get_video_info ();
248     const VideoBufferInfo &out_info = output->get_video_info ();
249     SmartPtr<CLContext> context = get_context ();
250     uint32_t input_image_w = XCAM_ALIGN_DOWN (in_info.width, 2);
251     uint32_t input_image_h = XCAM_ALIGN_DOWN (in_info.height, 2);
252 
253     CLImageDesc cl_desc;
254     cl_desc.format.image_channel_data_type = CL_UNORM_INT8;
255     cl_desc.format.image_channel_order = CL_R;
256     cl_desc.width = input_image_w;
257     cl_desc.height = input_image_h;
258     cl_desc.row_pitch = in_info.strides[NV12PlaneYIdx];
259     _input[NV12PlaneYIdx] = convert_to_climage (context, input, cl_desc, in_info.offsets[NV12PlaneYIdx]);
260 
261     cl_desc.format.image_channel_data_type = CL_UNORM_INT8;
262     cl_desc.format.image_channel_order = CL_RG;
263     cl_desc.width = input_image_w / 2;
264     cl_desc.height = input_image_h / 2;
265     cl_desc.row_pitch = in_info.strides[NV12PlaneUVIdx];
266     _input[NV12PlaneUVIdx] = convert_to_climage (context, input, cl_desc, in_info.offsets[NV12PlaneUVIdx]);
267 
268     cl_desc.format.image_channel_data_type = CL_UNSIGNED_INT16;
269     cl_desc.format.image_channel_order = CL_RGBA;
270     cl_desc.width = XCAM_ALIGN_DOWN (out_info.width, 4) / 8; //CL_RGBA * CL_UNSIGNED_INT16 = 8
271     cl_desc.height = XCAM_ALIGN_DOWN (out_info.height, 2);
272     cl_desc.row_pitch = out_info.strides[NV12PlaneYIdx];
273     _output[NV12PlaneYIdx] = convert_to_climage (context, output, cl_desc, out_info.offsets[NV12PlaneYIdx]);
274     cl_desc.height /= 2;
275     cl_desc.row_pitch = out_info.strides[NV12PlaneUVIdx];
276     _output[NV12PlaneUVIdx] = convert_to_climage (context, output, cl_desc, out_info.offsets[NV12PlaneUVIdx]);
277 
278     XCAM_ASSERT (
279         _input[NV12PlaneYIdx].ptr () && _input[NV12PlaneYIdx]->is_valid () &&
280         _input[NV12PlaneUVIdx].ptr () && _input[NV12PlaneUVIdx]->is_valid () &&
281         _output[NV12PlaneYIdx].ptr () && _output[NV12PlaneYIdx]->is_valid () &&
282         _output[NV12PlaneUVIdx].ptr () && _output[NV12PlaneUVIdx]->is_valid ());
283 
284     XCAM_FAIL_RETURN (
285         ERROR, _geo_map.ptr () && _geo_map->is_valid (),
286         XCAM_RETURN_ERROR_PARAM, "CLGeoMapHandler map data was not set");
287 
288     //calculate kernel map unit_x, unit_y.
289     float uint_x, uint_y;
290     get_map_uint (uint_x, uint_y);
291     if (uint_x < 1.0f && uint_y < 1.0f) {
292         uint_x = out_info.width / (float)_map_width;
293         uint_y = out_info.height / (float)_map_height;
294         set_map_uint (uint_x, uint_y);
295     }
296 
297     if (!_geo_map_normalized) {
298         XCAM_FAIL_RETURN (
299             ERROR, normalize_geo_map (input_image_w, input_image_h),
300             XCAM_RETURN_ERROR_PARAM, "CLGeoMapHandler normalized geo map failed");
301         _geo_map_normalized = true;
302     }
303 
304     return XCAM_RETURN_NO_ERROR;
305 }
306 
307 XCamReturn
execute_done(SmartPtr<VideoBuffer> & output)308 CLGeoMapHandler::execute_done (SmartPtr<VideoBuffer> &output)
309 {
310     XCAM_UNUSED (output);
311 
312     for (int i = 0; i < NV12PlaneMax; ++i) {
313         _input[i].release ();
314         _output[i].release ();
315     }
316 
317     return XCAM_RETURN_NO_ERROR;
318 }
319 
320 SmartPtr<CLImageKernel>
create_geo_map_kernel(const SmartPtr<CLContext> & context,SmartPtr<GeoKernelParamCallback> param_cb,bool need_lsc)321 create_geo_map_kernel (
322     const SmartPtr<CLContext> &context, SmartPtr<GeoKernelParamCallback> param_cb, bool need_lsc)
323 {
324     SmartPtr<CLImageKernel> kernel;
325     kernel = new CLGeoMapKernel (context, param_cb, need_lsc);
326     XCAM_ASSERT (kernel.ptr ());
327 
328     char build_options[1024];
329     snprintf (build_options, sizeof(build_options), "-DENABLE_LSC=%d", need_lsc ? 1 : 0);
330     XCAM_FAIL_RETURN (
331         ERROR, kernel->build_kernel (kernel_geo_map_info, build_options) == XCAM_RETURN_NO_ERROR,
332         NULL, "build geo map kernel failed");
333 
334     return kernel;
335 }
336 
337 SmartPtr<CLImageHandler>
create_geo_map_handler(const SmartPtr<CLContext> & context,bool need_lsc)338 create_geo_map_handler (const SmartPtr<CLContext> &context, bool need_lsc)
339 {
340     SmartPtr<CLGeoMapHandler> handler;
341     SmartPtr<CLImageKernel> kernel;
342 
343     handler = new CLGeoMapHandler (context);
344     XCAM_ASSERT (handler.ptr ());
345 
346     kernel = create_geo_map_kernel (context, handler, need_lsc);
347     XCAM_FAIL_RETURN (
348         ERROR, kernel.ptr (), NULL, "CLMapHandler build geo map kernel failed");
349     handler->add_kernel (kernel);
350 
351     return handler;
352 }
353 
354 }
355