blob: c0e20898d5cf924d881e71a80aebaf4452a634e2 [file] [log] [blame]
/*
* Copyright (C) 2015, Samsung Electronics Co. LTD
*
* 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.
*/
#ifndef EXYNOS_VISION_RESOURCE_MNGR_H
#define EXYNOS_VISION_RESOURCE_MNGR_H
#include <utils/threads.h>
#include <utils/Mutex.h>
#include <utils/List.h>
#include <utils/Vector.h>
#include <VX/vx.h>
#include "ExynosVisionMemoryAllocator.h"
#include "ExynosVisionPool.h"
#include "ExynosVisionState.h"
#define RES_DBG_MSG 0
namespace android {
enum RES_ELEMENT_STATE {
RES_ELEMENT_NO_LOCK,
RES_ELEMENT_WRITE_LOCK,
RES_ELEMENT_READ_LOCK
};
template<typename T>
class ExynosVisionResElement {
private:
T m_resource;
ExynosVisionState m_state;
vx_uint32 m_frame_id;
/* this indicates the index within resource manager */
vx_uint32 m_index;
/* for management read reference */
vx_int32 m_read_demand_number;
vx_int32 m_read_ref_count;
vx_int32 m_read_demand_count;
/* this indicates the data is valid after writing */
vx_bool m_valid;
public:
private:
public:
/* Constructor */
ExynosVisionResElement(void)
{
m_state.setState(RES_ELEMENT_NO_LOCK);
m_frame_id = 0;
m_index = 0;
m_read_demand_number = 0;
m_read_demand_count = 0;
m_read_ref_count = 0;
m_resource = NULL;
m_valid = vx_true_e;
}
/* Destructor */
virtual ~ExynosVisionResElement()
{
/* do nothing */
}
void clearReadInfo(void)
{
m_read_demand_number = 0;
m_read_demand_count = 0;
m_read_ref_count = 0;
}
void setResource(T resource)
{
m_resource = resource;
}
T getResource()
{
return m_resource;
}
void setId(vx_int32 frame_id)
{
m_frame_id = frame_id;
};
vx_uint32 getId()
{
return m_frame_id;
};
void setIndex(vx_int32 index)
{
m_index = index;
};
vx_uint32 getIndex()
{
return m_index;
};
vx_uint32 getReadRefCnt()
{
return m_read_ref_count;
};
vx_uint32 getReadDemandCnt()
{
return m_read_demand_count;
};
vx_uint32 getReadDemandNum()
{
return m_read_demand_number;
};
void setReadDemandNum(vx_uint32 demand_num)
{
m_read_demand_number = demand_num;
}
void incReadDemCnt(void)
{
m_read_demand_count++;
}
void incReadRefCnt(void)
{
m_read_ref_count++;
}
void decReadRefCnt(void)
{
m_read_ref_count--;
}
vx_bool isReadComplete(void)
{
if (m_read_ref_count == 0 && m_read_demand_count == m_read_demand_number)
return vx_true_e;
else
return vx_false_e;
}
void setState(vx_enum new_state)
{
m_state.setState(new_state);
}
vx_enum getState(void)
{
return m_state.getState();
}
void setValid(vx_bool valid)
{
m_valid = valid;
}
vx_bool getValid(void)
{
return m_valid;
}
};
enum RESOURCE_MNGR_TYPE {
/* resource manager is not assigned */
RESOURCE_MNGR_NULL,
/* single resource, support slot event, single object */
RESOURCE_MNGR_SOLID,
/* multi resource, support slot event, multi object */
RESOURCE_MNGR_SLOT,
/* multi resource, support queue event, single object */
RESOURCE_MNGR_QUEUE,
};
struct resource_solid_param {
};
struct resource_slot_param {
vx_uint32 slot_num;
};
struct resource_queue_param {
vx_uint32 direction;
};
struct resource_param {
union {
struct resource_solid_param solid_param;
struct resource_slot_param slot_param;
struct resource_queue_param queue_param;
} param;
};
enum RESOURCE_CLASS_TYPE {
RESOURCE_CLASS_NONE,
RESOURCE_CLASS_SLOT,
RESOURCE_CLASS_INPUT_QUEUE,
RESOURCE_CLASS_OUTPUT_QUEUE
};
template<typename T>
class ExynosVisionResManager {
private:
protected:
Mutex m_res_mutex;
vx_enum m_res_class_type;
List<ExynosVisionResElement<T>*> m_using_res_element_list;
private:
public:
/* Constructor */
ExynosVisionResManager(void)
{
m_res_class_type = RESOURCE_CLASS_NONE;
}
/* Destructor */
virtual ~ExynosVisionResManager()
{
/* do noting */
}
virtual vx_status registerResource(T)
{
VXLOGE("not implemented at res-class-type %d", m_res_class_type);
return VX_FAILURE;
}
virtual vx_status destroy(void)
{
VXLOGE("not implemented at res-class-type %d", m_res_class_type);
return VX_FAILURE;
}
virtual T waitAndGetEmptyResAndWrLk(vx_uint32 frame_id)
{
VXLOGE("not supported, frame_id:%d", frame_id);
return NULL;
}
virtual vx_status setFilledRes(vx_uint32 frame_id, vx_bool data_valid)
{
VXLOGE("not supported, frame_id:%d, data_valid:%d", frame_id, data_valid);
return VX_FAILURE;
}
virtual vx_status setFilledResAndRdLk(vx_uint32 frame_id, vx_uint32 demand_number, vx_bool data_valid)
{
VXLOGE("not supported, frame_id:%d, demand_num:%d, data_valid:%d", frame_id, demand_number, data_valid);
return VX_FAILURE;
}
virtual T getFilledRes(vx_uint32 frame_id, vx_bool *ret_data_valid)
{
VXLOGE("not supported, frame_id:%d, &ret_data_valid:%p", frame_id, ret_data_valid);
return NULL;
}
virtual vx_status putFilledRes(vx_uint32 frame_id)
{
VXLOGE("not supported, frame_id:%d", frame_id);
return VX_FAILURE;
}
/* output queue type */
virtual vx_status pushResource(vx_uint32 index, T resource)
{
VXLOGE("not supported, index:%d, resource:%p", index, resource);
return VX_FAILURE;
}
/* input queue type */
virtual vx_status pushResource(vx_uint32 index, T resource, vx_uint32 frame_id, vx_uint32 demand_number)
{
VXLOGE("not supported, index:%d, resource:%p, frame id:%d, demand:%d", index, resource, frame_id, demand_number);
return VX_FAILURE;
}
virtual vx_status popResource(vx_uint32 *ret_index, vx_bool *ret_data_valid, T *ret_resource)
{
VXLOGE("not supported, &index:%p, &data_valid:%p, &resource:%p", ret_index, ret_data_valid, ret_resource);
return VX_FAILURE;
}
virtual void displayBuff(vx_uint32 tab_num, vx_bool detail_info)
{
VXLOGE("not supported, %d, %d", tab_num, detail_info);
}
};
template<typename T>
class ExynosVisionResSlotType : public ExynosVisionResManager<T> {
private:
vx_uint32 m_slot_num;
/* m_buf_element_list has the all of the res element */
List<ExynosVisionResElement<T>*> m_registered_res_element_list;
ExynosVisionPool<ExynosVisionResElement<T>*> m_free_res_element_pool;
public:
private:
public:
/* Constructor */
ExynosVisionResSlotType(vx_uint32 slot_num = 1)
{
ExynosVisionResManager<T>::m_res_class_type = RESOURCE_CLASS_SLOT;
m_slot_num = slot_num;
}
/* Destructor */
virtual ~ExynosVisionResSlotType()
{
/* do nothing */
}
virtual vx_status registerResource(T resource)
{
if (m_registered_res_element_list.size() >= m_slot_num) {
ALOGE("[%s] resource number is overflowed, slot_num:%d", m_slot_num);
return VX_FAILURE;
}
ExynosVisionResManager<T>::m_res_mutex.lock();
ExynosVisionResElement<T> *res_element = new ExynosVisionResElement<T>();
res_element->setResource(resource);
res_element->setIndex(m_registered_res_element_list.size());
m_registered_res_element_list.push_back(res_element);
ExynosVisionResManager<T>::m_res_mutex.unlock();
m_free_res_element_pool.putResource(res_element);
return VX_SUCCESS;
}
virtual vx_status destroy(void)
{
vx_status status = VX_SUCCESS;
m_free_res_element_pool.release();
m_free_res_element_pool.flush();
typename List<ExynosVisionResElement<T>*>::iterator elem_iter;
for (elem_iter=m_registered_res_element_list.begin(); elem_iter!=m_registered_res_element_list.end(); elem_iter++)
delete (*elem_iter);
m_slot_num = 0;
return status;
}
virtual T waitAndGetEmptyResAndWrLk(vx_uint32 frame_id)
{
pool_exception_t pool_exception;
ExynosVisionResElement<T>* res_element = NULL;
pool_exception = m_free_res_element_pool.getResource(&res_element);
if (pool_exception == POOL_EXCEPTION_NONE) {
ExynosVisionResManager<T>::m_res_mutex.lock();
res_element->setId(frame_id);
res_element->setState(RES_ELEMENT_WRITE_LOCK);
res_element->setValid(vx_true_e);
ExynosVisionResManager<T>::m_using_res_element_list.push_back(res_element);
ExynosVisionResManager<T>::m_res_mutex.unlock();
return res_element->getResource();
} else {
VXLOGE("getting empty buffer");
displayBuff(0, vx_true_e);
return NULL;
}
}
virtual vx_status setFilledResAndRdLk(vx_uint32 frame_id, vx_uint32 demand_number, vx_bool data_valid)
{
vx_status status = VX_FAILURE;
typename List<ExynosVisionResElement<T>*>::iterator elem_iter;
ExynosVisionResManager<T>::m_res_mutex.lock();
for (elem_iter=ExynosVisionResManager<T>::m_using_res_element_list.begin();
elem_iter!=ExynosVisionResManager<T>::m_using_res_element_list.end();
elem_iter++) {
ExynosVisionResElement<T> *res_element = *elem_iter;
if (res_element->getId() == frame_id) {
res_element->setState(RES_ELEMENT_READ_LOCK);
res_element->setValid(data_valid);
res_element->setReadDemandNum(demand_number);
status = VX_SUCCESS;
break;
}
}
ExynosVisionResManager<T>::m_res_mutex.unlock();
if (status != VX_SUCCESS)
VXLOGE("cannot find perfer buffer, id:%d", frame_id);
return status;
}
virtual T getFilledRes(vx_uint32 frame_id, vx_bool *ret_data_valid)
{
#if (RES_DBG_MSG==1)
VXLOGD("frame:%d", frame_id);
VXLOGD("enter");
displayBuff(0, vx_true_e);
#endif
vx_status status = VX_FAILURE;
ExynosVisionResElement<T>* res_element = NULL;
typename List<ExynosVisionResElement<T>*>::iterator elem_iter;
ExynosVisionResManager<T>::m_res_mutex.lock();
for (elem_iter=ExynosVisionResManager<T>::m_using_res_element_list.begin();
elem_iter!=ExynosVisionResManager<T>::m_using_res_element_list.end();
elem_iter++) {
res_element = *elem_iter;
if (res_element->getId() == frame_id) {
res_element->incReadRefCnt();
res_element->incReadDemCnt();
*ret_data_valid = res_element->getValid();
status = VX_SUCCESS;
break;
}
}
ExynosVisionResManager<T>::m_res_mutex.unlock();
#if (RES_DBG_MSG==1)
VXLOGD("exit");
displayBuff(0, vx_true_e);
#endif
if (status != VX_SUCCESS) {
VXLOGE("cannot find perfer buffer, id:%d", frame_id);
this->displayBuff(0, vx_true_e);
return NULL;
} else {
return res_element->getResource();
}
}
virtual vx_status putFilledRes(vx_uint32 frame_id)
{
#if (RES_DBG_MSG==1)
VXLOGD("frame:%d", frame_id);
VXLOGD("enter");
displayBuff(0, vx_true_e);
#endif
vx_status status = VX_FAILURE;
ExynosVisionResElement<T> *res_element;
typename List<ExynosVisionResElement<T>*>::iterator elem_iter;
ExynosVisionResManager<T>::m_res_mutex.lock();
for (elem_iter=ExynosVisionResManager<T>::m_using_res_element_list.begin();
elem_iter!=ExynosVisionResManager<T>::m_using_res_element_list.end();
elem_iter++) {
res_element = *elem_iter;
if (res_element->getId() == frame_id) {
res_element->decReadRefCnt();
status = VX_SUCCESS;
break;
}
}
if (status != VX_SUCCESS) {
VXLOGE("cannot find perfer buffer, id:%d", frame_id);
} else {
if (res_element->isReadComplete()) {
ExynosVisionResManager<T>::m_using_res_element_list.erase(elem_iter);
res_element->clearReadInfo();
res_element->setId(0);
res_element->setState(RES_ELEMENT_NO_LOCK);
m_free_res_element_pool.putResource(res_element);
}
}
ExynosVisionResManager<T>::m_res_mutex.unlock();
#if (RES_DBG_MSG==1)
VXLOGD("exit");
displayBuff(0, vx_true_e);
#endif
return status;
}
virtual void displayBuff(vx_uint32 tab_num, vx_bool detail_info)
{
vx_char tap[MAX_TAB_NUM];
ExynosVisionResElement<T> *res_element = NULL;
vx_uint32 i;
typename List<ExynosVisionResElement<T>*>::iterator elem_iter;
VXLOGD("%s[SLOT]used buf num:%d, free buf num:%d", MAKE_TAB(tap, tab_num), ExynosVisionResManager<T>::m_using_res_element_list.size(), m_free_res_element_pool.getFreeNum());
if (detail_info == vx_true_e) {
for (elem_iter=ExynosVisionResManager<T>::m_using_res_element_list.begin(), i=0;
elem_iter!=ExynosVisionResManager<T>::m_using_res_element_list.end();
elem_iter++, i++) {
res_element = *elem_iter;
VXLOGD("%sused buf, frame_id:%d, state:%d, RRefCnt:%d, RDemCnt:%d, RDemNum:%d", MAKE_TAB(tap, tab_num), res_element->getId(), res_element->getState(),
res_element->getReadRefCnt(), res_element->getReadDemandCnt(), res_element->getReadDemandNum());
}
}
}
};
template<typename T>
class ExynosVisionResQueueType : public ExynosVisionResManager<T> {
#define MAX_QUEUE_RES_NUM 10
private:
protected:
Vector<ExynosVisionResElement<T>*> m_res_element_vector;
ExynosVisionPool<ExynosVisionResElement<T>*> m_done_res_element_pool;
public:
private:
public:
/* Constructor */
ExynosVisionResQueueType(void)
{
for (vx_uint32 i=0; i<MAX_QUEUE_RES_NUM; i++) {
ExynosVisionResElement<T> *res_element = new ExynosVisionResElement<T>();
res_element->setIndex(m_res_element_vector.size());
m_res_element_vector.push_back(res_element);
}
}
/* Destructor */
virtual ~ExynosVisionResQueueType()
{
for (vx_uint32 i=0; i<MAX_QUEUE_RES_NUM; i++) {
if (m_res_element_vector.editItemAt(i)->getResource() != NULL)
VXLOGE("index:%d still hold resource", i);
delete m_res_element_vector.editItemAt(i);
}
m_res_element_vector.clear();
}
virtual vx_status destroy(void)
{
return VX_SUCCESS;
}
virtual vx_status popResource(vx_uint32 *ret_index, vx_bool *ret_data_valid, T *ret_resource)
{
vx_status status = VX_SUCCESS;
pool_exception_t pool_exception;
ExynosVisionResElement<T>* res_element = NULL;
pool_exception = m_done_res_element_pool.getResource(&res_element);
if (pool_exception == POOL_EXCEPTION_NONE) {
ExynosVisionResManager<T>::m_res_mutex.lock();
if (res_element->getResource() == NULL)
VXLOGE("element holds null resource");
*ret_index = res_element->getIndex();
*ret_data_valid = res_element->getValid();
*ret_resource = res_element->getResource();
res_element->setResource(NULL);
res_element->setId(0);
ExynosVisionResManager<T>::m_res_mutex.unlock();
} else {
VXLOGE("getting empty buffer");
status = VX_FAILURE;
}
return status;
}
};
template<typename T>
class ExynosVisionResInputQueueType : public ExynosVisionResQueueType<T> {
private:
public:
private:
public:
/* Constructor */
ExynosVisionResInputQueueType(void)
{
ExynosVisionResManager<T>::m_res_class_type = RESOURCE_CLASS_INPUT_QUEUE;
}
virtual vx_status pushResource(vx_uint32 index, T resource, vx_uint32 frame_id, vx_uint32 demand_number) {
ExynosVisionResElement<T> *res_element;
ExynosVisionResManager<T>::m_res_mutex.lock();
if (index < MAX_QUEUE_RES_NUM) {
res_element = ExynosVisionResQueueType<T>::m_res_element_vector.editItemAt(index);
} else {
VXLOGE("index:%d is out of bound", index);
ExynosVisionResManager<T>::m_res_mutex.unlock();
return VX_FAILURE;
}
if (res_element->getResource() != NULL) {
VXLOGE("index:%d is already assigned resource", index);
ExynosVisionResManager<T>::m_res_mutex.unlock();
return VX_FAILURE;
}
res_element->setResource(resource);
res_element->setId(frame_id);
res_element->setReadDemandNum(demand_number);
res_element->setState(RES_ELEMENT_READ_LOCK);
res_element->setValid(vx_true_e);
ExynosVisionResManager<T>::m_using_res_element_list.push_back(res_element);
ExynosVisionResManager<T>::m_res_mutex.unlock();
return VX_SUCCESS;
}
virtual T getFilledRes(vx_uint32 frame_id, vx_bool *ret_data_valid)
{
vx_status status = VX_FAILURE;
ExynosVisionResElement<T>* res_element = NULL;
typename List<ExynosVisionResElement<T>*>::iterator elem_iter;
ExynosVisionResManager<T>::m_res_mutex.lock();
for (elem_iter=ExynosVisionResManager<T>::m_using_res_element_list.begin();
elem_iter!=ExynosVisionResManager<T>::m_using_res_element_list.end();
elem_iter++) {
res_element = *elem_iter;
if (res_element->getId() == frame_id) {
res_element->incReadRefCnt();
res_element->incReadDemCnt();
*ret_data_valid = res_element->getValid();
status = VX_SUCCESS;
break;
}
}
ExynosVisionResManager<T>::m_res_mutex.unlock();
if (status != VX_SUCCESS) {
VXLOGE("cannot find perfer buffer, id:%d", frame_id);
return NULL;
} else {
return res_element->getResource();
}
}
virtual vx_status putFilledRes(vx_uint32 frame_id)
{
vx_status status = VX_FAILURE;
ExynosVisionResElement<T> *res_element;
typename List<ExynosVisionResElement<T>*>::iterator elem_iter;
ExynosVisionResManager<T>::m_res_mutex.lock();
for (elem_iter=ExynosVisionResManager<T>::m_using_res_element_list.begin();
elem_iter!=ExynosVisionResManager<T>::m_using_res_element_list.end();
elem_iter++) {
res_element = *elem_iter;
if (res_element->getId() == frame_id) {
res_element->decReadRefCnt();
status = VX_SUCCESS;
break;
}
}
if (status != VX_SUCCESS) {
VXLOGE("cannot find perfer buffer, id:%d", frame_id);
} else {
if (res_element->isReadComplete()) {
ExynosVisionResManager<T>::m_using_res_element_list.erase(elem_iter);
res_element->clearReadInfo();
res_element->setState(RES_ELEMENT_NO_LOCK);
ExynosVisionResQueueType<T>::m_done_res_element_pool.putResource(res_element);
}
}
ExynosVisionResManager<T>::m_res_mutex.unlock();
return status;
}
virtual void displayBuff(vx_uint32 tab_num, vx_bool detail_info)
{
vx_char tap[MAX_TAB_NUM];
ExynosVisionResElement<T> *res_element = NULL;
vx_uint32 i;
typename List<ExynosVisionResElement<T>*>::iterator elem_iter;
VXLOGD("%s[QUEU][%d]rece buf num:%d, done buf num:%d", MAKE_TAB(tap, tab_num), detail_info, ExynosVisionResQueueType<T>::m_using_res_element_list.size(), ExynosVisionResQueueType<T>::m_done_res_element_pool.getFreeNum());
}
};
template<typename T>
class ExynosVisionResOutputQueueType : public ExynosVisionResQueueType<T> {
private:
ExynosVisionPool<ExynosVisionResElement<T>*> m_free_res_element_pool;
public:
private:
public:
/* Constructor */
ExynosVisionResOutputQueueType(void)
{
ExynosVisionResManager<T>::m_res_class_type = RESOURCE_CLASS_OUTPUT_QUEUE;
}
virtual vx_status pushResource(vx_uint32 index, T resource) {
ExynosVisionResElement<T> *res_element;
ExynosVisionResManager<T>::m_res_mutex.lock();
if (index < MAX_QUEUE_RES_NUM) {
res_element = ExynosVisionResQueueType<T>::m_res_element_vector.editItemAt(index);
} else {
VXLOGE("index:%d is out of bound", index);
ExynosVisionResManager<T>::m_res_mutex.unlock();
return VX_FAILURE;
}
if (res_element->getResource() != NULL) {
VXLOGE("index:%d is already assigned resource", index);
ExynosVisionResManager<T>::m_res_mutex.unlock();
return VX_FAILURE;
}
res_element->setResource(resource);
ExynosVisionResManager<T>::m_res_mutex.unlock();
m_free_res_element_pool.putResource(res_element);
return VX_SUCCESS;
}
virtual T waitAndGetEmptyResAndWrLk(vx_uint32 frame_id) {
pool_exception_t pool_exception;
ExynosVisionResElement<T>* res_element = NULL;
pool_exception = m_free_res_element_pool.getResource(&res_element);
if (pool_exception == POOL_EXCEPTION_NONE) {
ExynosVisionResManager<T>::m_res_mutex.lock();
res_element->setId(frame_id);
res_element->setState(RES_ELEMENT_WRITE_LOCK);
res_element->setValid(vx_true_e);
ExynosVisionResQueueType<T>::m_using_res_element_list.push_back(res_element);
ExynosVisionResManager<T>::m_res_mutex.unlock();
return res_element->getResource();
} else {
VXLOGE("getting empty buffer");
return NULL;
}
}
virtual vx_status setFilledRes(vx_uint32 frame_id, vx_bool data_valid)
{
vx_status status = VX_FAILURE;
ExynosVisionResElement<T> *res_element;
typename List<ExynosVisionResElement<T>*>::iterator elem_iter;
ExynosVisionResManager<T>::m_res_mutex.lock();
for (elem_iter=ExynosVisionResQueueType<T>::m_using_res_element_list.begin();
elem_iter!= ExynosVisionResQueueType<T>::m_using_res_element_list.end();
elem_iter++) {
res_element = *elem_iter;
if (res_element->getId() == frame_id) {
res_element->setState(RES_ELEMENT_NO_LOCK);
res_element->setValid(data_valid);
status = VX_SUCCESS;
break;
}
}
if (status != VX_SUCCESS) {
VXLOGE("cannot find perfer buffer, id:%d", frame_id);
} else {
ExynosVisionResQueueType<T>::m_using_res_element_list.erase(elem_iter);
ExynosVisionResQueueType<T>::m_done_res_element_pool.putResource(res_element);
}
ExynosVisionResManager<T>::m_res_mutex.unlock();
return status;
}
virtual void displayBuff(vx_uint32 tab_num, vx_bool detail_info)
{
vx_char tap[MAX_TAB_NUM];
ExynosVisionResElement<T> *res_element = NULL;
vx_uint32 i;
typename List<ExynosVisionResElement<T>*>::iterator elem_iter;
VXLOGD("%s[QUEU][%d]free buf num:%d, done buf num:%d", MAKE_TAB(tap, tab_num), detail_info,
m_free_res_element_pool.getFreeNum(),
ExynosVisionResQueueType<T>::m_done_res_element_pool.getFreeNum());
}
};
}; // namespace android
#endif