/* * cl_image_handler.cpp - CL image handler * * 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: Wind Yuan <feng.yuan@intel.com> */ #include "cl_image_handler.h" #if HAVE_LIBDRM #include "drm_display.h" #include "cl_image_bo_buffer.h" #include "drm_bo_buffer.h" #endif #include "cl_device.h" #include "swapped_buffer.h" namespace XCam { #define XCAM_CL_IMAGE_HANDLER_DEFAULT_BUF_NUM 4 CLImageKernel::CLImageKernel (const SmartPtr<CLContext> &context, const char *name, bool enable) : CLKernel (context, name) , _enable (enable) { } CLImageKernel::~CLImageKernel () { } /* * Default kernel arguments * arg0: * input, __read_only image2d_t * arg1: * output, __write_only image2d_t * suppose cl can get width/height pixels from * get_image_width/get_image_height */ XCamReturn CLImageKernel::pre_execute () { XCamReturn ret = XCAM_RETURN_NO_ERROR; CLArgList args; CLWorkSize work_size; XCAM_FAIL_RETURN ( ERROR, !is_arguments_set (), XCAM_RETURN_ERROR_PARAM, "cl image kernel(%s) pre_execute failed since arguments was set somewhere", get_kernel_name ()); ret = prepare_arguments (args, work_size); XCAM_FAIL_RETURN ( WARNING, ret == XCAM_RETURN_NO_ERROR, ret, "cl image kernel(%s) prepare arguments failed", get_kernel_name ()); ret = set_arguments (args, work_size); XCAM_FAIL_RETURN ( WARNING, ret == XCAM_RETURN_NO_ERROR, ret, "cl image kernel(%s) set_arguments failed", get_kernel_name ()); return ret; } XCamReturn CLImageKernel::prepare_arguments ( CLArgList &args, CLWorkSize &work_size) { XCAM_UNUSED (args); XCAM_UNUSED (work_size); XCAM_LOG_ERROR ( "cl image kernel(%s) prepare_arguments error." "Did you forget to set_arguments or prepare_arguments was not derived", get_kernel_name ()); return XCAM_RETURN_ERROR_CL; } CLImageHandler::CLImageHandler (const SmartPtr<CLContext> &context, const char *name) : _name (NULL) , _enable (true) , _context (context) , _buf_pool_type (CLImageHandler::CLVideoPoolType) , _disable_buf_pool (false) , _buf_pool_size (XCAM_CL_IMAGE_HANDLER_DEFAULT_BUF_NUM) , _buf_swap_flags ((uint32_t)(SwappedBuffer::OrderY0Y1) | (uint32_t)(SwappedBuffer::OrderUV0UV1)) , _buf_swap_init_order (SwappedBuffer::OrderY0Y1) , _result_timestamp (XCam::InvalidTimestamp) { XCAM_ASSERT (name); if (name) _name = strndup (name, XCAM_MAX_STR_SIZE); XCAM_OBJ_PROFILING_INIT; } CLImageHandler::~CLImageHandler () { if (_name) xcam_free (_name); } bool CLImageHandler::enable_buf_pool_swap_flags ( uint32_t flags, uint32_t init_order) { #if HAVE_LIBDRM _buf_swap_flags = flags; _buf_swap_init_order = init_order; SmartPtr<DrmBoBufferPool> pool = _buf_pool.dynamic_cast_ptr<DrmBoBufferPool> (); if (pool.ptr () && !pool->update_swap_init_order (init_order)) { XCAM_LOG_ERROR ( "Handler(%s) update swap order(0x%04x) to buffer pool failed", XCAM_STR (get_name ()), init_order); return false; } return true; #else XCAM_LOG_ERROR ("CLImageHandler doesn't support swapping flags"); XCAM_UNUSED (flags); XCAM_UNUSED (init_order); return false; #endif } bool CLImageHandler::add_kernel (const SmartPtr<CLImageKernel> &kernel) { _kernels.push_back (kernel); return true; } bool CLImageHandler::enable_handler (bool enable) { _enable = enable; return true; } bool CLImageHandler::is_handler_enabled () const { return _enable; } XCamReturn CLImageHandler::create_buffer_pool (const VideoBufferInfo &video_info) { if (_buf_pool.ptr ()) return XCAM_RETURN_ERROR_PARAM; SmartPtr<BufferPool> buffer_pool; if (_buf_pool_type == CLImageHandler::CLVideoPoolType) { buffer_pool = new CLVideoBufferPool (); } #if HAVE_LIBDRM else { SmartPtr<DrmDisplay> display = DrmDisplay::instance (); XCAM_FAIL_RETURN( WARNING, display.ptr (), XCAM_RETURN_ERROR_CL, "CLImageHandler(%s) failed to get drm dispay", XCAM_STR (_name)); if (_buf_pool_type == CLImageHandler::DrmBoPoolType) { buffer_pool = new DrmBoBufferPool (display); } else if (_buf_pool_type == CLImageHandler::CLBoPoolType) { buffer_pool = new CLBoBufferPool (display, get_context ()); } } #endif XCAM_FAIL_RETURN( WARNING, buffer_pool.ptr (), XCAM_RETURN_ERROR_CL, "CLImageHandler(%s) create buffer pool failed, pool_type:%d", XCAM_STR (_name), (int32_t)_buf_pool_type); XCAM_ASSERT (buffer_pool.ptr ()); // buffer_pool->set_swap_flags (_buf_swap_flags, _buf_swap_init_order); buffer_pool->set_video_info (video_info); XCAM_FAIL_RETURN( WARNING, buffer_pool->reserve (_buf_pool_size), XCAM_RETURN_ERROR_CL, "CLImageHandler(%s) failed to init drm buffer pool", XCAM_STR (_name)); _buf_pool = buffer_pool; return XCAM_RETURN_NO_ERROR; } bool CLImageHandler::is_ready () { if (_disable_buf_pool) return true; if (!_buf_pool.ptr ()) //execute not triggered return true; if (_buf_pool->has_free_buffers ()) return true; return false; } XCamReturn CLImageHandler::prepare_buffer_pool_video_info ( const VideoBufferInfo &input, VideoBufferInfo &output) { output = input; return XCAM_RETURN_NO_ERROR; } XCamReturn CLImageHandler::prepare_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) { XCAM_UNUSED (input); XCAM_UNUSED (output); XCAM_ASSERT (input.ptr () && output.ptr ()); return XCAM_RETURN_NO_ERROR; } XCamReturn CLImageHandler::ensure_parameters (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) { XCamReturn ret = prepare_parameters (input, output); XCAM_FAIL_RETURN( WARNING, ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS, ret, "CLImageHandler(%s) failed to prepare_parameters", XCAM_STR (_name)); reset_buf_cache (input, output); return ret; } void CLImageHandler::reset_buf_cache (const SmartPtr<VideoBuffer>& input, const SmartPtr<VideoBuffer>& output) { _input_buf_cache = input; _output_buf_cache = output; } XCamReturn CLImageHandler::prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) { XCamReturn ret = XCAM_RETURN_NO_ERROR; if (_disable_buf_pool) return XCAM_RETURN_NO_ERROR; if (!_buf_pool.ptr ()) { VideoBufferInfo output_video_info; ret = prepare_buffer_pool_video_info (input->get_video_info (), output_video_info); XCAM_FAIL_RETURN( WARNING, ret == XCAM_RETURN_NO_ERROR, ret, "CLImageHandler(%s) prepare output video info failed", XCAM_STR (_name)); ret = create_buffer_pool (output_video_info); XCAM_FAIL_RETURN( WARNING, ret == XCAM_RETURN_NO_ERROR, ret, "CLImageHandler(%s) ensure drm buffer pool failed", XCAM_STR (_name)); } output = _buf_pool->get_buffer (_buf_pool); XCAM_FAIL_RETURN( WARNING, output.ptr(), XCAM_RETURN_ERROR_UNKNOWN, "CLImageHandler(%s) failed to get drm buffer from pool", XCAM_STR (_name)); // TODO, need consider output is not sync up with input buffer output->set_timestamp (input->get_timestamp ()); output->copy_attaches (input); return XCAM_RETURN_NO_ERROR; } void CLImageHandler::emit_stop () { for (KernelList::iterator i_kernel = _kernels.begin (); i_kernel != _kernels.end (); ++i_kernel) { (*i_kernel)->pre_stop (); } if (_buf_pool.ptr ()) _buf_pool->stop (); } SmartPtr<VideoBuffer> & CLImageHandler::get_input_buf () { XCAM_ASSERT (_input_buf_cache.ptr ()); return _input_buf_cache; } SmartPtr<VideoBuffer> & CLImageHandler::get_output_buf () { XCAM_ASSERT (_output_buf_cache.ptr ()); return _output_buf_cache; } XCamReturn CLImageHandler::execute_kernel (SmartPtr<CLImageKernel> &kernel) { XCamReturn ret = XCAM_RETURN_NO_ERROR; if (!kernel->is_enabled ()) return XCAM_RETURN_NO_ERROR; if (!kernel->is_arguments_set ()) { XCAM_FAIL_RETURN ( WARNING, (ret = kernel->pre_execute ()) == XCAM_RETURN_NO_ERROR, ret, "cl_image_handler(%s) pre_execute kernel(%s) failed", XCAM_STR (_name), kernel->get_kernel_name ()); } CLArgList args = kernel->get_args (); ret = kernel->execute (kernel, false); XCAM_FAIL_RETURN ( WARNING, ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS, ret, "cl_image_handler(%s) execute kernel(%s) failed", XCAM_STR (_name), kernel->get_kernel_name ()); #if 0 ret = kernel->post_execute (args); XCAM_FAIL_RETURN ( WARNING, (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS), ret, "cl_image_handler(%s) post_execute kernel(%s) failed", XCAM_STR (_name), kernel->get_kernel_name ()); #endif return ret; } XCamReturn CLImageHandler::execute_kernels () { XCamReturn ret = XCAM_RETURN_NO_ERROR; for (KernelList::iterator i_kernel = _kernels.begin (); i_kernel != _kernels.end (); ++i_kernel) { SmartPtr<CLImageKernel> &kernel = *i_kernel; XCAM_FAIL_RETURN ( WARNING, kernel.ptr(), XCAM_RETURN_ERROR_PARAM, "kernel empty"); ret = execute_kernel (kernel); if (ret != XCAM_RETURN_NO_ERROR) break; } return ret; } XCamReturn CLImageHandler::execute (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) { XCamReturn ret = XCAM_RETURN_NO_ERROR; XCAM_FAIL_RETURN ( WARNING, !_kernels.empty (), XCAM_RETURN_ERROR_PARAM, "cl_image_handler(%s) no image kernel set", XCAM_STR (_name)); if (!is_handler_enabled ()) { output = input; return XCAM_RETURN_NO_ERROR; } XCAM_FAIL_RETURN ( WARNING, (ret = prepare_output_buf (input, output)) == XCAM_RETURN_NO_ERROR, ret, "cl_image_handler (%s) prepare output buf failed", XCAM_STR (_name)); XCAM_ASSERT (output.ptr ()); ret = ensure_parameters (input, output); XCAM_FAIL_RETURN ( WARNING, (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS), ret, "cl_image_handler (%s) ensure parameters failed", XCAM_STR (_name)); if (ret == XCAM_RETURN_BYPASS) return ret; XCAM_OBJ_PROFILING_START; ret = execute_kernels (); reset_buf_cache (NULL, NULL); #if ENABLE_PROFILING get_context ()->finish (); #endif XCAM_OBJ_PROFILING_END (XCAM_STR (_name), XCAM_OBJ_DUR_FRAME_NUM); XCAM_FAIL_RETURN ( WARNING, (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_BYPASS), ret, "cl_image_handler (%s) execute kernels failed", XCAM_STR (_name)); if (ret != XCAM_RETURN_NO_ERROR) return ret; ret = execute_done (output); return ret; } XCamReturn CLImageHandler::execute_done (SmartPtr<VideoBuffer> &output) { XCAM_UNUSED (output); return XCAM_RETURN_NO_ERROR; } void CLImageHandler::set_3a_result (SmartPtr<X3aResult> &result) { if (!result.ptr ()) return; int64_t ts = result->get_timestamp (); _result_timestamp = (ts != XCam::InvalidTimestamp) ? ts : _result_timestamp; X3aResultList::iterator i_res = _3a_results.begin (); for (; i_res != _3a_results.end(); ++i_res) { if (result->get_type () == (*i_res)->get_type ()) { (*i_res) = result; break; } } if (i_res == _3a_results.end ()) { _3a_results.push_back (result); } } SmartPtr<X3aResult> CLImageHandler::get_3a_result (XCam3aResultType type) { X3aResultList::iterator i_res = _3a_results.begin (); SmartPtr<X3aResult> res; for ( ; i_res != _3a_results.end(); ++i_res) { if (type == (*i_res)->get_type ()) { res = (*i_res); break; } } return res; } bool CLImageHandler::append_kernels (SmartPtr<CLImageHandler> handler) { XCAM_ASSERT (!handler->_kernels.empty ()); _kernels.insert (_kernels.end (), handler->_kernels.begin (), handler->_kernels.end ()); return true; } CLCloneImageHandler::CLCloneImageHandler (const SmartPtr<CLContext> &context, const char *name) : CLImageHandler (context, name) , _clone_flags (SwappedBuffer::SwapNone) { } XCamReturn CLCloneImageHandler::prepare_output_buf (SmartPtr<VideoBuffer> &input, SmartPtr<VideoBuffer> &output) { #if HAVE_LIBDRM XCAM_FAIL_RETURN ( ERROR, _clone_flags != (uint32_t)(SwappedBuffer::SwapNone), XCAM_RETURN_ERROR_PARAM, "CLCloneImageHandler(%s) clone output buffer failed since clone_flags none", XCAM_STR (get_name ())); XCAM_ASSERT (input.ptr ()); SmartPtr<SwappedBuffer> swap_input = input.dynamic_cast_ptr<DrmBoBuffer> (); XCAM_ASSERT (swap_input.ptr ()); SmartPtr<SwappedBuffer> swap_output = swap_input->swap_clone (swap_input, _clone_flags); SmartPtr<DrmBoBuffer> swapped_buf = swap_output.dynamic_cast_ptr<DrmBoBuffer> (); XCAM_FAIL_RETURN ( ERROR, swapped_buf.ptr (), XCAM_RETURN_ERROR_UNKNOWN, "CLCloneImageHandler(%s) clone output buffer failed(clone_flags:%d)", XCAM_STR (get_name ()), _clone_flags); output = swapped_buf; return XCAM_RETURN_NO_ERROR; #else XCAM_LOG_ERROR ("CLCloneImageHandler doesn't support DrmBoBuffer"); XCAM_UNUSED (input); XCAM_UNUSED (output); return XCAM_RETURN_ERROR_PARAM; #endif } };