blob: 6a814728cb442a89f9326a948d2fbaaeb6cb77f6 [file] [log] [blame]
/*
* soft_handler.cpp - soft image handler implementation
*
* Copyright (c) 2017 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 "soft_handler.h"
#include "soft_video_buf_allocator.h"
#include "thread_pool.h"
#include "soft_worker.h"
#define DEFAULT_SOFT_BUF_COUNT 4
namespace XCam {
class SyncMeta
: public MetaBase
{
public:
SyncMeta ()
: _done (false)
, _error (XCAM_RETURN_NO_ERROR) {}
void signal_done (XCamReturn err);
void wakeup ();
XCamReturn signal_wait_ret ();
bool is_error () const;
private:
mutable Mutex _mutex;
Cond _cond;
bool _done;
XCamReturn _error;
};
void
SyncMeta::signal_done (XCamReturn err)
{
SmartLock locker (_mutex);
_done = true;
_error = err;
_cond.broadcast ();
}
void
SyncMeta::wakeup ()
{
SmartLock locker (_mutex);
_error = XCAM_RETURN_ERROR_UNKNOWN;
_cond.broadcast ();
}
XCamReturn
SyncMeta::signal_wait_ret ()
{
SmartLock locker (_mutex);
if (_done)
return _error;
_cond.wait (_mutex);
return _error;
}
bool
SyncMeta::is_error () const
{
SmartLock locker (_mutex);
return !xcam_ret_is_ok (_error);
}
SoftHandler::SoftHandler (const char* name)
: ImageHandler (name)
, _need_configure (true)
, _enable_allocator (true)
, _wip_buf_count (0)
{
}
SoftHandler::~SoftHandler ()
{
}
bool
SoftHandler::set_threads (const SmartPtr<ThreadPool> &pool)
{
_threads = pool;
return true;
}
bool
SoftHandler::set_out_video_info (const VideoBufferInfo &info)
{
XCAM_ASSERT (info.width && info.height && info.format);
_out_video_info = info;
return true;
}
bool
SoftHandler::enable_allocator (bool enable)
{
_enable_allocator = enable;
return true;
}
XCamReturn
SoftHandler::confirm_configured ()
{
XCamReturn ret = XCAM_RETURN_NO_ERROR;
XCAM_ASSERT (_need_configure);
if (_enable_allocator) {
XCAM_FAIL_RETURN (
ERROR, _out_video_info.is_valid (), XCAM_RETURN_ERROR_PARAM,
"soft_hander(%s) configure resource failed before reserver buffer since out video info was not set",
XCAM_STR (get_name ()));
set_allocator (new SoftVideoBufAllocator);
ret = reserve_buffers (_out_video_info, DEFAULT_SOFT_BUF_COUNT);
XCAM_FAIL_RETURN (
ERROR, ret == XCAM_RETURN_NO_ERROR, ret,
"soft_hander(%s) configure resource failed in reserving buffers", XCAM_STR (get_name ()));
}
if (_threads.ptr () && !_threads->is_running ()) {
ret = _threads->start ();
XCAM_FAIL_RETURN (
ERROR, ret == XCAM_RETURN_NO_ERROR, ret,
"soft_hander(%s) configure resource failed when starting threads", XCAM_STR (get_name ()));
}
_need_configure = false;
return ret;
}
XCamReturn
SoftHandler::execute_buffer (const SmartPtr<ImageHandler::Parameters> &param, bool sync)
{
XCamReturn ret = XCAM_RETURN_NO_ERROR;
SmartPtr<SyncMeta> sync_meta;
XCAM_FAIL_RETURN (
ERROR, param.ptr (), XCAM_RETURN_ERROR_PARAM,
"soft_hander(%s) execute buffer failed, params is null",
XCAM_STR (get_name ()));
if (_need_configure) {
ret = configure_resource (param);
XCAM_FAIL_RETURN (
WARNING, xcam_ret_is_ok (ret), ret,
"soft_hander(%s) configure resource failed", XCAM_STR (get_name ()));
ret = confirm_configured ();
XCAM_FAIL_RETURN (
WARNING, xcam_ret_is_ok (ret), ret,
"soft_hander(%s) confirm configure failed", XCAM_STR (get_name ()));
}
if (!param->out_buf.ptr () && _enable_allocator) {
param->out_buf = get_free_buf ();
XCAM_FAIL_RETURN (
ERROR, param->out_buf.ptr (), XCAM_RETURN_ERROR_PARAM,
"soft_hander:%s execute buffer failed, output buffer failed in allocation.",
XCAM_STR (get_name ()));
}
XCAM_ASSERT (!param->find_meta<SyncMeta> ().ptr ());
sync_meta = new SyncMeta ();
XCAM_ASSERT (sync_meta.ptr ());
param->add_meta (sync_meta);
#if 0
SmartPtr<SoftWorker> worker = get_first_worker ().dynamic_cast_ptr<SoftWorker> ();
XCAM_FAIL_RETURN (
WARNING, worker.ptr (), XCAM_RETURN_ERROR_PARAM,
"No worder set to soft_hander(%s)", XCAM_STR (get_name ()));
SmartPtr<Worker::Arguments> args = get_first_worker_args (worker, params);
XCAM_FAIL_RETURN (
WARNING, args.ptr (), XCAM_RETURN_ERROR_PARAM,
"soft_hander(%s) get first worker(%s) args failed",
XCAM_STR (get_name ()), XCAM_STR (worker->get_name ()));
_params.push (params);
ret = worker->work (args);
#else
_params.push (param);
ret = start_work (param);
#endif
if (!xcam_ret_is_ok (ret)) {
_params.erase (param);
XCAM_LOG_WARNING ("soft_hander(%s) execute buffer failed in starting workers", XCAM_STR (get_name ()));
return ret;
}
++_wip_buf_count;
_cur_sync = sync_meta;
if (sync) {
XCAM_ASSERT (sync_meta.ptr ());
ret = sync_meta->signal_wait_ret ();
_cur_sync.release ();
}
return ret;
}
XCamReturn
SoftHandler::finish ()
{
XCamReturn ret = XCAM_RETURN_NO_ERROR;
SmartPtr<SyncMeta> sync = _cur_sync;
if (sync.ptr ()) {
ret = sync->signal_wait_ret ();
}
XCAM_ASSERT (_params.is_empty ());
//wait for _wip_buf_count = 0
//if (ret == XCAM_RETURN_NO_ERROR)
// XCAM_ASSERT (_wip_buf_count == 0);
return ret;
}
XCamReturn
SoftHandler::terminate ()
{
SmartPtr<SyncMeta> sync = _cur_sync;
if (sync.ptr ()) {
sync->wakeup ();
sync.release ();
}
_params.clear ();
return ImageHandler::terminate ();
}
void
SoftHandler::work_well_done (const SmartPtr<ImageHandler::Parameters> &param, XCamReturn err)
{
XCAM_ASSERT (param.ptr ());
XCAM_ASSERT (xcam_ret_is_ok (err));
if (!xcam_ret_is_ok (err)) {
XCAM_LOG_WARNING ("soft_hander(%s) work_well_done but errno(%d) is not ok", XCAM_STR (get_name ()), (int)err);
//continue work
}
if (!_params.erase (param)) {
XCAM_LOG_ERROR(
"soft_hander(%s) last_work_done param already removed, who removed it?", XCAM_STR (get_name ()));
return;
}
XCAM_LOG_DEBUG ("soft_hander(%s) work well done", XCAM_STR (get_name ()));
param_ended (param, err);
}
void
SoftHandler::work_broken (const SmartPtr<ImageHandler::Parameters> &param, XCamReturn err)
{
XCAM_ASSERT (param.ptr ());
XCAM_ASSERT (!xcam_ret_is_ok (err));
if (xcam_ret_is_ok (err)) {
XCAM_LOG_WARNING ("soft_hander(%s) work_broken but the errno(%d) is ok", XCAM_STR (get_name ()), (int)err);
//continue work
}
if (!_params.erase (param)) {
//already removed by other handlers
return;
}
XCAM_LOG_WARNING ("soft_hander(%s) work broken", XCAM_STR (get_name ()));
param_ended (param, err);
}
void
SoftHandler::param_ended (SmartPtr<ImageHandler::Parameters> param, XCamReturn err)
{
XCAM_ASSERT (param.ptr ());
SmartPtr<SyncMeta> sync_meta = param->find_meta<SyncMeta> ();
XCAM_ASSERT (sync_meta.ptr ());
sync_meta->signal_done (err);
--_wip_buf_count;
execute_status_check (param, err);
}
bool
SoftHandler::check_work_continue (const SmartPtr<ImageHandler::Parameters> &param, XCamReturn err)
{
if (!xcam_ret_is_ok (err)) {
work_broken (param, err);
return false;
}
if (is_param_error (param)) {
XCAM_LOG_WARNING (
"soft_handler(%s) check_work_continue found param broken", XCAM_STR(get_name ()));
return false;
}
return true;
}
bool
SoftHandler::is_param_error (const SmartPtr<ImageHandler::Parameters> &param)
{
XCAM_ASSERT (param.ptr ());
SmartPtr<SyncMeta> meta = param->find_meta<SyncMeta> ();
if (!meta.ptr ()) { // return ok if param not set
XCAM_ASSERT (meta.ptr ());
return false;
}
return meta->is_error ();
}
}