new fxDDClear(), fxDDDrawBitmp(), example extension registration code
[mesa.git] / src / mesa / drivers / glide / fxdd.c
index d7e7293b218e23fb419b041a508bc09526fd84a1..6fd6a1e69e184f6e69b509429b7dab43313d29cf 100644 (file)
 
 #if defined(FX)
 
+#include "image.h"
 #include "types.h"
 #include "fxdrv.h"
 #include "enums.h"
 #include "extensions.h"
-
+#include "pb.h"
 
 /* These lookup table are used to extract RGB values in [0,255] from
  * 16-bit pixel values.
@@ -169,95 +170,110 @@ static void fxDDClearColor(GLcontext *ctx, GLubyte red, GLubyte green,
   fxMesa->clearA=alpha;
 }
 
+
 /* Clear the color and/or depth buffers */
 static GLbitfield fxDDClear(GLcontext *ctx, GLbitfield mask, GLboolean all,
                             GLint x, GLint y, GLint width, GLint height )
 {
   fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
   const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask);
+  const FxU16 clearD = (FxU16) (ctx->Depth.Clear * 0xffff);
   GLbitfield softwareMask = mask & (DD_STENCIL_BIT | DD_ACCUM_BIT);
-  GLbitfield newMask = mask & ~(DD_STENCIL_BIT | DD_ACCUM_BIT);
 
-  if (MESA_VERBOSE&VERBOSE_DRIVER) {
+  if (MESA_VERBOSE & VERBOSE_DRIVER) {
     fprintf(stderr,"fxmesa: fxDDClear(%d,%d,%d,%d)\n", (int) x, (int) y,
             (int) width, (int) height);
   }
 
-  if (mask == (DD_BACK_LEFT_BIT | DD_DEPTH_BIT)
-      && colorMask == 0xffffffff) {
-    /* common case: clear back color buffer and depth buffer */
-    FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
-    FX_grBufferClear(fxMesa->clearC, fxMesa->clearA,
-                     (FxU16)(ctx->Depth.Clear*0xffff));
-    return 0;
-  }
-
-  /* depth masking */
-  if (newMask & DD_DEPTH_BIT) {
-    FX_grDepthMask(FXTRUE);
-    CLEAR_BITS(newMask, DD_DEPTH_BIT);
-  }
-  else {
-    FX_grDepthMask(FXFALSE);
-  }
-
   if (colorMask != 0xffffffff) {
-    /* do masked color clear in software */
-    softwareMask |= (newMask & (DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT));
-    CLEAR_BITS(newMask, (DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT));
+    /* do color buffer clears in software */
+    softwareMask |= (mask & (DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT));
+    mask &= ~(DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT);
   }
 
-  if (newMask & (DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT)) {
-    if (newMask & DD_FRONT_LEFT_BIT) {
-      if (mask & DD_DEPTH_BIT) {
-        /* XXX it appears that the depth buffer isn't cleared when
-         * glRenderBuffer(GR_BUFFER_FRONTBUFFER) is set.
-         * This is a work-around/
-         */
-        FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
-        FX_grColorMask(FXFALSE,FXFALSE);
-        FX_grBufferClear(fxMesa->clearC, fxMesa->clearA,
-                         (FxU16)(ctx->Depth.Clear*0xffff));
-        FX_grColorMask(ctx->Color.ColorMask[RCOMP] ||
-                       ctx->Color.ColorMask[GCOMP] ||
-                       ctx->Color.ColorMask[BCOMP],
-                       ctx->Color.ColorMask[ACOMP] && fxMesa->haveAlphaBuffer);
+  /*
+   * This could probably be done fancier but doing each possible case
+   * explicitly is less error prone.
+   */
+  switch (mask) {
+    case DD_BACK_LEFT_BIT | DD_DEPTH_BIT:
+      /* back buffer & depth */
+      FX_grDepthMask(FXTRUE);
+      FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
+      FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
+      if (!ctx->Depth.Mask) {
+        FX_grDepthMask(FXFALSE);
       }
+      break;
+    case DD_FRONT_LEFT_BIT | DD_DEPTH_BIT:
+      /* XXX it appears that the depth buffer isn't cleared when
+       * glRenderBuffer(GR_BUFFER_FRONTBUFFER) is set.
+       * This is a work-around/
+       */
+      /* clear depth */
+      FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
+      FX_grColorMask(FXFALSE,FXFALSE);
+      FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
+      /* clear front */
+      FX_grColorMask(FXTRUE, ctx->Color.ColorMask[ACOMP] && fxMesa->haveAlphaBuffer);
       FX_grRenderBuffer(GR_BUFFER_FRONTBUFFER);
-      FX_grBufferClear(fxMesa->clearC, fxMesa->clearA,
-                       (FxU16)(ctx->Depth.Clear*0xffff));
-    }
-
-    if (newMask & DD_BACK_LEFT_BIT) {
+      FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
+      break;
+    case DD_BACK_LEFT_BIT:
+      /* back buffer only */
+      FX_grDepthMask(FXFALSE);
+      FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
+      FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
+      if (!ctx->Depth.Mask) {
+        FX_grDepthMask(FXFALSE);
+      }
+      break;
+    case DD_FRONT_LEFT_BIT:
+      /* front buffer only */
+      FX_grDepthMask(FXFALSE);
+      FX_grRenderBuffer(GR_BUFFER_FRONTBUFFER);
+      FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
+      if (!ctx->Depth.Mask) {
+        FX_grDepthMask(FXFALSE);
+      }
+      break;
+    case DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT:
+      /* front and back */
+      FX_grDepthMask(FXFALSE);
+      FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
+      FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
+      FX_grRenderBuffer(GR_BUFFER_FRONTBUFFER);
+      FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
+      if (!ctx->Depth.Mask) {
+        FX_grDepthMask(FXFALSE);
+      }
+      break;
+    case DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT | DD_DEPTH_BIT:
+      /* clear front */
+      FX_grDepthMask(FXFALSE);
+      FX_grRenderBuffer(GR_BUFFER_FRONTBUFFER);
+      FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
+      /* clear back and depth */
+      FX_grDepthMask(FXTRUE);
       FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
+      FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
+      if (!ctx->Depth.Mask) {
+        FX_grDepthMask(FXFALSE);
+      }
+      break;
+    case DD_DEPTH_BIT:
+      /* just the depth buffer */
+      FX_grColorMask(FXFALSE,FXFALSE);
       FX_grBufferClear(fxMesa->clearC, fxMesa->clearA,
                        (FxU16)(ctx->Depth.Clear*0xffff));
-    }
-
-    CLEAR_BITS(newMask, (DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT));
-  }
-  else if (mask & DD_DEPTH_BIT) {
-    /* clear depth but not color */
-    FX_grColorMask(FXFALSE,FXFALSE);
-    FX_grBufferClear(fxMesa->clearC, fxMesa->clearA,
-                     (FxU16)(ctx->Depth.Clear*0xffff));
-    FX_grColorMask(ctx->Color.ColorMask[RCOMP] ||
-                   ctx->Color.ColorMask[GCOMP] ||
-                   ctx->Color.ColorMask[BCOMP],
-                   ctx->Color.ColorMask[ACOMP] && fxMesa->haveAlphaBuffer);
-  }
-
-  /* Restore depth mask state */
-  if (mask & DD_DEPTH_BIT) {
-    if (ctx->Depth.Mask) {
-      FX_grDepthMask(FXTRUE);
-    }
-    else {
-      FX_grDepthMask(FXFALSE);
-    }
+      FX_grColorMask(FXTRUE, ctx->Color.ColorMask[ACOMP] && fxMesa->haveAlphaBuffer);
+      break;
+    default:
+      /* error */
+      ;
   }
 
-  return newMask | softwareMask;
+  return softwareMask;
 }
 
 
@@ -311,11 +327,10 @@ static void fxDDSetReadBuffer(GLcontext *ctx, GLframebuffer *buffer,
 
 
 #ifdef XF86DRI
+/* test if window coord (px,py) is visible */
 static GLboolean inClipRects(fxMesaContext fxMesa, int px, int py)
 {
   int i;
-
-  py=fxMesa->height+fxMesa->y_offset-py;
   for (i=0; i<fxMesa->numClipRects; i++) {
     if ((px>=fxMesa->pClipRects[i].x1) && 
        (px<fxMesa->pClipRects[i].x2) &&
@@ -333,127 +348,165 @@ static GLboolean fxDDDrawBitMap(GLcontext *ctx, GLint px, GLint py,
                                 const GLubyte *bitmap)
 {
   fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
-  FxU16 *p;
   GrLfbInfo_t info;
-  const GLubyte *pb;
-  int x,y,xmin,xmax,ymin,ymax;
-  GLint r,g,b,a,scrwidth,scrheight,stride;
   FxU16 color;
-
-  /* TODO: with a little work, these bitmap unpacking parameter restrictions
-   * could be removed.
-   */
-  if((unpack->Alignment!=1) ||
-     (unpack->RowLength!=0) ||
-     (unpack->SkipPixels!=0) ||
-     (unpack->SkipRows!=0) ||
-     (unpack->SwapBytes) ||
-     (unpack->LsbFirst))
+  const struct gl_pixelstore_attrib *finalUnpack;
+  struct gl_pixelstore_attrib scissoredUnpack;
+
+  /* check if there's any raster operations enabled which we can't handle */
+  if (ctx->RasterMask & (ALPHATEST_BIT |
+                         BLEND_BIT |
+                         DEPTH_BIT |
+                         FOG_BIT |
+                         LOGIC_OP_BIT |
+                         SCISSOR_BIT |
+                         STENCIL_BIT |
+                         MASKING_BIT |
+                         ALPHABUF_BIT |
+                         MULTI_DRAW_BIT))
     return GL_FALSE;
 
   if (ctx->Scissor.Enabled) {
-        xmin=ctx->Scissor.X;
-        xmax=ctx->Scissor.X+ctx->Scissor.Width;
-        ymin=ctx->Scissor.Y;
-        ymax=ctx->Scissor.Y+ctx->Scissor.Height;
-  } else {
-        xmin=0;
-        xmax=fxMesa->width;
-        ymin=0;
-        ymax=fxMesa->height;
-  }
-
-  xmin+=fxMesa->x_offset;
-  xmax+=fxMesa->x_offset;
-
-#ifdef XF86DRI
-#define ISCLIPPED(rx, ry) ( ((rx)<xmin) || ((rx)>=xmax) || !inClipRects(fxMesa, rx, ry))
-#else
-#define ISCLIPPED(rx, ry) ( ((rx)<xmin) || ((rx)>=xmax) )
-#endif
-#define DRAWBIT(i) {       \
-  if(!ISCLIPPED(x+px, y))  \
-    if( (*pb) & (1<<(i)) ) \
-      (*p)=color;          \
-  p++;                     \
-  x++;                     \
-  if(x>=width) {           \
-    pb++;                  \
-    break;                 \
-  }                        \
-}
-
-  scrwidth=fxMesa->width;
-  scrheight=fxMesa->height;
-
-  if ((px>=scrwidth) || (px+width<=0) || (py>=scrheight) || (py+height<=0))
-    return GL_TRUE;
+    /* This is a bit tricky, but by carefully adjusting the px, py,
+     * width, height, skipPixels and skipRows values we can do
+     * scissoring without special code in the rendering loop.
+     */
 
-  pb=bitmap;
+    /* we'll construct a new pixelstore struct */
+    finalUnpack = &scissoredUnpack;
+    scissoredUnpack = *unpack;
+    if (scissoredUnpack.RowLength == 0)
+      scissoredUnpack.RowLength = width;
+
+    /* clip left */
+    if (px < ctx->Scissor.X) {
+      scissoredUnpack.SkipPixels += (ctx->Scissor.X - px);
+      width -= (ctx->Scissor.X - px);
+      px = ctx->Scissor.X;
+    }
+    /* clip right */
+    if (px + width >= ctx->Scissor.X + ctx->Scissor.Width) {
+      width -= (px + width - (ctx->Scissor.X + ctx->Scissor.Width));
+    }
+    /* clip bottom */
+    if (py < ctx->Scissor.Y) {
+      scissoredUnpack.SkipRows += (ctx->Scissor.Y - py);
+      height -= (ctx->Scissor.Y - py);
+      py = ctx->Scissor.Y;
+    }
+    /* clip top */
+    if (py + height >= ctx->Scissor.Y + ctx->Scissor.Height) {
+      height -= (py + height - (ctx->Scissor.Y + ctx->Scissor.Height));
+    }
 
-  if(py<0) {
-    pb+=(height*(-py)) >> (3+1);
-    height+=py;
-    py=0;
+    if (width <= 0 || height <= 0)
+      return GL_TRUE;  /* totally scissored away */
+  }  
+  else {
+    finalUnpack = unpack;
   }
 
-  if (py+height>=scrheight)
-    height-=(py+height)-scrheight;
+  /* compute pixel value */
+  {
+    GLint r = (GLint) (ctx->Current.RasterColor[0] * 255.0f);
+    GLint g = (GLint) (ctx->Current.RasterColor[1] * 255.0f);
+    GLint b = (GLint) (ctx->Current.RasterColor[2] * 255.0f);
+    /*GLint a = (GLint)(ctx->Current.RasterColor[3]*255.0f);*/
+    if (fxMesa->bgrOrder)
+      color = (FxU16)
+        ( ((FxU16)0xf8 & b) << (11-3))  |
+        ( ((FxU16)0xfc & g) << (5-3+1)) |
+        ( ((FxU16)0xf8 & r) >> 3);
+    else
+      color = (FxU16)
+        ( ((FxU16)0xf8 & r) << (11-3))  |
+        ( ((FxU16)0xfc & g) << (5-3+1)) |
+        ( ((FxU16)0xf8 & b) >> 3);
+  }
 
-  info.size=sizeof(info);
-  if(!FX_grLfbLock(GR_LFB_WRITE_ONLY,
-                  fxMesa->currentFB,
-                  GR_LFBWRITEMODE_565,
-                  GR_ORIGIN_UPPER_LEFT,
-                  FXFALSE,
-                  &info)) {
+  info.size = sizeof(info);
+  if (!FX_grLfbLock(GR_LFB_WRITE_ONLY,
+                    fxMesa->currentFB,
+                    GR_LFBWRITEMODE_565,
+                    GR_ORIGIN_UPPER_LEFT,
+                    FXFALSE,
+                    &info)) {
 #ifndef FX_SILENT
     fprintf(stderr,"fx Driver: error locking the linear frame buffer\n");
 #endif
     return GL_TRUE;
   }
 
-  r=(GLint)(ctx->Current.RasterColor[0]*255.0f);
-  g=(GLint)(ctx->Current.RasterColor[1]*255.0f);
-  b=(GLint)(ctx->Current.RasterColor[2]*255.0f);
-  a=(GLint)(ctx->Current.RasterColor[3]*255.0f);
-  if (fxMesa->bgrOrder)
-    color=(FxU16)
-      ( ((FxU16)0xf8 & b) <<(11-3))  |
-      ( ((FxU16)0xfc & g) <<(5-3+1)) |
-      ( ((FxU16)0xf8 & r) >> 3);
-  else
-    color=(FxU16)
-      ( ((FxU16)0xf8 & r) <<(11-3))  |
-      ( ((FxU16)0xfc & g) <<(5-3+1)) |
-      ( ((FxU16)0xf8 & b) >> 3);
-
-  stride=info.strideInBytes>>1;
-
-  /* This code is a bit slow... */
-
-  if (py>ymin) ymin=py;
-  if (py+height<ymax) ymax=py+height;
-
-  px+=fxMesa->x_offset;
-  scrheight=fxMesa->height+fxMesa->y_offset;
-
-  for(y=ymin; y<ymax; y++) {
-
-    p=((FxU16 *)info.lfbPtr)+px+((scrheight-y)*stride);
+#ifdef XF86DRI
+#define INSIDE(c, x, y) inClipRects((c), (x), (y))
+#else
+#define INSIDE(c, x, y) (1)
+#endif
 
-    for(x=0;;) {
-      DRAWBIT(7);       DRAWBIT(6);     DRAWBIT(5);     DRAWBIT(4);
-      DRAWBIT(3);       DRAWBIT(2);     DRAWBIT(1);     DRAWBIT(0);
-      pb++;
+  {
+    const GLint winX = fxMesa->x_offset;
+    const GLint winY = fxMesa->y_offset + fxMesa->height - 1;
+#ifdef XF86DRI
+    const GLint dstStride = fxMesa->screen_width;
+#else
+    const GLint dstStride = info.strideInBytes / 2; /* stride in GLushorts */
+#endif
+    GLint row;
+    /* compute dest address of bottom-left pixel in bitmap */
+    GLushort *dst = (GLushort *) info.lfbPtr
+                  + (winY - py) * dstStride
+                  + (winX + px);
+
+    for (row = 0; row < height; row++) {
+      const GLubyte *src = (const GLubyte *) gl_pixel_addr_in_image( finalUnpack,
+                 bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, 0, row, 0 );
+      if (finalUnpack->LsbFirst) {
+        /* least significan bit first */
+        GLubyte mask = 1U << (finalUnpack->SkipPixels & 0x7);
+        GLint col;
+        for (col=0; col<width; col++) {
+          if (*src & mask) {
+            if (INSIDE(fxMesa, winX + px + col, winY - py - row))
+              dst[col] = color;
+          }
+          if (mask == 128U) {
+            src++;
+            mask = 1U;
+          }
+          else {
+            mask = mask << 1;
+          }
+        }
+        if (mask != 1)
+          src++;
+      }
+      else {
+        /* most significan bit first */
+        GLubyte mask = 128U >> (finalUnpack->SkipPixels & 0x7);
+        GLint col;
+        for (col=0; col<width; col++) {
+          if (*src & mask) {
+            if (INSIDE(fxMesa, winX + px + col, winY - py - row))
+              dst[col] = color;
+          }
+          if (mask == 1U) {
+            src++;
+            mask = 128U;
+          }
+          else {
+            mask = mask >> 1;
+          }
+        }
+        if (mask != 128)
+          src++;
+      }
+      dst -= dstStride;
     }
   }
 
-  FX_grLfbUnlock(GR_LFB_WRITE_ONLY,fxMesa->currentFB);
-
-#undef ISCLIPPED
-#undef DRAWBIT
+#undef INSIDE
 
+  FX_grLfbUnlock(GR_LFB_WRITE_ONLY,fxMesa->currentFB);
   return GL_TRUE;
 }
 
@@ -510,7 +563,7 @@ static const GLubyte *fxDDGetString(GLcontext *ctx, GLenum name)
           }
         }
         /* now make the GL_RENDERER string */
-        sprintf(buffer, "Mesa DRI %s 20000208", hardware);
+        sprintf(buffer, "Mesa DRI %s 20000224", hardware);
         return buffer;
       }
     case GL_VENDOR:
@@ -692,28 +745,55 @@ int fxDDInitFxMesaContext( fxMesaContext fxMesa )
 }
 
 
-
+#if 0
+/* Example extension function */
+static void fxFooBarEXT(GLint i)
+{
+   printf("You called glFooBarEXT(%d)\n", i);
+}
+#endif
 
 
 void fxDDInitExtensions( GLcontext *ctx )
 {
    fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
 
-   gl_extensions_add( ctx, DEFAULT_ON, "3DFX_set_global_palette", 0 );
-   gl_extensions_add( ctx, DEFAULT_ON, "GL_FXMESA_global_texture_lod_bias", 0);
+   gl_extensions_disable(ctx, "GL_EXT_blend_logic_op");
+   gl_extensions_disable(ctx, "GL_EXT_blend_minmax");
+   gl_extensions_disable(ctx, "GL_EXT_blend_subtract");
+   gl_extensions_disable(ctx, "GL_EXT_blend_color");
+   gl_extensions_disable(ctx, "GL_EXT_paletted_texture");
+
+   gl_extensions_add(ctx, DEFAULT_ON, "3DFX_set_global_palette", 0);
+   gl_extensions_add(ctx, DEFAULT_ON, "GL_FXMESA_global_texture_lod_bias", 0);
    
-   if(fxMesa->haveTwoTMUs)
-      gl_extensions_add( ctx, DEFAULT_ON, "GL_EXT_texture_env_add", 0);
+   if (!fxMesa->haveTwoTMUs)
+      gl_extensions_disable(ctx, "GL_EXT_texture_env_add");
    
    if (!fxMesa->emulateTwoTMUs) 
-      gl_extensions_disable( ctx, "GL_ARB_multitexture" );
+      gl_extensions_disable(ctx, "GL_ARB_multitexture");
+
+
+   /* Example of hooking in an extension function.
+    * For DRI-based drivers, also see __driRegisterExtensions in the
+    * tdfx_xmesa.c file.
+    */
+#if 0
+   {
+     void **dispatchTable = (void **) ctx->Exec;
+     const int _gloffset_FooBarEXT = 555;  /* just an example number! */
+     const int tabSize = _glapi_get_dispatch_table_size();
+     assert(_gloffset_FooBarEXT < tabSize);
+     dispatchTable[_gloffset_FooBarEXT] = (void *) fxFooBarEXT;
+     /* XXX You would also need to hook into the display list dispatch
+      * table.  Really, the implementation of extensions might as well
+      * be in the core of Mesa since core Mesa and the device driver
+      * is one big shared lib.
+      */
+  }
+#endif
 }
 
-/*
-  This driver may need to move the drawing operations to a different sub
-  window. This modifies the viewport command to add our X,Y offset to all
-  drawn objects that go through the viewport transformation.
-*/
 
 /************************************************************************/
 /************************************************************************/
@@ -847,6 +927,16 @@ static void fxDDUpdateDDPointers(GLcontext *ctx)
   }
 }
 
+static void fxDDReducedPrimitiveChange(GLcontext *ctx, GLenum prim)
+{
+  if (ctx->Polygon.CullFlag) {
+    if (ctx->PB->primitive != GL_POLYGON) { /* Lines or Points */
+      FX_grCullMode(GR_CULL_DISABLE);
+      FX_CONTEXT(ctx)->cullMode=GR_CULL_DISABLE;
+    }
+  }
+}
+
 void fxSetupDDPointers(GLcontext *ctx)
 {
   if (MESA_VERBOSE&VERBOSE_DRIVER) {
@@ -910,6 +1000,7 @@ void fxSetupDDPointers(GLcontext *ctx)
   ctx->Driver.CullFace=fxDDCullFace;
   ctx->Driver.ShadeModel=fxDDShadeModel;
   ctx->Driver.Enable=fxDDEnable;
+  ctx->Driver.ReducedPrimitiveChange=fxDDReducedPrimitiveChange;
 
   ctx->Driver.RegisterVB=fxDDRegisterVB;
   ctx->Driver.UnregisterVB=fxDDUnregisterVB;