Basic work to support deep color channels:
[mesa.git] / src / mesa / drivers / glide / fxdd.c
index cbe63695fa24cb743842905bc5cc998cbaf1b342..b69b6999ea6328e402067a659ab16752563ef281 100644 (file)
@@ -2,9 +2,9 @@
 
 /*
  * Mesa 3-D graphics library
- * Version:  3.1
+ * Version:  3.3
  *
- * Copyright (C) 1999  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2000  Brian Paul   All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
 
 #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.
@@ -70,9 +71,11 @@ GLubyte FX_PixelToB[0x10000];
  * Initialize the FX_PixelTo{RGB} arrays.
  * Input: bgrOrder - if TRUE, pixels are in BGR order, else RGB order.
  */
-void fxInitPixelTables(GLboolean bgrOrder)
+void fxInitPixelTables(fxMesaContext fxMesa, GLboolean bgrOrder)
 {
   GLuint pixel;
+
+  fxMesa->bgrOrder=bgrOrder;
   for (pixel = 0; pixel <= 0xffff; pixel++) {
     GLuint r, g, b;
     if (bgrOrder) {
@@ -99,23 +102,8 @@ void fxInitPixelTables(GLboolean bgrOrder)
 /*****                 Miscellaneous functions                    *****/
 /**********************************************************************/
 
-/* Enalbe/Disable dithering */
-void fxDDDither(GLcontext *ctx, GLboolean enable)
-{
-  if (MESA_VERBOSE&VERBOSE_DRIVER) {
-    fprintf(stderr,"fxmesa: fxDDDither()\n");
-  }
-
-  if (enable) {
-    FX_grDitherMode(GR_DITHER_4x4);
-  } else {
-    FX_grDitherMode(GR_DITHER_DISABLE);
-  }
-}
-
-
 /* Return buffer size information */
-void fxDDBufferSize(GLcontext *ctx, GLuint *width, GLuint *height)
+static void fxDDBufferSize(GLcontext *ctx, GLuint *width, GLuint *height)
 {
   fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
 
@@ -167,88 +155,130 @@ 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;
-  GLbitfield newmask;
+  const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask);
+  const FxU16 clearD = (FxU16) (ctx->Depth.Clear * 0xffff);
+  GLbitfield softwareMask = mask & (DD_STENCIL_BIT | DD_ACCUM_BIT);
 
-  if (MESA_VERBOSE&VERBOSE_DRIVER) {
-    fprintf(stderr,"fxmesa: fxDDClear(%d,%d,%d,%d)\n",x,y,width,height);
+  /* we can't clear stencil or accum buffers */
+  mask &= ~(DD_STENCIL_BIT | DD_ACCUM_BIT);
+
+  if (MESA_VERBOSE & VERBOSE_DRIVER) {
+    fprintf(stderr,"fxmesa: fxDDClear(%d,%d,%d,%d)\n", (int) x, (int) y,
+            (int) width, (int) height);
   }
 
-  switch(mask & (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)) {
-  case (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT):
-    /* clear color and depth buffer */
+  if (colorMask != 0xffffffff) {
+    /* do masked 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 (ctx->Color.DrawDestMask & BACK_LEFT_BIT) {
+  /*
+   * 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,
-                      (FxU16)(ctx->Depth.Clear*0xffff));
-    }
-    if (ctx->Color.DrawDestMask & FRONT_LEFT_BIT) {
+      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_grDepthMask(FXTRUE);
+      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));
-    }
-
-    newmask=mask & (~(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT));
-    break;
-  case (GL_COLOR_BUFFER_BIT):
-    /* clear color buffer */
-
-    if(ctx->Color.ColorMask) {
+      FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
+      break;
+    case DD_BACK_LEFT_BIT:
+      /* back buffer only */
       FX_grDepthMask(FXFALSE);
-
-      if (ctx->Color.DrawDestMask & BACK_LEFT_BIT) {
-        FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
-        FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, 0);
+      FX_grRenderBuffer(GR_BUFFER_BACKBUFFER);
+      FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
+      if (ctx->Depth.Mask) {
+        FX_grDepthMask(FXTRUE);
       }
-      if (ctx->Color.DrawDestMask & FRONT_LEFT_BIT) {
-        FX_grRenderBuffer(GR_BUFFER_FRONTBUFFER);
-        FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, 0);
+      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(FXTRUE);
       }
-
-      if(ctx->Depth.Mask) {
+      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(FXTRUE);
       }
-    }
-
-    newmask=mask & (~(GL_COLOR_BUFFER_BIT));
-    break;
-  case (GL_DEPTH_BUFFER_BIT):
-    /* clear depth buffer */
-
-    if(ctx->Depth.Mask) {
+      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_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);
-    }
-
-    newmask=mask & (~(GL_DEPTH_BUFFER_BIT));
-    break;
-  default:
-    newmask=mask;
-    break;
+      FX_grDepthMask(FXTRUE);
+      FX_grBufferClear(fxMesa->clearC, fxMesa->clearA, clearD);
+      FX_grColorMask(FXTRUE, ctx->Color.ColorMask[ACOMP] && fxMesa->haveAlphaBuffer);
+      if (ctx->Color.DrawDestMask & FRONT_LEFT_BIT)
+        FX_grRenderBuffer(GR_BUFFER_FRONTBUFFER);
+      if (!ctx->Depth.Test || !ctx->Depth.Mask)
+        FX_grDepthMask(FXFALSE);
+      break;
+    default:
+      /* error */
+      ;
   }
-   
-  return newmask;
+
+  return softwareMask;
 }
 
 
-/*  Set the buffer used in double buffering */
-static GLboolean fxDDSetBuffer(GLcontext *ctx, GLenum mode )
+/* Set the buffer used for drawing */
+/* XXX support for separate read/draw buffers hasn't been tested */
+static GLboolean fxDDSetDrawBuffer(GLcontext *ctx, GLenum mode)
 {
   fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
 
   if (MESA_VERBOSE&VERBOSE_DRIVER) {
-    fprintf(stderr,"fxmesa: fxDDSetBuffer(%x)\n",mode);
+    fprintf(stderr,"fxmesa: fxDDSetBuffer(%x)\n", (int) mode);
   }
 
   if (mode == GL_FRONT_LEFT) {
@@ -261,18 +291,44 @@ static GLboolean fxDDSetBuffer(GLcontext *ctx, GLenum mode )
     FX_grRenderBuffer(fxMesa->currentFB);
     return GL_TRUE;
   }
+  else if (mode == GL_NONE) {
+    FX_grColorMask(FXFALSE,FXFALSE);
+    return GL_TRUE;
+  }
   else {
     return GL_FALSE;
   }
 }
 
 
+/* Set the buffer used for reading */
+/* XXX support for separate read/draw buffers hasn't been tested */
+static void fxDDSetReadBuffer(GLcontext *ctx, GLframebuffer *buffer,
+                              GLenum mode )
+{
+  fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
+  (void) buffer;
+
+  if (MESA_VERBOSE&VERBOSE_DRIVER) {
+    fprintf(stderr,"fxmesa: fxDDSetBuffer(%x)\n", (int) mode);
+  }
+
+  if (mode == GL_FRONT_LEFT) {
+    fxMesa->currentFB = GR_BUFFER_FRONTBUFFER;
+    FX_grRenderBuffer(fxMesa->currentFB);
+  }
+  else if (mode == GL_BACK_LEFT) {
+    fxMesa->currentFB = GR_BUFFER_BACKBUFFER;
+    FX_grRenderBuffer(fxMesa->currentFB);
+  }
+}
+
+
 #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) &&
@@ -284,129 +340,299 @@ static GLboolean inClipRects(fxMesaContext fxMesa, int px, int py)
 #endif
 
 
-static GLboolean fxDDDrawBitMap(GLcontext *ctx, GLint px, GLint py,
+static GLboolean fxDDDrawBitmap(GLcontext *ctx, GLint px, GLint py,
                                 GLsizei width, GLsizei height,
                                 const struct gl_pixelstore_attrib *unpack,
                                 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);
-  color=(FxU16)
-    ( ((FxU16)0xf8 & b) <<(11-3))  |
-    ( ((FxU16)0xfc & g) <<(5-3+1)) |
-    ( ((FxU16)0xf8 & r) >> 3);
-
-  stride=info.strideInBytes>>1;
+#ifdef XF86DRI
+#define INSIDE(c, x, y) inClipRects((c), (x), (y))
+#else
+#define INSIDE(c, x, y) (1)
+#endif
 
-  /* This code is a bit slow... */
+  {
+    const GLint winX = fxMesa->x_offset;
+    const GLint winY = fxMesa->y_offset + fxMesa->height - 1;
+    /* The dest stride depends on the hardware and whether we're drawing
+     * to the front or back buffer.  This compile-time test seems to do
+     * the job for now.
+     */
+#ifdef XF86DRI
+    const GLint dstStride = (fxMesa->glCtx->Color.DrawBuffer == GL_FRONT)
+                          ? (fxMesa->screen_width) : (info.strideInBytes / 2);
+#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 *) _mesa_image_address( 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;
+    }
+  }
 
-  if (py>ymin) ymin=py;
-  if (py+height<ymax) ymax=py+height;
+#undef INSIDE
 
-  px+=fxMesa->x_offset;
-  scrheight=fxMesa->height+fxMesa->y_offset;
+  FX_grLfbUnlock(GR_LFB_WRITE_ONLY,fxMesa->currentFB);
+  return GL_TRUE;
+}
 
-  for(y=ymin; y<ymax; y++) {
 
-    p=((FxU16 *)info.lfbPtr)+px+((scrheight-y)*stride);
+static GLboolean fxDDReadPixels( GLcontext *ctx, GLint x, GLint y,
+                                 GLsizei width, GLsizei height,
+                                 GLenum format, GLenum type,
+                                 const struct gl_pixelstore_attrib *packing,
+                                 GLvoid *dstImage )
+{
+  if (ctx->ImageTransferState) {
+    return GL_FALSE;  /* can't do this */
+  }
+  else {
+    fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
+    GrLfbInfo_t info;
+    GLboolean result = GL_FALSE;
+
+    BEGIN_BOARD_LOCK();
+    if (grLfbLock(GR_LFB_READ_ONLY,
+                  fxMesa->currentFB,
+                  GR_LFBWRITEMODE_ANY,
+                  GR_ORIGIN_UPPER_LEFT,
+                  FXFALSE,
+                  &info)) {
+      const GLint winX = fxMesa->x_offset;
+      const GLint winY = fxMesa->y_offset + fxMesa->height - 1;
+#ifdef XF86DRI
+      const GLint srcStride = (fxMesa->glCtx->Color.DrawBuffer == GL_FRONT)
+                          ? (fxMesa->screen_width) : (info.strideInBytes / 2);
+#else
+      const GLint srcStride = info.strideInBytes / 2; /* stride in GLushorts */
+#endif
+      const GLushort *src = (const GLushort *) info.lfbPtr
+                          + (winY - y) * srcStride + (winX + x);
+      GLubyte *dst = (GLubyte *) _mesa_image_address(packing, dstImage,
+                                         width, height, format, type, 0, 0, 0);
+      GLint dstStride = _mesa_image_row_stride(packing, width, format, type);
+
+      if (format == GL_RGB && type == GL_UNSIGNED_BYTE) {
+        /* convert 5R6G5B into 8R8G8B */
+        GLint row, col;
+        const GLint halfWidth = width >> 1;
+        const GLint extraPixel = (width & 1);
+        for (row = 0; row < height; row++) {
+          GLubyte *d = dst;
+          for (col = 0; col < halfWidth; col++) {
+            const GLuint pixel = ((const GLuint *) src)[col];
+            const GLint pixel0 = pixel & 0xffff;
+            const GLint pixel1 = pixel >> 16;
+            *d++ = FX_PixelToR[pixel0];
+            *d++ = FX_PixelToG[pixel0];
+            *d++ = FX_PixelToB[pixel0];
+            *d++ = FX_PixelToR[pixel1];
+            *d++ = FX_PixelToG[pixel1];
+            *d++ = FX_PixelToB[pixel1];
+          }
+          if (extraPixel) {
+            GLushort pixel = src[width-1];
+            *d++ = FX_PixelToR[pixel];
+            *d++ = FX_PixelToG[pixel];
+            *d++ = FX_PixelToB[pixel];
+          }
+          dst += dstStride;
+          src -= srcStride;
+        }
+        result = GL_TRUE;
+      }
+      else if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
+        /* convert 5R6G5B into 8R8G8B8A */
+        GLint row, col;
+        const GLint halfWidth = width >> 1;
+        const GLint extraPixel = (width & 1);
+        for (row = 0; row < height; row++) {
+          GLubyte *d = dst;
+          for (col = 0; col < halfWidth; col++) {
+            const GLuint pixel = ((const GLuint *) src)[col];
+            const GLint pixel0 = pixel & 0xffff;
+            const GLint pixel1 = pixel >> 16;
+            *d++ = FX_PixelToR[pixel0];
+            *d++ = FX_PixelToG[pixel0];
+            *d++ = FX_PixelToB[pixel0];
+            *d++ = 255;
+            *d++ = FX_PixelToR[pixel1];
+            *d++ = FX_PixelToG[pixel1];
+            *d++ = FX_PixelToB[pixel1];
+            *d++ = 255;
+          }
+          if (extraPixel) {
+            const GLushort pixel = src[width-1];
+            *d++ = FX_PixelToR[pixel];
+            *d++ = FX_PixelToG[pixel];
+            *d++ = FX_PixelToB[pixel];
+            *d++ = 255;
+          }
+          dst += dstStride;
+          src -= srcStride;
+        }
+        result = GL_TRUE;
+      }
+      else if (format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5) {
+        /* directly memcpy 5R6G5B pixels into client's buffer */
+        const GLint widthInBytes = width * 2;
+        GLint row;
+        for (row = 0; row < height; row++) {
+          MEMCPY(dst, src, widthInBytes);
+          dst += dstStride;
+          src -= srcStride;
+        }
+        result = GL_TRUE;
+      }
+      else {
+        result = GL_FALSE;
+      }
 
-    for(x=0;;) {
-      DRAWBIT(7);       DRAWBIT(6);     DRAWBIT(5);     DRAWBIT(4);
-      DRAWBIT(3);       DRAWBIT(2);     DRAWBIT(1);     DRAWBIT(0);
-      pb++;
+      grLfbUnlock(GR_LFB_READ_ONLY, fxMesa->currentFB);
     }
+    END_BOARD_LOCK();
+    return result;
   }
+}
 
-  FX_grLfbUnlock(GR_LFB_WRITE_ONLY,fxMesa->currentFB);
-
-#undef ISCLIPPED
-#undef DRAWBIT
 
-  return GL_TRUE;
-}
 
 static void fxDDFinish(GLcontext *ctx)
 {
@@ -420,7 +646,7 @@ static GLint fxDDGetParameteri(const GLcontext *ctx, GLint param)
   case DD_HAVE_HARDWARE_FOG:
     return 1;
   default:
-    fprintf(stderr,"fx Driver: internal error in fxDDGetParameteri(): %x\n",param);
+    fprintf(stderr,"fx Driver: internal error in fxDDGetParameteri(): %x\n", (int) param);
     fxCloseHardware();
     exit(-1);
     return 0;
@@ -440,53 +666,79 @@ void fxDDSetNearFar(GLcontext *ctx, GLfloat n, GLfloat f)
  */
 static const GLubyte *fxDDGetString(GLcontext *ctx, GLenum name)
 {
-   switch (name) {
-   case GL_RENDERER:
 #if defined(GLX_DIRECT_RENDERING)
-      return "Mesa Glide - DRI VB/V3";
+  /* Building for DRI driver */
+  switch (name) {
+    case GL_RENDERER:
+      {
+        static char buffer[100];
+        char hardware[100];
+        strcpy(hardware, grGetString(GR_HARDWARE));
+        if (strcmp(hardware, "Voodoo3 (tm)") == 0)
+          strcpy(hardware, "Voodoo3");
+        else if (strcmp(hardware, "Voodoo Banshee (tm)") == 0)
+          strcpy(hardware, "VoodooBanshee");
+        else {
+          /* unexpected result: replace spaces with hyphens */
+          int i;
+          for (i = 0; hardware[i]; i++) {
+            if (hardware[i] == ' ' || hardware[i] == '\t')
+              hardware[i] = '-';
+          }
+        }
+        /* now make the GL_RENDERER string */
+        sprintf(buffer, "Mesa DRI %s 20000510", hardware);
+        return buffer;
+      }
+    case GL_VENDOR:
+      return "Precision Insight, Inc.";
+    default:
+      return NULL;
+  }
+
 #else
+
+  /* Building for Voodoo1/2 stand-alone Mesa */
+  switch (name) {
+    case GL_RENDERER:
       {
-        static char buf[80];
-
-        if (glbHWConfig.SSTs[glbCurrentBoard].type==GR_SSTTYPE_VOODOO) 
-        {
-           GrVoodooConfig_t *vc = 
-              &glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig;
-
-           sprintf(buf,
-                   "Mesa Glide v0.30 Voodoo_Graphics %d "
-                   "CARD/%d FB/%d TM/%d TMU/%s",
-                   glbCurrentBoard,
-                   (vc->sliDetect ? (vc->fbRam*2) : vc->fbRam),
-                   (vc->tmuConfig[GR_TMU0].tmuRam +
-                    ((vc->nTexelfx>1) ? vc->tmuConfig[GR_TMU1].tmuRam : 0)),
-                   vc->nTexelfx,
-                   (vc->sliDetect ? "SLI" : "NOSLI"));
-        }
-        else if (glbHWConfig.SSTs[glbCurrentBoard].type==GR_SSTTYPE_SST96)
-        {
-           GrSst96Config_t *sc = 
-              &glbHWConfig.SSTs[glbCurrentBoard].sstBoard.SST96Config;
-
-           sprintf(buf,
-                   "Glide v0.30 Voodoo_Rush %d "
-                   "CARD/%d FB/%d TM/%d TMU/NOSLI",
-                   glbCurrentBoard,
-                   sc->fbRam,
-                   sc->tmuConfig.tmuRam,
-                   sc->nTexelfx);
-        }
-        else
-        {
-           strcpy(buf, "Glide v0.30 UNKNOWN");
-        }
-
-        return (GLubyte *) buf;
+        static char buf[80];
+
+        if (glbHWConfig.SSTs[glbCurrentBoard].type==GR_SSTTYPE_VOODOO) {
+          GrVoodooConfig_t *vc = 
+            &glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig;
+
+          sprintf(buf,
+                  "Mesa Glide v0.30 Voodoo_Graphics %d "
+                  "CARD/%d FB/%d TM/%d TMU/%s",
+                  glbCurrentBoard,
+                  (vc->sliDetect ? (vc->fbRam*2) : vc->fbRam),
+                  (vc->tmuConfig[GR_TMU0].tmuRam +
+                   ((vc->nTexelfx>1) ? vc->tmuConfig[GR_TMU1].tmuRam : 0)),
+                  vc->nTexelfx,
+                  (vc->sliDetect ? "SLI" : "NOSLI"));
+        }
+        else if (glbHWConfig.SSTs[glbCurrentBoard].type==GR_SSTTYPE_SST96) {
+          GrSst96Config_t *sc = 
+            &glbHWConfig.SSTs[glbCurrentBoard].sstBoard.SST96Config;
+
+          sprintf(buf,
+                  "Glide v0.30 Voodoo_Rush %d "
+                  "CARD/%d FB/%d TM/%d TMU/NOSLI",
+                  glbCurrentBoard,
+                  sc->fbRam,
+                  sc->tmuConfig.tmuRam,
+                  sc->nTexelfx);
+        }
+        else {
+          strcpy(buf, "Glide v0.30 UNKNOWN");
+        }
+        return (GLubyte *) buf;
       }
-#endif
-   default:
+    default:
       return NULL;
-   }
+  }
+#endif
 }
 
 
@@ -513,6 +765,11 @@ int fxDDInitFxMesaContext( fxMesaContext fxMesa )
    else
       fxMesa->maxPendingSwapBuffers=2;
    
+   if(getenv("MESA_FX_INFO"))
+      fxMesa->verbose=GL_TRUE;
+   else
+      fxMesa->verbose=GL_FALSE;
+
    fxMesa->color=0xffffffff;
    fxMesa->clearC=0;
    fxMesa->clearA=0;
@@ -570,10 +827,10 @@ int fxDDInitFxMesaContext( fxMesaContext fxMesa )
    FX_grLfbWriteColorFormat(GR_COLORFORMAT_ABGR); /* Not every Glide has this */
 #endif
 
+   fxMesa->textureAlign=FX_grGetInteger(FX_TEXTURE_ALIGN);
    fxMesa->glCtx->Const.MaxTextureLevels=9;
    fxMesa->glCtx->Const.MaxTextureSize=256;
    fxMesa->glCtx->Const.MaxTextureUnits=fxMesa->emulateTwoTMUs ? 2 : 1;
-   fxMesa->glCtx->NewState|=NEW_DRVSTATE1;
    fxMesa->new_state = NEW_ALL;
   
    fxDDSetupInit();
@@ -606,47 +863,61 @@ int fxDDInitFxMesaContext( fxMesaContext fxMesa )
         fxMesa->glCtx->NrPipelineStages);
 
    /* Run the config file */
-   gl_context_initialize( fxMesa->glCtx );
+   _mesa_context_initialize( fxMesa->glCtx );
 
    return 1;
 }
 
 
-
+#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_fog_coord");
+
+   gl_extensions_add(ctx, DEFAULT_ON, "3DFX_set_global_palette", 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");
 
-/*
-  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.
-*/
-
-/************************************************************************/
-/************************************************************************/
-/************************************************************************/
 
-/* This is a no-op, since the z-buffer is in hardware */
-static void fxAllocDepthBuffer(GLcontext *ctx)
-{
-   if (MESA_VERBOSE&VERBOSE_DRIVER) {
-     fprintf(stderr,"fxmesa: fxAllocDepthBuffer()\n");
-   }
+   /* 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
 }
 
+
 /************************************************************************/
 /************************************************************************/
 /************************************************************************/
@@ -662,7 +933,7 @@ static GLboolean fxIsInHardware(GLcontext *ctx)
   if (!ctx->Hint.AllowDrawMem)
      return GL_TRUE;           /* you'll take it and like it */
 
-  if((ctx->RasterMask & STENCIL_BIT) ||
+  if((ctx->RasterMask & (STENCIL_BIT | MULTI_DRAW_BIT)) ||
      ((ctx->Color.BlendEnabled) && (ctx->Color.BlendEquation!=GL_FUNC_ADD_EXT)) ||
      ((ctx->Color.ColorLogicOpEnabled) && (ctx->Color.LogicOp!=GL_COPY)) ||
      (ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR) ||
@@ -684,17 +955,26 @@ static GLboolean fxIsInHardware(GLcontext *ctx)
       return GL_FALSE;
     }
 
-    if((ctx->Texture.ReallyEnabled & TEXTURE0_2D) &&
-       (ctx->Texture.Unit[0].EnvMode==GL_BLEND)) {
-      return GL_FALSE;
+    if (ctx->Texture.ReallyEnabled & TEXTURE0_2D) {
+      if (ctx->Texture.Unit[0].EnvMode == GL_BLEND &&
+         (ctx->Texture.ReallyEnabled & TEXTURE1_2D ||
+          ctx->Texture.Unit[0].EnvColor[0] != 0 ||
+          ctx->Texture.Unit[0].EnvColor[1] != 0 ||
+          ctx->Texture.Unit[0].EnvColor[2] != 0 ||
+          ctx->Texture.Unit[0].EnvColor[3] != 1)) {
+        return GL_FALSE;
+      }
+      if (ctx->Texture.Unit[0].Current->Image[0]->Border > 0)
+        return GL_FALSE;
     }
 
-    if((ctx->Texture.ReallyEnabled & TEXTURE1_2D) &&
-       (ctx->Texture.Unit[1].EnvMode==GL_BLEND)) {
-      return GL_FALSE;
+    if (ctx->Texture.ReallyEnabled & TEXTURE1_2D) {
+      if (ctx->Texture.Unit[1].EnvMode == GL_BLEND)
+        return GL_FALSE;
+      if (ctx->Texture.Unit[0].Current->Image[0]->Border > 0)
+        return GL_FALSE;
     }
 
-
     if (MESA_VERBOSE & (VERBOSE_DRIVER|VERBOSE_TEXTURE))
        fprintf(stderr, "fxMesa: fxIsInHardware, envmode is %s/%s\n",
               gl_lookup_enum_by_nr(ctx->Texture.Unit[0].EnvMode),
@@ -779,6 +1059,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) {
@@ -787,16 +1077,13 @@ void fxSetupDDPointers(GLcontext *ctx)
 
   ctx->Driver.UpdateState=fxDDUpdateDDPointers;
 
-  ctx->Driver.AllocDepthBuffer=fxAllocDepthBuffer;
-  ctx->Driver.DepthTestSpan=fxDDDepthTestSpanGeneric;
-  ctx->Driver.DepthTestPixels=fxDDDepthTestPixelsGeneric;
-  ctx->Driver.ReadDepthSpanFloat=fxDDReadDepthSpanFloat;
-  ctx->Driver.ReadDepthSpanInt=fxDDReadDepthSpanInt;
+  ctx->Driver.WriteDepthSpan=fxDDWriteDepthSpan;
+  ctx->Driver.WriteDepthPixels=fxDDWriteDepthPixels;
+  ctx->Driver.ReadDepthSpan=fxDDReadDepthSpan;
+  ctx->Driver.ReadDepthPixels=fxDDReadDepthPixels;
          
   ctx->Driver.GetString=fxDDGetString;
 
-  ctx->Driver.Dither=fxDDDither;
-
   ctx->Driver.NearFar=fxDDSetNearFar;
 
   ctx->Driver.GetParameteri=fxDDGetParameteri;
@@ -808,11 +1095,13 @@ void fxSetupDDPointers(GLcontext *ctx)
   ctx->Driver.Index=NULL;
   ctx->Driver.Color=fxDDSetColor;
 
-  ctx->Driver.SetBuffer=fxDDSetBuffer;
+  ctx->Driver.SetDrawBuffer=fxDDSetDrawBuffer;
+  ctx->Driver.SetReadBuffer=fxDDSetReadBuffer;
   ctx->Driver.GetBufferSize=fxDDBufferSize;
 
-  ctx->Driver.Bitmap=fxDDDrawBitMap;
+  ctx->Driver.Bitmap=fxDDDrawBitmap;
   ctx->Driver.DrawPixels=NULL;
+  ctx->Driver.ReadPixels=fxDDReadPixels;
 
   ctx->Driver.Finish=fxDDFinish;
   ctx->Driver.Flush=NULL;
@@ -820,14 +1109,14 @@ void fxSetupDDPointers(GLcontext *ctx)
   ctx->Driver.RenderStart=NULL;
   ctx->Driver.RenderFinish=NULL;
 
+  ctx->Driver.TexImage2D = fxDDTexImage2D;
+  ctx->Driver.TexSubImage2D = fxDDTexSubImage2D;
+  ctx->Driver.GetTexImage = fxDDGetTexImage;
   ctx->Driver.TexEnv=fxDDTexEnv;
-  ctx->Driver.TexImage=fxDDTexImg;
-  ctx->Driver.TexSubImage=fxDDTexSubImg;
   ctx->Driver.TexParameter=fxDDTexParam;
   ctx->Driver.BindTexture=fxDDTexBind;
   ctx->Driver.DeleteTexture=fxDDTexDel;
   ctx->Driver.UpdateTexturePalette=fxDDTexPalette;
-  ctx->Driver.UseGlobalTexturePalette=fxDDTexUseGlbPalette;
 
   ctx->Driver.RectFunc=NULL;
 
@@ -842,6 +1131,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;