dri: use BorderColor instead of _BorderChan
[mesa.git] / src / mesa / drivers / dri / r200 / r200_tcl.c
index 746cdb4778a452d05253fdeadaad7a2f233ad8e8..99aecfe1e90050171534de7b225247c3b0852a89 100644 (file)
@@ -1,4 +1,3 @@
-/* $XFree86: xc/lib/GL/mesa/src/drv/r200/r200_tcl.c,v 1.2 2002/12/16 16:18:55 dawes Exp $ */
 /*
 Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
 
@@ -33,14 +32,14 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  *   Keith Whitwell <keith@tungstengraphics.com>
  */
 
-#include "glheader.h"
-#include "imports.h"
-#include "mtypes.h"
-#include "enums.h"
-#include "colormac.h"
-#include "light.h"
+#include "main/glheader.h"
+#include "main/imports.h"
+#include "main/mtypes.h"
+#include "main/enums.h"
+#include "main/colormac.h"
+#include "main/light.h"
 
-#include "array_cache/acache.h"
+#include "vbo/vbo.h"
 #include "tnl/tnl.h"
 #include "tnl/t_pipeline.h"
 
@@ -62,13 +61,16 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #define HAVE_TRI_STRIPS  1
 #define HAVE_TRI_STRIP_1 0
 #define HAVE_TRI_FANS    1
-#define HAVE_QUADS       0     /* hw quad verts in wrong order??? */
+#define HAVE_QUADS       1
 #define HAVE_QUAD_STRIPS 1
 #define HAVE_POLYGONS    1
 #define HAVE_ELTS        1
 
 
-#define HW_POINTS           R200_VF_PRIM_POINTS
+#define HW_POINTS           ((ctx->Point.PointSprite || \
+                               ((ctx->_TriangleCaps & (DD_POINT_SIZE | DD_POINT_ATTEN)) && \
+                               !(ctx->_TriangleCaps & (DD_POINT_SMOOTH)))) ? \
+                               R200_VF_PRIM_POINT_SPRITES : R200_VF_PRIM_POINTS)
 #define HW_LINES            R200_VF_PRIM_LINES
 #define HW_LINE_LOOP        0
 #define HW_LINE_STRIP       R200_VF_PRIM_LINE_STRIP
@@ -101,7 +103,7 @@ static GLboolean discrete_prim[0x10] = {
 };
    
 
-#define LOCAL_VARS r200ContextPtr rmesa = R200_CONTEXT(ctx); (void)rmesa
+#define LOCAL_VARS r200ContextPtr rmesa = R200_CONTEXT(ctx)
 #define ELT_TYPE  GLushort
 
 #define ELT_INIT(prim, hw_prim) \
@@ -177,11 +179,11 @@ while (0)
  * discrete and there are no intervening state changes.  (Somewhat
  * duplicates changes to DrawArrays code)
  */
-static void EMIT_PRIM( GLcontext *ctx, 
-                      GLenum prim, 
-                      GLuint hwprim, 
-                      GLuint start, 
-                      GLuint count)    
+static void r200EmitPrim( GLcontext *ctx, 
+                         GLenum prim, 
+                         GLuint hwprim, 
+                         GLuint start, 
+                         GLuint count) 
 {
    r200ContextPtr rmesa = R200_CONTEXT( ctx );
    r200TclPrimitive( ctx, prim, hwprim );
@@ -201,7 +203,9 @@ static void EMIT_PRIM( GLcontext *ctx,
                     count - start );
 }
 
-
+#define EMIT_PRIM(ctx, prim, hwprim, start, count) do {         \
+   r200EmitPrim( ctx, prim, hwprim, start, count );             \
+   (void) rmesa; } while (0)
 
 /* Try & join small primitives
  */
@@ -218,12 +222,15 @@ static void EMIT_PRIM( GLcontext *ctx,
 
 #ifdef MESA_BIG_ENDIAN
 /* We could do without (most of) this ugliness if dest was always 32 bit word aligned... */
-#define EMIT_ELT(dest, offset, x) do {                                \
+#define EMIT_ELT(dest, offset, x) do {                          \
         int off = offset + ( ( (GLuint)dest & 0x2 ) >> 1 );     \
         GLushort *des = (GLushort *)( (GLuint)dest & ~0x2 );    \
-        (des)[ off + 1 - 2 * ( off & 1 ) ] = (GLushort)(x); } while (0)
+        (des)[ off + 1 - 2 * ( off & 1 ) ] = (GLushort)(x);    \
+       (void)rmesa; } while (0)
 #else
-#define EMIT_ELT(dest, offset, x) (dest)[offset] = (GLushort) (x)
+#define EMIT_ELT(dest, offset, x) do {                         \
+       (dest)[offset] = (GLushort) (x);                        \
+       (void)rmesa; } while (0)
 #endif
 
 #define EMIT_TWO_ELTS(dest, offset, x, y)  *(GLuint *)((dest)+offset) = ((y)<<16)|(x);
@@ -262,12 +269,107 @@ void r200TclPrimitive( GLcontext *ctx,
 
    if (newprim != rmesa->tcl.hw_primitive ||
        !discrete_prim[hw_prim&0xf]) {
+      /* need to disable perspective-correct texturing for point sprites */
+      if ((prim & PRIM_MODE_MASK) == GL_POINTS && ctx->Point.PointSprite) {
+        if (rmesa->hw.set.cmd[SET_RE_CNTL] & R200_PERSPECTIVE_ENABLE) {
+           R200_STATECHANGE( rmesa, set );
+           rmesa->hw.set.cmd[SET_RE_CNTL] &= ~R200_PERSPECTIVE_ENABLE;
+        }
+      }
+      else if (!(rmesa->hw.set.cmd[SET_RE_CNTL] & R200_PERSPECTIVE_ENABLE)) {
+        R200_STATECHANGE( rmesa, set );
+        rmesa->hw.set.cmd[SET_RE_CNTL] |= R200_PERSPECTIVE_ENABLE;
+      }
       R200_NEWPRIM( rmesa );
       rmesa->tcl.hw_primitive = newprim;
    }
 }
 
 
+/**********************************************************************/
+/*             Fog blend factor computation for hw tcl                */
+/*             same calculation used as in t_vb_fog.c                 */
+/**********************************************************************/
+
+#define FOG_EXP_TABLE_SIZE 256
+#define FOG_MAX (10.0)
+#define EXP_FOG_MAX .0006595
+#define FOG_INCR (FOG_MAX/FOG_EXP_TABLE_SIZE)
+static GLfloat exp_table[FOG_EXP_TABLE_SIZE];
+
+#if 1
+#define NEG_EXP( result, narg )                                                \
+do {                                                                   \
+   GLfloat f = (GLfloat) (narg * (1.0/FOG_INCR));                      \
+   GLint k = (GLint) f;                                                        \
+   if (k > FOG_EXP_TABLE_SIZE-2)                                       \
+      result = (GLfloat) EXP_FOG_MAX;                                  \
+   else                                                                        \
+      result = exp_table[k] + (f-k)*(exp_table[k+1]-exp_table[k]);     \
+} while (0)
+#else
+#define NEG_EXP( result, narg )                                        \
+do {                                                           \
+   result = exp(-narg);                                                \
+} while (0)
+#endif
+
+
+/**
+ * Initialize the exp_table[] lookup table for approximating exp().
+ */
+void
+r200InitStaticFogData( void )
+{
+   GLfloat f = 0.0F;
+   GLint i = 0;
+   for ( ; i < FOG_EXP_TABLE_SIZE ; i++, f += FOG_INCR) {
+      exp_table[i] = (GLfloat) exp(-f);
+   }
+}
+
+
+/**
+ * Compute per-vertex fog blend factors from fog coordinates by
+ * evaluating the GL_LINEAR, GL_EXP or GL_EXP2 fog function.
+ * Fog coordinates are distances from the eye (typically between the
+ * near and far clip plane distances).
+ * Note the fog (eye Z) coords may be negative so we use ABS(z) below.
+ * Fog blend factors are in the range [0,1].
+ */
+float
+r200ComputeFogBlendFactor( GLcontext *ctx, GLfloat fogcoord )
+{
+   GLfloat end  = ctx->Fog.End;
+   GLfloat d, temp;
+   const GLfloat z = FABSF(fogcoord);
+
+   switch (ctx->Fog.Mode) {
+   case GL_LINEAR:
+      if (ctx->Fog.Start == ctx->Fog.End)
+         d = 1.0F;
+      else
+         d = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
+      temp = (end - z) * d;
+      return CLAMP(temp, 0.0F, 1.0F);
+      break;
+   case GL_EXP:
+      d = ctx->Fog.Density;
+      NEG_EXP( temp, d * z );
+      return temp;
+      break;
+   case GL_EXP2:
+      d = ctx->Fog.Density*ctx->Fog.Density;
+      NEG_EXP( temp, d * z * z );
+      return temp;
+      break;
+   default:
+      _mesa_problem(ctx, "Bad fog mode in make_fog_coord");
+      return 0;
+   }
+}
+
+
 /**********************************************************************/
 /*                          Render pipeline stage                     */
 /**********************************************************************/
@@ -282,6 +384,13 @@ static GLboolean r200_run_tcl_render( GLcontext *ctx,
    TNLcontext *tnl = TNL_CONTEXT(ctx);
    struct vertex_buffer *VB = &tnl->vb;
    GLuint i;
+   GLubyte *vimap_rev;
+/* use hw fixed order for simplicity, pos 0, weight 1, normal 2, fog 3, 
+   color0 - color3 4-7, texcoord0 - texcoord5 8-13, pos 1 14. Must not use
+   more than 12 of those at the same time. */
+   GLubyte map_rev_fixed[15] = {255, 255, 255, 255, 255, 255, 255, 255,
+                           255, 255, 255, 255, 255, 255, 255};
+
 
    /* TODO: separate this from the swtnl pipeline 
     */
@@ -294,14 +403,92 @@ static GLboolean r200_run_tcl_render( GLcontext *ctx,
    if (VB->Count == 0)
       return GL_FALSE;
 
+   /* Validate state:
+    */
+   if (rmesa->NewGLState)
+      r200ValidateState( ctx );
+
+   if (!ctx->VertexProgram._Enabled) {
+   /* NOTE: inputs != tnl->render_inputs - these are the untransformed
+    * inputs.
+    */
+      map_rev_fixed[0] = VERT_ATTRIB_POS;
+      /* technically there is no reason we always need VA_COLOR0. In theory
+         could disable it depending on lighting, color materials, texturing... */
+      map_rev_fixed[4] = VERT_ATTRIB_COLOR0;
+
+      if (ctx->Light.Enabled) {
+        map_rev_fixed[2] = VERT_ATTRIB_NORMAL;
+      }
+
+      /* this also enables VA_COLOR1 when using separate specular
+         lighting model, which is unnecessary.
+         FIXME: OTOH, we're missing the case where a ATI_fragment_shader accesses
+         the secondary color (if lighting is disabled). The chip seems
+         misconfigured for that though elsewhere (tcl output, might lock up) */
+      if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) {
+        map_rev_fixed[5] = VERT_ATTRIB_COLOR1;
+      }
+
+      if ( (ctx->Fog.FogCoordinateSource == GL_FOG_COORD) && ctx->Fog.Enabled ) {
+        map_rev_fixed[3] = VERT_ATTRIB_FOG;
+      }
+
+      for (i = 0 ; i < ctx->Const.MaxTextureUnits; i++) {
+        if (ctx->Texture.Unit[i]._ReallyEnabled) {
+           if (rmesa->TexGenNeedNormals[i]) {
+              map_rev_fixed[2] = VERT_ATTRIB_NORMAL;
+           }
+           map_rev_fixed[8 + i] = VERT_ATTRIB_TEX0 + i;
+        }
+      }
+      vimap_rev = &map_rev_fixed[0];
+   }
+   else {
+      /* vtx_tcl_output_vtxfmt_0/1 need to match configuration of "fragment
+        part", since using some vertex interpolator later which is not in
+        out_vtxfmt0/1 will lock up. It seems to be ok to write in vertex
+        prog to a not enabled output however, so just don't mess with it.
+        We only need to change compsel. */
+      GLuint out_compsel = 0;
+      GLuint vp_out = rmesa->curr_vp_hw->mesa_program.Base.OutputsWritten;
+
+      vimap_rev = &rmesa->curr_vp_hw->inputmap_rev[0];
+      assert(vp_out & (1 << VERT_RESULT_HPOS));
+      out_compsel = R200_OUTPUT_XYZW;
+      if (vp_out & (1 << VERT_RESULT_COL0)) {
+        out_compsel |= R200_OUTPUT_COLOR_0;
+      }
+      if (vp_out & (1 << VERT_RESULT_COL1)) {
+        out_compsel |= R200_OUTPUT_COLOR_1;
+      }
+      if (vp_out & (1 << VERT_RESULT_FOGC)) {
+         out_compsel |= R200_OUTPUT_DISCRETE_FOG;
+      }
+      if (vp_out & (1 << VERT_RESULT_PSIZ)) {
+        out_compsel |= R200_OUTPUT_PT_SIZE;
+      }
+      for (i = VERT_RESULT_TEX0; i < VERT_RESULT_TEX6; i++) {
+        if (vp_out & (1 << i)) {
+           out_compsel |= R200_OUTPUT_TEX_0 << (i - VERT_RESULT_TEX0);
+        }
+      }
+      if (rmesa->hw.vtx.cmd[VTX_TCL_OUTPUT_COMPSEL] != out_compsel) {
+        R200_STATECHANGE( rmesa, vtx );
+        rmesa->hw.vtx.cmd[VTX_TCL_OUTPUT_COMPSEL] = out_compsel;
+      }
+   }
+
+   /* Do the actual work:
+    */
    r200ReleaseArrays( ctx, ~0 /* stage->changed_inputs */ );
-   r200EmitArrays( ctx, stage->inputs );
+   r200EmitArrays( ctx, vimap_rev );
 
    rmesa->tcl.Elts = VB->Elts;
 
    for (i = 0 ; i < VB->PrimitiveCount ; i++)
    {
-      GLuint prim = VB->Primitive[i].mode;
+      GLuint prim = _tnl_translate_prim(&VB->Primitive[i]);
       GLuint start = VB->Primitive[i].start;
       GLuint length = VB->Primitive[i].count;
 
@@ -319,84 +506,15 @@ static GLboolean r200_run_tcl_render( GLcontext *ctx,
 
 
 
-static void r200_check_tcl_render( GLcontext *ctx,
-                                  struct tnl_pipeline_stage *stage )
-{
-   r200ContextPtr rmesa = R200_CONTEXT(ctx);
-   GLuint inputs = VERT_BIT_POS;
-   GLuint unit;
-
-   /* Validate state:
-    */
-   if (rmesa->NewGLState)
-      r200ValidateState( ctx );
-
-   if (ctx->RenderMode == GL_RENDER) {
-      /* Make all this event-driven:
-       */
-      if (ctx->Light.Enabled) {
-        inputs |= VERT_BIT_NORMAL;
-
-        if (1 || ctx->Light.ColorMaterialEnabled) {
-           inputs |= VERT_BIT_COLOR0;
-        }
-      }
-      else {
-        inputs |= VERT_BIT_COLOR0;
-        
-        if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) {
-           inputs |= VERT_BIT_COLOR1;
-        }
-      }
-
-      for (unit = 0 ; unit < ctx->Const.MaxTextureUnits; unit++) {
-        if (ctx->Texture.Unit[unit]._ReallyEnabled) {
-           if (ctx->Texture.Unit[unit].TexGenEnabled) {
-              if (rmesa->TexGenNeedNormals[unit]) {
-                 inputs |= VERT_BIT_NORMAL;
-              }
-           } else {
-              inputs |= VERT_BIT_TEX(unit);
-           }
-        }
-      }
-
-      stage->inputs = inputs;
-      stage->active = 1;
-   }
-   else
-      stage->active = 0;
-}
-
-static void r200_init_tcl_render( GLcontext *ctx,
-                                   struct tnl_pipeline_stage *stage )
-{
-   stage->check = r200_check_tcl_render;
-   stage->check( ctx, stage );
-}
-
-static void dtr( struct tnl_pipeline_stage *stage )
-{
-   (void)stage;
-}
-
-
 /* Initial state for tcl stage.  
  */
 const struct tnl_pipeline_stage _r200_tcl_stage =
 {
    "r200 render",
-   (_DD_NEW_SEPARATE_SPECULAR |
-    _NEW_LIGHT|
-    _NEW_TEXTURE|
-    _NEW_FOG|
-    _NEW_RENDERMODE),          /* re-check (new inputs) */
-   0,                          /* re-run (always runs) */
-   GL_TRUE,                    /* active */
-   0, 0,                       /* inputs (set in check_render), outputs */
-   0, 0,                       /* changed_inputs, private */
-   dtr,                                /* destructor */
-   r200_init_tcl_render,       /* check - initially set to alloc data */
+   NULL,                       /*  private */
+   NULL,
+   NULL,
+   NULL,
    r200_run_tcl_render /* run */
 };
 
@@ -433,19 +551,7 @@ static void transition_to_swtnl( GLcontext *ctx )
     * need to put the card into D3D mode to make it work:
     */
    R200_STATECHANGE( rmesa, vap );
-   rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL] &= ~R200_VAP_TCL_ENABLE;
-   rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL] |= R200_VAP_D3D_TEX_DEFAULT;
-
-   R200_STATECHANGE( rmesa, vte );
-   rmesa->hw.vte.cmd[VTE_SE_VTE_CNTL] &= ~R200_VTX_W0_FMT;
-
-   R200_STATECHANGE( rmesa, set );
-   rmesa->hw.set.cmd[SET_RE_CNTL] |= (R200_VTX_STQ0_D3D |
-                                     R200_VTX_STQ1_D3D |
-                                     R200_VTX_STQ2_D3D |
-                                     R200_VTX_STQ3_D3D |
-                                     R200_VTX_STQ4_D3D |
-                                     R200_VTX_STQ5_D3D);
+   rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL] &= ~(R200_VAP_TCL_ENABLE|R200_VAP_PROG_VTX_SHADER_ENABLE);
 }
 
 static void transition_to_hwtnl( GLcontext *ctx )
@@ -462,7 +568,7 @@ static void transition_to_hwtnl( GLcontext *ctx )
    if ( rmesa->dma.flush )                     
       rmesa->dma.flush( rmesa );       
 
-   rmesa->dma.flush = 0;
+   rmesa->dma.flush = NULL;
    
    if (rmesa->swtcl.indexed_verts.buf) 
       r200ReleaseDmaRegion( rmesa, &rmesa->swtcl.indexed_verts, 
@@ -470,22 +576,24 @@ static void transition_to_hwtnl( GLcontext *ctx )
 
    R200_STATECHANGE( rmesa, vap );
    rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL] |= R200_VAP_TCL_ENABLE;
-   rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL] &= ~(R200_VAP_FORCE_W_TO_ONE |
-                                          R200_VAP_D3D_TEX_DEFAULT);
+   rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL] &= ~R200_VAP_FORCE_W_TO_ONE;
+
+   if (ctx->VertexProgram._Enabled) {
+      rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL] |= R200_VAP_PROG_VTX_SHADER_ENABLE;
+   }
+
+   if ( ((rmesa->hw.ctx.cmd[CTX_PP_FOG_COLOR] & R200_FOG_USE_MASK)
+      == R200_FOG_USE_SPEC_ALPHA) &&
+      (ctx->Fog.FogCoordinateSource == GL_FOG_COORD )) {
+      R200_STATECHANGE( rmesa, ctx );
+      rmesa->hw.ctx.cmd[CTX_PP_FOG_COLOR] &= ~R200_FOG_USE_MASK;
+      rmesa->hw.ctx.cmd[CTX_PP_FOG_COLOR] |= R200_FOG_USE_VTX_FOG;
+   }
 
    R200_STATECHANGE( rmesa, vte );
    rmesa->hw.vte.cmd[VTE_SE_VTE_CNTL] &= ~(R200_VTX_XY_FMT|R200_VTX_Z_FMT);
    rmesa->hw.vte.cmd[VTE_SE_VTE_CNTL] |= R200_VTX_W0_FMT;
 
-   R200_STATECHANGE( rmesa, set );
-   rmesa->hw.set.cmd[SET_RE_CNTL] &= ~(R200_VTX_STQ0_D3D |
-                                      R200_VTX_STQ1_D3D |
-                                      R200_VTX_STQ2_D3D |
-                                      R200_VTX_STQ3_D3D |
-                                      R200_VTX_STQ4_D3D |
-                                      R200_VTX_STQ5_D3D);
-
-
    if (R200_DEBUG & DEBUG_FALLBACKS) 
       fprintf(stderr, "R200 end tcl fallback\n");
 }
@@ -503,7 +611,8 @@ static char *fallbackStrings[] = {
    "Texgen unit 4",
    "Texgen unit 5",
    "User disable",
-   "Bitmap as points"
+   "Bitmap as points",
+   "Vertex program"
 };