blob: 129a551ef150fdbebf77c67de6a0588e21336469 [file] [log] [blame]
/*
* Copyright (C) 2019 MediaTek Inc.
*
* 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.
*/
#define LOG_TAG "MtkCam/P1NodeImp"
//
#include <memory>
#include "mtkcam/pipeline/hwnode/p1/P1DeliverMgr.h"
#include "P1NodeImp.h"
#include <string>
#include <vector>
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
namespace NSCam {
namespace v3 {
namespace NSP1Node {
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/******************************************************************************
*
******************************************************************************/
P1DeliverMgr::P1DeliverMgr()
: mspP1NodeImp(nullptr),
mOpenId(-1),
mLogLevel(0),
mLogLevelI(0),
mBurstNum(1),
mLoopRunning(MFALSE),
mLoopState(LOOP_STATE_INIT),
mSentNum(0),
mExitPending(MFALSE) {}
/******************************************************************************
*
******************************************************************************/
P1DeliverMgr::~P1DeliverMgr() {
mNumList.clear();
mActQueue.clear();
}
/******************************************************************************
*
******************************************************************************/
void P1DeliverMgr::init(std::shared_ptr<P1NodeImp> pP1NodeImp) {
mspP1NodeImp = pP1NodeImp;
config();
}
/******************************************************************************
*
******************************************************************************/
void P1DeliverMgr::uninit() {
exit();
mspP1NodeImp = nullptr;
}
/******************************************************************************
*
******************************************************************************/
void P1DeliverMgr::config() {
std::lock_guard<std::mutex> _l(mDeliverLock);
mNumList.clear();
mActQueue.clear();
if (mspP1NodeImp != nullptr) {
mOpenId = mspP1NodeImp->getOpenId();
mLogLevel = mspP1NodeImp->mLogLevel;
mLogLevelI = mspP1NodeImp->mLogLevelI;
if (mspP1NodeImp->mBurstNum > 1) {
mBurstNum = mspP1NodeImp->mBurstNum;
}
size_t const res_size = (size_t)(mBurstNum * P1NODE_DEF_QUEUE_DEPTH);
mNumList.reserve(res_size);
mNumList.clear();
mActQueue.reserve(res_size);
mActQueue.clear();
MY_LOGI("ActQueue.Capacity[%d]", (MUINT32)mActQueue.capacity());
}
}
/******************************************************************************
*
******************************************************************************/
void P1DeliverMgr::runningSet(MBOOL bRunning) {
std::lock_guard<std::mutex> _l(mDeliverLock);
mLoopRunning = bRunning;
return;
}
/******************************************************************************
*
******************************************************************************/
MBOOL
P1DeliverMgr::runningGet() {
std::lock_guard<std::mutex> _l(mDeliverLock);
return mLoopRunning;
}
/******************************************************************************
*
******************************************************************************/
status_t P1DeliverMgr::run() {
mThread = std::thread(std::bind(&P1DeliverMgr::threadLoop, this));
return NO_ERROR;
}
/******************************************************************************
*
******************************************************************************/
void P1DeliverMgr::join() {
if (mThread.joinable()) {
mThread.join();
}
}
/******************************************************************************
*
******************************************************************************/
void P1DeliverMgr::exit() {
MY_LOGD("DeliverMgr loop exit");
{
std::lock_guard<std::mutex> _l(mDeliverLock);
mExitPending = MTRUE;
}
trigger();
MY_LOGD("DeliverMgr loop join");
if (mThread.joinable()) {
mThread.join();
}
MY_LOGD("DeliverMgr loop finish");
}
/******************************************************************************
*
******************************************************************************/
status_t P1DeliverMgr::readyToRun() {
MY_LOGD("readyToRun DeliverMgr thread");
return OK;
}
/******************************************************************************
*
******************************************************************************/
void P1DeliverMgr::requestExit() {
std::lock_guard<std::mutex> _l(mDeliverLock);
mExitPending = true;
}
/******************************************************************************
*
******************************************************************************/
bool P1DeliverMgr::threadLoop() {
while (this->_threadLoop() == MTRUE) {
}
MY_LOGI("threadLoop exit");
return true;
}
/******************************************************************************
*
******************************************************************************/
bool P1DeliverMgr::_threadLoop() {
{
std::lock_guard<std::mutex> _l(mDeliverLock);
if (mExitPending) {
MY_LOGD("DeliverMgr try to leave");
if (mActQueue.size() > 0) {
MY_LOGI("the deliver queue is not empty, go-on the loop");
} else {
MY_LOGI("DeliverMgr Leaving");
return MFALSE;
}
}
}
return deliverLoop();
}
/******************************************************************************
*
******************************************************************************/
MBOOL
P1DeliverMgr::deliverLoop() {
MBOOL res = MTRUE;
std::vector<P1FrameAct> outQueue;
outQueue.clear();
outQueue.reserve((size_t)(mBurstNum * P1NODE_DEF_QUEUE_DEPTH));
//
if (mspP1NodeImp != nullptr && mspP1NodeImp->mpTimingCheckerMgr != nullptr) {
mspP1NodeImp->mpTimingCheckerMgr->onCheck();
}
//
if (mspP1NodeImp != nullptr) { // check the DropQ
mspP1NodeImp->onProcessDropFrame(MFALSE);
}
//
{
std::unique_lock<std::mutex> _l(mDeliverLock);
MINT32 currentNum = 0;
//
mLoopState = LOOP_STATE_INIT;
currentNum = (mActQueue.empty()) ? (P1_FRM_NUM_NULL)
: ((mActQueue.end() - 1)->frmNum);
if (!mExitPending) {
if (currentNum == mSentNum) {
mLoopState = LOOP_STATE_WAITING;
MY_LOGD("deliverLoop wait ++");
std::cv_status status = mDeliverCond.wait_for(
_l, std::chrono::nanoseconds(P1_DELIVERY_CHECK_INV_NS));
if (status == std::cv_status::timeout) {
MY_LOGI("Delivery(%lld) NumList[%zu] NodeQueue[%zu]",
P1_DELIVERY_CHECK_INV_NS, mNumList.size(), mActQueue.size());
if ((!mNumList.empty()) || (!mActQueue.empty())) {
dumpNumList(MFALSE);
dumpActQueue(MFALSE);
}
if (mspP1NodeImp != nullptr) {
if (mspP1NodeImp->mLongExp.get() == MFALSE) {
mspP1NodeImp->mLogInfo.inspect(LogInfo::IT_NO_DELIVERY);
}
}
}
MY_LOGD("deliverLoop wait --");
} // else , there is new coming node need to check
} else {
MY_LOGD("deliverLoop need to exit");
}
//
mLoopState = LOOP_STATE_PROCESSING;
mSentNum = currentNum;
//
NumList_T::iterator it_list = mNumList.begin();
ActQueue_T::iterator it_act = mActQueue.begin();
MBOOL isFound = MFALSE;
size_t i = mNumList.size();
for (; it_list != mNumList.end() && i > 0; i--) {
isFound = MFALSE;
it_act = mActQueue.begin();
for (; it_act != mActQueue.end();) {
if (it_act->frmNum == (*it_list)) {
outQueue.push_back(*it_act);
it_act = mActQueue.erase(it_act);
isFound = MTRUE;
break;
} else {
it_act++;
}
}
if (isFound) { // this number of list is found in the ActQueue, go-on to
// find the next number of list to output
it_list = mNumList.erase(it_list);
} else { // this number of list is not found in the ActQueue, stop the
// searching and wait for the next trigger (ex: sendActQueue)
break;
}
}
// check the BYPASS act
if (!mActQueue.empty()) { // in the most case, while BYPASS act exist, the
// BYPASS act is the first and the only one act
// in the ActQueue
ActQueue_T::iterator it_check = mActQueue.begin();
for (; it_check != mActQueue.end();) { // the bypass acts should be
// in-order in the ActQueue
if (it_check->reqType == REQ_TYPE_ZSL ||
it_check->reqType == REQ_TYPE_REDO ||
it_check->reqType == REQ_TYPE_YUV) {
outQueue.push_back(*it_check);
it_check = mActQueue.erase(it_check); // go-on
} else {
it_check++;
}
}
}
}
//
if (!outQueue.empty()) {
std::vector<P1FrameAct>::iterator it = outQueue.begin();
for (; it != outQueue.end(); it++) {
mspP1NodeImp->releaseFrame(&(*it));
/* DO NOT use this P1QueAct after releaseAction() */
}
outQueue.clear();
}
{
std::lock_guard<std::mutex> _l(mDeliverLock);
mLoopState = LOOP_STATE_DONE;
mDoneCond.notify_all();
}
return res;
}
/******************************************************************************
*
******************************************************************************/
MBOOL
P1DeliverMgr::isActListEmpty() {
std::lock_guard<std::mutex> _l(mDeliverLock);
if (CC_UNLIKELY(!mLoopRunning)) {
return MTRUE;
}
return (mNumList.empty());
}
/******************************************************************************
*
******************************************************************************/
MBOOL
P1DeliverMgr::registerActList(MINT32 num) {
std::lock_guard<std::mutex> _l(mDeliverLock);
if (CC_UNLIKELY(!mLoopRunning)) {
return MFALSE;
}
mNumList.push_back(num);
return (!mNumList.empty());
}
/******************************************************************************
*
******************************************************************************/
MBOOL
P1DeliverMgr::sendActQueue(P1QueAct* rAct, MBOOL needTrigger) {
P1Act act = GET_ACT_PTR(act, *rAct, MFALSE);
P1FrameAct frameAct(rAct);
if (CC_LIKELY(frameAct.ready())) {
std::lock_guard<std::mutex> _l(mDeliverLock);
mActQueue.push_back(frameAct);
} else {
MY_LOGE("FrameAct not ready to deliver - " P1INFO_ACT_STR,
P1INFO_ACT_VAR(*act));
}
if (needTrigger) {
trigger();
}
//
return MTRUE;
}
/******************************************************************************
*
******************************************************************************/
MBOOL
P1DeliverMgr::waitFlush(MBOOL needTrigger) {
size_t queueSize = 0;
LOOP_STATE loopState = LOOP_STATE_INIT;
MBOOL isListEmpty = MFALSE;
if (!runningGet()) {
return MTRUE;
}
//
{
std::lock_guard<std::mutex> _l(mDeliverLock);
queueSize = mActQueue.size();
isListEmpty =
mNumList.empty(); // (mNumList.size() > 0) ? (MFALSE) : (MTRUE);
loopState = mLoopState;
}
status_t status = OK;
while ((queueSize > 0) || (loopState == LOOP_STATE_PROCESSING) ||
(status != OK)) {
if (needTrigger) {
trigger();
}
{
std::unique_lock<std::mutex> _l(mDeliverLock);
if ((mActQueue.size() > 0 && mLoopState == LOOP_STATE_WAITING) ||
(mLoopState == LOOP_STATE_PROCESSING)) {
MY_LOGD("doneLoop wait ++");
std::cv_status err = mDoneCond.wait_for(
_l, std::chrono::nanoseconds(P1_COMMON_CHECK_INV_NS));
MY_LOGD("doneLoop wait --");
if (err == std::cv_status::timeout) {
MY_LOGI(
"WaitFlushStatus(%d) LoopState(%d) "
"NumList[%zu] NodeQueue[%zu]",
status, mLoopState, mNumList.size(), mActQueue.size());
if (mspP1NodeImp != nullptr) {
mspP1NodeImp->mLogInfo.inspect(LogInfo::IT_FLUSH_BLOCKING);
}
}
} else {
status = OK;
}
queueSize = mActQueue.size();
isListEmpty =
mNumList.empty(); // (mNumList.size() > 0) ? (MFALSE) : (MTRUE);
loopState = mLoopState;
}
}
//
if (CC_UNLIKELY(!isListEmpty)) {
MY_LOGW("ListEmpty(%d)", isListEmpty);
dumpInfo();
return MFALSE;
}
return MTRUE;
}
/******************************************************************************
*
******************************************************************************/
MBOOL
P1DeliverMgr::trigger(void) {
std::lock_guard<std::mutex> _l(mDeliverLock);
if (mLoopRunning) {
MY_LOGD("DeliverMgr trigger (%zu)", mActQueue.size());
mDeliverCond.notify_all();
}
return MTRUE;
}
/******************************************************************************
*
******************************************************************************/
MVOID
P1DeliverMgr::dumpInfo(void) {
std::lock_guard<std::mutex> _l(mDeliverLock);
MY_LOGI("DeliverMgr - Burst(%d) LoopRunning(%d) LoopState(%d)", mBurstNum,
mLoopRunning, mLoopState);
dumpNumList(MFALSE);
dumpActQueue(MFALSE);
}
/******************************************************************************
*
******************************************************************************/
void P1DeliverMgr::dumpNumList(MBOOL isLock) {
std::string str("");
size_t size = 0;
//
NEED_LOCK(isLock, mDeliverLock);
//
size = mNumList.size();
NumList_T::iterator it = mNumList.begin();
for (; it != mNumList.end(); it++) {
str += base::StringPrintf("%d ", *it);
}
//
NEED_UNLOCK(isLock, mDeliverLock);
//
MY_LOGI("dump NumList[%zu] = {%s}", size, str.c_str());
}
/******************************************************************************
*
******************************************************************************/
void P1DeliverMgr::dumpActQueue(MBOOL isLock) {
std::string str("");
size_t size = 0;
//
NEED_LOCK(isLock, mDeliverLock);
//
size = mActQueue.size();
ActQueue_T::iterator it = mActQueue.begin();
for (; it != mActQueue.end(); it++) {
str += base::StringPrintf("%d ", (*it).queId);
}
//
NEED_UNLOCK(isLock, mDeliverLock);
//
MY_LOGI("dump ActQueue[%zu] = {%s}", size, str.c_str());
}
}; // namespace NSP1Node
}; // namespace v3
}; // namespace NSCam