tf.c 8.05 KB
/**************************************************************************
 *                                                                        *
 *               Copyright (C) 1994, Silicon Graphics, Inc.               *
 *                                                                        *
 *  These coded instructions, statements, and computer programs  contain  *
 *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
 *  are protected by Federal copyright law.  They  may  not be disclosed  *
 *  to  third  parties  or copied or duplicated in any form, in whole or  *
 *  in part, without the prior written consent of Silicon Graphics, Inc.  *
 *                                                                        *
 **************************************************************************/

/*
 *  Texture Filter Unit
 *
 *  This unit implements a bi-planar interpolator for filtering texture
 *  maps, and can also be used to implement part of the color conversion
 *  YUV->RGB equation.  Feedback is provided so that a YUV texture can be
 *  filtered and then color converted and the subsequent clock.
 * 
 *  NOTE:  incoming pixels are either RGBA or UVYY.
 *         texture interpolation is triangular:
 *	     tf = (txh - txt)*sfrac + (txv - txt)*tfrac + txt
 *	   when mid_texel mode bit is set and at center of pixel:
 *	     tf = (txh + txv + txt + txo) / 4
 *	   when doing YUV->RGB conversion:
 *	     r' = y + k0*v
 *	     g' = y + k1*u + k2*v
 *	     b' = y + k3*u
 */

#include <stdio.h>
#include "tf.h"

#define SIGN_EXTEND_9B(x)       ((x & 0x100) ? ((x) | ~0x1ff) : (x))


#define POSEDGE         (save_clk && !save_clk_old)
#define NEGEDGE         (!save_clk && save_clk_old)


/***************************************************************************
 *  triangular_interp() - return s,8.0 number
 *
 ***************************************************************************/

int
  triangular_interp(int suba_a, int suba_b, int mula, int subb_a, 
		int subb_b, int mulb, int startp, int offa, int offb)
{
  int suba_out, subb_out, mula_out, mulb_out, result;
  int mul_comb;

  suba_a   = SIGN_EXTEND_9B(suba_a);
  suba_b   = SIGN_EXTEND_9B(suba_b);
  mula     = SIGN_EXTEND_9B(mula);
  subb_a   = SIGN_EXTEND_9B(subb_a);
  subb_b   = SIGN_EXTEND_9B(subb_b);
  mulb     = SIGN_EXTEND_9B(mulb);
  startp   = SIGN_EXTEND_9B(startp);
  offa     = SIGN_EXTEND_9B(offa);
  offb     = SIGN_EXTEND_9B(offb);

  /* fprintf(stderr," %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", suba_a, suba_b, mula, subb_a, subb_b, mulb, startp, offa, offb);  */

  suba_out = suba_a - suba_b;
  subb_out = subb_a - subb_b;
  mula_out = mula * suba_out; /* Full Precision */
  mulb_out = mulb * subb_out; /* Full Precision */
  mul_comb = (mula_out + mulb_out) >> 6;
  /* note, + 2 is for rounding */
  result = (mul_comb + (startp << 2) + offa + (offb+1) + 2) >> 2;

  /* fprintf(stderr,"%08x %08x %08x %08x %08x\n", suba_out, subb_out, mula_out, mulb_out, result); */
  return(result & 0x1ff);
}

/***************************************************************************
 *  tf() - interface to texture filter
 *
 ***************************************************************************/

void
  tf(tf_t **pp0, tf_t **pp1)
{
  /* pointer to memory structures */
  tf_t *p0, *p1;
  int save_clk;
  int save_clk_old;

  /* temporary signals */
  int bilerp, loop_back;
  int suba_a, suba_b;
  int subb_a, subb_b;
  int mula, mulb;
  int startp, offa, offb;
  int suba_out, mula_out, subb_out, mulb_out;
  int shift_r, shift_l;
  int interp, sl, sr;

  int pcr, far, fbr, pcg, pcb, fab, fbb, pca;
  int mid_uv, mid_y;

     
  /* get started */
  p0 = *pp0;
  p1 = *pp1;
  save_clk = p0->gclk;
  save_clk_old = p1->gclk_old;


  if(POSEDGE)
  {
    /* transfer all next-clock register values to register outputs. */
    *pp0 = p1; /* swap */
    *pp1 = p0;
    p0 = *pp0; /* fix pointers */
    p1 = *pp1;

    /* Update all next-clock register values */

	/* delay lod fraction */
	p0->lod_frac_d1 = p1->lod_frac;
	p0->tf_lod_frac = p1->lod_frac_d1;

	/* generate cycle */
	if(p1->st_span || !p1->ncyc)
      	  p0->cycle = 0;
    	else
          p0->cycle = ~p1->cycle;

	/* ************************************************
                    ORDER DEPENDENT SECTION
	 * ************************************************/

	/*  determine mux selects */
	bilerp = (p1->cycle) ? p1->bilerp1m : p1->bilerp0m;

	/*  L o o p   B a c k   M u x   */

	loop_back = p1->convert_one && p1->cycle;
        p0->loop_d1 = loop_back;

        pcr = p1->loop_d1 ? p1->tf_b : p1->txtrb_d1;
        far = p1->loop_d1 ? p1->tf_r : p1->txtr_sfuv_d1;
        fbr = p1->loop_d1 ? p1->tf_g : p1->txtg_tfuv_d1;

        pcg = p1->loop_d1 ? p1->tf_b : p1->txtgb_d1;

        pcb = p1->loop_d1 ? p1->tf_b : p1->txtb_d1;
        fab = p1->loop_d1 ? p1->tf_r : p1->txtr_sfy_d1;
        fbb = p1->loop_d1 ? p1->tf_g : p1->txtg_tfy_d1;

        pca = p1->loop_d1 ? p1->tf_b : p1->txta_d1;


	/*   M i d   UV / Y */

        mid_uv = bilerp && p1->mid_texel &&
		(p1->sfrac_rg & 0xf8) == 0x80 && (p1->tfrac_rg & 0xf8) == 0x80;
        mid_y  = bilerp && p1->mid_texel &&
		(p1->sfrac_ba & 0xf8) == 0x80 && (p1->tfrac_ba & 0xf8) == 0x80;

	/*  R E D   C o m p o n e n t  */

	p0->txtrb_d1     = bilerp ? p1->tm_ra : p1->tm_ba;
	p0->xar          = bilerp ? p1->tm_rb : 0;
	p0->yar          = bilerp ? p1->tm_ra : 0;
	p0->xbr          = bilerp ? p1->tm_rc : p1->k0_coeff;
	p0->ybr          = bilerp ? p1->tm_ra : ~SIGN_EXTEND_9B(p1->k0_coeff);
	p0->txtr_sfuv_d1 = bilerp ? (mid_uv ? (p1->sfrac_rg >> 1) : p1->sfrac_rg) : p1->tm_ra;
	p0->txtg_tfuv_d1 = bilerp ? (mid_uv ? (p1->tfrac_rg >> 1) : p1->tfrac_rg) : p1->tm_ga;
	p0->por          = mid_uv ? p1->tm_rd : 0;
	p0->ptr          = ~( mid_uv ? SIGN_EXTEND_9B(p1->tm_ra) : 0x0 );

	/* do the math */
	p0->tf_r = triangular_interp(p1->xar, p1->yar, far, p1->xbr, p1->ybr, fbr, 
		    pcr, p1->por, p1->ptr);

	/*  G R E E N    C o m p o n e n t  */

	p0->txtgb_d1 = bilerp ? p1->tm_ga : p1->tm_ba;
	p0->xag      = bilerp ? p1->tm_gb : p1->k1_coeff;
	p0->yag      = bilerp ? p1->tm_ga : ~SIGN_EXTEND_9B(p1->k1_coeff);
	p0->xbg      = bilerp ? p1->tm_gc : p1->k2_coeff;
	p0->ybg      = bilerp ? p1->tm_ga : ~SIGN_EXTEND_9B(p1->k2_coeff);
	p0->pog      = mid_uv ? p1->tm_gd : 0;
	p0->ptg      = ~(mid_uv ? SIGN_EXTEND_9B(p1->tm_ga) : 0);

	/* do the math */
	p0->tf_g = triangular_interp(p1->xag, p1->yag, far, p1->xbg, p1->ybg, fbr, 
		    pcg, p1->pog, p1->ptg);


	/*  B L U E    C o m p o n e n t  */

	p0->txtb_d1     = p1->tm_ba;
	p0->xab         = bilerp ? p1->tm_bb : p1->k3_coeff;
	p0->yab         = bilerp ? p1->tm_ba : ~SIGN_EXTEND_9B(p1->k3_coeff);
	p0->xbb         = bilerp ? p1->tm_bc : 0;
	p0->ybb         = bilerp ? p1->tm_ba : 0;
	p0->txtr_sfy_d1 = bilerp ? (mid_y ? (p1->sfrac_ba >> 1) : p1->sfrac_ba) : p1->tm_ra;
	p0->txtg_tfy_d1 = bilerp ? (mid_y ? (p1->tfrac_ba >> 1) : p1->tfrac_ba) : p1->tm_ga;
	p0->pob         = mid_y ? p1->tm_bd : 0;
	p0->ptb         = ~( mid_y ? SIGN_EXTEND_9B(p1->tm_ba) : 0x0);

	/* do the math */
	p0->tf_b = triangular_interp(p1->xab, p1->yab, fab, p1->xbb, p1->ybb, fbb, 
		    pcb, p1->pob, p1->ptb);


	/*  A L P H A     C o m p o n e n t  */

	p0->txta_d1 = bilerp ? p1->tm_aa : p1->tm_ba;
	p0->xaa     = bilerp ? p1->tm_ab : 0;
	p0->yaa     = bilerp ? p1->tm_aa : 0;
	p0->xba     = bilerp ? p1->tm_ac : 0;
	p0->yba     = bilerp ? p1->tm_aa : 0;
	p0->poa     = mid_y ? p1->tm_ad : 0;
	p0->pta     = ~(mid_y ? SIGN_EXTEND_9B(p1->tm_aa) : 0x0);

	/* do the math */
	p0->tf_a = triangular_interp(p1->xaa, p1->yaa, fab, p1->xba, p1->yba, fbb, 
		    pca, p1->poa, p1->pta);


	/* ************************************************
                 END OF ORDER DEPENDENT SECTION
	 * ************************************************/
  } /* posedge */

  p0->gclk_old = p1->gclk_old = save_clk;
}

 
/***************************************************************************
 *  tf_init() - init texture filter 
 ***************************************************************************/
void
  tf_init(tf_t *p0, tf_t *p1)
{
    p1->cycle = p0->cycle = 0;
    p1->gclk = p0->gclk = 0;
    p1->gclk_old = p0->gclk_old = 0;
}