Minor Clean ups for graph
[keystone-rtos/fvid2.git] / src / fvid2_graph.c
1 /*
2  *  Copyright (c) Texas Instruments Incorporated 2018
3  *
4  *  Redistribution and use in source and binary forms, with or without
5  *  modification, are permitted provided that the following conditions
6  *  are met:
7  *
8  *    Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *
11  *    Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the
14  *    distribution.
15  *
16  *    Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
33 /**
34  *  \file fvid2_graph.c
35  *
36  *  \brief File containing the graph functions for resource management.
37  *
38  */
40 /* ========================================================================== */
41 /*                             Include Files                                  */
42 /* ========================================================================== */
44 #include <stdint.h>
45 #include <ti/drv/fvid2/fvid2.h>
47 /* ========================================================================== */
48 /*                           Macros & Typedefs                                */
49 /* ========================================================================== */
51 /* None */
53 /* ========================================================================== */
54 /*                         Structure Declarations                             */
55 /* ========================================================================== */
57 /**
58  *  \brief Structure describing graph stack.
59  */
60 typedef struct
61 {
62     Fvid2_GraphNodeInfo *node[FVID2_GRAPH_MAX_NODES];
63     /**< Array of node pointers */
64     int32_t stNum[FVID2_GRAPH_MAX_NODES];
65     /**< Keeps track of which child of this node is next to be visited, on
66      *   the stack for a node. */
67     uint8_t isVisited[FVID2_GRAPH_MAX_NODES];
68     /**< Flag keeps track of whether given node is visited or not */
69     int32_t top;
70     /**< Top marker of the stack */
71 } Fvid2_GraphStack;
73 /* ========================================================================== */
74 /*                         Internal Function Declarations                     */
75 /* ========================================================================== */
77 static int32_t Fvid2_graphConnect(const Fvid2_GraphNodeList *inNodeList,
78                                   const Fvid2_GraphEdgeList *inEdgeList);
80 static void Fvid2_graphStackReset(void);
82 static void Fvid2_graphStackPush(Fvid2_GraphNodeInfo *node);
84 static void Fvid2_graphStackPop(void);
86 static uint32_t Fvid2_graphStackIsVisited(const Fvid2_GraphNodeInfo *node);
88 int32_t Fvid2_graphStackIsLastNode(const Fvid2_GraphNodeInfo *currNode,
89                                    uint32_t isForward);
91 /* ========================================================================== */
92 /*                            Global Variables                                */
93 /* ========================================================================== */
95 static Fvid2_GraphStack gFvid2GraphNodeStack;
97 /* ========================================================================== */
98 /*                          Function Definitions                              */
99 /* ========================================================================== */
101 /* Helper function */
102 static int32_t Fvid2_graphConnect(const Fvid2_GraphNodeList *inNodeList,
103                                   const Fvid2_GraphEdgeList *inEdgeList)
105     Fvid2_GraphNodeInfo *nodes = inNodeList->list;
106     Fvid2_GraphEdgeInfo *edges = inEdgeList->list;
107     uint32_t cnt, startNode, endNode, index1, index2;
108     for (cnt = 0; cnt < inNodeList->numNodes; cnt++)
109     {
110         Fvid2Utils_memset(&nodes[cnt].inputNodeSet, 0, sizeof (Fvid2_GraphNodeSet));
111         Fvid2Utils_memset(&nodes[cnt].outputNodeSet, 0, sizeof (Fvid2_GraphNodeSet));
112     }
114     for (cnt = 0U; cnt < inEdgeList->numEdges; cnt++)
115     {
116         startNode = edges[cnt].startNode;
117         endNode   = edges[cnt].endNode;
118         /* End Node is output node for the start Node so update
119          * information in start node*/
120         index1 = nodes[startNode].outputNodeSet.numNodes;
121         nodes[startNode].outputNodeSet.node[index1] = &nodes[endNode];
122         nodes[startNode].outputNodeSet.numNodes++;
123         GT_assert(Fvid2Trace, (index1 < FVID2_GRAPH_MAX_NUM_PATHS));
125         /* Start Node is input node for the end Node so update
126          * information in end node*/
127         index2 = nodes[endNode].inputNodeSet.numNodes;
128         nodes[endNode].inputNodeSet.node[index2] = &nodes[startNode];
129         nodes[endNode].inputNodeSet.numNodes++;
130         GT_assert(Fvid2Trace, (index2 < FVID2_GRAPH_MAX_NUM_PATHS));
132         /* Dummy node's input is always enabled */
133         if ((TRUE == nodes[endNode].isDummy) &&
134             (TRUE == nodes[startNode].isDummy))
135         {
136             nodes[startNode].outputNodeSet.isEnabled[index1] = TRUE;
137             nodes[endNode].inputNodeSet.isEnabled[index2]    = TRUE;
138         }
139     }
141     return FVID2_SOK;
144 /** \brief Creates static DSS topology for the fixed edges/nodes. There
145  *  are some dummy nodes in the DSS topology. Input and output of these
146  *  nodes are always enabled and cannot be changed. This function creates
147  *  this static table.
148  *  Called at the init time only
149  */
150 Fvid2_GraphInfo *Fvid2_graphInit(const Fvid2_GraphNodeList *inNodeList,
151                                  const Fvid2_GraphEdgeList *inEdgeList,
152                                  Fvid2_GraphInfo *graphHandle)
154     GT_assert(Fvid2Trace, (graphHandle != NULL));
155     GT_assert(Fvid2Trace, (graphHandle->nodeList != NULL));
156     GT_assert(Fvid2Trace, (graphHandle->edgeList != NULL));
158     GT_assert(Fvid2Trace, (inNodeList != NULL));
159     GT_assert(Fvid2Trace, (inEdgeList != NULL));
161     graphHandle->nodeList->numNodes = inNodeList->numNodes;
162     graphHandle->edgeList->numEdges = inEdgeList->numEdges;
163     graphHandle->nodeList->list = inNodeList->list;
164     graphHandle->edgeList->list = inEdgeList->list;
166     Fvid2_graphConnect(inNodeList, inEdgeList);
167     return graphHandle;
170 int32_t Fvid2_graphDeInit(Fvid2_GraphInfo *graphHandle)
172     return FVID2_SOK;
175 /** \brief Function to get the pointer to node for the given index
176  */
177 Fvid2_GraphNodeInfo *Fvid2_graphGetNodeInfo(
178                             const Fvid2_GraphNodeList *nodeList,
179                             uint32_t cnt)
181     Fvid2_GraphNodeInfo *node = NULL;
182     if (cnt < nodeList->numNodes)
183     {
184         node = &nodeList->list[cnt];
185     }
186     return (node);
189 /** \brief This function allocates nodes within the CORE by enabling
190  *  specified edges.
191  *
192  *  To enable an edge, it enables output of source node and
193  *  enables input of the target node.
194  *
195  *  Returns error if a node is already active.
196  *
197  *  TODO: First edge is assumed as input, Why/How to disable edges?,
198  *  Multiple handle support.
199  *  TODO: If FAIL, run through again and disable if anything was enabled.
200  */
202 uint32_t Fvid2_graphIsNodeInputAvailable(
203                             const Fvid2_GraphNodeList *nodeList,
204                             uint32_t nodeId)
206     uint32_t j;
207     uint32_t retVal  = TRUE;
208     Fvid2_GraphNodeInfo *curNode = Fvid2_graphGetNodeInfo(nodeList, nodeId);
209     if (NULL == curNode)
210     {
211         retVal = FALSE;
212     }
213     else
214     {
215         for (j = 0; j < curNode->inputNodeSet.numNodes; j++)
216         {
217             if (FVID2_GRAPH_NODE_MODE_ENABLE == curNode->inputNodeSet.isEnabled[j])
218             {
219                 retVal = FALSE;
220                 break;
221             }
222         }
223     }
224     return retVal;
227 uint32_t Fvid2_graphIsNodeOutputAvailable(
228                             const Fvid2_GraphNodeList *nodeList,
229                             uint32_t nodeId)
231     uint32_t j;
232     uint32_t retVal  = TRUE;
233     Fvid2_GraphNodeInfo *curNode = Fvid2_graphGetNodeInfo(nodeList, nodeId);
234     if (NULL == curNode)
235     {
236         retVal = FALSE;
237     }
238     else
239     {
240         for (j = 0; j < curNode->outputNodeSet.numNodes; j++)
241         {
242             if (FVID2_GRAPH_NODE_MODE_ENABLE == curNode->outputNodeSet.isEnabled[j])
243             {
244                 retVal = FALSE;
245                 break;
246             }
247         }
248     }
249     return retVal;
252 int32_t Fvid2_graphAllocNodes(const Fvid2_GraphNodeList *nodeList,
253                               const Fvid2_GraphEdgeList *edgeList,
254                               uint32_t mode)
256     uint32_t i, j;
257     int32_t retVal = FVID2_SOK;
258     Fvid2_GraphEdgeInfo *inputEdgeList = edgeList->list;
259     for (i = 0; i < edgeList->numEdges; i++)
260     {
261         Fvid2_GraphNodeInfo *startNode = Fvid2_graphGetNodeInfo(
262             nodeList, inputEdgeList[i].startNode);
263         GT_assert(Fvid2Trace, (startNode != NULL));
264         Fvid2_GraphNodeInfo *endNode = Fvid2_graphGetNodeInfo(
265             nodeList, inputEdgeList[i].endNode);
266         GT_assert(Fvid2Trace, (endNode != NULL));
267         if ((startNode->nodeId == FVID2_GRAPH_INVALID_NODE_ID) &&
268             (endNode->nodeId == FVID2_GRAPH_INVALID_NODE_ID))
269         {
270             break;
271         }
273         /* TODO: Multiple connections from different path probably does not work
274         **/
275         /*      here. Will it be ever required? */
276         /* Example: One handle connects one source for blender, Second handle */
277         /*         connects second source for blender - Is such a case required?
278         **/
279         if (FVID2_GRAPH_NODE_OUT_SINGLE == startNode->nodeOutNum)
280         {
281             uint32_t inUse = FALSE;
282             for (j = 0; j < startNode->outputNodeSet.numNodes; j++)
283             {
284                 if (FVID2_GRAPH_NODE_MODE_ENABLE == startNode->outputNodeSet.isEnabled[j])
285                 {
286                     inUse = TRUE;
287                     break;
288                 }
289             }
290             if ((FALSE == inUse) || (FVID2_GRAPH_NODE_MODE_DISABLE == mode))
291             {
292                 for (j = 0; j < startNode->outputNodeSet.numNodes; j++)
293                 {
294                     if (startNode->outputNodeSet.node[j] == endNode)
295                     {
296                         startNode->outputNodeSet.isEnabled[j] = mode;
297                         break;
298                     }
299                 }
300                 if (j == startNode->outputNodeSet.numNodes)
301                 {
302                     retVal = FVID2_EFAIL;
303                 }
304             }
305         }
306         else if (FVID2_GRAPH_NODE_OUT_MULTI == startNode->nodeOutNum)
307         {
308             for (j = 0; j < startNode->outputNodeSet.numNodes; j++)
309             {
310                 if (startNode->outputNodeSet.node[j] == endNode)
311                 {
312                     startNode->outputNodeSet.isEnabled[j] = mode;
313                     break;
314                 }
315             }
316             if (j == startNode->outputNodeSet.numNodes)
317             {
318                 retVal = FVID2_EFAIL;
319             }
320         }
321         else
322         {
323             /*Do nothing */
324         }
326         if (FVID2_GRAPH_NODE_IN_SINGLE == endNode->nodeInNum)
327         {
328             uint32_t inUse = FALSE;
329             for (j = 0; j < endNode->inputNodeSet.numNodes; j++)
330             {
331                 if (FVID2_GRAPH_NODE_MODE_ENABLE == endNode->inputNodeSet.isEnabled[j])
332                 {
333                     inUse = TRUE;
334                     break;
335                 }
336             }
337             if ((FALSE == inUse) || (FVID2_GRAPH_NODE_MODE_DISABLE == mode))
338             {
339                 for (j = 0; j < endNode->inputNodeSet.numNodes; j++)
340                 {
341                     if (endNode->inputNodeSet.node[j] == startNode)
342                     {
343                         endNode->inputNodeSet.isEnabled[j] = mode;
344                         break;
345                     }
346                 }
347                 if (j == endNode->inputNodeSet.numNodes)
348                 {
349                     retVal = FVID2_EFAIL;
350                 }
351             }
352         }
353         else if (FVID2_GRAPH_NODE_IN_MULTI == endNode->nodeInNum)
354         {
355             for (j = 0; j < endNode->inputNodeSet.numNodes; j++)
356             {
357                 if (endNode->inputNodeSet.node[j] == startNode)
358                 {
359                     endNode->inputNodeSet.isEnabled[j] = mode;
360                     break;
361                 }
362             }
363             if (j == endNode->inputNodeSet.numNodes)
364             {
365                 retVal = FVID2_EFAIL;
366             }
367         }
368         else
369         {
370             /*Do nothing */
371         }
372     }
374     return retVal;
377 /**
378  * findPath()
379  */
380 /**
381  * Inputs
382  * PORTA/B_08/16/24
383  * isCSCEnabled
384  * isSCEnabled
385  */
386 /**
387  * Algo:
388  * Decide FirstNode
389  * Decide LastNodes
390  * curNode = FirstNode
391  * if(isCSCEnabled) {join curNode to CSC; curNode = CSC}
392  * if(isSCEnabled)  {join curNode to SC; curNode = SC}
393  * foreach(LastNode_option1, LastNode_option2)
394  * {
395  * join curNode to LastNode
396  * if (successful) break
397  * else next
398  * }
399  */
401 /** \brief This function gets a list of valid nodes in an edge list and
402  *  also enable the input in each entry. Fill in VpsCore_VipPathObj
403  *
404  *  Should be called only after Fvid2_graphAllocNodes() is successful
405  *
406  *  TODO: Connections should be made in this function and not copied from
407  *  main graph (as is done currently) since this will fail for multiple handle
408  *  scenarios.
409  */
410 int32_t Fvid2_graphGetPath(const Fvid2_GraphNodeList *inNodeList,
411                            const Fvid2_GraphEdgeList *inEdgeList,
412                            Fvid2_GraphNodeList *outNodeList,
413                            Fvid2_GraphEdgeList *outEdgeList,
414                            uint32_t maxOutNodeCnt,
415                            uint32_t maxOutEdgeCnt)
417     uint32_t i, j;
418     uint32_t pathEdgeCount = inEdgeList->numEdges;
419     uint32_t pathNodeCount = 0;
420     uint32_t numInNodes = inNodeList->numNodes;
421     uint32_t nodes[FVID2_GRAPH_MAX_NODES] = {0};
423     for (i = 0; i < inEdgeList->numEdges; i++)
424     {
425         j = inEdgeList->list[i].startNode;
426         nodes[j] = 1U;
427         j = inEdgeList->list[i].endNode;
428         nodes[j] = 1U;
429     }
431     for (i = 0; i < numInNodes; i++)
432     {
433         if (nodes[i] == 1U)
434         {
435             pathNodeCount++;
436         }
437     }
439     GT_assert(Fvid2Trace, (pathNodeCount < maxOutNodeCnt));
440     outNodeList->numNodes = pathNodeCount;
442     GT_assert(Fvid2Trace, (outNodeList->list != NULL));
444     GT_assert(Fvid2Trace, (pathEdgeCount < maxOutEdgeCnt));
445     outEdgeList->numEdges = pathEdgeCount;
446     GT_assert(Fvid2Trace, (outEdgeList->list != NULL));
448     for (i = 0; i < pathEdgeCount; i++)
449     {
450         outEdgeList->list[i].startNode =
451             inEdgeList->list[i].startNode;
452         outEdgeList->list[i].endNode =
453             inEdgeList->list[i].endNode;
454     }
456     j = 0;
457     for (i = 0; i < numInNodes; i++)
458     {
459         if (nodes[i] == 1U)
460         {
461             Fvid2Utils_memcpy((void *) &outNodeList->list[j],
462                             (void *) &inNodeList->list[i],
463                             sizeof (Fvid2_GraphNodeInfo));
465             /* Reset connection info from the original graph */
466             Fvid2Utils_memset((void *) (outNodeList->list[j].inputNodeSet.node), 0,
467                               sizeof (Fvid2_GraphNodeInfo *) * FVID2_GRAPH_MAX_NUM_PATHS);
468             Fvid2Utils_memset((void *) (outNodeList->list[j].outputNodeSet.node), 0,
469                               sizeof (Fvid2_GraphNodeInfo *) * FVID2_GRAPH_MAX_NUM_PATHS);
470             j++;
471         }
472     }
474     return FVID2_SOK;
477 int32_t Fvid2_graphFreePath(Fvid2_GraphNodeList *nodeList,
478                       Fvid2_GraphEdgeList *edgeList)
480     if (NULL != nodeList->list)
481     {
482         nodeList->numNodes = 0;
483         nodeList->list = NULL;
484     }
485     if (NULL != edgeList->list)
486     {
487         edgeList->numEdges = 0;
488         edgeList->list = NULL;
489     }
490     return FVID2_SOK;
493 void Fvid2_graphInitTraverser(Fvid2_GraphNodeInfo *node)
495     /* Initialize Stack */
496     Fvid2_graphStackReset();
498     /* Push root node onto stack */
499     Fvid2_graphStackPush(node);
502 static void Fvid2_graphStackReset(void)
504     Fvid2Utils_memset(&gFvid2GraphNodeStack, 0, sizeof (gFvid2GraphNodeStack));
505     gFvid2GraphNodeStack.top = (-(int32_t)1);
507     /* Initialize All stack numbers with -1 */
508     Fvid2Utils_memset(gFvid2GraphNodeStack.stNum, 0, sizeof (uint32_t) * FVID2_GRAPH_MAX_NODES);
509     Fvid2Utils_memset(gFvid2GraphNodeStack.isVisited, 0, sizeof (FVID2_GRAPH_MAX_NODES));
512 /* Push a node on the stack */
513 static void Fvid2_graphStackPush(Fvid2_GraphNodeInfo *node)
515     gFvid2GraphNodeStack.top++;
516     gFvid2GraphNodeStack.node[gFvid2GraphNodeStack.top] = node;
519 /* Remove top node from the stack */
520 static void Fvid2_graphStackPop(void)
522     /* Remove the node from the stack */
523     gFvid2GraphNodeStack.stNum[gFvid2GraphNodeStack.top] = 0;
524     gFvid2GraphNodeStack.node[gFvid2GraphNodeStack.top]  = NULL;
525     gFvid2GraphNodeStack.top--;
528 static uint32_t Fvid2_graphStackIsVisited(const Fvid2_GraphNodeInfo *node)
530     uint32_t visited = TRUE;
532     if (0 == gFvid2GraphNodeStack.isVisited[node->nodeId])
533     {
534         visited = FALSE;
535     }
537     return (visited);
540 int32_t Fvid2_graphStackIsLastNode(const Fvid2_GraphNodeInfo *currNode,
541                                    uint32_t isForward)
543     int32_t ret = (int32_t) TRUE;
545     if (((TRUE == isForward) && (0 != currNode->outputNodeSet.numNodes)) ||
546         ((FALSE == isForward) && (0 != currNode->inputNodeSet.numNodes)))
547     {
548         ret = (int32_t) FALSE;
549     }
551     return (ret);
554 /* Function to get the next enabled node for the currNode */
555 Fvid2_GraphNodeInfo *Fvid2_graphGetNextChildNode(
556                             const Fvid2_GraphNodeInfo *currNode,
557                             uint32_t isForward)
559     Fvid2_GraphNodeInfo *node = NULL;
560     uint32_t isEnabled = TRUE;
561     uint32_t nodeId, nextNodeNum;
562     uint32_t loopEnd = 1U;
564     nodeId = gFvid2GraphNodeStack.top;
565     nextNodeNum = (uint32_t) gFvid2GraphNodeStack.stNum[nodeId];
566     do
567     {
568         /* Traversing from input Node to Venc Nodes */
569         if (TRUE == isForward)
570         {
571             /* Get the next node from the output nodes */
572             if (nextNodeNum < currNode->outputNodeSet.numNodes)
573             {
574                 node = currNode->outputNodeSet.node[nextNodeNum];
575                 isEnabled = currNode->outputNodeSet.isEnabled[nextNodeNum];
576             }
577             else
578             {
579                 loopEnd = 0;
580             }
581         }
582         else  /* Traversing from Venc Nodes to input node */
583         {
584             /* Get the next node from the input nodes */
585             if (nextNodeNum < currNode->inputNodeSet.numNodes)
586             {
587                 node = currNode->inputNodeSet.node[(nextNodeNum)];
588                 isEnabled = currNode->inputNodeSet.isEnabled[nextNodeNum];
589             }
590             else
591             {
592                 loopEnd = 0;
593             }
594         }
595         if (0U == loopEnd)
596         {
597             break;
598         }
599         nextNodeNum += 1U;
600     } while (FALSE == isEnabled);
602     if (FALSE == isEnabled)
603     {
604         node = NULL;
605     }
606     else
607     {
608         gFvid2GraphNodeStack.stNum[nodeId] = (int32_t) nextNodeNum;
609     }
610     return (node);
613 /* Get the top node on the stack */
614 Fvid2_GraphNodeInfo *Fvid2_graphStackPeak(uint32_t *stNum)
616     *stNum = (uint32_t) gFvid2GraphNodeStack.stNum[gFvid2GraphNodeStack.top];
617     return (gFvid2GraphNodeStack.node[gFvid2GraphNodeStack.top]);
620 Fvid2_GraphNodeInfo *Fvid2_graphGetNextNodeToTraverse(uint32_t isForward)
622     uint32_t nodeId;
623     Fvid2_GraphNodeInfo *currNode = NULL, *nextNode = NULL;
625     while (gFvid2GraphNodeStack.top > (-(int32_t)1))
626     {
627         /* Get the stack top node */
628         currNode = Fvid2_graphStackPeak(&nodeId);
630         if (FALSE == Fvid2_graphStackIsVisited(currNode))
631         {
632             /* If current node is ot visited, return it to the caller. */
633             break;
634         }
635         else
636         {
637             /* Get the Next Node */
638             nextNode = Fvid2_graphGetNextChildNode(currNode, isForward);
640             /* If next node is not null, push it onto stack so that it can
641              * be traversed */
642             if (NULL != nextNode)
643             {
644                 /* Push the start node onto stack */
645                 Fvid2_graphStackPush(nextNode);
646             }
647             else
648             {
649                 /* Remove the node from the stack */
650                 Fvid2_graphStackPop();
651             }
652         }
653     }
654     if ((-(int32_t)1) == gFvid2GraphNodeStack.top)
655     {
656         currNode = NULL;
657     }
659     if (NULL != currNode)
660     {
661         nodeId = currNode->nodeId;
662         gFvid2GraphNodeStack.isVisited[nodeId] = (uint8_t) 1;
663     }
665     return (currNode);
668 int32_t Fvid2_graphGetEnabledIndex(const uint32_t *array, uint32_t size)
670     uint32_t i;
671     int32_t  retVal = FVID2_EFAIL;
673     for (i = 0; i < size; i++)
674     {
675         if ((uint32_t) 0 != array[i])
676         {
677             retVal = (int32_t) i;
678             break;
679         }
680     }
681     return retVal;
684 void Fvid2_graphAddEdge(Fvid2_GraphEdgeInfo *edge,
685                         uint32_t startNode,
686                         uint32_t endNode)
688     if (startNode != endNode)
689     {
690         edge->startNode = startNode;
691         edge->endNode = endNode;
692     }