blob: 6e11ef9c5beb510fa091e316a28dcbcacf21434e [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.
*/
#define LOG_TAG "ExynosVisionGraph"
#include <cutils/log.h>
#include "ExynosVisionAutoTimer.h"
#include "ExynosVisionGraph.h"
#include "ExynosVisionSubgraph.h"
#define GRAPHDBG /* VXLOGD */
namespace android {
ExynosVisionGraph::ExynosVisionGraph(ExynosVisionContext *context)
: ExynosVisionReference(context, VX_TYPE_GRAPH, (ExynosVisionReference*)context, vx_true_e)
{
memset(&perf, 0x0, sizeof(perf));
m_error_status = VX_SUCCESS;
m_verified = vx_false_e;
m_parent_node = NULL;
m_graph_state.setState(GRAPH_STATE_NOT_VERIFIED);
m_schedule_complete_event = NULL;
m_exec_mode = GRAPH_EXEC_NORMAL;
m_performance_monitor = NULL;
m_is_replaced_flag = vx_false_e;
m_error_queue = NULL;
m_schedule_queue = NULL;
m_verify_time = 0;
}
ExynosVisionGraph::~ExynosVisionGraph()
{
}
vx_status
ExynosVisionGraph::init(void)
{
vx_status status = VX_SUCCESS;
m_performance_monitor = new ExynosVisionPerfMonitor<ExynosVisionNode*>;
if (m_performance_monitor == NULL)
VXLOGE("performance monitor can't create");
m_error_queue = new ExynosVisionQueue<graph_error_message_t>(0);
m_error_thread = new ExynosVisionThread<ExynosVisionGraph>(this, &ExynosVisionGraph::errorThreadFunc, "graph_err", PRIORITY_DEFAULT);
if (m_error_thread.get() != NULL) {
m_error_thread->run();
} else {
status = VX_FAILURE;
}
m_schedule_queue = new ExynosVisionQueue<graph_schedule_message_t>(0);
m_schedule_thread = new ExynosVisionThread<ExynosVisionGraph>(this, &ExynosVisionGraph::scheduleThreadFunc, "graph_shd", PRIORITY_DEFAULT);
if (m_schedule_thread.get() != NULL) {
m_schedule_thread->run();
} else {
status = VX_FAILURE;
}
if (getContext()->getPerfMonitor() != NULL) {
getContext()->getPerfMonitor()->registerObjectForTrace(this, GRAPH_TIMEPAIR_NUMBER);
} else {
VXLOGE("performance monitor is not assigned");
}
m_schedule_complete_event = new ExynosVisionEvent(0);
return status;
}
vx_status
ExynosVisionGraph::destroy(void)
{
vx_status status = VX_SUCCESS;
VXLOGD3("%s destroy", getName());
if (m_parent_node)
m_parent_node = NULL;
List<ExynosVisionSubgraph*>::iterator sg_iter;
for (sg_iter=m_sg_list.begin(); sg_iter!=m_sg_list.end(); sg_iter++) {
status = (*sg_iter)->destroy();
if (status != VX_SUCCESS)
VXLOGE("destorying sg(%d) fails, err:%d", (*sg_iter)->getId(), status);
delete *sg_iter;
}
m_sg_list.clear();
m_param_vector.clear();
List<ExynosVisionNode*>::iterator node_iter;
for (node_iter=m_node_list.begin(); node_iter!=m_node_list.end(); node_iter++) {
while((*node_iter)->getExternalCnt()) {
status = ExynosVisionReference::releaseReferenceInt((ExynosVisionReference**)&(*node_iter), VX_REF_EXTERNAL);
if (status != VX_SUCCESS) {
VXLOGE("release external reference of %s fails, err:%d", (*node_iter)->getName(), status);
}
}
ExynosVisionReference::releaseReferenceInt((ExynosVisionReference**)&(*node_iter), VX_REF_INTERNAL, this);
if (*node_iter != NULL) {
VXLOGE("%s was not destoyed", (*node_iter)->getName());
(*node_iter)->displayInfo(0, vx_true_e);
}
}
m_node_list.clear();
status_t ret;
if (m_error_queue) {
m_error_queue->wakeupPendingThreadAndQDisable();
ret = m_error_thread->requestExitAndWait();
if (ret != NO_ERROR) {
VXLOGE("thread of subgraph cann't exit, ret:%d", ret);
status = VX_FAILURE;
}
VXLOGD3("[TD]err-thread, finishing to exit thread");
m_error_queue->release();
delete m_error_queue;
m_error_queue = NULL;
}
if (m_schedule_queue) {
m_schedule_queue->wakeupPendingThreadAndQDisable();
ret = m_schedule_thread->requestExitAndWait();
if (ret != NO_ERROR) {
VXLOGE("thread of subgraph cann't exit, ret:%d", ret);
status = VX_FAILURE;
}
VXLOGD3("[TD]shd-thread, finishing to exit thread");
m_schedule_queue->release();
delete m_schedule_queue;
m_schedule_queue = NULL;
}
if (m_performance_monitor) {
delete m_performance_monitor;
m_performance_monitor = NULL;
}
if (m_schedule_complete_event) {
delete m_schedule_complete_event;
m_schedule_complete_event = NULL;
}
if (getContext()->getPerfMonitor() != NULL) {
getContext()->getPerfMonitor()->releaseObjectForTrace(this);
} else {
VXLOGE("performance monitor is not assigned");
}
return status;
}
ExynosVisionNode*
ExynosVisionGraph::createGenericNode(ExynosVisionKernel *kernel)
{
EXYNOS_VISION_SYSTEM_IN();
/* VX_REF_INTERNAL for m_node_list of graph */
ExynosVisionNode *node = new ExynosVisionNode(getContext(), this);
if (node->getCreationStatus() != VX_SUCCESS) {
VXLOGE("node object creation fail(%d)", node->getCreationStatus());
delete node;
return (ExynosVisionNode*)getContext()->getErrorObject(node->getCreationStatus());
}
node->init(this, kernel);
m_internal_lock.lock();
m_node_list.push_back(node);
node->incrementReference(VX_REF_INTERNAL, this);
/* force a re-verify */
m_verified = vx_false_e;
m_internal_lock.unlock();
VXLOGD2("Created %s from %s", node->getName(), node->getKernelName());
EXYNOS_VISION_SYSTEM_OUT();
return node;
}
ExynosVisionNode*
ExynosVisionGraph::createNodeByStructure(vx_enum kernel_enum, ExynosVisionDataReference *params[], vx_uint32 num)
{
vx_status status = VX_SUCCESS;
ExynosVisionNode *node = NULL;
ExynosVisionContext *context = getContext();
ExynosVisionKernel *kernel = context->getKernelByEnum(kernel_enum);
if (kernel) {
VXLOGD3("kernel name:%s", kernel->getKernelName());
node = createGenericNode(kernel);
if (node->getStatus() == VX_SUCCESS) {
vx_uint32 p = 0;
for (p = 0; p < num; p++) {
if (params[p] == NULL)
continue;
status = node->setParameterByIndex(p, params[p]);
if (status != VX_SUCCESS) {
VXLOGE("Kernel %d Parameter %u is invalid.\n", kernel_enum, p);
context->addLogEntry(this, status, "Kernel %d Parameter %u is invalid.\n", kernel_enum, p);
return (ExynosVisionNode*)context->getErrorObject(status);
}
}
}
else {
VXLOGE("Failed to create node with kernel enum %d", kernel_enum);
context->addLogEntry(this, VX_ERROR_INVALID_PARAMETERS, "Failed to create node with kernel enum %d\n", kernel_enum);
}
} else {
VXLOGE("failed to retrieve kernel enum %d", kernel_enum);
context->addLogEntry(this, VX_ERROR_NOT_SUPPORTED, "failed to retrieve kernel enum %d\n", kernel_enum);
status = VX_ERROR_NOT_SUPPORTED;
return (ExynosVisionNode*)context->getErrorObject(status);
}
return node;
}
vx_status
ExynosVisionGraph::removeNode(ExynosVisionNode *node)
{
if (m_graph_state.getState() == GRAPH_STATE_PROCESSING) {
VXLOGE("%s, can't remove node during processing", getName());
return VX_FAILURE;
}
vx_status status = VX_SUCCESS;
m_verified = vx_false_e;
m_graph_state.setState(GRAPH_STATE_NOT_VERIFIED);
if (node->getSubgraph()) {
List<ExynosVisionSubgraph*>::iterator sg_iter;
for (sg_iter=m_sg_list.begin(); sg_iter!=m_sg_list.end(); sg_iter++) {
if (*sg_iter == node->getSubgraph())
break;
}
if (sg_iter != m_sg_list.end()) {
status = (*sg_iter)->destroy();
if (status != VX_SUCCESS)
VXLOGE("destorying %s fails, err:%d", (*sg_iter)->getSgName(), status);
delete *sg_iter;
m_sg_list.erase(sg_iter);
} else {
VXLOGE("%s doesn't have %s", this->getName(), (*sg_iter)->getSgName());
}
}
List<ExynosVisionNode*>::iterator node_iter;
for (node_iter=m_node_list.begin(); node_iter!=m_node_list.end(); node_iter++) {
if (*node_iter == node) {
break;
}
}
if (node_iter == m_node_list.end()) {
VXLOGE("%s doesn't have %s", getName(), node->getName());
status = VX_ERROR_INVALID_PARAMETERS;
} else {
status = (*node_iter)->disconnectParentGraph();
m_node_list.erase(node_iter);
status = ExynosVisionReference::releaseReferenceInt((ExynosVisionReference**)&*node_iter, VX_REF_INTERNAL, this);
if (status != VX_SUCCESS)
VXLOGE("releasoing node fails, err:%d", status);
}
return status;
}
vx_status
ExynosVisionGraph::addParameterToGraph(ExynosVisionParameter *param)
{
VXLOGD3("add param to graph:node:%s(%s), index:%d", param->getNodeHandle()->getName(), param->getKernelHandle()->getKernelName(), param->getIndex());
struct graph_param_info graph_param;
graph_param.node = param->getNode();
graph_param.index = param->getIndex();
m_param_vector.push_back(graph_param);
return VX_SUCCESS;
}
vx_status
ExynosVisionGraph::setGraphParameterByIndex(vx_uint32 index, ExynosVisionDataReference *ref)
{
if (m_param_vector.size() <= index) {
VXLOGE("%s, out of bound, graph's param:%d, index:%d", getName(), m_param_vector.size(), index);
return VX_FAILURE;
}
vx_status status;
ExynosVisionNode *node = m_param_vector[index].node;
vx_uint32 node_index = m_param_vector[index].index;
status = node->setParameterByIndex(node_index, ref);
if (status != VX_SUCCESS) {
VXLOGE("setting node param fails, err:%d", status);
}
return status;
}
ExynosVisionParameter*
ExynosVisionGraph::getGraphParameterByIndex(vx_uint32 index)
{
if (m_param_vector.size() <= index) {
VXLOGE("%s, out of bound, graph's param:%d, index:%d", getName(), m_param_vector.size(), index);
return NULL;
}
ExynosVisionNode *node = m_param_vector[index].node;
vx_uint32 node_index = m_param_vector[index].index;
ExynosVisionParameter *parameter;
parameter = node->getParameterByIndex(node_index);
if (parameter == NULL) {
VXLOGE("getting node param fails, err:%d");
}
return parameter;
}
vx_status
ExynosVisionGraph::replaceNodeToGraph(ExynosVisionNode *node, ExynosVisionGraph *child_graph)
{
vx_status status = VX_SUCCESS;
ExynosVisionGraph *parent_graph = this;
vx_uint32 param_num;
List<ExynosVisionNode*>::iterator node_iter;
List<ExynosVisionNode*> clone_node_list;
map<ExynosVisionNode*, ExynosVisionNode*> replaced_node_map;
vx_enum kernel_enum;
ExynosVisionDataReference *params[VX_INT_MAX_PARAMS];
vx_bool match = vx_true_e;
param_num = node->getKernelHandle()->getNumParams();
/* check to make sure the signature of the node matches the signature of the graph. */
if (child_graph->getNumParams() > 0) {
for (vx_uint32 p = 0; p < param_num; p++) {
const struct graph_param_info *graph_param = child_graph->getParameterHandle(p);
if ((graph_param->node) && (graph_param->node != node)) {
ExynosVisionNode *graph_param_node = graph_param->node;
vx_uint32 graph_param_index = graph_param->index;
VXLOGD2("node:%s, p:%d / graph_param_node:%s, graph_param_index:%d", node->getName(), p, graph_param_node->getName(), graph_param_index);
if (node->getDataRefByIndex(p) != graph_param_node->getDataRefByIndex(graph_param_index)) {
VXLOGE("graph parameter's node has invalid data object");
match = vx_false_e;
break;
}
} else {
VXLOGE("graph parameter's node is invalid object");
match = vx_false_e;
break;
}
}
} else {
VXLOGE("to replace node, the graph must have some parameters with replacing node");
}
if (match == vx_false_e) {
goto EXIT;
}
for (node_iter=child_graph->m_node_list.begin(); node_iter!=child_graph->m_node_list.end(); node_iter++) {
ExynosVisionNode *emigrant_node = *node_iter;
kernel_enum = emigrant_node->getKernelHandle()->getEnumeration();
param_num = emigrant_node->getKernelHandle()->getNumParams();
for (vx_uint32 p=0; p<param_num; p++) {
params[p] = emigrant_node->getDataRefByIndex(p);
}
ExynosVisionNode *immigrant_node = parent_graph->createNodeByStructure(kernel_enum, params, param_num);
if (immigrant_node == NULL) {
VXLOGE("creating node fails");
status = VX_ERROR_INVALID_GRAPH;
break;
}
/* emigrant_node will be removed later */
replaced_node_map[emigrant_node] = immigrant_node;
}
if (status != VX_SUCCESS) {
VXLOGE("Emigration of nodes fails, err:%d", status);
goto EXIT;
}
/* update graph parameter if exists. (it means that the current graph is also the child graph.)
if the parameters of replaced node is the one of graph parameter, it should be replaced to the parameter of replacing node in child-graph. */
Vector<graph_param_info>::iterator graph_param_iter;
for (graph_param_iter=m_param_vector.begin(); graph_param_iter!=m_param_vector.end(); graph_param_iter++) {
VXLOGD3("%s graph param, node:%s, param:%d", getName(), graph_param_iter->node->getName(), graph_param_iter->index);
if (graph_param_iter->node == node) {
const struct graph_param_info *child_graph_param = child_graph->getParameterHandle(graph_param_iter->index);
graph_param_iter->node = replaced_node_map[child_graph_param->node];
graph_param_iter->index = child_graph_param->index;
VXLOGD3("replace graph param: %s -> %s", graph_param_iter->node->getName(), child_graph_param->node->getName());
}
}
status = parent_graph->removeNode(node);
if (status != VX_SUCCESS) {
VXLOGE("removing %s from %s fails, err:%d", node->getName(), parent_graph->getName(), status);
goto EXIT;
}
clone_node_list = child_graph->m_node_list;
for (node_iter=clone_node_list.begin(); node_iter!=clone_node_list.end(); node_iter++) {
ExynosVisionNode *emigrant_node = *node_iter;
status = child_graph->removeNode(emigrant_node);
if (status != VX_SUCCESS) {
VXLOGE("removing %s from %s fails, err:%d", emigrant_node->getName(), child_graph->getName(), status);
}
}
EXIT:
if (status == VX_SUCCESS) {
m_is_replaced_flag = vx_true_e;
}
return status;
}
vx_status
ExynosVisionGraph::verifyGraph(void)
{
vx_status status = VX_FAILURE;
uint64_t verify_start, verify_end;
Mutex::Autolock lock(m_external_lock);
if (m_verified == vx_true_e) {
VXLOGD("already verified %s", getName());
return VX_SUCCESS;
}
verify_start = ExynosVisionDurationTimer::getTimeUs();
/* reset the frame count */
m_frame_cnt_map.clear();
VXLOGD3("Topological Sort phase - first");
status = topologicalSort();
if (status != VX_SUCCESS) {
VXLOGE("topological sort fail in verify(%d)", status);
goto Exit;
}
VXLOGD3("Parameter Validation phase");
status = parameterValidation();
if (status != VX_SUCCESS) {
VXLOGE("parameter validation fail in verify(%d)", status);
goto Exit;
}
VXLOGD3("Check data reference phase");
status = checkDataReference();
if (status != VX_SUCCESS) {
VXLOGE("single writer check fail in verify(%d)", status);
goto Exit;
}
VXLOGD3("Kernel Initialize phase");
status = initializeKernel();
if (status != VX_SUCCESS) {
VXLOGE("kernel initialization fails in verify(%d)", status);
goto Exit;
}
if (m_is_replaced_flag) {
VXLOGD3("Topological Sort phase - second");
status = topologicalSort();
if (status != VX_SUCCESS) {
VXLOGE("topological sort fail in verify(%d)", status);
goto Exit;
}
}
VXLOGD3("grouping subgraph phase\n");
status = groupingSubgraph();
if (status != VX_SUCCESS) {
VXLOGE("grouping subgraph fails in verify(%d)", status);
goto Exit;
}
VXLOGD3("fixing subgraph phase\n");
status = fixAllSubgraph();
if (status != VX_SUCCESS) {
VXLOGE("fixing subgraph fails in verify(%d)", status);
goto Exit;
}
VXLOGD3("checking graph execution mode phase\n");
status = checkExecutionModePropriety();
if (status != VX_SUCCESS) {
VXLOGE("checking execution mode fails in verify(%d)", status);
goto Exit;
}
Exit:
verify_end = ExynosVisionDurationTimer::getTimeUs();
m_verify_time = verify_end - verify_start;
if (status == VX_SUCCESS) {
m_verified = vx_true_e;
m_graph_state.setState(GRAPH_STATE_VERIFIED);
} else {
m_verified = vx_false_e;
}
return status;
}
vx_status
ExynosVisionGraph::topologicalSort(void)
{
EXYNOS_VISION_SYSTEM_IN();
vx_status status;
List<ExynosVisionNode*> prev_node_list;
List<ExynosVisionNode*> cur_node_list;
map<vx_uint32, vx_uint32> sorted_parent_node_num_map;
const List<ExynosVisionNode*> *const_node_list;
m_sorted_node_list.clear();
/* Find all head nodes */
for (List<ExynosVisionNode*>::iterator iter_node = m_node_list.begin(); iter_node != m_node_list.end(); iter_node++ ) {
(*iter_node)->calculateConnectedNode();
if ((*iter_node)->isHeader()) {
GRAPHDBG("head node:(%s/%s)", (*iter_node)->getName(), (*iter_node)->getKernelName());
prev_node_list.push_back(*iter_node);
}
}
while(1) {
/* Insert finding nodes to sorting queue */
const_node_list = &prev_node_list;
m_sorted_node_list.insert(m_sorted_node_list.end(), const_node_list->begin(), const_node_list->end());
cur_node_list.clear();
/* find 1st level children of previous nodes and check that all of its parents are inserted sorting queue already. */
for (List<ExynosVisionNode*>::iterator parent_node = prev_node_list.begin(); parent_node != prev_node_list.end(); parent_node++) {
for (vx_uint32 op = 0; op < (*parent_node)->getOutputDataRefNum(); op++) {
ExynosVisionDataReference *data_ref = (*parent_node)->getOutputDataRefByIndex(op);
if (data_ref == NULL) {
if ((*parent_node)->getParamState(VX_OUTPUT, op) == VX_PARAMETER_STATE_OPTIONAL) {
continue;
} else {
VXLOGE("some parameter is not assigned at %s", (*parent_node)->getName());
status = VX_ERROR_INVALID_REFERENCE;
m_sorted_node_list.clear();
goto EXIT;
}
}
for (vx_uint32 child_node_idx = 0; child_node_idx < data_ref->getIndirectOutputNodeNum(this); child_node_idx++) {
ExynosVisionNode *child_node = data_ref->getIndirectOutputNode(this, child_node_idx);
sorted_parent_node_num_map[child_node->getId()]++;
if (child_node->getPreNodeNum() == sorted_parent_node_num_map[child_node->getId()]) {
GRAPHDBG("cur node:(%s/%s)", child_node->getName(), child_node->getKernelName());
cur_node_list.push_back(child_node);
}
}
}
}
/* Set last finding node to previous group */
prev_node_list.clear();
const_node_list = &cur_node_list;
prev_node_list.insert(prev_node_list.end(), const_node_list->begin(), const_node_list->end());
for (List<ExynosVisionNode*>::iterator iter_pos=m_sorted_node_list.begin(); iter_pos!=m_sorted_node_list.end(); iter_pos++) {
GRAPHDBG("sorted node:(%s/%s)", (*iter_pos)->getName(), (*iter_pos)->getKernelName());
}
if (!cur_node_list.size())
break;
if (m_sorted_node_list.size() > m_node_list.size())
break;
}
GRAPHDBG("sorted node num:%d", m_sorted_node_list.size());
if (m_node_list.size() == m_sorted_node_list.size()) {
status = VX_SUCCESS;
} else {
VXLOGE("one node is not connected in graph");
status = VX_ERROR_INVALID_GRAPH;
}
EXIT:
EXYNOS_VISION_SYSTEM_OUT();
return status;
}
vx_status
ExynosVisionGraph::parameterValidation(void)
{
EXYNOS_VISION_SYSTEM_IN();
vx_status status = VX_SUCCESS;
GRAPHDBG("sorted node num:%d", m_sorted_node_list.size());
for (List<ExynosVisionNode*>::iterator iter_node = m_sorted_node_list.begin(); iter_node != m_sorted_node_list.end(); iter_node++ ) {
status = (*iter_node)->verifyNode();
if (status != VX_SUCCESS) {
VXLOGE("node verifying fail at node(%d), %d", (*iter_node)->getId(), status);
break;
}
}
EXYNOS_VISION_SYSTEM_OUT();
return status;
}
vx_status
ExynosVisionGraph::checkDataReference(void)
{
EXYNOS_VISION_SYSTEM_IN();
vx_status status = VX_SUCCESS;
m_ref_header_list.clear();
m_ref_footer_list.clear();
GRAPHDBG("sorted node num:%d", m_sorted_node_list.size());
for (List<ExynosVisionNode*>::iterator node_iter1 = m_sorted_node_list.begin(); node_iter1!=m_sorted_node_list.end(); node_iter1++) {
/* find header reference */
for (vx_uint32 input_ref_idx=0; input_ref_idx < (*node_iter1)->getInputDataRefNum(); input_ref_idx++) {
ExynosVisionDataReference *in_ref = (*node_iter1)->getInputDataRefByIndex(input_ref_idx);
if (in_ref == NULL)
continue;
GRAPHDBG("%s, input node num:%d, output node num:%d", in_ref->getName(),
in_ref->getDirectInputNodeNum(this), in_ref->getIndirectInputNodeNum(this),
in_ref->getDirectOutputNodeNum(this), in_ref->getIndirectOutputNodeNum(this));
if (in_ref->getIndirectInputNodeNum(this) == 0)
m_ref_header_list.push_back(in_ref);
}
for (vx_uint32 output_ref_idx1 = 0; output_ref_idx1 < (*node_iter1)->getOutputDataRefNum(); output_ref_idx1++) {
ExynosVisionDataReference *out_ref = (*node_iter1)->getOutputDataRefByIndex(output_ref_idx1);
/* find footer reference */
if (out_ref == NULL)
continue;
GRAPHDBG("%s, input node num:%d/%d, output node num:%d/%d", out_ref->getName(),
out_ref->getDirectInputNodeNum(this), out_ref->getIndirectInputNodeNum(this),
out_ref->getDirectOutputNodeNum(this), out_ref->getIndirectOutputNodeNum(this));
if (out_ref->getIndirectOutputNodeNum(this) == 0)
m_ref_footer_list.push_back(out_ref);
/* check multiple writer */
if (out_ref->getIndirectInputNodeNum(this) >= 2) {
VXLOGE("%s has multiple node writer", out_ref->getName(), out_ref->getType());
status = VX_ERROR_MULTIPLE_WRITERS;
continue;
}
#if 0
/* the checking of the in-direct input node number could cover below. */
for (List<ExynosVisionNode*>::iterator node_iter2 = m_sorted_node_list.begin(); node_iter2!=m_sorted_node_list.end(); node_iter2++) {
if ((*node_iter1) == (*node_iter2))
continue;
for (vx_uint32 output_ref_idx2 = 0; output_ref_idx2 < (*node_iter2)->getOutputDataRefNum(); output_ref_idx2++) {
ExynosVisionDataReference *op2 = (*node_iter2)->getOutputDataRefByIndex(output_ref_idx2);
if ((out_ref != NULL) &&
(op2 != NULL) &&
ExynosVisionDataReference::checkWriteDependency(out_ref, op2) == vx_true_e) {
status = VX_ERROR_MULTIPLE_WRITERS;
VXLOGE("node(%d) and node(%d0) are trying to output to the same ref", (*node_iter1)->getId(), (*node_iter2)->getId());
getContext()->addLogEntry(this, status, "node(%d) and node(%d0) are trying to output to the same ref", (*node_iter1)->getId(), (*node_iter2)->getId());
break;
}
}
}
#endif
}
}
EXYNOS_VISION_SYSTEM_OUT();
return status;
}
vx_status
ExynosVisionGraph::initializeKernel(void)
{
EXYNOS_VISION_SYSTEM_IN();
vx_status status = VX_SUCCESS;
vx_status kernel_init_status;
for (List<ExynosVisionNode*>::iterator node_iter=m_sorted_node_list.begin(); node_iter!=m_sorted_node_list.end(); node_iter++) {
ExynosVisionNode *node = (*node_iter);
status = node->initilalizeKernel();
if (status != VX_SUCCESS) {
VXLOGE("node(%d,%s) is not initialized", node->getId(), node->getKernelName());
break;
}
}
EXYNOS_VISION_SYSTEM_OUT();
return status;
}
vx_status
ExynosVisionGraph::groupingSubgraph(void)
{
EXYNOS_VISION_SYSTEM_IN();
vx_status status = VX_FAILURE;
for (List<ExynosVisionNode*>::iterator node_iter = m_sorted_node_list.begin(); node_iter != m_sorted_node_list.end(); node_iter++ ) {
ExynosVisionNode *cur_node = *node_iter;
ExynosVisionSubgraph *cur_subgraph = new ExynosVisionSubgraph(this);
status = cur_subgraph->init(cur_node);
cur_node->setSubgraph(cur_subgraph);
if (status != VX_SUCCESS) {
VXLOGE("subgraph can't init, err:%d", status);
break;
}
m_sg_list.push_back(cur_subgraph);
}
EXYNOS_VISION_SYSTEM_OUT();
return status;
}
vx_status
ExynosVisionGraph::fixAllSubgraph(void)
{
EXYNOS_VISION_SYSTEM_IN();
vx_status status;
for (List<ExynosVisionSubgraph*>::iterator subgraph_iter = m_sg_list.begin(); subgraph_iter != m_sg_list.end(); subgraph_iter++ ) {
status = (*subgraph_iter)->fixSubgraph();
if (status != VX_SUCCESS) {
VXLOGE("subgraph is not fixed, err:%d", status);
break;
}
if ((*subgraph_iter)->isHeader()) {
m_sg_header_list.push_back((*subgraph_iter));
}
if ((*subgraph_iter)->isFooter()) {
m_sg_footer_list.push_back((*subgraph_iter));
}
}
EXYNOS_VISION_SYSTEM_OUT();
return status;
}
vx_status
ExynosVisionGraph::checkExecutionModePropriety(void)
{
EXYNOS_VISION_SYSTEM_IN();
vx_status status = VX_SUCCESS;
if (getExecMode() == GRAPH_EXEC_STREAM) {
for (List<ExynosVisionNode*>::iterator iter_node = m_sorted_node_list.begin(); iter_node != m_sorted_node_list.end(); iter_node++ ) {
for (vx_uint32 p = 0; p < (*iter_node)->getKernelHandle()->getNumParams(); p++) {
ExynosVisionDataReference *data_ref = (*iter_node)->getDataRefByIndex(p);
if (data_ref == NULL)
continue;
/* there are some restricts in stream mode.
1. can't contain delay object
2. can't contain alliance object.
3. can't contain object that doesn't have own resource. */
if ((data_ref->isDelayElement() == vx_true_e) ||
(data_ref->getDirectInputNodeNum(this) != data_ref->getIndirectInputNodeNum(this)) ||
(data_ref->getDirectOutputNodeNum(this) != data_ref->getIndirectOutputNodeNum(this)) ||
(data_ref->getResourceType() == RESOURCE_MNGR_NULL)) {
VXLOGE("%s can't support stream mode", data_ref->getName());
status = VX_FAILURE;
goto EXIT;
}
}
}
}
EXYNOS_VISION_SYSTEM_OUT();
EXIT:
return status;
}
vx_status
ExynosVisionGraph::setParentNode(ExynosVisionNode* node)
{
m_parent_node = node;
return VX_SUCCESS;
}
vx_status
ExynosVisionGraph::processGraph(void)
{
EXYNOS_VISION_SYSTEM_IN();
vx_status status = VX_FAILURE;
if (getExecMode() != GRAPH_EXEC_NORMAL) {
VXLOGE("processing graph could be executed only on normal mode");
return VX_FAILURE;
}
if (m_verified == vx_false_e) {
status = verifyGraph();
if (status != VX_SUCCESS) {
VXLOGE("verifying graph fail, err:%d", status);
return status;
}
}
Mutex::Autolock lock(m_external_lock);
if (m_graph_state.getState() != GRAPH_STATE_VERIFIED) {
VXLOGE("%s is not verified", getName());
return status;
}
m_error_status = VX_SUCCESS;
m_graph_state.setState(GRAPH_STATE_PROCESSING);
vx_uint32 frame_cnt;
if (m_parent_node == NULL) {
frame_cnt = requestNewFrameCnt(this);
} else {
/* child graph */
frame_cnt = m_parent_node->getCurFrameCnt();
}
time_pair_t *time_pair = getContext()->getPerfMonitor()->requestTimePairStr(this, frame_cnt);
TIMESTAMP_START(time_pair, TIMEPAIR_PROCESS);
List<ExynosVisionSubgraph*>::iterator sg_iter;
for (sg_iter=m_sg_footer_list.begin(); sg_iter!=m_sg_footer_list.end(); sg_iter++) {
VXLOGD2("%s, clear complete flag", (*sg_iter)->getSgName());
status = (*sg_iter)->clearSubgraphComplete();
if (status != VX_SUCCESS) {
VXLOGE("clearing subgraph complete flag fails, err:%d", status);
}
}
for (sg_iter=m_sg_header_list.begin(); sg_iter!=m_sg_header_list.end(); sg_iter++) {
VXLOGD2("trigger to %s to start", (*sg_iter)->getSgName());
status = (*sg_iter)->pushTrigger(frame_cnt);
if (status != VX_SUCCESS) {
VXLOGE("pushing done event fails, err:%d", status);
}
}
for (sg_iter=m_sg_footer_list.begin(); sg_iter!=m_sg_footer_list.end(); sg_iter++) {
VXLOGD2("waiting complete signal from %s", (*sg_iter)->getSgName());
status = (*sg_iter)->waitSubgraphComplete(m_sg_list.size() * COMPLETE_WAIT_TIME);
if (status != VX_SUCCESS) {
VXLOGE("waiting complete signal fails from %s, err:%d", (*sg_iter)->getSgName(), status);
/* update error status if any error is not reproted. */
if (m_error_status == VX_SUCCESS)
m_error_status = status;
} else {
VXLOGD2("receive complete signal from %s", (*sg_iter)->getSgName());
}
}
m_graph_state.setState(GRAPH_STATE_VERIFIED);
TIMESTAMP_END(time_pair, TIMEPAIR_PROCESS);
if (time_pair) {
getContext()->getPerfMonitor()->releaseTimePairStr(this, frame_cnt, time_pair);
}
EXYNOS_VISION_SYSTEM_OUT();
return m_error_status;
}
vx_status
ExynosVisionGraph::stopProcessGraph(void)
{
EXYNOS_VISION_SYSTEM_IN();
vx_status status = VX_FAILURE;
List<ExynosVisionSubgraph*>::iterator sg_iter;
for (sg_iter=m_sg_list.begin(); sg_iter!=m_sg_list.end(); sg_iter++) {
VXLOGD("request stop to %s", (*sg_iter)->getSgName());
status = (*sg_iter)->flushWaitEvent();
if (status != VX_SUCCESS) {
VXLOGE("clearing subgraph done fails, err:%d", status);
}
}
EXYNOS_VISION_SYSTEM_OUT();
return status;
}
vx_status
ExynosVisionGraph::scheduleGraph(void)
{
vx_status status;
m_schedule_complete_event->clearEvent();
status = pushScheduleEvent();
if (status != VX_SUCCESS) {
VXLOGE("scheudling graph fails, err:%d", status);
}
return status;
}
vx_status
ExynosVisionGraph::waitGraph(void)
{
vx_status status = VX_SUCCESS;
event_exception_t exception_state;
VXLOGD2("Start waiting %s complete", getName());
exception_state = m_schedule_complete_event->waitEvent();
VXLOGD2("End waiting %s complete, exception:%d", getName(), exception_state);
if (exception_state != EVENT_EXCEPTION_NONE) {
status = VX_FAILURE;
}
return status;
}
vx_status
ExynosVisionGraph::queryGraph(vx_enum attribute, void *ptr, vx_size size)
{
vx_status status = VX_SUCCESS;
switch (attribute) {
case VX_GRAPH_ATTRIBUTE_PERFORMANCE:
if (VX_CHECK_PARAM(ptr, size, vx_perf_t, 0x3) && (getContext()->getPerfMonitor())) {
vx_perf_t *vx_perf = getContext()->getPerfMonitor()->getVxPerfInfo(this);
if (vx_perf)
memcpy(ptr, vx_perf, size);
else
memset(ptr, 0x0, size);
} else {
status = VX_ERROR_INVALID_PARAMETERS;
}
break;
case VX_GRAPH_ATTRIBUTE_STATUS:
if (VX_CHECK_PARAM(ptr, size, vx_status, 0x3))
*(vx_status *)ptr = m_error_status;
else
status = VX_ERROR_INVALID_PARAMETERS;
break;
case VX_GRAPH_ATTRIBUTE_NUMNODES:
if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3))
*(vx_uint32 *)ptr = m_node_list.size();
else
status = VX_ERROR_INVALID_PARAMETERS;
break;
case VX_GRAPH_ATTRIBUTE_NUMPARAMETERS:
if (VX_CHECK_PARAM(ptr, size, vx_uint32, 0x3)) {
*(vx_uint32 *)ptr = getNumParams();
status = VX_ERROR_INVALID_PARAMETERS;
} else {
status = VX_ERROR_INVALID_PARAMETERS;
}
break;
default:
status = VX_ERROR_NOT_SUPPORTED;
break;
}
return status;
}
vx_status
ExynosVisionGraph::setGraphAttribute(vx_enum attribute, const void *ptr, vx_size size)
{
vx_status status = VX_ERROR_NOT_SUPPORTED;
VXLOGE("there are no settable attributes, attribute:0x%x, ptr:%p, size:%d", attribute, ptr, size);
return status;
}
vx_uint32
ExynosVisionGraph::requestNewFrameCnt(ExynosVisionReference *ref)
{
return ++m_frame_cnt_map[ref];
}
vx_status
ExynosVisionGraph::pushErrorEvent(ExynosVisionSubgraph *subgraph, vx_status error)
{
VXLOGE("push error:%d from %s", error, subgraph->getSgName());
graph_error_message_t error_message;
error_message.subgraph = subgraph;
error_message.error = error;
m_error_queue->pushProcessQ(&error_message);
return VX_SUCCESS;
}
queue_exception_t
ExynosVisionGraph::popErrorEvent(graph_error_message_t *error_message)
{
vx_status status;
queue_exception_t exception;
if (!m_error_queue)
VXLOGE("m_error_queue is NULL");
exception = m_error_queue->waitAndPopProcessQ(error_message);
if (exception == QUEUE_EXCEPTION_TIME_OUT)
VXLOGE("queue fails, exception:%d", exception);
return exception;
}
vx_status
ExynosVisionGraph::pushScheduleEvent(void)
{
graph_schedule_message_t schedule_message;
m_schedule_queue->pushProcessQ(&schedule_message);
return VX_SUCCESS;
}
queue_exception_t
ExynosVisionGraph::popScheduleEvent(graph_schedule_message_t *schedule_message)
{
vx_status status;
queue_exception_t exception;
if (!m_schedule_queue)
VXLOGE("m_schedule_queue is NULL");
exception = m_schedule_queue->waitAndPopProcessQ(schedule_message);
if (exception == QUEUE_EXCEPTION_TIME_OUT)
VXLOGE("queue fails, exception:%d", exception);
return exception;
}
vx_status
ExynosVisionGraph::stopGraph()
{
stopProcessGraph();
return VX_SUCCESS;
}
bool
ExynosVisionGraph::errorThreadFunc(void)
{
vx_status status;
vx_uint32 frame_cnt;
queue_exception_t exception;
graph_error_message_t error_message;
VXLOGD2("[TD]err-thread, waiting to err event");
exception = popErrorEvent(&error_message);
VXLOGD2("[TD]err-thread, poping err event, exception:%d", exception);
if (exception == QUEUE_EXCEPTION_NONE) {
if (error_message.error != VX_SUCCESS) {
VXLOGE("pop error event, %s, error:%d", error_message.subgraph->getSgName(), error_message.error);
m_error_status |= error_message.error;
stopGraph();
} else {
VXLOGE("error report is corrupted");
}
}
if (exception == QUEUE_EXCEPTION_DISABLE)
return false;
else
return true;
}
bool
ExynosVisionGraph::scheduleThreadFunc(void)
{
vx_status status;
vx_uint32 frame_cnt;
queue_exception_t exception;
graph_schedule_message_t schedule_message;
VXLOGD2("[TD]shd-thread, waiting to schedule event");
exception = popScheduleEvent(&schedule_message);
VXLOGD2("[TD]shd-thread, poping schedule event, exception:%d", exception);
if (exception == QUEUE_EXCEPTION_NONE)
processGraph();
if (m_schedule_queue->getRemainedMsgNum() == 0)
m_schedule_complete_event->setEvent();
if (exception == QUEUE_EXCEPTION_DISABLE)
return false;
else
return true;
}
void
ExynosVisionGraph::displayInfo(vx_uint32 tab_num, vx_bool detail_info)
{
vx_char tap[MAX_TAB_NUM];
VXLOGI("%s========================================================", MAKE_TAB(tap, tab_num));
VXLOGI("%s[Graph ][%d] %s, node_num:%d, refCnt:%d/%d", MAKE_TAB(tap, tab_num), detail_info, getName(), m_node_list.size(),
getInternalCnt(), getExternalCnt());
if (m_parent_node)
VXLOGI("%s Parent node:%s(%s)", MAKE_TAB(tap, tab_num), m_parent_node->getName(), m_parent_node->getKernelName());
VXLOGI("%s[-------] all subgraph: %d", MAKE_TAB(tap, tab_num), m_sg_list.size());
if (m_sg_list.size() != 0) {
List<ExynosVisionSubgraph*>::iterator sg_iter;
for (sg_iter=m_sg_list.begin(); sg_iter!=m_sg_list.end(); sg_iter++)
(*sg_iter)->displayInfo(tab_num+1, vx_true_e);
} else {
List<ExynosVisionNode*>::iterator node_iter;
for (node_iter=m_node_list.begin(); node_iter!=m_node_list.end(); node_iter++)
(*node_iter)->displayInfo(tab_num+1, vx_true_e);
}
VXLOGI("%s========================================================", MAKE_TAB(tap, tab_num));
}
void
ExynosVisionGraph::displayPerf(vx_uint32 tab_num, vx_bool detail_info)
{
vx_char tap[MAX_TAB_NUM];
VXLOGI("%s========================================================", MAKE_TAB(tap, tab_num));
VXLOGI("%s[Graph ] %s", MAKE_TAB(tap, tab_num), getName());
vx_perf_t *vx_perf = getContext()->getPerfMonitor()->getVxPerfInfo(this);
if (getContext()->getPerfMonitor() == NULL) {
VXLOGE("unregistered graph, %s", getName());
return;
}
VXLOGI("%s\tverify: %0.3lf ms", MAKE_TAB(tap, tab_num), (vx_float32)m_verify_time/1000.0f);
VXLOGI("%s\tprocess [%llu]: %0.3lf ms", MAKE_TAB(tap, tab_num), vx_perf[TIMEPAIR_PROCESS].num, (vx_float32)vx_perf[TIMEPAIR_PROCESS].avg/1000.0f);
if (detail_info == vx_true_e) {
List<ExynosVisionSubgraph*>::iterator sg_iter;
for (sg_iter=m_sg_list.begin(); sg_iter!=m_sg_list.end(); sg_iter++)
(*sg_iter)->displayPerf(tab_num+1, vx_true_e);
}
VXLOGI("%s========================================================", MAKE_TAB(tap, tab_num));
}
}; /* namespace android */