| /* |
| * cl_geo_map_handler.cpp - CL geometry map handler |
| * |
| * Copyright (c) 2016 Intel Corporation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * Author: Wind Yuan <[email protected]> |
| */ |
| |
| #include "cl_utils.h" |
| #include "cl_geo_map_handler.h" |
| #include "cl_device.h" |
| |
| namespace XCam { |
| |
| static const XCamKernelInfo kernel_geo_map_info = { |
| "kernel_geo_map", |
| #include "kernel_geo_map.clx" |
| , 0, |
| }; |
| |
| // GEO_MAP_CHANNEL for CL_RGBA channel |
| #define GEO_MAP_CHANNEL 4 /* only use channel_0, channel_1 */ |
| |
| CLGeoMapKernel::CLGeoMapKernel ( |
| const SmartPtr<CLContext> &context, const SmartPtr<GeoKernelParamCallback> handler, bool need_lsc) |
| : CLImageKernel (context) |
| , _handler (handler) |
| , _need_lsc (need_lsc) |
| { |
| XCAM_ASSERT (handler.ptr ()); |
| } |
| |
| XCamReturn |
| CLGeoMapKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) |
| { |
| SmartPtr<CLImage> input_y = _handler->get_geo_input_image (NV12PlaneYIdx); |
| SmartPtr<CLImage> input_uv = _handler->get_geo_input_image (NV12PlaneUVIdx); |
| SmartPtr<CLImage> output_y = _handler->get_geo_output_image (NV12PlaneYIdx); |
| SmartPtr<CLImage> output_uv = _handler->get_geo_output_image (NV12PlaneUVIdx); |
| const CLImageDesc &outuv_desc = output_uv->get_image_desc (); |
| SmartPtr<CLImage> geo_image = _handler->get_geo_map_table (); |
| |
| float geo_scale_size[2]; //width/height |
| float out_size[2]; |
| _handler->get_geo_equivalent_out_size (geo_scale_size[0], geo_scale_size[1]); |
| _handler->get_geo_pixel_out_size (out_size[0], out_size[1]); |
| |
| args.push_back (new CLMemArgument (input_y)); |
| args.push_back (new CLMemArgument (input_uv)); |
| args.push_back (new CLMemArgument (geo_image)); |
| args.push_back (new CLArgumentTArray<float, 2> (geo_scale_size)); |
| |
| if (_need_lsc) { |
| SmartPtr<CLImage> lsc_image = _handler->get_lsc_table (); |
| float *gray_threshold = _handler->get_lsc_gray_threshold (); |
| XCAM_FAIL_RETURN ( |
| ERROR, |
| lsc_image.ptr() && lsc_image->is_valid () && gray_threshold, |
| XCAM_RETURN_ERROR_PARAM, |
| "CLGeoMapHandler::lsc table or gray threshold was not found"); |
| args.push_back (new CLMemArgument (lsc_image)); |
| args.push_back (new CLArgumentTArray<float, 2> (gray_threshold)); |
| } |
| args.push_back (new CLMemArgument (output_y)); |
| args.push_back (new CLMemArgument (output_uv)); |
| args.push_back (new CLArgumentTArray<float, 2> (out_size)); |
| |
| work_size.dim = XCAM_DEFAULT_IMAGE_DIM; |
| work_size.local[0] = 16; |
| work_size.local[1] = 4; |
| work_size.global[0] = XCAM_ALIGN_UP (outuv_desc.width, work_size.local[0]); |
| work_size.global[1] = XCAM_ALIGN_UP (outuv_desc.height, work_size.local[1]); |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| CLGeoMapHandler::CLGeoMapHandler (const SmartPtr<CLContext> &context) |
| : CLImageHandler (context, "CLGeoMapHandler") |
| , _output_width (0) |
| , _output_height (0) |
| , _map_width (0) |
| , _map_height (0) |
| , _map_aligned_width (0) |
| , _uint_x (0.0f) |
| , _uint_y (0.0f) |
| , _geo_map_normalized (false) |
| { |
| } |
| |
| void |
| CLGeoMapHandler::get_geo_equivalent_out_size (float &width, float &height) |
| { |
| width = _map_width * _uint_x; |
| height = _map_height * _uint_y; |
| } |
| |
| void |
| CLGeoMapHandler::get_geo_pixel_out_size (float &width, float &height) |
| { |
| width = _output_width; |
| height = _output_height; |
| } |
| |
| bool |
| CLGeoMapHandler::set_map_uint (float uint_x, float uint_y) |
| { |
| _uint_x = uint_x; |
| _uint_y = uint_y; |
| return true; |
| } |
| |
| bool |
| CLGeoMapHandler::set_map_data (GeoPos *data, uint32_t width, uint32_t height) |
| { |
| uint32_t size = width * height * GEO_MAP_CHANNEL * sizeof (float); // 4 for CL_RGBA, |
| float *map_ptr = NULL; |
| |
| XCAM_FAIL_RETURN ( |
| ERROR, check_geo_map_buf (width, height), false, |
| "CLGeoMapKernel check geo map buffer failed"); |
| |
| XCamReturn ret = _geo_map->enqueue_map ((void *&)map_ptr, 0, size); |
| XCAM_FAIL_RETURN ( |
| WARNING, ret == XCAM_RETURN_NO_ERROR, false, |
| "CLGeoMapKernel map buffer failed"); |
| |
| uint32_t start, idx; |
| for (uint32_t h = 0; h < height; ++h) { |
| for (uint32_t w = 0; w < width; ++w) { |
| start = (h * _map_aligned_width + w) * GEO_MAP_CHANNEL; |
| idx = h * width + w; |
| |
| map_ptr [start] = data [idx].x; |
| map_ptr [start + 1] = data [idx].y; |
| } |
| } |
| _geo_map->enqueue_unmap ((void *&)map_ptr); |
| _geo_map_normalized = false; |
| return true; |
| } |
| |
| bool |
| CLGeoMapHandler::check_geo_map_buf (uint32_t width, uint32_t height) |
| { |
| XCAM_ASSERT (width && height); |
| if (width == _map_width && height == _map_height && _geo_map.ptr ()) { |
| return true; // geo memory already created |
| } |
| |
| uint32_t aligned_width = XCAM_ALIGN_UP (width, XCAM_CL_IMAGE_ALIGNMENT_X); // 4 channel for CL_RGBA, but only use RG |
| uint32_t row_pitch = aligned_width * GEO_MAP_CHANNEL * sizeof (float); |
| uint32_t size = row_pitch * height; |
| SmartPtr<CLContext> context = get_context (); |
| XCAM_ASSERT (context.ptr ()); |
| _geo_map = new CLBuffer (context, size); |
| |
| if (!_geo_map.ptr () || !_geo_map->is_valid ()) { |
| XCAM_LOG_ERROR ("CLGeoMapKernel create geo map buffer failed."); |
| _geo_map.release (); |
| return false; |
| } |
| |
| CLImageDesc cl_geo_desc; |
| cl_geo_desc.format.image_channel_data_type = CL_FLOAT; |
| cl_geo_desc.format.image_channel_order = CL_RGBA; // CL_FLOAT need co-work with CL_RGBA |
| cl_geo_desc.width = width; |
| cl_geo_desc.height = height; |
| cl_geo_desc.row_pitch = row_pitch; |
| _geo_image = new CLImage2D (context, cl_geo_desc, 0, _geo_map); |
| if (!_geo_image.ptr () || !_geo_image->is_valid ()) { |
| XCAM_LOG_ERROR ("CLGeoMapKernel convert geo map buffer to image2d failed."); |
| _geo_map.release (); |
| _geo_image.release (); |
| return false; |
| } |
| |
| _map_width = width; |
| _map_height = height; |
| _map_aligned_width = aligned_width; |
| return true; |
| } |
| |
| |
| bool |
| CLGeoMapHandler::normalize_geo_map (uint32_t image_w, uint32_t image_h) |
| { |
| XCamReturn ret = XCAM_RETURN_NO_ERROR; |
| |
| uint32_t row_pitch = _map_aligned_width * GEO_MAP_CHANNEL * sizeof (float); // 4 channel for CL_RGBA, but only use RG |
| uint32_t size = row_pitch * _map_height; |
| float *map_ptr = NULL; |
| |
| XCAM_ASSERT (image_w && image_h); |
| XCAM_FAIL_RETURN ( |
| ERROR, _geo_map.ptr () && _geo_map->is_valid (), |
| false, "CLGeoMapKernel geo_map was not initialized"); |
| |
| ret = _geo_map->enqueue_map ((void *&)map_ptr, 0, size); |
| XCAM_FAIL_RETURN (WARNING, ret == XCAM_RETURN_NO_ERROR, false, "CLGeoMapKernel map buffer failed"); |
| uint32_t idx = 0; |
| for (uint32_t h = 0; h < _map_height; ++h) { |
| for (uint32_t w = 0; w < _map_width; ++w) { |
| idx = (h * _map_aligned_width + w) * GEO_MAP_CHANNEL; |
| |
| map_ptr [idx] /= image_w; |
| map_ptr [idx + 1] /= image_h; |
| } |
| } |
| _geo_map->enqueue_unmap ((void *&)map_ptr); |
| |
| return true; |
| } |
| |
| XCamReturn |
| CLGeoMapHandler::prepare_buffer_pool_video_info ( |
| const VideoBufferInfo &input, VideoBufferInfo &output) |
| { |
| XCAM_FAIL_RETURN ( |
| WARNING, input.format == V4L2_PIX_FMT_NV12, XCAM_RETURN_ERROR_PARAM, |
| "CLGeoMapHandler(%s) input buffer format(%s) not NV12", get_name (), xcam_fourcc_to_string (input.format)); |
| |
| if (!_output_width || !_output_height) { |
| _output_width = input.width; |
| _output_height = input.height; |
| } |
| output.init ( |
| input.format, _output_width, _output_height, |
| XCAM_ALIGN_UP (_output_width, 16), XCAM_ALIGN_UP (_output_height, 16)); |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| XCamReturn |
| CLGeoMapHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) |
| { |
| const VideoBufferInfo &in_info = input->get_video_info (); |
| const VideoBufferInfo &out_info = output->get_video_info (); |
| SmartPtr<CLContext> context = get_context (); |
| uint32_t input_image_w = XCAM_ALIGN_DOWN (in_info.width, 2); |
| uint32_t input_image_h = XCAM_ALIGN_DOWN (in_info.height, 2); |
| |
| CLImageDesc cl_desc; |
| cl_desc.format.image_channel_data_type = CL_UNORM_INT8; |
| cl_desc.format.image_channel_order = CL_R; |
| cl_desc.width = input_image_w; |
| cl_desc.height = input_image_h; |
| cl_desc.row_pitch = in_info.strides[NV12PlaneYIdx]; |
| _input[NV12PlaneYIdx] = convert_to_climage (context, input, cl_desc, in_info.offsets[NV12PlaneYIdx]); |
| |
| cl_desc.format.image_channel_data_type = CL_UNORM_INT8; |
| cl_desc.format.image_channel_order = CL_RG; |
| cl_desc.width = input_image_w / 2; |
| cl_desc.height = input_image_h / 2; |
| cl_desc.row_pitch = in_info.strides[NV12PlaneUVIdx]; |
| _input[NV12PlaneUVIdx] = convert_to_climage (context, input, cl_desc, in_info.offsets[NV12PlaneUVIdx]); |
| |
| cl_desc.format.image_channel_data_type = CL_UNSIGNED_INT16; |
| cl_desc.format.image_channel_order = CL_RGBA; |
| cl_desc.width = XCAM_ALIGN_DOWN (out_info.width, 4) / 8; //CL_RGBA * CL_UNSIGNED_INT16 = 8 |
| cl_desc.height = XCAM_ALIGN_DOWN (out_info.height, 2); |
| cl_desc.row_pitch = out_info.strides[NV12PlaneYIdx]; |
| _output[NV12PlaneYIdx] = convert_to_climage (context, output, cl_desc, out_info.offsets[NV12PlaneYIdx]); |
| cl_desc.height /= 2; |
| cl_desc.row_pitch = out_info.strides[NV12PlaneUVIdx]; |
| _output[NV12PlaneUVIdx] = convert_to_climage (context, output, cl_desc, out_info.offsets[NV12PlaneUVIdx]); |
| |
| XCAM_ASSERT ( |
| _input[NV12PlaneYIdx].ptr () && _input[NV12PlaneYIdx]->is_valid () && |
| _input[NV12PlaneUVIdx].ptr () && _input[NV12PlaneUVIdx]->is_valid () && |
| _output[NV12PlaneYIdx].ptr () && _output[NV12PlaneYIdx]->is_valid () && |
| _output[NV12PlaneUVIdx].ptr () && _output[NV12PlaneUVIdx]->is_valid ()); |
| |
| XCAM_FAIL_RETURN ( |
| ERROR, _geo_map.ptr () && _geo_map->is_valid (), |
| XCAM_RETURN_ERROR_PARAM, "CLGeoMapHandler map data was not set"); |
| |
| //calculate kernel map unit_x, unit_y. |
| float uint_x, uint_y; |
| get_map_uint (uint_x, uint_y); |
| if (uint_x < 1.0f && uint_y < 1.0f) { |
| uint_x = out_info.width / (float)_map_width; |
| uint_y = out_info.height / (float)_map_height; |
| set_map_uint (uint_x, uint_y); |
| } |
| |
| if (!_geo_map_normalized) { |
| XCAM_FAIL_RETURN ( |
| ERROR, normalize_geo_map (input_image_w, input_image_h), |
| XCAM_RETURN_ERROR_PARAM, "CLGeoMapHandler normalized geo map failed"); |
| _geo_map_normalized = true; |
| } |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| XCamReturn |
| CLGeoMapHandler::execute_done (SmartPtr<VideoBuffer> &output) |
| { |
| XCAM_UNUSED (output); |
| |
| for (int i = 0; i < NV12PlaneMax; ++i) { |
| _input[i].release (); |
| _output[i].release (); |
| } |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| SmartPtr<CLImageKernel> |
| create_geo_map_kernel ( |
| const SmartPtr<CLContext> &context, SmartPtr<GeoKernelParamCallback> param_cb, bool need_lsc) |
| { |
| SmartPtr<CLImageKernel> kernel; |
| kernel = new CLGeoMapKernel (context, param_cb, need_lsc); |
| XCAM_ASSERT (kernel.ptr ()); |
| |
| char build_options[1024]; |
| snprintf (build_options, sizeof(build_options), "-DENABLE_LSC=%d", need_lsc ? 1 : 0); |
| XCAM_FAIL_RETURN ( |
| ERROR, kernel->build_kernel (kernel_geo_map_info, build_options) == XCAM_RETURN_NO_ERROR, |
| NULL, "build geo map kernel failed"); |
| |
| return kernel; |
| } |
| |
| SmartPtr<CLImageHandler> |
| create_geo_map_handler (const SmartPtr<CLContext> &context, bool need_lsc) |
| { |
| SmartPtr<CLGeoMapHandler> handler; |
| SmartPtr<CLImageKernel> kernel; |
| |
| handler = new CLGeoMapHandler (context); |
| XCAM_ASSERT (handler.ptr ()); |
| |
| kernel = create_geo_map_kernel (context, handler, need_lsc); |
| XCAM_FAIL_RETURN ( |
| ERROR, kernel.ptr (), NULL, "CLMapHandler build geo map kernel failed"); |
| handler->add_kernel (kernel); |
| |
| return handler; |
| } |
| |
| } |