/*
* 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
}
};