/* * cl_image_warp_handler.cpp - CL image warping 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: Zong Wei */ #include "cl_utils.h" #include "cl_image_warp_handler.h" namespace XCam { #define CL_IMAGE_WARP_WG_WIDTH 8 #define CL_IMAGE_WARP_WG_HEIGHT 4 static const XCamKernelInfo kernel_image_warp_info [] = { { "kernel_image_warp_8_pixel", #include "kernel_image_warp.clx" , 0, }, { "kernel_image_warp_1_pixel", #include "kernel_image_warp.clx" , 0, } }; CLImageWarpKernel::CLImageWarpKernel ( const SmartPtr &context, const char *name, uint32_t channel, SmartPtr &handler) : CLImageKernel (context, name) , _channel (channel) { _handler = handler.dynamic_cast_ptr (); } XCamReturn CLImageWarpKernel::prepare_arguments ( CLArgList &args, CLWorkSize &work_size) { SmartPtr context = get_context (); SmartPtr input = _handler->get_warp_input_buf (); SmartPtr output = _handler->get_output_buf (); const VideoBufferInfo & video_info_in = input->get_video_info (); const VideoBufferInfo & video_info_out = output->get_video_info (); uint32_t info_index = 0; if (_channel == CL_IMAGE_CHANNEL_Y) { info_index = 0; } else if (_channel == CL_IMAGE_CHANNEL_UV) { info_index = 1; } CLImageDesc cl_desc_in, cl_desc_out; cl_desc_in.format.image_channel_order = info_index == 0 ? CL_R : CL_RG; cl_desc_in.format.image_channel_data_type = CL_UNORM_INT8; cl_desc_in.width = video_info_in.width >> info_index; cl_desc_in.height = video_info_in.height >> info_index; cl_desc_in.row_pitch = video_info_in.strides[info_index]; #if CL_IMAGE_WARP_WRITE_UINT cl_desc_out.format.image_channel_data_type = info_index == 0 ? CL_UNSIGNED_INT16 : CL_UNSIGNED_INT32; cl_desc_out.format.image_channel_order = CL_RGBA; cl_desc_out.width = XCAM_ALIGN_DOWN (video_info_out.width >> info_index, 8) / 8; cl_desc_out.height = video_info_out.height >> info_index; #else cl_desc_out.format.image_channel_order = info_index == 0 ? CL_R : CL_RG; cl_desc_out.format.image_channel_data_type = CL_UNORM_INT8; cl_desc_out.width = video_info_out.width >> info_index; cl_desc_out.height = video_info_out.height >> info_index; #endif cl_desc_out.row_pitch = video_info_out.strides[info_index]; SmartPtr image_in = convert_to_climage (context, input, cl_desc_in, video_info_in.offsets[info_index]); CLWarpConfig warp_config = _handler->get_warp_config (); if ((warp_config.trim_ratio > 0.5f) || (warp_config.trim_ratio < 0.0f)) { warp_config.trim_ratio = 0.0f; } float sample_rate_x = (float)warp_config.width / (float)video_info_in.width; float sample_rate_y = (float)warp_config.height / (float)video_info_in.height; XCAM_LOG_DEBUG ("warp analyze image sample rate(%fx%f)", sample_rate_x, sample_rate_y); warp_config.proj_mat[2] = warp_config.proj_mat[2] / sample_rate_x; warp_config.proj_mat[5] = warp_config.proj_mat[5] / sample_rate_y; warp_config.proj_mat[6] = warp_config.proj_mat[6] * sample_rate_x; warp_config.proj_mat[7] = warp_config.proj_mat[7] * sample_rate_y; /* For NV12 image (YUV420), UV plane has half horizontal & vertical coordinate size of Y plane, need to adjust the projection matrix as: H(uv) = [0.5, 0, 0; 0, 0.5, 0; 0, 0, 1] * H(y) * [2, 0, 0; 0, 2, 0; 0, 0, 1] */ if (_channel == CL_IMAGE_CHANNEL_UV) { warp_config.proj_mat[2] = 0.5 * warp_config.proj_mat[2]; warp_config.proj_mat[5] = 0.5 * warp_config.proj_mat[5]; warp_config.proj_mat[6] = 2.0 * warp_config.proj_mat[6]; warp_config.proj_mat[7] = 2.0 * warp_config.proj_mat[7]; } /* Trim image: shift toward origin then scale up Trim Matrix (TMat) TMat = [ scale_x, 0.0f, shift_x; 0.0f, scale_y, shift_y; 1.0f, 1.0f, 1.0f; ] Warp Perspective Matrix = TMat * HMat */ #if CL_IMAGE_WARP_WRITE_UINT float shift_x = warp_config.trim_ratio * cl_desc_out.width * 8.0f; #else float shift_x = warp_config.trim_ratio * cl_desc_out.width; #endif float shift_y = warp_config.trim_ratio * cl_desc_out.height; float scale_x = 1.0f - 2.0f * warp_config.trim_ratio; float scale_y = 1.0f - 2.0f * warp_config.trim_ratio; warp_config.proj_mat[0] = scale_x * warp_config.proj_mat[0] + shift_x * warp_config.proj_mat[6]; warp_config.proj_mat[1] = scale_x * warp_config.proj_mat[1] + shift_x * warp_config.proj_mat[7]; warp_config.proj_mat[2] = scale_x * warp_config.proj_mat[2] + shift_x * warp_config.proj_mat[8]; warp_config.proj_mat[3] = scale_y * warp_config.proj_mat[3] + shift_y * warp_config.proj_mat[6]; warp_config.proj_mat[4] = scale_y * warp_config.proj_mat[4] + shift_y * warp_config.proj_mat[7]; warp_config.proj_mat[5] = scale_y * warp_config.proj_mat[5] + shift_y * warp_config.proj_mat[8]; XCAM_LOG_DEBUG ("warp config image size(%dx%d)", warp_config.width, warp_config.height); XCAM_LOG_DEBUG ("proj_mat[%d]=(%f, %f, %f, %f, %f, %f, %f, %f, %f);", warp_config.frame_id, warp_config.proj_mat[0], warp_config.proj_mat[1], warp_config.proj_mat[2], warp_config.proj_mat[3], warp_config.proj_mat[4], warp_config.proj_mat[5], warp_config.proj_mat[6], warp_config.proj_mat[7], warp_config.proj_mat[8]); SmartPtr image_out = convert_to_climage (context, output, cl_desc_out, video_info_out.offsets[info_index]); XCAM_FAIL_RETURN ( WARNING, image_in->is_valid () && image_out->is_valid (), XCAM_RETURN_ERROR_MEM, "cl image kernel(%s) in/out memory not available", get_kernel_name ()); //set args; work_size.dim = XCAM_DEFAULT_IMAGE_DIM; work_size.local[0] = CL_IMAGE_WARP_WG_WIDTH; work_size.local[1] = CL_IMAGE_WARP_WG_HEIGHT; work_size.global[0] = XCAM_ALIGN_UP (cl_desc_out.width, work_size.local[0]); work_size.global[1] = XCAM_ALIGN_UP(cl_desc_out.height, work_size.local[1]); args.push_back (new CLMemArgument (image_in)); args.push_back (new CLMemArgument (image_out)); args.push_back (new CLArgumentT (warp_config)); return XCAM_RETURN_NO_ERROR; } CLImageWarpHandler::CLImageWarpHandler (const SmartPtr &context, const char *name) : CLImageHandler (context, name) { } bool CLImageWarpHandler::is_ready () { bool ret = !_warp_config_list.empty (); return ret && CLImageHandler::is_ready (); } XCamReturn CLImageWarpHandler::execute_done (SmartPtr &output) { XCAM_UNUSED (output); if (!_warp_config_list.empty ()) { _warp_config_list.pop_front (); } return XCAM_RETURN_NO_ERROR; } SmartPtr CLImageWarpHandler::get_warp_input_buf () { return CLImageHandler::get_input_buf (); } bool CLImageWarpHandler::set_warp_config (const XCamDVSResult& config) { CLWarpConfig warp_config; warp_config.frame_id = config.frame_id; warp_config.width = config.frame_width; warp_config.height = config.frame_height; for( int i = 0; i < 9; i++ ) { warp_config.proj_mat[i] = config.proj_mat[i]; } XCAM_LOG_DEBUG ("warp_mat{%d}=[%f, %f, %f; %f, %f, %f; %f, %f, %f]", warp_config.frame_id + 1, warp_config.proj_mat[0], warp_config.proj_mat[1], warp_config.proj_mat[2], warp_config.proj_mat[3], warp_config.proj_mat[4], warp_config.proj_mat[5], warp_config.proj_mat[6], warp_config.proj_mat[7], warp_config.proj_mat[8]); #if 0 printf ("warp_mat{%d}=[%f, %f, %f; %f, %f, %f; %f, %f, %f]; \n", warp_config.frame_id + 1, warp_config.proj_mat[0], warp_config.proj_mat[1], warp_config.proj_mat[2], warp_config.proj_mat[3], warp_config.proj_mat[4], warp_config.proj_mat[5], warp_config.proj_mat[6], warp_config.proj_mat[7], warp_config.proj_mat[8]); #endif _warp_config_list.push_back (warp_config); return true; } CLWarpConfig CLImageWarpHandler::get_warp_config () { CLWarpConfig warp_config; if (_warp_config_list.size () > 0) { warp_config = *(_warp_config_list.begin ()); } else { warp_config.frame_id = -1; warp_config.proj_mat[0] = 1.0f; warp_config.proj_mat[1] = 0.0f; warp_config.proj_mat[2] = 0.0f; warp_config.proj_mat[3] = 0.0f; warp_config.proj_mat[4] = 1.0f; warp_config.proj_mat[5] = 0.0f; warp_config.proj_mat[6] = 0.0f; warp_config.proj_mat[7] = 0.0f; warp_config.proj_mat[8] = 1.0f; } return warp_config; } static SmartPtr create_kernel_image_warp ( const SmartPtr &context, uint32_t channel, SmartPtr handler) { SmartPtr warp_kernel; const char *name = (channel == CL_IMAGE_CHANNEL_Y ? "kernel_image_warp_y" : "kernel_image_warp_uv"); char build_options[1024]; xcam_mem_clear (build_options); snprintf (build_options, sizeof (build_options), " -DWARP_Y=%d ", (channel == CL_IMAGE_CHANNEL_Y ? 1 : 0)); warp_kernel = new CLImageWarpKernel (context, name, channel, handler); XCAM_ASSERT (warp_kernel.ptr ()); XCAM_FAIL_RETURN ( ERROR, warp_kernel->build_kernel (kernel_image_warp_info[KernelImageWarp], build_options) == XCAM_RETURN_NO_ERROR, NULL, "build image warp kernel failed"); XCAM_ASSERT (warp_kernel->is_valid ()); return warp_kernel; } SmartPtr create_cl_image_warp_handler (const SmartPtr &context) { SmartPtr warp_handler; SmartPtr warp_kernel; warp_handler = new CLImageWarpHandler (context); XCAM_ASSERT (warp_handler.ptr ()); warp_kernel = create_kernel_image_warp (context, CL_IMAGE_CHANNEL_Y, warp_handler); XCAM_ASSERT (warp_kernel.ptr ()); warp_handler->add_kernel (warp_kernel); warp_kernel = create_kernel_image_warp (context, CL_IMAGE_CHANNEL_UV, warp_handler); XCAM_ASSERT (warp_kernel.ptr ()); warp_handler->add_kernel (warp_kernel); return warp_handler; } };