| /* |
| * 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 <[email protected]> |
| */ |
| |
| #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<CLContext> &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<CLContext> context = get_context (); |
| |
| SmartPtr<VideoBuffer> input = get_input_buffer (); |
| SmartPtr<VideoBuffer> output = get_output_buffer (); |
| SmartPtr<CLImage> 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<uint32_t> (output_width)); |
| args.push_back (new CLArgumentT<uint32_t> (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<CLContext> &context, |
| CLImageScalerMemoryLayout mem_layout, |
| SmartPtr<CLImageScaler> &scaler |
| ) |
| : CLScalerKernel (context, mem_layout) |
| , _scaler (scaler) |
| { |
| } |
| |
| SmartPtr<VideoBuffer> |
| CLImageScalerKernel::get_input_buffer () |
| { |
| return _scaler->get_input_buf (); |
| } |
| |
| SmartPtr<VideoBuffer> |
| CLImageScalerKernel::get_output_buffer () |
| { |
| return _scaler->get_scaler_buf (); |
| } |
| |
| CLImageScaler::CLImageScaler (const SmartPtr<CLContext> &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<VideoBuffer> &input, SmartPtr<VideoBuffer> &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<VideoBuffer> &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<VideoBuffer> &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<VideoBuffer> &buffer) |
| { |
| if (_scaler_callback.ptr ()) |
| return _scaler_callback->scaled_image_ready (buffer); |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| static SmartPtr<CLImageKernel> |
| create_scale_kernel ( |
| const SmartPtr<CLContext> &context, SmartPtr<CLImageScaler> &handler, CLImageScalerMemoryLayout layout) |
| { |
| SmartPtr<CLImageKernel> 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<CLImageHandler> |
| create_cl_image_scaler_handler (const SmartPtr<CLContext> &context, const uint32_t format) |
| { |
| SmartPtr<CLImageScaler> scaler_handler; |
| SmartPtr<CLImageKernel> 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; |
| } |
| |
| }; |