Esempio n. 1
0
/* fut_add_chan inserts a new output channel into a fut.
 * Unlike itbls, otbls, and gtbls, the channel structure is not sharable
 * and so the caller must not free the chan after this call.	(If the
 * passed channel structure needs to be saved, use fut_copy_chan).
 * The iomask in this case simply tells which output channel is being
 * added, and if this channel already exists, an error (0) is returned.
 *
 * fut_add_chan is intended to be used in conjunction with fut_new_chan
 * to construct futs with independent input tables.	It does not update
 * the list of common input tables as does fut_new and fut_defchan and
 * should not be mixed with calls to fut_defchan.
 */
KpInt32_t
	fut_add_chan (fut_p	fut, KpInt32_t iomask, fut_chan_p chan)
{
	KpInt32_t		ochan;

	if ( ! IS_FUT(fut) || (chan != FUT_NULL_CHAN && ! IS_CHAN(chan)) ) {
		return (0);
	}

					/* get output channel no. */
	ochan = FUT_CHAN ((KpInt32_t)FUT_OMASK(iomask));

					/* prohibit redefinition of channel */
	if ( ochan >= FUT_NOCHAN || fut->chan[ochan] != NULL)
		return (0);
					/* insert channel into fut */
	fut->chan[ochan] = chan;
	fut->chanHandle[ochan] = (IS_CHAN(fut->chan[ochan])) ?
								fut->chan[ochan]->handle : FUT_NULL_HANDLE;

					/* update iomasks */
	if ( IS_CHAN(chan) ) {
		fut->iomask.out |= FUT_BIT(ochan);
		fut->iomask.in |= chan->imask;
	}

	return (1);
}
Esempio n. 2
0
/* fut_new allocates and initializes a new fut_t data structure.
 * iomask specifies which (common) input tables and which output channels
 * are being defined.	Additional channels may be added later using
 * fut_defchan.
 *
 * NOTES:
 *	1. All the tables must be packed into a single array.
 *
 *	2. If a needed input table is not supplied (as determined from the
 *	grid table) or if a supplied input table is NULL, then a ramp
 *	input table will be automatically generated and inserted into
 *	the common itbl list.	The grid sizes are inferred from the
 *	supplied grid tables.
 */
fut_p
	fut_new (	KpInt32_t		iomask,
				fut_itbl_p FAR*	itbls,
				fut_gtbl_p FAR*	gtbls,
				fut_otbl_p FAR*	otbls)
{
fut_itbl_p	itbl[FUT_NICHAN];
fut_otbl_p	otbl[FUT_NOCHAN];
fut_gtbl_p	gtbl[FUT_NOCHAN];
fut_p		fut;
KpInt32_t	tIndex, imask, omask, i;

					/* get input and output masks */
	imask = (KpInt32_t)FUT_IMASK(iomask);
	omask = (KpInt32_t)FUT_OMASK(iomask);
	if ( imask > FUT_ALLIN || omask > FUT_ALLOUT ) {
		DIAG("fut_new: too many input or output channels.\n", 0);
		return (NULL);
	}

	/* get args specified by iomask */
	for ( i=0, tIndex = 0; i<FUT_NICHAN; i++ ) {
		itbl[i] = (((imask & FUT_BIT(i)) != 0) && (itbls != NULL))
					? itbls[tIndex++] : FUT_NULL_ITBL;
	}
	for ( i=0, tIndex = 0; i<FUT_NOCHAN; i++ ) {
		gtbl[i] = FUT_NULL_GTBL;
		otbl[i] = FUT_NULL_OTBL;

		if ((omask & FUT_BIT(i)) != 0) {
			if (gtbls != NULL) {
				gtbl[i] = gtbls[tIndex];
			}

			if (otbls != NULL) {
				otbl[i] = otbls[tIndex];
			}

			tIndex++;
		}
	}

				/* allocate and clear the fut_t structure */
	fut = fut_alloc_fut ();
	if ( fut == NULL ) {
		return (NULL);
	}

				/* set the interpolation order */
	fut->iomask.order = (KpInt32_t)FUT_ORDMASK(iomask);

				/* insert the specified input tables */
	for ( i=0; i<FUT_NICHAN; i++ ) {
		if ( itbl[i] == NULL) continue;
		if ( ! IS_ITBL (itbl[i]) ) {
			fut_free (fut);
			return (NULL);
		}
		fut->iomask.in |= FUT_BIT(i);
		fut->itbl[i] = fut_share_itbl(itbl[i]);
		fut->itblHandle[i] = fut->itbl[i]->handle;
	}

				/* define the specified output channels */
	for ( i=0; i<FUT_NOCHAN; i++ ) {
		if ( gtbl[i] == NULL) continue;
		if ( ! fut_defchan(fut,FUT_OUT(FUT_BIT(i)),NULL,gtbl[i],otbl[i]) ) {
			fut_free (fut);
			return (NULL);
		}
	}
	fut->lutConfig = LUT_TYPE_UNKNOWN;
	return (fut);
}
Esempio n. 3
0
fut_p
	fut_comp (fut_p fut1, fut_p fut0, KpInt32_t iomask)
{
KpInt32_t		ok = 1, nGridPoints, omask, evalomask, imask, pmask, order, i, j, nEntries, nOutChans;
fut_p			fut2 = NULL, evalFut = NULL;
fut_itbl_p		oitbls[FUT_NICHAN];
mf2_tbldat_p	indat[FUT_NICHAN], outdat[FUT_NOCHAN];
fut_gtbl_p		fut1_gtbls[FUT_NOCHAN];

	if (( ! IS_FUT(fut0)) || ( ! IS_FUT(fut1))) {
		return (NULL);
	}

	/* extract component masks from iomask */
	omask = FUT_OMASK(iomask);		/* which output chans? */
	pmask = FUT_PMASK(iomask);		/* which ones allowed to pass through? */
	order = FUT_ORDMASK(iomask);	/* which interpolation to use? */
	if ( order == FUT_DEFAULT ) {
		order = fut1->iomask.order;
	}

	/* adjust masks for iomask_check below */
	pmask &= fut0->iomask.out;		/* available for "pass through" */
	if ( omask == 0 ) {				/* required outputs (0 means all) */
		omask = fut1->iomask.out;
	}

	/* see if fut0 can provide required inputs to fut1 */
	imask = fut0->iomask.out;		/* available inputs for fut1 */
	iomask = FUT_OUT(omask) | FUT_IN(imask) | FUT_PASS(pmask);
	if ( ! fut_iomask_check (fut1, iomask) ) {
		return (NULL);
	}

	/* make sure the futs are in the reference state */
	if ((fut_to_mft (fut0) != 1) || (fut_to_mft (fut1) != 1)) {
		return (NULL);
	}	

	/* fut1 will be used to process the grid tables of fut0, placing the
	 * results in the grid tables of fut2.  Fut0's grid table data must first
	 * be passed through its output tables before sending it through fut1's
	 * input tables.  This is accomplished more efficiently by composing
	 * fut1's input tables with fut0's output tables and using these directly
	 * on fut0 grid data rather than the normal input tables.
	 *
	 * Create the result fut (fut2) which will be the composition of fut1
	 * and fut0.  Fut2 will inherit the input tables of fut0 and the output
	 * tables of fut1.  Its grid data will be in the same color coordinates
	 * as fut1's.
	 */
	fut2 = fut_new (FUT_IN(FUT_ALLIN), fut0->itbl, NULL, NULL);
	if ( fut2 == NULL ) {
		return (NULL);
	}

	/* for each desired channel i in fut2, create a new grid table.  The
	 * dimensions of each new grid table are derived from fut0 and fut1
	 * like so:  for every input required for channel i of fut1, form the
	 * union of the input sets of all corresponding fut0 outputs.
	 */

	/* null all io tables and table pointers */
	KpMemSet (oitbls, 0, sizeof(oitbls));

	imask = 0;			/* will be the input mask for all inputs needed to fut1 */
	evalomask = 0;		/* omask for evaluation */

	for (i = 0; (i < FUT_NOCHAN) && ok; i++) {
		KpInt32_t	size[FUT_NICHAN];
		fut_gtbl_p	gtbl;
		KpInt32_t	imask1, imask2;

		fut1_gtbls[i] = NULL;	/* assume not needed */

		if ((omask & FUT_BIT(i)) == 0) {	/* is this output channel needed? */
			continue;						/* no */
		}

		/* if a specified output is to be passed through from fut0, do that here */
		if ( ! IS_CHAN(fut1->chan[i]) && IS_CHAN(fut0->chan[i])) {

			ok = fut_defchan (fut2, FUT_OUT(FUT_BIT(i)), NULL,
							fut0->chan[i]->gtbl, fut0->chan[i]->otbl);

			continue;			/* no need to evaluate this ochan */
		}

		if (! IS_CHAN(fut1->chan[i])) {
			ok = 0;						/* something wrong */
			goto GetOut;
		}

		/* At this point we know that (fut1->chan[i] != 0).  We also
		 * have determined (from iomask_check above) that fut0->chan[j] != 0.
		 */
		imask2 = 0;						/* determine inputs from fut0 needed for this channel */
		imask1 = fut1->chan[i]->imask;	/* inputs used by this chan */

		for (j = 0; (j < FUT_NICHAN) && ok; j++) {
			if ((imask1 & FUT_BIT(j)) != 0) {		/* this input chan is needed */
				if ( ! IS_CHAN(fut0->chan[j])) {	/* available? */
					ok = 0;							/* composition fails */
					goto GetOut;
				}

				if (fut1->itbl[j] != fut1->chan[i]->itbl[j]) {	/* shared itbl? */
					goto nextOChan;								/* nope, ignore this ochan */
				}

				imask2 |= fut0->chan[j]->imask;
			}				
		}

		evalomask |= FUT_BIT(i);	/* will be evalutating this channel */
		imask |= imask1;			/* build mask of all needed inputs */
			
		/* determine required dimensions from mask */
		for (j = 0; j < FUT_NICHAN; j++) {
			size[j] = (imask2 & (KpInt32_t)FUT_BIT(j)) ? fut0->itbl[j]->size : 1;
		}

		/* create the new grid table
		 * insert it along with fut1's output table into fut2
		 */
		gtbl = fut_new_gtblEx (FUT_IN(FUT_ALLIN), NULL, NULL, size);
		ok = fut_defchan (fut2, FUT_OUT(FUT_BIT(i)), NULL, gtbl, fut1->chan[i]->otbl);
		fut_free_gtbl (gtbl);
		if (!ok) {
			goto GetOut;
		}

		fut1_gtbls[i] = fut1->chan[i]->gtbl;	/* collect gtbls for evaluation fut */

		/* verify the input data for the evaluation of the output channel in fut1 */
		for (j = 0; j < FUT_NICHAN; j++) {
			if ((imask1 & FUT_BIT(j)) != 0) {									/* this channel needed as input */
				if ((fut0->chan[j]->imask & (~fut2->chan[i]->imask)) != 0) {	/* it's inputs must be used by output */
					ok = 0;				/* composition fails */
					goto GetOut;
				}
			}
		}
nextOChan:;
	}

	/* collect the gtbls which are the input data for the chan evaluation.
	 * also pre-compose fut0's otbls with fut1's itbls.
	 */
	for (i = 0; i < FUT_NICHAN; i++) {
		oitbls[i] = NULL;

		if (ok) {
			fut_chan_p theChan = fut0->chan[i];
			
			if ((imask & FUT_BIT(i)) == 0) {
				continue;				/* this output from fut0 not required */
			}

			indat[i] = theChan->gtbl->refTbl;	/* collect gtbls: the input data for the evaluation */

			ok = (indat[i] != NULL);
			
			/* allocate memory for composed i/o tables
			 * these have the same size as the output tables of the channel supplying the input */
			if (ok) {
				fut_itbl_p	theITbl = fut1->itbl[i];
				fut_otbl_p	theOTbl = theChan->otbl;

				oitbls[i] = fut_alloc_itbl ();		/* get an itbl */

				oitbls[i]->size = theITbl->size;
				oitbls[i]->dataClass = KCP_FIXED_RANGE;

				nEntries = MAX(theITbl->refTblEntries, theOTbl->refTblEntries);

				ok = (fut_alloc_imftdat (oitbls[i], nEntries) != NULL);

				if (ok) {	/* make input table for evaluation */
					ok = fut_comp_iotblMF (theITbl, theOTbl, oitbls[i]);
				}
			}
		}
	}

	/* make an evaluation fut with the composed I/O tables, fut1's gtbls, and no otbls */
	evalFut = fut_new (iomask, oitbls, fut1_gtbls, NULL);
	if (( ! ok) ||
		(evalFut == NULL) ||		/* if evaluation fut ok */
		(fut_to_mft (fut2) != 1)) {	/* make sure the futs are in the reference state */
		ok = 0;
		goto GetOut;
	}	
	else {	/* Finally, we are ready to pass fut0's grid tables through fut1 */
		for (i = 0, nOutChans = 0; (i < FUT_NOCHAN) && ok; i++) {
			if ((evalomask & FUT_BIT(i)) != 0) {
				fut_gtbl_p	gtbl;
				
				gtbl = fut2->chan[i]->gtbl;
				nGridPoints = gtbl->tbl_size / sizeof (fut_gtbldat_t);	/* grid points for eval */

				if (evalFut->iomask.in != evalFut->chan[i]->imask) {	/* must evaluate this channel singly */
					evalomask &= ~FUT_BIT(i);							/* remove channel from multiple eval list */
					ok = evaluateFut (evalFut, FUT_BIT(i), KCM_USHORT, nGridPoints,
									(KpGenericPtr_t FAR*) indat, (KpGenericPtr_t FAR*) &(gtbl->refTbl));
				}
				else {
					outdat[nOutChans] = gtbl->refTbl;
					nOutChans++;
				}

			}
		}

		/* eval result is composed fut's gtbls */
		ok = evaluateFut (evalFut, evalomask, KCM_USHORT, nGridPoints,
						 (KpGenericPtr_t FAR*) indat, (KpGenericPtr_t FAR*) outdat);
	}

GetOut:
	/* must always free up the evaluation fut and io tables, even if an error occurred! */
	fut_free (evalFut);
	fut_free_tbls (FUT_NICHAN, (void *)oitbls);

	/* check for errors */
	if ( !ok ) {
		fut_free (fut2);
		fut2 = NULL;
	}

	return (fut2);
}
Esempio n. 4
0
fut_p
	constructfut (	KpInt32_t		iomask,
					KpInt32_p		sizeArray,
					fut_calcData_p	fData,
					fut_ifunc_p		ifunArray,
					fut_gfunc_p		gfunArray,
					fut_ofunc_p		ofunArray,
					PTDataClass_t	iClass,
					PTDataClass_t	oClass)
{
fut_p		futp;
KpInt32_t	i1, imask, omask;
fut_itbl_p	itbls[FUT_NICHAN] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
fut_gtbl_p	gtbls[FUT_NOCHAN] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
fut_otbl_p	otbls[FUT_NOCHAN] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
fut_ifunc_t	ifun;
fut_gfunc_t	gfun;
fut_ofunc_t	ofun;
fData_t			fDataL;
fut_calcData_p	fDataP;

	if (sizeArray == NULL) return NULL;

	if (fData == NULL) {
		fDataP = &fDataL.std;
	}
	else {
		fDataP = fData;
	}
	
	imask = FUT_IMASK(iomask);
	omask = FUT_OMASK(iomask);

	#if defined KCP_DIAG_LOG
	{KpChar_t	string[256], str2[256];
	KpInt32_t	i1;
	sprintf (string, "constructfut\n iomask %x, sizeArray[]", iomask);
	for (i1 = 0; i1 < FUT_NICHAN; i1++) {
		if ((FUT_BIT(i1) & imask) != 0) {
			sprintf (str2, " %d", sizeArray[i1]);
			strcat (string, str2);
		}
	}
	sprintf (str2, ", fData %x, ifunArray %x, gfunArray %x, ofunArray %x, iClass %d, oClass %d\n",
					fData, ifunArray, gfunArray, ofunArray, iClass, oClass);
	strcat (string, str2);
	kcpDiagLog (string);}
	#endif
	
	/* Compute shared input tables:  */
	for (i1 = 0; i1 < FUT_NICHAN; i1++) {
		if ((imask & FUT_BIT(i1)) != 0) {
			if ((ifunArray == NULL) || (ifunArray[i1] == NULL)) {
				ifun = fut_irampEx;
				fDataP = &fDataL.std;
				if (iClass == KCP_VARIABLE_RANGE) {
					fDataL.scale = KCP_16_TO_8_ENCODING;
				}
				else {
					fDataL.scale = 1.0;
				}
			}
			else {
				ifun = ifunArray[i1];
			}

			fDataP->chan = i1;	/* define the channel # */

			itbls[i1] = fut_new_itblEx (KCP_REF_TABLES, iClass, sizeArray[i1], ifun, fDataP);
			itbls[i1]->id = fut_unique_id ();
			itbls[i1]->dataClass = iClass;
		}
	}

	/* Compute grid tables and output tables:  */
	for (i1 = 0; i1 < FUT_NOCHAN; i1++) {
		if ((omask & FUT_BIT(i1)) != 0) {
			if ((gfunArray == NULL) || (gfunArray[i1] == NULL)) {
				gfun = fut_grampEx;
			}
			else {
				gfun = gfunArray[i1];
			}

			fDataP->chan = i1;	/* define the channel # */

			gtbls[i1] = fut_new_gtblEx (KCP_REF_TABLES, iomask, gfun, fDataP, sizeArray);
			gtbls[i1]->id = fut_unique_id();

			if ((ofunArray == NULL) || (ofunArray[i1] == NULL)) {
				ofun = fut_orampEx;
				fDataP = &fDataL.std;
				if (oClass == KCP_VARIABLE_RANGE) {
					fDataL.scale = KCP_8_TO_16_ENCODING;
				}
				else {
					fDataL.scale = 1.0;
				}
			}
			else {
				ofun = ofunArray[i1];
			}

			otbls[i1] = fut_new_otblEx (KCP_REF_TABLES, oClass, ofun, fDataP);
			otbls[i1]->id = fut_unique_id();
			otbls[i1]->dataClass = oClass;
		}
	}

	/* Assemble FuT:  */
	futp = fut_new (iomask, itbls, gtbls, otbls);

	fut_free_tbls (FUT_NICHAN, (KpGenericPtr_t *)itbls);
	fut_free_tbls (FUT_NOCHAN, (KpGenericPtr_t *)gtbls);
	fut_free_tbls (FUT_NOCHAN, (KpGenericPtr_t *)otbls);

	if (fut_to_mft (futp) != 1) {		/* convert to reference tables */
		fut_free (futp);
		futp = NULL;
	}

	return (futp);
}
Esempio n. 5
0
PTErr_t
	PTEvaluate (	PTRefNum_t		PTRefNum,
					PTEvalDTPB_p	evalDef,
					PTEvalTypes_t	evalID,
					KpInt32_t		devNum,
					KpInt32_t		aSync,
					opRefNum_p		opRefNum,
					callBack_p		callBack)
{
PTErr_t			PTErr;
PTEvalDTPB_t	lEvalDef;
PTCompDef_t		thisInput [FUT_NICHAN], thisOutput [FUT_NOCHAN];
PTRefNum_t		PTList [MAX_PT_CHAIN_SIZE];
PTTable_p		evalList [MAX_PT_CHAIN_SIZE], PTTableP;
PTTable_p*		listStart;
KpInt32_t		theSerialCount, i1, i2, i3, i4, nOutputs, nFuts, PTcount;
KpUInt32_t		tempMemNeeded, oMask, ioMaskList [MAX_PT_CHAIN_SIZE];
PTImgAddr_t		addr;
#if defined (KCP_ACCEL)
PTEvalTypes_t	evaluator;
KpInt32_t		numEvals;
#endif

	if (devNum) {}
	if (aSync) {}
	if (opRefNum) {}

#if defined (KCP_MACPPC_MP)
	KCPInitializeMP ();
#endif

	PTErr = getPTStatus (PTRefNum);			/* must be an active or serial PT */
	if ((PTErr != KCP_PT_ACTIVE) && (PTErr != KCP_SERIAL_PT)) {
		goto ErrOut0;
	}

#if defined (KCP_ACCEL)
	PTErr = GetEval (evalID, &evaluator);	/* get an evaluator */
	if (PTErr != KCP_SUCCESS) {
		goto ErrOut0;
	}
#endif

	/* valid PTEvalDTPB_p? */
	if (evalDef == NULL) goto ErrOut1;
	if (evalDef->input == NULL) goto ErrOut1;
	if (evalDef->output == NULL) goto ErrOut1;
	if (evalDef->nInputs > FUT_NICHAN) goto ErrOut3;
	if (evalDef->nOutputs > FUT_NOCHAN) goto ErrOut3;

	/* set up the local evaluation structures */
	/* set input and output to NULL */
	/* this preserves the channel position while allowing */
	/* the number of channels to indicate the number of valid addresses */
	/* this is needed to keep both the CTE and SW evaluations happy */
	for (i1 = 0; i1 < FUT_NICHAN; i1++) {
		thisInput[i1].pelStride = 0;
		thisInput[i1].lineStride = 0;
		thisInput[i1].addr = NULL;
	} 

	lEvalDef.nPels = evalDef->nPels;
	lEvalDef.nLines = evalDef->nLines;

	lEvalDef.nInputs = FUT_NICHAN;
	lEvalDef.dataTypeI = evalDef->dataTypeI;
	lEvalDef.input = thisInput;
	for (i1 = 0; i1 < evalDef->nInputs; i1++) {
		lEvalDef.input[i1].pelStride	= evalDef->input[i1].pelStride;
		lEvalDef.input[i1].lineStride	= evalDef->input[i1].lineStride;
		lEvalDef.input[i1].addr			= evalDef->input[i1].addr;
	} 

	/* output addresses are loaded in the evaluation loop, no need to do anything here */

	/* clear the PT and evaluation lists, just for clarity */
	for (i1 = 0; i1 < MAX_PT_CHAIN_SIZE; i1++) {
		PTList[i1] = NULL;
		evalList[i1] = NULL;
	}

	/* get the list of PTs which we must actually evaluate */
	PTErr = resolvePTData (PTRefNum, &theSerialCount, PTList);

	/* set up list of futs through which the image is evaluated */
	for (i1 = 0; i1 < theSerialCount; i1++) {
		PTTableP = lockPTTable (PTList[i1]);	/* lock tables while evaluating */
		evalList[i1] = PTTableP;
	}

	/* initialize the evaluation list */
	PTErr = setupEvalList (theSerialCount, evalList, ioMaskList, evalDef, &tempMemNeeded);
	if (PTErr != KCP_SUCCESS) {
		goto ErrOut2;
	}

	/* if temporary memory is not needed, */
	/* then evaluate a full image at a time until */
	/* the image has been processed through all futs */
	/* if temporary memory is needed, */
	/* then this level processes the image just once */
	/* and a lower level processes the image through all futs */
	if (tempMemNeeded == 0) {
		PTcount = theSerialCount;
	}
	else {
		PTcount = 1;
	}

	initProgressPasses (PTcount, callBack);

	/* process the image through each fut in the list */ 
	for (i1 = 0; i1 < PTcount; i1++) {

		/* set up the output data addresses */
		/* use io mask to order output channels properly */
		if (tempMemNeeded == 1) {
			nFuts = theSerialCount;					/* this many futs to evaluate */
			listStart = &evalList[0];
			oMask = FUT_OMASK(ioMaskList[nFuts-1]);	/* use mask of last fut */
		}
		else {
			nFuts = 1;								/* evaluate one fut */
			listStart = &evalList[i1];
			oMask = FUT_OMASK(ioMaskList[i1]);		/* use mask of this fut */
		}

		/* initialize the output data structures */
		lEvalDef.nOutputs = FUT_NOCHAN;
		lEvalDef.dataTypeO = evalDef->dataTypeO;
		lEvalDef.output = thisOutput;

		for (i2 = 0; i2 < FUT_NOCHAN; i2++) {
			thisOutput[i2].pelStride = 0;
			thisOutput[i2].lineStride = 0;
			thisOutput[i2].addr = NULL;
		} 

		/* set the output channel addresses */
		if (i1 == (PTcount -1)) {		/* last, just use supplied stuff */
			for (i2 = 0, nOutputs = 0; i2 < evalDef->nOutputs; i2++) {
				lEvalDef.output[i2].pelStride	= evalDef->output[i2].pelStride;
				lEvalDef.output[i2].lineStride	= evalDef->output[i2].lineStride;
				lEvalDef.output[i2].addr		= evalDef->output[i2].addr;

				nOutputs++;		/* count actual outputs */
			}

			getDataBytes (evalDef->dataTypeO, &i3);	/* get output data size */
			if (i3 == 0) {
				nOutputs = 3;
			}
		}
		else {
			for (i2 = oMask, i3 = 0, i4 = 0, nOutputs = 0; i2 != 0; i2 >>= 1, i3++) {
				if ((i2 & 1) == 1) {	/* this output channel is needed */
					while ((addr = evalDef->output[i4].addr) == NULL) {
						i4++;		/* get next available output channel */
					}

					if (i4 > evalDef->nOutputs) {
						PTErr = KCP_PTERR_4;				/* programming error */
						goto ErrOut2;
					}

					lEvalDef.output[i3].pelStride	= evalDef->output[i4].pelStride;
					lEvalDef.output[i3].lineStride	= evalDef->output[i4].lineStride;
					lEvalDef.output[i3].addr		= addr;

					i4++;			/* next output address */
					nOutputs++;		/* count actual outputs */
				}
			}
		}

#if defined (KCP_ACCEL)
		/* if there are less than FASTER_IN_SW evaluations, it's faster to do it in software. */
		numEvals = lEvalDef.nPels * lEvalDef.nLines * nOutputs;
		
		if ((numEvals < FASTER_IN_SW) || (tempMemNeeded == 1)) {
			evaluator = KCP_EVAL_SW;
		}
		
		switch (evaluator) {
		case KCP_EVAL_SW:		/* evaluate in software */

software_evaluation:
#endif

			PTErr = PTEvalSeq (nFuts, listStart, ioMaskList, &lEvalDef, callBack);
			if (PTErr != KCP_SUCCESS) {
				goto ErrOut2;
			}

#if defined (KCP_ACCEL)
			break;

		case KCP_EVAL_CTE:	/* evaluate using the NFE */
		{
		PTRefNum_t		thePTRefNum;
		KpHandle_t		PTData;

			thePTRefNum = listStart[0]->refNum;			/* get the PT reference number */

			PTData = getPTData (thePTRefNum);	/* get the transform data */

			PTErr = PT_eval_cteDT (PTData, &lEvalDef, 0, 0, callBack);

			if ((PTErr == KCP_CTE_GRID_TOO_BIG) || (PTErr == KCP_CTE_NOT_ATTEMPTED)) {
				goto software_evaluation;
			}
			
			break;
		}

		default:
			PTErr = KCP_INVAL_EVAL;

			break;
		}
#else
		if (evalID) {}	/* unreferenced formal parameter */
#endif
				
		/* output for this PT is input for next PT */
		lEvalDef.nInputs = lEvalDef.nOutputs;
		lEvalDef.dataTypeI = lEvalDef.dataTypeO;

		for (i2 = 0; i2 < lEvalDef.nInputs; i2++) {
			lEvalDef.input[i2].pelStride	= lEvalDef.output[i2].pelStride;
			lEvalDef.input[i2].lineStride	= lEvalDef.output[i2].lineStride;
			lEvalDef.input[i2].addr			= lEvalDef.output[i2].addr;
		}
	}


ErrOut2:
	/* unlock the PTs used for evaluation */
	for (i1 = 0; i1 < theSerialCount; i1++) {
		unlockPTTable (PTList[i1]);
	}

ErrOut0:
	return (PTErr);


ErrOut1:
	PTErr = KCP_BAD_PTR;
	goto ErrOut0;

ErrOut3:
	PTErr = KCP_INVAL_EVAL;
	goto ErrOut0;
}