- Fake projective textures on a single texture unit. A fallback is only
authorFelix Kuehling <fxkuehl@gmx.de>
Wed, 22 Dec 2004 00:21:32 +0000 (00:21 +0000)
committerFelix Kuehling <fxkuehl@gmx.de>
Wed, 22 Dec 2004 00:21:32 +0000 (00:21 +0000)
  needed if a second texture unit is enabled.
- Also worked around an application bug in Chromium B.S.U.: it sends 3D
  texture coordinates while only a 2D texture is enabled. This used to
  trigger a PTEX fallback. Now the 3rd coordinate is just ignored.
- Fixed the _savage_texnorm_stage to never normalize homogenous texture
  coordinates.

src/mesa/drivers/dri/savage/savagecontext.h
src/mesa/drivers/dri/savage/savagedma.c
src/mesa/drivers/dri/savage/savagetris.c

index 24bde237c350e627afd64132821956b760b7d328..f41b73e0de53f5973800a97745af32c476abaf6d 100644 (file)
@@ -141,6 +141,7 @@ struct savage_context_t {
     /* Manage our own state */
     GLuint new_state; 
     GLuint new_gl_state;
+    GLboolean ptexHack;
 
     GLuint BCIBase;  
     GLuint MMIO_BASE;
@@ -179,6 +180,7 @@ struct savage_context_t {
    GLenum render_primitive;
 
    GLuint DrawPrimitiveCmd;
+   GLuint HwVertexSize;
 
    /* Fallback rasterization functions 
     */
index eab13862607023e221d9387bd1616ed651323f91..86ee763a31fb9b06bbfecc0f706c774e8f458995 100644 (file)
@@ -312,8 +312,8 @@ static drmBuf vertex_buffer = {
 };
 
 void savageFakeVertices (savageContextPtr imesa, drmBufPtr buffer) {
-    GLuint vertexStride = imesa->vertex_size; /* stride in dwords */
-    GLuint vertexSize = imesa->vertex_size; /* the real vertex size in dwords */
+    GLuint vertexStride = imesa->HwVertexSize; /* stride in dwords */
+    GLuint vertexSize = imesa->HwVertexSize; /* the real vertex size in dwords */
     GLuint nVertices = buffer->used / (vertexStride*4);
     u_int32_t *data = (u_int32_t*)buffer->address;
     u_int32_t vertexFormat = imesa->DrawPrimitiveCmd & SAVAGE_HW_SKIPFLAGS;
index 55c2f7f76629811e153a8d7bb5d74bfa774902e3..666863a8ee70c5ae1f448523c265263c0d946a3b 100644 (file)
@@ -77,14 +77,14 @@ static GLenum reduced_prim[GL_POLYGON+1] = {
  ***********************************************************************/
 
 #if defined (USE_X86_ASM)
-#define EMIT_VERT( j, vb, vertex_size, start, v )      \
-do {   int __tmp;                                      \
-        vb += start;                                   \
-       __asm__ __volatile__( "rep ; movsl"             \
-                        : "=%c" (j), "=D" (vb), "=S" (__tmp)           \
-                        : "0" (vertex_size-start),     \
-                          "D" ((long)vb),              \
-                          "S" ((long)&v->ui[start]));  \
+#define EMIT_VERT( j, vb, vertex_size, start, v )              \
+do {   int __tmp;                                              \
+        vb += start;                                           \
+       __asm__ __volatile__( "rep ; movsl"                     \
+                        : "=%c" (j), "=D" (vb), "=S" (__tmp)   \
+                        : "0" (vertex_size-start),             \
+                          "D" ((long)vb),                      \
+                          "S" ((long)&(v)->ui[start]));        \
 } while (0)
 #else
 #define EMIT_VERT( j, vb, vertex_size, start, v )      \
@@ -99,7 +99,7 @@ static void __inline__ savage_draw_triangle (savageContextPtr imesa,
                                             savageVertexPtr v0,
                                             savageVertexPtr v1,
                                             savageVertexPtr v2) {
-   GLuint vertsize = imesa->vertex_size;
+   GLuint vertsize = imesa->HwVertexSize;
    u_int32_t *vb = savageAllocDmaLow (imesa, 3*4*vertsize);
    GLuint j;
 
@@ -113,7 +113,7 @@ static void __inline__ savage_draw_quad (savageContextPtr imesa,
                                         savageVertexPtr v1,
                                         savageVertexPtr v2,
                                         savageVertexPtr v3) {
-   GLuint vertsize = imesa->vertex_size;
+   GLuint vertsize = imesa->HwVertexSize;
    u_int32_t *vb = savageAllocDmaLow (imesa, 6*4*vertsize);
    GLuint j;
 
@@ -127,7 +127,7 @@ static void __inline__ savage_draw_quad (savageContextPtr imesa,
 
 static __inline__ void savage_draw_point (savageContextPtr imesa,
                                          savageVertexPtr tmp) {
-   GLuint vertsize = imesa->vertex_size;
+   GLuint vertsize = imesa->HwVertexSize;
    u_int32_t *vb = savageAllocDmaLow (imesa, 6*4*vertsize);
    const GLfloat x = tmp->v.x;
    const GLfloat y = tmp->v.y;
@@ -162,7 +162,7 @@ static __inline__ void savage_draw_point (savageContextPtr imesa,
 static __inline__ void savage_draw_line (savageContextPtr imesa,
                                         savageVertexPtr v0,
                                         savageVertexPtr v1 ) {
-   GLuint vertsize = imesa->vertex_size;
+   GLuint vertsize = imesa->HwVertexSize;
    u_int32_t *vb = savageAllocDmaLow (imesa, 6*4*vertsize);
    GLfloat width = imesa->glCtx->Line._Width;
    GLfloat dx, dy, ix, iy;
@@ -200,6 +200,117 @@ static __inline__ void savage_draw_line (savageContextPtr imesa,
    *(float *)&vb[1] = v1->v.y + iy;
    EMIT_VERT (j, vb, vertsize, 2, v1);
 } 
+
+/* Fallback drawing functions for the ptex hack. Code duplication
+ * (especially lines and points) isn't beautiful, but I didn't feel
+ * like inventing yet another template. :-/
+ */
+#define PTEX_VERTEX( j, tmp, vertex_size, start, v)    \
+do {                                                   \
+   GLfloat rhw = 1.0 / v->f[vertex_size];              \
+   for ( j = start ; j < vertex_size ; j++ )           \
+      tmp.f[j] = v->f[j];                              \
+   tmp.f[3] *= v->f[vertex_size];                      \
+   tmp.f[vertex_size-2] *= rhw;                                \
+   tmp.f[vertex_size-1] *= rhw;                                \
+} while (0)
+
+static void __inline__ savage_ptex_tri (savageContextPtr imesa,
+                                       savageVertexPtr v0,
+                                       savageVertexPtr v1,
+                                       savageVertexPtr v2) {
+   GLuint vertsize = imesa->HwVertexSize;
+   u_int32_t *vb = savageAllocDmaLow (imesa, 3*4*vertsize);
+   savageVertex tmp;
+   GLuint j;
+
+   PTEX_VERTEX (j, tmp, vertsize, 0, v0); EMIT_VERT (j, vb, vertsize, 0, &tmp);
+   PTEX_VERTEX (j, tmp, vertsize, 0, v1); EMIT_VERT (j, vb, vertsize, 0, &tmp);
+   PTEX_VERTEX (j, tmp, vertsize, 0, v2); EMIT_VERT (j, vb, vertsize, 0, &tmp);
+}
+
+static __inline__ void savage_ptex_line (savageContextPtr imesa,
+                                        savageVertexPtr v0,
+                                        savageVertexPtr v1 ) {
+   GLuint vertsize = imesa->HwVertexSize;
+   u_int32_t *vb = savageAllocDmaLow (imesa, 6*4*vertsize);
+   GLfloat width = imesa->glCtx->Line._Width;
+   GLfloat dx, dy, ix, iy;
+   savageVertex tmp0, tmp1;
+   GLuint j;
+
+   PTEX_VERTEX (j, tmp0, vertsize, 2, v0);
+   PTEX_VERTEX (j, tmp1, vertsize, 2, v1);
+
+   dx = v0->v.x - v1->v.x;
+   dy = v0->v.y - v1->v.y;
+
+   ix = width * .5; iy = 0;
+   if (dx * dx > dy * dy) {
+      iy = ix; ix = 0;
+   }
+
+   *(float *)&vb[0] = v0->v.x - ix;
+   *(float *)&vb[1] = v0->v.y - iy;
+   EMIT_VERT (j, vb, vertsize, 2, &tmp0);
+
+   *(float *)&vb[0] = v1->v.x + ix;
+   *(float *)&vb[1] = v1->v.y + iy;
+   EMIT_VERT (j, vb, vertsize, 2, &tmp1);
+
+   *(float *)&vb[0] = v0->v.x + ix;
+   *(float *)&vb[1] = v0->v.y + iy;
+   EMIT_VERT (j, vb, vertsize, 2, &tmp0);
+
+   *(float *)&vb[0] = v0->v.x - ix;
+   *(float *)&vb[1] = v0->v.y - iy;
+   EMIT_VERT (j, vb, vertsize, 2, &tmp0);
+
+   *(float *)&vb[0] = v1->v.x - ix;
+   *(float *)&vb[1] = v1->v.y - iy;
+   EMIT_VERT (j, vb, vertsize, 2, &tmp1);
+
+   *(float *)&vb[0] = v1->v.x + ix;
+   *(float *)&vb[1] = v1->v.y + iy;
+   EMIT_VERT (j, vb, vertsize, 2, &tmp1);
+} 
+
+static __inline__ void savage_ptex_point (savageContextPtr imesa,
+                                         savageVertexPtr v0) {
+   GLuint vertsize = imesa->HwVertexSize;
+   u_int32_t *vb = savageAllocDmaLow (imesa, 6*4*vertsize);
+   const GLfloat x = v0->v.x;
+   const GLfloat y = v0->v.y;
+   const GLfloat sz = imesa->glCtx->Point._Size * .5;
+   savageVertex tmp;
+   GLuint j;
+
+   PTEX_VERTEX (j, tmp, vertsize, 2, v0);
+
+   *(float *)&vb[0] = x - sz;
+   *(float *)&vb[1] = y - sz;
+   EMIT_VERT (j, vb, vertsize, 2, &tmp);
+
+   *(float *)&vb[0] = x + sz;
+   *(float *)&vb[1] = y - sz;
+   EMIT_VERT (j, vb, vertsize, 2, &tmp);
+
+   *(float *)&vb[0] = x + sz;
+   *(float *)&vb[1] = y + sz;
+   EMIT_VERT (j, vb, vertsize, 2, &tmp);
+
+   *(float *)&vb[0] = x + sz;
+   *(float *)&vb[1] = y + sz;
+   EMIT_VERT (j, vb, vertsize, 2, &tmp);
+
+   *(float *)&vb[0] = x - sz;
+   *(float *)&vb[1] = y + sz;
+   EMIT_VERT (j, vb, vertsize, 2, &tmp);
+
+   *(float *)&vb[0] = x - sz;
+   *(float *)&vb[1] = y - sz;
+   EMIT_VERT (j, vb, vertsize, 2, &tmp);
+}
  
 /***********************************************************************
  *          Macros for t_dd_tritmp.h to draw basic primitives          *
@@ -591,6 +702,18 @@ static void savageChooseRenderState(GLcontext *ctx)
    GLuint flags = ctx->_TriangleCaps;
    GLuint index = 0;
 
+   /* Hook in fallback functions for the ptex hack. Do this first, so
+    * that a real fallback will overwrite them with the respective
+    * savage_fallback_... function.
+    */
+   if (imesa->ptexHack) {
+      /* Do textures make sense with points? */
+      imesa->draw_point = savage_ptex_point;
+      imesa->draw_line = savage_ptex_line;
+      imesa->draw_tri = savage_ptex_tri;
+      index |= SAVAGE_FALLBACK_BIT;
+   }
+
    if (flags & (ANY_RASTER_FLAGS|ANY_FALLBACK_FLAGS)) {
       imesa->draw_point = savage_draw_point;
       imesa->draw_line = savage_draw_line;
@@ -604,7 +727,7 @@ static void savageChooseRenderState(GLcontext *ctx)
 
       /* Hook in fallbacks for specific primitives.
        */
-      if (flags & (POINT_FALLBACK|LINE_FALLBACK|TRI_FALLBACK)) {
+      if (flags & ANY_FALLBACK_FLAGS) {
         if (flags & POINT_FALLBACK) imesa->draw_point = savage_fallback_point;
         if (flags & LINE_FALLBACK)  imesa->draw_line = savage_fallback_line;
         if (flags & TRI_FALLBACK)   imesa->draw_tri = savage_fallback_tri;
@@ -706,6 +829,28 @@ static void savageRenderPrimitive( GLcontext *ctx, GLenum prim )
    }
 }
 
+/* Check if projective texture coordinates are used and if we can fake
+ * them. Fallback to swrast we can't. Returns GL_TRUE if projective
+ * texture coordinates must be faked, GL_FALSE otherwise.
+ */
+static GLboolean savageCheckPTexHack( GLcontext *ctx )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   struct vertex_buffer *VB = &tnl->vb;
+   GLuint index = tnl->render_inputs;
+
+   if (index & _TNL_BIT_TEX(0) && VB->TexCoordPtr[0]->size == 4) {
+      if ((index & _TNL_BITS_TEX_ANY) == _TNL_BIT_TEX(0))
+        return GL_TRUE; /* apply ptex hack */
+      else
+        FALLBACK(ctx, SAVAGE_FALLBACK_PROJ_TEXTURE, GL_TRUE);
+   }
+   if ((index & _TNL_BIT_TEX(1)) && VB->TexCoordPtr[1]->size == 4)
+      FALLBACK(ctx, SAVAGE_FALLBACK_PROJ_TEXTURE, GL_TRUE);
+
+   return GL_FALSE; /* don't apply ptex hack */
+}
+
 
 #define EMIT_ATTR( ATTR, STYLE, INDEX, SKIP )                          \
 do {                                                                   \
@@ -724,17 +869,19 @@ do {                                                                      \
    imesa->vertex_attr_count++;                                         \
 } while (0)
 
-#define SAVAGE_EMIT_XYZ 0x0001
-#define SAVAGE_EMIT_W   0x0002
-#define SAVAGE_EMIT_C0  0x0004
-#define SAVAGE_EMIT_C1  0x0008
-#define SAVAGE_EMIT_FOG 0x0010
-#define SAVAGE_EMIT_S0  0x0020
-#define SAVAGE_EMIT_T0  0x0040
-#define SAVAGE_EMIT_ST0 0x0060
-#define SAVAGE_EMIT_S1  0x0080
-#define SAVAGE_EMIT_T1  0x0100
-#define SAVAGE_EMIT_ST1 0x0180
+#define SAVAGE_EMIT_XYZ  0x0001
+#define SAVAGE_EMIT_W    0x0002
+#define SAVAGE_EMIT_C0   0x0004
+#define SAVAGE_EMIT_C1   0x0008
+#define SAVAGE_EMIT_FOG  0x0010
+#define SAVAGE_EMIT_S0   0x0020
+#define SAVAGE_EMIT_T0   0x0040
+#define SAVAGE_EMIT_Q0   0x0080
+#define SAVAGE_EMIT_ST0  0x0060
+#define SAVAGE_EMIT_STQ0 0x00e0
+#define SAVAGE_EMIT_S1   0x0100
+#define SAVAGE_EMIT_T1   0x0200
+#define SAVAGE_EMIT_ST1  0x0300
 
 
 static void savageRenderStart( GLcontext *ctx )
@@ -745,10 +892,26 @@ static void savageRenderStart( GLcontext *ctx )
    GLuint index = tnl->render_inputs;
    GLuint setupIndex = SAVAGE_EMIT_XYZ;
    GLuint drawCmd = SAVAGE_HW_SKIPFLAGS;
+   GLboolean ptexHack;
    if (imesa->savageScreen->chipset < S3_SAVAGE4)
       drawCmd &= ~SAVAGE_HW_NO_UV1;
    drawCmd &= ~SAVAGE_HW_NO_Z; /* all mesa vertices have a z coordinate */
 
+   /* Check if we need to apply the ptex hack. Choose a new render
+    * state if necessary. (Note: this can't be done in
+    * savageRunPipeline, since the number of vertex coordinates can
+    * change in the pipeline. texmat or texgen or both?) */
+   ptexHack = savageCheckPTexHack( ctx );
+   if (ptexHack != imesa->ptexHack) {
+      imesa->ptexHack = ptexHack;
+      savageChooseRenderState (ctx);
+   }
+   /* Handle fallback cases identified in savageCheckPTexHack. */
+   if (SAVAGE_CONTEXT(ctx)->Fallback) {
+      tnl->Driver.Render.Start(ctx);
+      return;
+   }
+
    /* Important:
     */
    VB->AttribPtr[VERT_ATTRIB_POS] = VB->NdcPtr;
@@ -779,21 +942,22 @@ static void savageRenderStart( GLcontext *ctx )
    }
 
    if (index & _TNL_BIT_TEX(0)) {
-      if (VB->TexCoordPtr[0]->size > 2) {
-        /* projective textures are not supported by the hardware */
-        FALLBACK(ctx, SAVAGE_FALLBACK_PROJ_TEXTURE, GL_TRUE);
-      }
-      if (VB->TexCoordPtr[0]->size == 2)
+      if (ptexHack)
+        EMIT_ATTR( _TNL_ATTRIB_TEX0, EMIT_3F_XYW, SAVAGE_EMIT_STQ0, SAVAGE_HW_NO_UV0);
+      else if (VB->TexCoordPtr[0]->size == 4)
+        assert (0); /* should be caught by savageCheckPTexHack */
+      else if (VB->TexCoordPtr[0]->size >= 2)
+        /* The chromium menu emits some 3D tex coords even though no
+         * 3D texture is enabled. Ignore the 3rd coordinate. */
         EMIT_ATTR( _TNL_ATTRIB_TEX0, EMIT_2F, SAVAGE_EMIT_ST0, SAVAGE_HW_NO_UV0 );
       else
         EMIT_ATTR( _TNL_ATTRIB_TEX0, EMIT_1F, SAVAGE_EMIT_S0, SAVAGE_HW_NO_U0 );
    }
    if (index & _TNL_BIT_TEX(1)) {
-      if (VB->TexCoordPtr[1]->size > 2) {
-        /* projective textures are not supported by the hardware */
-        FALLBACK(ctx, SAVAGE_FALLBACK_PROJ_TEXTURE, GL_TRUE);
-      }
-      if (VB->TexCoordPtr[1]->size == 2)
+      if (VB->TexCoordPtr[1]->size == 4)
+        /* Projective textures are not supported by the hardware */
+        assert (0); /* should be caught by savageCheckPTexHack */
+      else if (VB->TexCoordPtr[1]->size >= 2)
         EMIT_ATTR( _TNL_ATTRIB_TEX1, EMIT_2F, SAVAGE_EMIT_ST1, SAVAGE_HW_NO_UV1 );
       else
         EMIT_ATTR( _TNL_ATTRIB_TEX1, EMIT_1F, SAVAGE_EMIT_S1, SAVAGE_HW_NO_U1 );
@@ -811,14 +975,23 @@ static void savageRenderStart( GLcontext *ctx )
       imesa->SetupIndex = setupIndex;
 
       imesa->DrawPrimitiveCmd = drawCmd;
+      imesa->HwVertexSize = imesa->vertex_size;
+
+      if (setupIndex & SAVAGE_EMIT_Q0) {
+        /* The vertex setup code emits homogenous texture
+         * coordinates. They are converted to normal 2D coords by
+         * savage_ptex_tri/line/point. Now we have two different
+         * vertex sizes. Functions that emit vertices to the hardware
+         * need to use HwVertexSize, anything that manipulates the
+         * vertices generated by t_vertex uses vertex_size. */
+        imesa->HwVertexSize--;
+        assert (imesa->ptexHack);
+      } else
+        assert (!imesa->ptexHack);
    }
 
-   if (!SAVAGE_CONTEXT(ctx)->Fallback) {
-      /* Update hardware state and get the lock */
-      savageDDRenderStart( ctx );
-   } else {
-      tnl->Driver.Render.Start(ctx);
-   }
+   /* Update hardware state and get the lock */
+   savageDDRenderStart( ctx );
 }
 
 static void savageRenderFinish( GLcontext *ctx )
@@ -959,7 +1132,9 @@ static GLboolean run_texnorm_stage( GLcontext *ctx,
       return GL_TRUE;
 
    for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
-      if (!(stage->inputs & stage->changed_inputs & VERT_BIT_TEX(i)))
+      if (!(stage->inputs & stage->changed_inputs & VERT_BIT_TEX(i)) ||
+         VB->TexCoordPtr[i]->size == 4)
+        /* Never try to normalize homogenous tex coords! */
         continue;
 
       GLuint reallyEnabled = ctx->Texture.Unit[i]._ReallyEnabled;