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 (at) 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 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 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 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 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 110 CLGeoMapHandler::get_geo_pixel_out_size (float &width, float &height) 111 { 112 width = _output_width; 113 height = _output_height; 114 } 115 116 bool 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 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 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 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 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 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 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> 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> 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