/* * cl_image_scaler.cpp - CL image scaler * * Copyright (c) 2015 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_scaler.h" namespace XCam { static const XCamKernelInfo kernel_scale_info = { "kernel_image_scaler", #include "kernel_image_scaler.clx" , 0, }; CLScalerKernel::CLScalerKernel ( const SmartPtr &context, CLImageScalerMemoryLayout mem_layout ) : CLImageKernel (context, "kernel_image_scaler") , _mem_layout (mem_layout) { } XCamReturn CLScalerKernel::prepare_arguments (CLArgList &args, CLWorkSize &work_size) { XCamReturn ret = XCAM_RETURN_NO_ERROR; SmartPtr context = get_context (); SmartPtr input = get_input_buffer (); SmartPtr output = get_output_buffer (); SmartPtr image_in, image_out; XCAM_FAIL_RETURN ( WARNING, input.ptr () && output.ptr (), XCAM_RETURN_ERROR_MEM, "cl image kernel(%s) get input/output buffer failed", XCAM_STR(get_kernel_name ())); const VideoBufferInfo &input_info = input->get_video_info (); const VideoBufferInfo &output_info = output->get_video_info (); uint32_t output_width = 0, output_height = 0; CLImageDesc output_imageDesc; uint32_t channel_bits = XCAM_ALIGN_UP (output_info.color_bits, 8); if (channel_bits == 8) output_imageDesc.format.image_channel_data_type = CL_UNSIGNED_INT8; else if (channel_bits == 16) output_imageDesc.format.image_channel_data_type = CL_UNSIGNED_INT16; if ((CL_IMAGE_SCALER_NV12_UV == get_mem_layout ()) && (V4L2_PIX_FMT_NV12 == input_info.format)) { output_imageDesc.format.image_channel_order = CL_RG; output_imageDesc.width = output_info.width / 2; output_imageDesc.height = output_info.height / 2; output_imageDesc.row_pitch = output_info.strides[1]; image_out = convert_to_climage (context, output, output_imageDesc, output_info.offsets[1]); output_width = output_info.width / 2; output_height = output_info.height / 2; } else { output_imageDesc.format.image_channel_order = CL_R; output_imageDesc.width = output_info.width; output_imageDesc.height = output_info.height; output_imageDesc.row_pitch = output_info.strides[0]; image_out = convert_to_climage (context, output, output_imageDesc, output_info.offsets[0]); output_width = output_info.width; output_height = output_info.height; } CLImageDesc input_imageDesc; channel_bits = XCAM_ALIGN_UP (input_info.color_bits, 8); if (channel_bits == 8) input_imageDesc.format.image_channel_data_type = CL_UNSIGNED_INT8; else if (channel_bits == 16) input_imageDesc.format.image_channel_data_type = CL_UNSIGNED_INT16; if ((CL_IMAGE_SCALER_NV12_UV == get_mem_layout ()) && (V4L2_PIX_FMT_NV12 == input_info.format)) { input_imageDesc.format.image_channel_order = CL_RG; input_imageDesc.width = input_info.width / 2; input_imageDesc.height = input_info.height / 2; input_imageDesc.row_pitch = input_info.strides[1]; image_in = convert_to_climage (context, input, input_imageDesc, input_info.offsets[1]); } else { input_imageDesc.format.image_channel_order = CL_R; input_imageDesc.width = input_info.width; input_imageDesc.height = input_info.height; input_imageDesc.row_pitch = input_info.strides[0]; image_in = convert_to_climage (context, input, input_imageDesc, input_info.offsets[0]); } //set args; args.push_back (new CLMemArgument (image_in)); args.push_back (new CLMemArgument (image_out)); args.push_back (new CLArgumentT (output_width)); args.push_back (new CLArgumentT (output_height)); work_size.dim = XCAM_DEFAULT_IMAGE_DIM; work_size.global[0] = XCAM_ALIGN_UP (output_width, XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE0); work_size.global[1] = XCAM_ALIGN_UP (output_height, XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE1); work_size.local[0] = XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE0; work_size.local[1] = XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE1; return ret; } CLImageScalerKernel::CLImageScalerKernel ( const SmartPtr &context, CLImageScalerMemoryLayout mem_layout, SmartPtr &scaler ) : CLScalerKernel (context, mem_layout) , _scaler (scaler) { } SmartPtr CLImageScalerKernel::get_input_buffer () { return _scaler->get_input_buf (); } SmartPtr CLImageScalerKernel::get_output_buffer () { return _scaler->get_scaler_buf (); } CLImageScaler::CLImageScaler (const SmartPtr &context) : CLImageHandler (context, "CLImageScaler") , _h_scaler_factor (0.5) , _v_scaler_factor (0.5) { } void CLImageScaler::emit_stop () { if (_scaler_buf_pool.ptr ()) _scaler_buf_pool->stop (); } bool CLImageScaler::set_scaler_factor (const double h_factor, const double v_factor) { _h_scaler_factor = h_factor; _v_scaler_factor = v_factor; return true; } bool CLImageScaler::get_scaler_factor (double &h_factor, double &v_factor) const { h_factor = _h_scaler_factor; v_factor = _v_scaler_factor; return true; }; XCamReturn CLImageScaler::prepare_output_buf (SmartPtr &input, SmartPtr &output) { XCamReturn ret = XCAM_RETURN_NO_ERROR; output = input; ret = prepare_scaler_buf (input->get_video_info (), _scaler_buf); XCAM_FAIL_RETURN( WARNING, ret == XCAM_RETURN_NO_ERROR, ret, "CLImageScalerKernel prepare scaled video buf failed"); _scaler_buf->set_timestamp (input->get_timestamp ()); return ret; } XCamReturn CLImageScaler::execute_done (SmartPtr &output) { XCAM_UNUSED (output); get_context ()->finish(); XCAM_ASSERT (_scaler_buf.ptr ()); //post buffer out return post_buffer (_scaler_buf); } XCamReturn CLImageScaler::prepare_scaler_buf (const VideoBufferInfo &video_info, SmartPtr &output) { if (!_scaler_buf_pool.ptr ()) { VideoBufferInfo scaler_video_info; uint32_t new_width = XCAM_ALIGN_UP ((uint32_t)(video_info.width * _h_scaler_factor), 2 * XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE0); uint32_t new_height = XCAM_ALIGN_UP ((uint32_t)(video_info.height * _v_scaler_factor), 2 * XCAM_CL_IMAGE_SCALER_KERNEL_LOCAL_WORK_SIZE1); scaler_video_info.init (video_info.format, new_width, new_height); _scaler_buf_pool = new CLVideoBufferPool (); XCAM_ASSERT (_scaler_buf_pool.ptr ()); _scaler_buf_pool->set_video_info (scaler_video_info); _scaler_buf_pool->reserve (6); } output = _scaler_buf_pool->get_buffer (_scaler_buf_pool); XCAM_ASSERT (output.ptr ()); return XCAM_RETURN_NO_ERROR; } XCamReturn CLImageScaler::post_buffer (const SmartPtr &buffer) { if (_scaler_callback.ptr ()) return _scaler_callback->scaled_image_ready (buffer); return XCAM_RETURN_NO_ERROR; } static SmartPtr create_scale_kernel ( const SmartPtr &context, SmartPtr &handler, CLImageScalerMemoryLayout layout) { SmartPtr kernel; kernel = new CLImageScalerKernel (context, layout, handler); XCAM_ASSERT (kernel.ptr ()); XCAM_FAIL_RETURN ( ERROR, kernel->build_kernel (kernel_scale_info, NULL) == XCAM_RETURN_NO_ERROR, NULL, "build scaler kernel(%s) failed", kernel_scale_info.kernel_name); XCAM_ASSERT (kernel->is_valid ()); return kernel; } SmartPtr create_cl_image_scaler_handler (const SmartPtr &context, const uint32_t format) { SmartPtr scaler_handler; SmartPtr scaler_kernel; scaler_handler = new CLImageScaler (context); XCAM_ASSERT (scaler_handler.ptr ()); if (V4L2_PIX_FMT_NV12 == format) { //Y scaler_kernel = create_scale_kernel (context, scaler_handler, CL_IMAGE_SCALER_NV12_Y); XCAM_FAIL_RETURN (ERROR, scaler_kernel.ptr (), NULL, "build CL_IMAGE_SCALER_NV12_Y kernel failed"); scaler_handler->add_kernel (scaler_kernel); //UV scaler_kernel = create_scale_kernel (context, scaler_handler, CL_IMAGE_SCALER_NV12_UV); XCAM_FAIL_RETURN (ERROR, scaler_kernel.ptr (), NULL, "build CL_IMAGE_SCALER_NV12_UV kernel failed"); scaler_handler->add_kernel (scaler_kernel); } else if (XCAM_PIX_FMT_RGBA64 == format) { scaler_kernel = create_scale_kernel (context, scaler_handler, CL_IMAGE_SCALER_RGBA); XCAM_FAIL_RETURN (ERROR, scaler_kernel.ptr (), NULL, "build CL_IMAGE_SCALER_RGBA kernel failed"); scaler_handler->add_kernel (scaler_kernel); } else { XCAM_LOG_ERROR ("create cl image scaler failed, unknown format:0x%08x", format); return NULL; } return scaler_handler; } };