Imported the Savage DRI driver from the savage-2-0-0-branch of DRI CVS
authorFelix Kuehling <fxkuehl@gmx.de>
Sun, 22 Feb 2004 16:11:12 +0000 (16:11 +0000)
committerFelix Kuehling <fxkuehl@gmx.de>
Sun, 22 Feb 2004 16:11:12 +0000 (16:11 +0000)
with modifications to make it work with current Mesa 6.

21 files changed:
src/mesa/drivers/dri/savage/savage_3d_reg.h [new file with mode: 0644]
src/mesa/drivers/dri/savage/savage_bci.h [new file with mode: 0644]
src/mesa/drivers/dri/savage/savage_init.h [new file with mode: 0644]
src/mesa/drivers/dri/savage/savage_xmesa.c [new file with mode: 0644]
src/mesa/drivers/dri/savage/savagecontext.h [new file with mode: 0644]
src/mesa/drivers/dri/savage/savagedd.c [new file with mode: 0644]
src/mesa/drivers/dri/savage/savagedd.h [new file with mode: 0644]
src/mesa/drivers/dri/savage/savagedma.c [new file with mode: 0644]
src/mesa/drivers/dri/savage/savagedma.h [new file with mode: 0644]
src/mesa/drivers/dri/savage/savageioctl.c [new file with mode: 0644]
src/mesa/drivers/dri/savage/savageioctl.h [new file with mode: 0644]
src/mesa/drivers/dri/savage/savagespan.c [new file with mode: 0644]
src/mesa/drivers/dri/savage/savagespan.h [new file with mode: 0644]
src/mesa/drivers/dri/savage/savagestate.c [new file with mode: 0644]
src/mesa/drivers/dri/savage/savagestate.h [new file with mode: 0644]
src/mesa/drivers/dri/savage/savagetex.c [new file with mode: 0644]
src/mesa/drivers/dri/savage/savagetex.h [new file with mode: 0644]
src/mesa/drivers/dri/savage/savagetris.c [new file with mode: 0644]
src/mesa/drivers/dri/savage/savagetris.h [new file with mode: 0644]
src/mesa/drivers/dri/savage/savagevb.c [new file with mode: 0644]
src/mesa/drivers/dri/savage/savagevb.h [new file with mode: 0644]

diff --git a/src/mesa/drivers/dri/savage/savage_3d_reg.h b/src/mesa/drivers/dri/savage/savage_3d_reg.h
new file mode 100644 (file)
index 0000000..b56a900
--- /dev/null
@@ -0,0 +1,1063 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef SAVAGE_3D_REG_H
+#define SAVAGE_3D_REG_H
+
+#define uint32 unsigned long
+#define uint16 unsigned short
+
+#define VIDEO_MEM_ADR                   0x02
+#define SYSTEM_MEM_ADR                  0x01
+#define AGP_MEM_ADR                     0x03
+
+/***********************************************************
+
+  ----------- 3D ENGINE UNIT Registers -------------
+
+  *********************************************************/
+
+typedef union
+{
+    struct
+    {
+        unsigned int reserved : 4;
+        unsigned int ofs      : 28;
+    }ni;
+    unsigned int ui;
+} Reg_ZPixelOffset;
+
+typedef union
+{
+    /* This reg exists only on Savage4. */
+    struct
+    {
+        unsigned int cmpFunc     :  3;
+        unsigned int stencilEn   :  1;
+        unsigned int readMask    :  8;
+        unsigned int writeMask   :  8;
+        unsigned int failOp      :  3;
+        unsigned int passZfailOp :  3;
+        unsigned int passZpassOp :  3;
+        unsigned int reserved    :  3;
+    }ni;
+    unsigned int ui;
+} Reg_StencilCtrl;
+
+/**************************
+ Texture Registers
+**************************/
+typedef union
+{
+    /* The layout of this reg differs between Savage4 and Savage3D. */
+    struct
+    {
+        unsigned int tex0Width  : 4;
+        unsigned int tex0Height : 4;
+        unsigned int tex0Fmt    : 4;
+        unsigned int tex1Width  : 4;
+        unsigned int tex1Height : 4;
+        unsigned int tex1Fmt    : 4;
+        unsigned int texBLoopEn : 1;
+        unsigned int tex0En     : 1;
+        unsigned int tex1En     : 1;
+        unsigned int orthProjEn : 1;
+        unsigned int reserved   : 1;
+        unsigned int palSize    : 2;
+        unsigned int newPal     : 1;
+    }s4;
+    struct
+    {
+        unsigned int texWidth  : 4;
+        unsigned int reserved1 : 4;
+        unsigned int texHeight : 4;
+        unsigned int reserved2 : 4;
+       /* Savage3D supports only the first 8 texture formats defined in
+          enum TexFmt in savge_bci.h. */
+        unsigned int texFmt    : 3;
+        unsigned int palSize   : 2;
+        unsigned int reserved3 : 10;
+        unsigned int newPal    : 1;
+    }s3d;
+    unsigned int ui;
+} Reg_TexDescr;
+
+typedef union
+{
+    /* The layout of this reg is the same on Savage4 and Savage3D,
+       but the Savage4 has two of them, Savage3D has only one. */
+    struct
+    {
+        unsigned int inSysTex : 1;
+        unsigned int inAGPTex : 1;
+        unsigned int reserved : 1;
+        unsigned int addr     : 29;
+    }ni;
+    unsigned int ui;
+} Reg_TexAddr;
+
+typedef union
+{
+    /* The layout of this reg is the same on Savage4 and Savage3D,
+       but the Savage4 has two of them, Savage3D has only one. */
+    struct
+    {
+        unsigned int reserved : 3;
+        unsigned int addr     : 29;
+    }ni;
+    unsigned int ui;
+} Reg_TexPalAddr;
+
+typedef union
+{
+    /* The layout of this reg on Savage4 and Savage3D are very similar. */
+    struct
+    {
+        unsigned int xprClr0 : 16;
+        unsigned int xprClr1 : 16; /* this is reserved on Savage3D */
+    }ni;
+    unsigned int ui;
+} Reg_TexXprClr;   /* transparency color in RGB565 format*/
+
+typedef union
+{
+    /* The layout of this reg differs between Savage4 and Savage3D.
+     * Savage4 has two of them, Savage3D has only one. */
+    struct
+    {
+        unsigned int filterMode         : 2;
+        unsigned int mipmapEnable       : 1;
+        unsigned int dBias              : 9;
+        unsigned int dMax               : 4;
+        unsigned int uMode              : 2;
+        unsigned int vMode              : 2;
+        unsigned int useDFraction       : 1;
+        unsigned int texXprEn           : 1;
+        unsigned int clrBlendAlphaSel   : 2;
+        unsigned int clrArg1CopyAlpha   : 1;
+        unsigned int clrArg2CopyAlpha   : 1;
+        unsigned int clrArg1Invert      : 1;
+        unsigned int clrArg2Invert      : 1;
+        unsigned int alphaBlendAlphaSel : 2;
+        unsigned int alphaArg1Invert    : 1;
+        unsigned int alphaArg2Invert    : 1;
+    }s4;
+    struct
+    {
+        unsigned int filterMode    : 2;
+        unsigned int mipmapDisable : 1;
+        unsigned int dBias         : 9;
+        unsigned int uWrapEn       : 1;
+        unsigned int vWrapEn       : 1;
+        unsigned int wrapMode      : 2;
+        unsigned int texEn         : 1;
+        unsigned int useDFraction  : 1;
+        unsigned int reserved1     : 1;
+       /* Color Compare Alpha Blend Control
+           0 -  reduce dest alpha to 0 or 1
+           1 - blend with destination
+          The Utah-Driver doesn't know how to use it and sets it to 0. */
+        unsigned int CCA           : 1;
+        unsigned int texXprEn      : 1;
+        unsigned int reserved2     : 11;
+    }s3d;
+    unsigned int ui;
+} Reg_TexCtrl;
+
+typedef union
+{
+    /* This reg exists only on Savage4. */
+    struct
+    {
+        unsigned int colorArg1Sel    : 2;
+        unsigned int colorArg2Sel    : 3;
+        unsigned int colorInvAlphaEn : 1;
+        unsigned int colorInvArg2En  : 1;
+        unsigned int colorPremodSel  : 1;
+        unsigned int colorMod1Sel    : 1;
+        unsigned int colorMod2Sel    : 2;
+        unsigned int colorAddSel     : 2;
+        unsigned int colorDoBlend    : 1;
+        unsigned int colorDo2sCompl  : 1;
+        unsigned int colorAddBiasEn  : 1;
+        unsigned int alphaArg1Sel    : 2;
+        unsigned int alphaArg2Sel    : 3;
+        unsigned int alphaMod1Sel    : 1;
+        unsigned int alphaMod2Sel    : 2;
+        unsigned int alphaAdd0Sel    : 1;
+        unsigned int alphaDoBlend    : 1;
+        unsigned int alphaDo2sCompl  : 1;
+        unsigned int colorStageClamp : 1;
+        unsigned int alphaStageClamp : 1;
+        unsigned int colorDoDiffMul  : 1;
+        unsigned int LeftShiftVal    : 2;
+    }ni;
+    unsigned int ui;
+} Reg_TexBlendCtrl;
+
+typedef union
+{
+    /* This reg exists only on Savage4. */
+    struct
+    {
+        unsigned int blue  : 8;
+        unsigned int green : 8;
+        unsigned int red   : 8;
+        unsigned int alpha : 8;
+    }ni;
+    unsigned int ui;
+} Reg_TexBlendColor;
+
+/********************************
+ Tiled Surface Registers
+**********************************/
+
+typedef union
+{
+    struct
+    {
+        unsigned int frmBufOffset : 13;
+        unsigned int reserved     : 12;
+        unsigned int widthInTile  : 6;
+        unsigned int bitPerPixel  : 1;
+    }ni;
+    unsigned int ui;
+} Reg_TiledSurface;
+
+/********************************
+ Draw/Shading Control Registers
+**********************************/
+
+typedef union
+{
+    /* This reg exists only on Savage4. */
+    struct
+    {
+        unsigned int scissorXStart : 11;
+        unsigned int DPerfAccelEn  : 1;
+        unsigned int scissorYStart : 12;
+        unsigned int alphaRefVal   : 8;
+    }ni;
+    unsigned int ui;
+} Reg_DrawCtrl0;
+
+typedef union
+{
+    /* This reg exists only on Savage4. */
+    struct
+    {
+        unsigned int scissorXEnd      : 11;
+        unsigned int XYOffsetEn       :  1;
+        unsigned int scissorYEnd      : 12;
+        unsigned int ditherEn         :  1;
+        unsigned int nonNormTexCoord  :  1;
+        unsigned int cullMode         :  2;
+        unsigned int alphaTestCmpFunc :  3;
+        unsigned int alphaTestEn      :  1;
+    }ni;
+    unsigned int ui;
+} Reg_DrawCtrl1;
+
+typedef union
+{
+    /* This reg exists only on Savage4. */
+    struct
+    {
+        unsigned int dstAlphaMode        :  3;
+        unsigned int DstMinusSrc         :  1;
+        unsigned int srcAlphaMode        :  3;
+        unsigned int binaryFinalAlpha    :  1;
+        unsigned int dstAlphaModeHighBit :  1;
+        unsigned int srcAlphaModeHighBit :  1;
+        unsigned int reserved1           : 15;
+        unsigned int wrZafterAlphaTst    :  1;
+        unsigned int drawUpdateEn        :  1;
+        unsigned int zUpdateEn           :  1;
+        unsigned int flatShadeEn         :  1;
+        unsigned int specShadeEn         :  1;
+        unsigned int flushPdDestWrites   :  1;
+        unsigned int flushPdZbufWrites   :  1;
+    }ni;
+    unsigned int ui;
+} Reg_DrawLocalCtrl;
+
+typedef union
+{
+    /* This reg exists only on Savage3D. */
+    struct
+    {
+        unsigned int ditherEn          : 1;
+        unsigned int XYOffsetEn        : 1;
+        unsigned int cullMode          : 2;
+        unsigned int vertexCountReset  : 1;
+        unsigned int flatShadeEn       : 1;
+        unsigned int specShadeEn       : 1;
+        unsigned int dstAlphaMode      : 3;
+        unsigned int srcAlphaMode      : 3;
+        unsigned int reserved1         : 1;
+        unsigned int alphaTestCmpFunc  : 3;
+        unsigned int alphaTestEn       : 1;
+        unsigned int alphaRefVal       : 8;
+        unsigned int texBlendCtrl      : 3;
+        unsigned int flushPdDestWrites : 1;
+        unsigned int flushPdZbufWrites : 1;
+       /* havn't found an equivalent for Savage4. Utah-driver sets it to 0. */
+        unsigned int interpMode        : 1;
+    }ni;
+    unsigned int ui;
+} Reg_DrawCtrl;
+
+#define SAVAGETBC_DECAL_S3D                     0
+#define SAVAGETBC_MODULATE_S3D                  1
+#define SAVAGETBC_DECALALPHA_S3D                2
+#define SAVAGETBC_MODULATEALPHA_S3D             3
+#define SAVAGETBC_4_S3D                         4
+#define SAVAGETBC_5_S3D                         5
+#define SAVAGETBC_COPY_S3D                      6
+#define SAVAGETBC_7_S3D                         7
+
+typedef union
+{
+    /* This reg exists only on Savage3D. */
+    struct
+    {
+        unsigned int scissorXStart : 11;
+       unsigned int reserved1     : 5;
+        unsigned int scissorYStart : 11;
+       unsigned int reserved2     : 5;
+    } ni;
+    unsigned int ui;
+} Reg_ScissorsStart;
+
+typedef union
+{
+    /* This reg exists only on Savage3D. */
+    struct
+    {
+        unsigned int scissorXEnd : 11;
+       unsigned int reserved1   : 5;
+        unsigned int scissorYEnd : 11;
+       unsigned int reserved2   : 5;
+    } ni;
+    unsigned int ui;
+} Reg_ScissorsEnd;
+
+/********************************
+ Address Registers
+**********************************/
+
+typedef union
+{
+    /* I havn't found a Savage3D equivalent of this reg in the Utah-driver. 
+     * But Tim Roberts claims that the Savage3D supports DMA vertex and
+     * command buffers. */
+    struct
+    {
+        unsigned int isSys    : 1;
+        unsigned int isAGP    : 1;
+        unsigned int reserved : 1;
+        unsigned int addr     : 29; /*quad word aligned*/
+    }ni;
+    unsigned int ui;
+} Reg_VertBufAddr;
+
+typedef union
+{
+    /* I havn't found a Savage3D equivalent of this reg in the Utah-driver. 
+     * But Tim Roberts claims that the Savage3D supports DMA vertex and
+     * command buffers. */
+    struct
+    {
+        unsigned int isSys    : 1;
+        unsigned int isAGP    : 1;
+        unsigned int reserved : 1;
+        unsigned int addr     : 29; /*4-quad word aligned*/
+    }ni;
+    unsigned int ui;
+} Reg_DMABufAddr;
+
+/********************************
+ H/W Debug Registers
+**********************************/
+typedef union
+{
+    /* The layout of this reg is the same on Savage4 and Savage3D. */
+    struct
+    {
+        unsigned int y01        : 1;
+        unsigned int y12        : 1;
+        unsigned int y20        : 1;
+        unsigned int u01        : 1;
+        unsigned int u12        : 1;
+        unsigned int u20        : 1;
+        unsigned int v01        : 1;
+        unsigned int v12        : 1;
+        unsigned int v20        : 1;
+        unsigned int cullEn     : 1;
+        unsigned int cullOrient : 1;
+        unsigned int loadNewTex : 1;
+        unsigned int loadNewPal : 1;
+        unsigned int doDSetup   : 1;
+        unsigned int reserved   : 17;
+        unsigned int kickOff    : 1;
+    }ni;
+    unsigned int ui;
+} Reg_Flag;
+
+/********************************
+ Z Buffer Registers -- Global
+**********************************/
+
+typedef union
+{
+    /* The layout of this reg differs between Savage4 and Savage3D. */
+    struct
+    {
+        unsigned int zCmpFunc      : 3;
+        unsigned int reserved1     : 2;
+        unsigned int zBufEn        : 1;
+        unsigned int reserved2     : 1;
+        unsigned int zExpOffset    : 8;
+        unsigned int reserved3     : 1;
+        unsigned int stencilRefVal : 8;
+        unsigned int autoZEnable   : 1;
+        unsigned int frameID       : 1;
+        unsigned int reserved4     : 4;
+        unsigned int floatZEn      : 1;
+        unsigned int wToZEn        : 1;
+    }s4;
+    struct {
+        unsigned int zCmpFunc         : 3;
+        unsigned int drawUpdateEn     : 1;
+        unsigned int zUpdateEn        : 1;
+        unsigned int zBufEn           : 1;
+        unsigned int reserved1        : 2;
+        unsigned int zExpOffset       : 8;
+        unsigned int wrZafterAlphaTst : 1;
+        unsigned int reserved2        : 15;
+    }s3d;
+    GLuint ui;
+}Reg_ZBufCtrl;
+
+typedef union
+{
+    /* The layout of this reg on Savage4 and Savage3D are very similar. */
+    struct
+    {
+       /* In the Utah-Driver the offset is defined as 13-bit, 2k-aligned. */
+        unsigned int offset           : 14;
+        unsigned int reserved         : 11; /* 12-bits in Utah-driver */
+        unsigned int zBufWidthInTiles : 6;
+        unsigned int zDepthSelect     : 1;
+    }ni;
+    unsigned int ui;
+} Reg_ZBufOffset;
+
+typedef union
+{
+    /* The layout of this reg is the same on Savage4 and Savage3D. */
+    struct
+    {
+        unsigned int rLow      : 6;
+        unsigned int reserved1 : 2;
+        unsigned int rHigh     : 6;
+        unsigned int reserved2 : 2;
+        unsigned int wLow      : 6;
+        unsigned int reserved3 : 2;
+        unsigned int wHigh     : 6;
+        unsigned int reserved4 : 2;
+    }ni;
+    unsigned int ui;
+} Reg_ZWatermarks;
+
+/********************************
+ Fog Registers -- Global
+**********************************/
+typedef union
+{
+    /* The layout of this reg is the same on Savage4 and Savage3D. */
+    struct
+    {
+        unsigned int fogClr      : 24;
+        unsigned int expShift    : 3;
+        unsigned int reserved    : 1;
+        unsigned int fogEn       : 1;
+        unsigned int fogMode     : 1;
+        unsigned int fogEndShift : 2;
+    }ni;
+    unsigned int ui;
+}Reg_FogCtrl;
+
+typedef struct
+{
+    /* According to the Utah-driver the fog table has 64 entries on
+       Savage3D. Savage4 uses only 32 entries. */
+    union
+    {
+        unsigned char ucEntry[64];
+        uint32 ulEntry[16];
+    }ni;
+} Reg_FogTable;
+
+/*not in spec, but tempo for pp and driver*/
+typedef union
+{
+    struct
+    {
+        unsigned int fogDensity : 16;
+        unsigned int fogStart   : 16;
+    }ni;
+    unsigned int ui;
+}Reg_FogParam;
+
+/**************************************
+ Destination Buffer Registers -- Global
+***************************************/
+
+typedef union
+{
+    /* The layout of this reg on Savage4 and Savage3D are very similar. */
+    struct
+    {
+        unsigned int dstWidthInTile :  7;
+        unsigned int reserved       :  1;
+       /* In the Utah-Driver the offset is defined as 13-bit, 2k-aligned. */
+        unsigned int offset         : 14;
+        unsigned int reserved1      :  7;
+       /* antiAliasMode does not exist in the Utah-driver. But it includes the
+        * high bit of this in the destPixFmt. However, only values 0 and 2
+        * are used as dstPixFmt, so antiAliasMode is effectively always 0
+        * in the Utah-driver. In other words, treat as reserved on SavageIX.*/
+        unsigned int antiAliasMode  :  2;
+        unsigned int dstPixFmt      :  1;
+    }ni;
+    unsigned int ui;
+}Reg_DestCtrl;
+
+typedef union
+{
+    /* The layout of this reg on Savage4 and Savage3D are very similar. */
+    struct
+    {
+        unsigned int destReadLow   : 6;
+        unsigned int destReadHigh  : 6;
+        unsigned int destWriteLow  : 6;
+        unsigned int destWriteHigh : 6;
+        unsigned int texRead       : 4;
+        unsigned int reserved4     : 2;
+       /* The Utah-driver calls this pixel FIFO length:
+        * 00 - 240, 01 - 180, 10 - 120, 11 - 60
+        * However, it is not used in either driver. */
+        unsigned int destFlush     : 2;
+    }ni;
+    unsigned int ui;
+}Reg_DestTexWatermarks;
+
+typedef struct _REGISTERS_
+{
+    union
+    {
+        struct
+        {
+            unsigned int fDrawLocalCtrlChanged     : 1;
+            unsigned int fTexPalAddrChanged        : 1;
+            unsigned int fTex0CtrlChanged          : 1;
+            unsigned int fTex1CtrlChanged          : 1;
+
+            unsigned int fTex0AddrChanged          : 1;
+            unsigned int fTex1AddrChanged          : 1;
+            unsigned int fTex0BlendCtrlChanged     : 1;
+            unsigned int fTex1BlendCtrlChanged     : 1;
+
+            unsigned int fTexXprClrChanged         : 1;
+            unsigned int fTexDescrChanged          : 1;
+            unsigned int fFogTableChanged          : 1;
+            unsigned int fFogCtrlChanged           : 1;
+
+            unsigned int fStencilCtrlChanged       : 1;
+            unsigned int fZBufCtrlChanged          : 1;
+            unsigned int fZBufOffsetChanged        : 1;
+            unsigned int fDestCtrlChanged          : 1;
+
+            unsigned int fDrawCtrl0Changed         : 1;
+            unsigned int fDrawCtrl1Changed         : 1;
+            unsigned int fZWatermarksChanged       : 1;
+            unsigned int fDestTexWatermarksChanged : 1;
+
+            unsigned int fTexBlendColorChanged     : 1;
+            unsigned int fDrawCtrlChanged          : 1;
+            unsigned int fScissorsStartChanged     : 1;
+            unsigned int fScissorsEndChanged       : 1;
+
+           unsigned int fScissorsChanged          : 1; /* doesn't correspond to
+                                                          a real register. */
+
+            unsigned int fReserved                 : 7;
+       }ni;
+        GLuint uiRegistersChanged;
+    }changed;
+
+    Reg_DrawLocalCtrl      DrawLocalCtrl;      /* Savage4 only */
+
+    Reg_TexPalAddr         TexPalAddr;
+    Reg_TexCtrl            TexCtrl[2];         /* Savage3D uses only one */
+    Reg_TexAddr            TexAddr[2];         /* Savage3D uses only one */
+    Reg_TexBlendCtrl       TexBlendCtrl[2];    /* Savage4 only */
+
+    Reg_TexXprClr          TexXprClr;
+    Reg_TexDescr           TexDescr;
+
+    Reg_FogTable           FogTable;           /* Savage4 uses only 32 entries */
+
+    Reg_FogCtrl            FogCtrl;
+
+    Reg_StencilCtrl        StencilCtrl;        /* Savage4 only */
+    Reg_ZBufCtrl           ZBufCtrl;
+    Reg_ZBufOffset         ZBufOffset;
+    Reg_DestCtrl           DestCtrl;
+    Reg_DrawCtrl0          DrawCtrl0;          /* Savage4 only */
+    Reg_DrawCtrl1          DrawCtrl1;          /* Savage4 only */
+    Reg_ZWatermarks        ZWatermarks;
+    Reg_DestTexWatermarks  DestTexWatermarks;
+    Reg_TexBlendColor      TexBlendColor;      /* Savage4 only */
+
+    Reg_DrawCtrl           DrawCtrl;           /* Savage3D only */
+    Reg_ScissorsStart      ScissorsStart;      /* Savage3D only */
+    Reg_ScissorsEnd        ScissorsEnd;        /* Savage3D only */
+} REGISTERS;
+
+/* All registers that affect textures */
+#define SAVAGE_TEXTURE_CHANGED 0x000002FE
+/* Engine must be idle when global registers are changed */
+#define SAVAGE_GLOBAL_CHANGED  0x00FFFC00
+
+/* Savage4/Twister/ProSavage register BCI addresses */
+#define SAVAGE_DRAWLOCALCTRL_S4       0x1e
+#define SAVAGE_TEXPALADDR_S4          0x1f
+#define SAVAGE_TEXCTRL0_S4            0x20
+#define SAVAGE_TEXCTRL1_S4            0x21
+#define SAVAGE_TEXADDR0_S4            0x22
+#define SAVAGE_TEXADDR1_S4            0x23
+#define SAVAGE_TEXBLEND0_S4           0x24
+#define SAVAGE_TEXBLEND1_S4           0x25
+#define SAVAGE_TEXXPRCLR_S4           0x26 /* never used */
+#define SAVAGE_TEXDESCR_S4            0x27
+#define SAVAGE_FOGTABLE_S4            0x28
+#define SAVAGE_FOGCTRL_S4             0x30
+#define SAVAGE_STENCILCTRL_S4         0x31
+#define SAVAGE_ZBUFCTRL_S4            0x32
+#define SAVAGE_ZBUFOFF_S4             0x33
+#define SAVAGE_DESTCTRL_S4            0x34
+#define SAVAGE_DRAWCTRLGLOBAL0_S4     0x35
+#define SAVAGE_DRAWCTRLGLOBAL1_S4     0x36
+#define SAVAGE_ZWATERMARK_S4          0x37
+#define SAVAGE_DESTTEXRWWATERMARK_S4  0x38
+#define SAVAGE_TEXBLENDCOLOR_S4       0x39
+/* Savage3D/MX/IC register BCI addresses */
+#define SAVAGE_TEXPALADDR_S3D         0x18
+#define SAVAGE_TEXXPRCLR_S3D          0x19 /* never used */
+#define SAVAGE_TEXADDR_S3D            0x1A
+#define SAVAGE_TEXDESCR_S3D           0x1B
+#define SAVAGE_TEXCTRL_S3D            0x1C
+#define SAVAGE_FOGTABLE_S3D           0x20
+#define SAVAGE_FOGCTRL_S3D            0x30
+#define SAVAGE_DRAWCTRL_S3D           0x31
+#define SAVAGE_ZBUFCTRL_S3D           0x32
+#define SAVAGE_ZBUFOFF_S3D            0x33
+#define SAVAGE_DESTCTRL_S3D           0x34
+#define SAVAGE_SCSTART_S3D            0x35
+#define SAVAGE_SCEND_S3D              0x36
+#define SAVAGE_ZWATERMARK_S3D         0x37 
+#define SAVAGE_DESTTEXRWWATERMARK_S3D 0x38
+
+#define DV_PF_555           (0x1<<8)
+#define DV_PF_565           (0x2<<8)
+#define DV_PF_8888          (0x4<<8)
+
+#define SAVAGEPACKCOLORA4L4(l,a) \
+  ((l >> 4) | (a & 0xf0))
+
+#define SAVAGEPACKCOLOR4444(r,g,b,a) \
+  ((((a) & 0xf0) << 8) | (((r) & 0xf0) << 4) | ((g) & 0xf0) | ((b) >> 4))
+
+#define SAVAGEPACKCOLOR1555(r,g,b,a) \
+  ((((r) & 0xf8) << 7) | (((g) & 0xf8) << 2) | (((b) & 0xf8) >> 3) | \
+    ((a) ? 0x8000 : 0))
+
+#define SAVAGEPACKCOLOR8888(r,g,b,a) \
+  (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+
+#define SAVAGEPACKCOLOR565(r,g,b) \
+  ((((r) & 0xf8) << 8) | (((g) & 0xfc) << 3) | (((b) & 0xf8) >> 3))
+
+
+
+/*AlphaFunc*/
+#define LCS_A_NEVER              0x0200
+#define LCS_A_LESS               0x0201
+#define LCS_A_EQUAL              0x0202
+#define LCS_A_LEQUAL             0x0203
+#define LCS_A_GREATER            0x0204
+#define LCS_A_NOTEQUAL           0x0205
+#define LCS_A_GEQUAL             0x0206
+#define LCS_A_ALWAYS             0x0207
+/*stencilFunc*/
+#define LCS_S_NEVER              0x0200
+#define LCS_S_LESS               0x0201
+#define LCS_S_EQUAL              0x0202
+#define LCS_S_LEQUAL             0x0203
+#define LCS_S_GREATER            0x0204
+#define LCS_S_NOTEQUAL           0x0205
+#define LCS_S_GEQUAL             0x0206
+#define LCS_S_ALWAYS             0x0207
+/*depthFunc*/
+
+#define LCS_Z_NEVER              0x0200
+#define LCS_Z_LESS               0x0201
+#define LCS_Z_EQUAL              0x0202
+#define LCS_Z_LEQUAL             0x0203
+#define LCS_Z_GREATER            0x0204
+#define LCS_Z_NOTEQUAL           0x0205
+#define LCS_Z_GEQUAL             0x0206
+#define LCS_Z_ALWAYS             0x0207
+#if 0
+#define LCS_UPDATE_LINEWIDTH    (0x1<<15)
+#define LCS_LINEWIDTH_MASK      (0x7<<12)
+#define LCS_LINEWIDTH_SHIFT           12
+#define LCS_LINEWIDTH_0_5       (0x1<<12)
+#define LCS_LINEWIDTH_1_0       (0x2<<12)
+#define LCS_LINEWIDTH_2_0       (0x4<<12)
+#define LCS_LINEWIDTH_3_0       (0x6<<12)
+#define LCS_UPDATE_ALPHA_INTERP (0x1<<11)
+#define LCS_ALPHA_FLAT          (0x1<<10)
+#define LCS_ALPHA_INTERP        (0x0<<10)
+#define LCS_UPDATE_FOG_INTERP   (0x1<<9)
+#define LCS_FOG_INTERP          (0x0<<8)
+#define LCS_FOG_FLAT            (0x1<<8)
+#define LCS_UPDATE_SPEC_INTERP  (0x1<<7)
+#define LCS_SPEC_INTERP         (0x0<<6)
+#define LCS_SPEC_FLAT           (0x1<<6)
+#define LCS_UPDATE_RGB_INTERP   (0x1<<5)
+#define LCS_RGB_INTERP          (0x0<<4)
+#define LCS_RGB_FLAT            (0x1<<4)
+#define LCS_UPDATE_CULL_MODE    (0x1<<3)
+#define LCS_CULL_MASK           (0x7<<0)
+#define LCS_CULL_DISABLE        (0x1<<0)
+#define LCS_CULL_CW             (0x2<<0)
+#define LCS_CULL_CCW            (0x3<<0)
+#define LCS_CULL_BOTH           (0x4<<0)
+
+#define LCS_INTERP_FLAT (LCS_ALPHA_FLAT|LCS_RGB_FLAT|LCS_SPEC_FLAT)
+#define LCS_UPDATE_INTERP (LCS_UPDATE_ALPHA_INTERP|    \
+                          LCS_UPDATE_RGB_INTERP|       \
+                          LCS_UPDATE_SPEC_INTERP)
+
+#endif 
+
+/*#define GFX_OP_PRIMITIVE     ((0x3<<29)|(0x1f<<24))*/
+#define PR_TRIANGLES         (0x0<<18)
+/*#define PR_TRISTRIP_0        (0x1<<18)*/
+/*#define PR_TRISTRIP_1        (0x2<<18)*/
+/*#define PR_TRIFAN            (0x3<<18)*/
+#define PR_POLYGON           (0x4<<18)
+#define PR_LINES             (0x5<<18)
+/*#define PR_LINESTRIP         (0x6<<18)*/
+/*#define PR_RECTS             (0x7<<18)*/
+
+/* GFXRENDERSTATE_MAP_COORD_SETS, p116
+ */
+#define GFX_OP_MAP_COORD_SETS ((0x3<<29)|(0x1c<<24)|(0x1<<19))
+#define MCS_COORD_ID_SHIFT         16
+#define MCS_COORD_0                (0<<16)
+#define MCS_COORD_1                (1<<16)
+#define MCS_UPDATE_NORMALIZED      (1<<15)
+#define MCS_NORMALIZED_COORDS_MASK (1<<14)
+#define MCS_NORMALIZED_COORDS      (1<<14)
+#define MCS_UPDATE_V_STATE         (1<<7)
+#define MCS_V_STATE_MASK           (0x3<<4)
+#define MCS_V_WRAP                 (0x0<<4)
+#define MCS_V_MIRROR               (0x1<<4)
+#define MCS_V_CLAMP                (0x2<<4)
+#define MCS_V_WRAP_SHORTEST        (0x3<<4)
+#define MCS_UPDATE_U_STATE         (1<<3)
+#define MCS_U_STATE_MASK           (0x3<<0)
+#define MCS_U_WRAP                 (0x0<<0)
+#define MCS_U_MIRROR               (0x1<<0)
+#define MCS_U_CLAMP                (0x2<<0)
+#define MCS_U_WRAP_SHORTEST        (0x3<<0)
+
+#define GFX_OP_MAP_TEXELS   ((0x3<<29)|(0x1c<<24)|(0x0<<19))
+#define MT_UPDATE_TEXEL1_STATE     (1<<15)
+#define MT_TEXEL1_DISABLE          (0<<14)
+#define MT_TEXEL1_ENABLE           (1<<14)
+#define MT_TEXEL1_COORD0           (0<<11)
+#define MT_TEXEL1_COORD1           (1<<11)
+#define MT_TEXEL1_MAP0             (0<<8)
+#define MT_TEXEL1_MAP1             (1<<8)
+#define MT_UPDATE_TEXEL0_STATE     (1<<7)
+#define MT_TEXEL0_DISABLE          (0<<6)
+#define MT_TEXEL0_ENABLE           (1<<6)
+#define MT_TEXEL0_COORD0           (0<<3)
+#define MT_TEXEL0_COORD1           (1<<3)
+#define MT_TEXEL0_MAP0             (0<<0)
+#define MT_TEXEL0_MAP1             (1<<0)
+
+#define GFX_OP_COLOR_FACTOR      ((0x3<<29)|(0x1d<<24)|(0x1<<16)|0x0)
+
+/* GFXRENDERSTATE_MAP_ALPHA_BLEND_STAGES, p132
+ */
+#define GFX_OP_MAP_ALPHA_STAGES  ((0x3<<29)|(0x1<<24))
+#define MA_STAGE_SHIFT           20
+#define MA_STAGE_0               (0<<20)
+#define MA_STAGE_1               (1<<20)
+#define MA_STAGE_2               (2<<20)
+#define MA_UPDATE_ARG1           (1<<18)
+#define MA_ARG1_MASK             ((0x7<<15)|(0x1<<13))
+#define MA_ARG1_ALPHA_FACTOR     (0x1<<15)
+#define MA_ARG1_ITERATED_ALPHA   (0x3<<15)
+#define MA_ARG1_CURRENT_ALPHA    (0x5<<15)
+#define MA_ARG1_TEX0_ALPHA       (0x6<<15)
+#define MA_ARG1_TEX1_ALPHA       (0x7<<15)
+#define MA_ARG1_INVERT           (0x1<<13)
+#define MA_ARG1_DONT_INVERT      (0x0<<13)
+#define MA_UPDATE_ARG2           (1<<12)
+#define MA_ARG2_MASK             ((0x7<<8)|(0x1<<6))
+#define MA_ARG2_ALPHA_FACTOR     (0x1<<8)
+#define MA_ARG2_ITERATED_ALPHA   (0x3<<8)
+#define MA_ARG2_CURRENT_ALPHA    (0x5<<8)
+#define MA_ARG2_TEX0_ALPHA       (0x6<<8)
+#define MA_ARG2_TEX1_ALPHA       (0x7<<8)
+#define MA_ARG2_INVERT           (0x1<<6)
+#define MA_ARG2_DONT_INVERT      (0x0<<6)
+#define MA_UPDATE_OP             (1<<5)
+#define MA_OP_MASK                   (0xf)
+#define MA_OP_ARG1                   (0x1)
+#define MA_OP_ARG2                   (0x2)
+#define MA_OP_MODULATE               (0x3)
+#define MA_OP_MODULATE_X2            (0x4)
+#define MA_OP_MODULATE_X4            (0x5)
+#define MA_OP_ADD                    (0x6)
+#define MA_OP_ADD_SIGNED             (0x7)
+#define MA_OP_LIN_BLEND_ITER_ALPHA   (0x8)
+#define MA_OP_LIN_BLEND_ALPHA_FACTOR (0xa)
+#define MA_OP_LIN_BLEND_TEX0_ALPHA   (0x10)
+#define MA_OP_LIN_BLEND_TEX1_ALPHA   (0x11)
+
+
+/* GFXRENDERSTATE_MAP_COLOR_BLEND_STAGES, p129
+ */
+#define GFX_OP_MAP_COLOR_STAGES  ((0x3<<29)|(0x0<<24))
+#define MC_STAGE_SHIFT           20
+#define MC_STAGE_0               (0<<20)
+#define MC_STAGE_1               (1<<20)
+#define MC_STAGE_2               (2<<20)
+#define MC_UPDATE_DEST           (1<<19)
+#define MC_DEST_MASK             (1<<18)
+#define MC_DEST_CURRENT          (0<<18)
+#define MC_DEST_ACCUMULATOR      (1<<18)
+#define MC_UPDATE_ARG1           (1<<17)
+#define MC_ARG1_MASK             ((0x7<<14)|(0x1<<13)|(0x1<<12))
+#define MC_ARG1_ONE              (0x0<<14)
+#define MC_ARG1_COLOR_FACTOR     (0x1<<14)
+#define MC_ARG1_ACCUMULATOR      (0x2<<14)
+#define MC_ARG1_ITERATED_COLOR   (0x3<<14)
+#define MC_ARG1_SPECULAR_COLOR   (0x4<<14)
+#define MC_ARG1_CURRENT_COLOR    (0x5<<14)
+#define MC_ARG1_TEX0_COLOR       (0x6<<14)
+#define MC_ARG1_TEX1_COLOR       (0x7<<14)
+#define MC_ARG1_DONT_REPLICATE_ALPHA   (0x0<<13)
+#define MC_ARG1_REPLICATE_ALPHA        (0x1<<13)
+#define MC_ARG1_DONT_INVERT      (0x0<<12)
+#define MC_ARG1_INVERT           (0x1<<12)
+#define MC_UPDATE_ARG2           (1<<11)
+#define MC_ARG2_MASK             ((0x7<<8)|(0x1<<7)|(0x1<<6))
+#define MC_ARG2_ONE              (0x0<<8)
+#define MC_ARG2_COLOR_FACTOR     (0x1<<8)
+#define MC_ARG2_ACCUMULATOR      (0x2<<8)
+#define MC_ARG2_ITERATED_COLOR   (0x3<<8)
+#define MC_ARG2_SPECULAR_COLOR   (0x4<<8)
+#define MC_ARG2_CURRENT_COLOR    (0x5<<8)
+#define MC_ARG2_TEX0_COLOR       (0x6<<8)
+#define MC_ARG2_TEX1_COLOR       (0x7<<8)
+#define MC_ARG2_DONT_REPLICATE_ALPHA   (0x0<<7)
+#define MC_ARG2_REPLICATE_ALPHA        (0x1<<7)
+#define MC_ARG2_DONT_INVERT      (0x0<<6)
+#define MC_ARG2_INVERT           (0x1<<6)
+#define MC_UPDATE_OP             (1<<5)
+#define MC_OP_MASK                   (0xf)
+#define MC_OP_DISABLE                (0x0)
+#define MC_OP_ARG1                   (0x1)
+#define MC_OP_ARG2                   (0x2)
+#define MC_OP_MODULATE               (0x3)
+#define MC_OP_MODULATE_X2            (0x4)
+#define MC_OP_MODULATE_X4            (0x5)
+#define MC_OP_ADD                    (0x6)
+#define MC_OP_ADD_SIGNED             (0x7)
+#define MC_OP_LIN_BLEND_ITER_ALPHA   (0x8)
+#define MC_OP_LIN_BLEND_ALPHA_FACTOR (0xa)
+#define MC_OP_LIN_BLEND_TEX0_ALPHA   (0x10)
+#define MC_OP_LIN_BLEND_TEX1_ALPHA   (0x11)
+#define MC_OP_LIN_BLEND_TEX0_COLOR   (0x12)
+#define MC_OP_LIN_BLEND_TEX1_COLOR   (0x13)
+#define MC_OP_SUBTRACT               (0x14)
+
+/* GFXRENDERSTATE_MAP_PALETTE_LOAD, p128
+ * 
+ * Format:
+ *     0:  GFX_OP_MAP_PALETTE_LOAD
+ *     1:  16bpp color[0]
+ *     ...
+ *     256: 16bpp color[255]
+ */
+#define GFX_OP_MAP_PALETTE_LOAD ((0x3<<29)|(0x1d<<24)|(0x82<<16)|0xff)
+
+/* GFXRENDERSTATE_MAP_LOD_CONTROL, p127
+ */
+#define GFX_OP_MAP_LOD_CTL       ((0x3<<29)|(0x1c<<24)|(0x4<<19))
+#define MLC_MAP_ID_SHIFT         16
+#define MLC_MAP_0                (0<<16)
+#define MLC_MAP_1                (1<<16)
+#define MLC_UPDATE_DITHER_WEIGHT (1<<10)
+#define MLC_DITHER_WEIGHT_MASK   (0x3<<8)
+#define MLC_DITHER_WEIGHT_FULL   (0x0<<8)
+#define MLC_DITHER_WEIGHT_50     (0x1<<8)
+#define MLC_DITHER_WEIGHT_25     (0x2<<8)
+#define MLC_DITHER_WEIGHT_12     (0x3<<8)
+#define MLC_UPDATE_LOD_BIAS      (1<<7)
+#define MLC_LOD_BIAS_MASK        ((1<<7)-1)
+
+/* GFXRENDERSTATE_MAP_LOD_LIMITS, p126
+ */
+#define GFX_OP_MAP_LOD_LIMITS   ((0x3<<29)|(0x1c<<24)|(0x3<<19))
+#define MLL_MAP_ID_SHIFT         16
+#define MLL_MAP_0                (0<<16)
+#define MLL_MAP_1                (1<<16)
+#define MLL_UPDATE_MAX_MIP       (1<<13)
+#define MLL_MAX_MIP_SHIFT        5
+#define MLL_MAX_MIP_MASK         (0xff<<5)
+#define MLL_MAX_MIP_ONE          (0x10<<5)
+#define MLL_UPDATE_MIN_MIP       (1<<4)
+#define MLL_MIN_MIP_SHIFT        0
+#define MLL_MIN_MIP_MASK         (0xf<<0)
+
+/* GFXRENDERSTATE_MAP_FILTER, p124
+ */
+#define GFX_OP_MAP_FILTER       ((0x3<<29)|(0x1c<<24)|(0x2<<19))
+#define MF_MAP_ID_SHIFT         16
+#define MF_MAP_0                (0<<16)
+#define MF_MAP_1                (1<<16)
+#define MF_UPDATE_ANISOTROPIC   (1<<12)
+#define MF_ANISOTROPIC_MASK     (1<<10)
+#define MF_ANISOTROPIC_ENABLE   (1<<10)
+#define MF_UPDATE_MIP_FILTER    (1<<9)
+#define MF_MIP_MASK             (0x3<<6)
+#define MF_MIP_NONE             (0x0<<6)
+#define MF_MIP_NEAREST          (0x1<<6)
+#define MF_MIP_DITHER           (0x2<<6)
+#define MF_MIP_LINEAR           (0x3<<6)
+#define MF_UPDATE_MAG_FILTER    (1<<5)
+#define MF_MAG_MASK             (1<<3)
+#define MF_MAG_LINEAR           (1<<3)
+#define MF_MAG_NEAREST          (0<<3)
+#define MF_UPDATE_MIN_FILTER    (1<<2)
+#define MF_MIN_MASK             (1<<0)
+#define MF_MIN_LINEAR           (1<<0)
+#define MF_MIN_NEAREST          (0<<0)
+
+/* GFXRENDERSTATE_MAP_INFO, p118
+ */
+#define GFX_OP_MAP_INFO      ((0x3<<29)|(0x1d<<24)|0x2)
+#define MI1_MAP_ID_SHIFT         28
+#define MI1_MAP_0                (0<<28)
+#define MI1_MAP_1                (1<<28)
+#define MI1_FMT_MASK             (0x7<<24)
+#define MI1_FMT_8CI              (0x0<<24)
+#define MI1_FMT_8BPP             (0x1<<24)
+#define MI1_FMT_16BPP            (0x2<<24)
+#define MI1_FMT_422              (0x5<<24)
+#define MI1_PF_MASK              (0x3<<21)
+#define MI1_PF_8CI_RGB565         (0x0<<21)
+#define MI1_PF_8CI_ARGB1555       (0x1<<21)
+#define MI1_PF_8CI_ARGB4444       (0x2<<21)
+#define MI1_PF_8CI_AY88           (0x3<<21)
+#define MI1_PF_16BPP_RGB565       (0x0<<21)
+#define MI1_PF_16BPP_ARGB1555     (0x1<<21)
+#define MI1_PF_16BPP_ARGB4444     (0x2<<21)
+#define MI1_PF_16BPP_AY88         (0x3<<21)
+#define MI1_PF_422_YCRCB_SWAP_Y   (0x0<<21)
+#define MI1_PF_422_YCRCB          (0x1<<21)
+#define MI1_PF_422_YCRCB_SWAP_UV  (0x2<<21)
+#define MI1_PF_422_YCRCB_SWAP_YUV (0x3<<21)
+#define MI1_OUTPUT_CHANNEL_MASK   (0x3<<19)
+#define MI1_COLOR_CONV_ENABLE     (1<<18)
+#define MI1_VERT_STRIDE_MASK      (1<<17)
+#define MI1_VERT_STRIDE_1         (1<<17)
+#define MI1_VERT_OFFSET_MASK      (1<<16)
+#define MI1_VERT_OFFSET_1         (1<<16)
+#define MI1_ENABLE_FENCE_REGS     (1<<10)
+#define MI1_TILED_SURFACE         (1<<9)
+#define MI1_TILE_WALK_X           (0<<8)
+#define MI1_TILE_WALK_Y           (1<<8)
+#define MI1_PITCH_MASK            (0xf<<0)
+#define MI2_DIMENSIONS_ARE_LOG2   (1<<31)
+#define MI2_DIMENSIONS_ARE_EXACT  (0<<31)
+#define MI2_HEIGHT_SHIFT          16
+#define MI2_HEIGHT_MASK           (0x1ff<<16)
+#define MI2_WIDTH_SHIFT           0
+#define MI2_WIDTH_MASK            (0x1ff<<0)
+#define MI3_BASE_ADDR_MASK        (~0xf)
+
+#define SAVAGE_VFMT_T0 (GFX_OP_VERTEX_FMT |    \
+                     VF_TEXCOORD_COUNT_1 |     \
+                     VF_SPEC_FOG_ENABLE |      \
+                     VF_RGBA_ENABLE |          \
+                     VF_XYZW)
+
+#define SAVAGE_VFMT_T0T1 (GFX_OP_VERTEX_FMT |  \
+                       VF_TEXCOORD_COUNT_2 |   \
+                       VF_SPEC_FOG_ENABLE |    \
+                       VF_RGBA_ENABLE |        \
+                       VF_XYZW)
+
+#define GFX_OP_VERTEX_FMT  ((0x3<<29)|(0x5<<24))
+#define VF_TEXCOORD_COUNT_SHIFT    8
+#define VF_TEXCOORD_COUNT_0        (0<<8)
+#define VF_TEXCOORD_COUNT_1        (1<<8)
+#define VF_TEXCOORD_COUNT_2        (2<<8)
+#define VF_SPEC_FOG_ENABLE         (1<<7)
+#define VF_RGBA_ENABLE             (1<<6)
+#define VF_Z_OFFSET_ENABLE         (1<<5)
+#define VF_XYZ                     (0x1<<1)
+#define VF_XYZW                    (0x2<<1)
+#define VF_XY                      (0x3<<1)
+#define VF_XYW                     (0x4<<1)
+
+/* Master data transfer engine */
+#define MDT_SRCADD_ALIGMENT (~0x1fUL)
+#define MDT_SRC_PCI 0x1
+#define MDT_SRC_AGP 0x3
+#endif
+
+
diff --git a/src/mesa/drivers/dri/savage/savage_bci.h b/src/mesa/drivers/dri/savage/savage_bci.h
new file mode 100644 (file)
index 0000000..adaf579
--- /dev/null
@@ -0,0 +1,741 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef SAVAGE_BCI_H
+#define SAVAGE_BCI_H
+/***********************
+  3D and 2D command
+************************/
+
+typedef enum {
+    AMO_BurstCmdData=   0x01010000,
+    AMO_3DReg=          0x01048500,
+    AMO_MotionCompReg=  0x01048900,
+    AMO_VideoEngUnit=   0x01048A00,
+    AMO_CmdBufAddr=     0x01048c14,
+    AMO_TiledSurfReg0=  0x01048C40,
+    AMO_TiledSurfReg1=  0x01048C44,
+    AMO_TiledSurfReg2=  0x01048C48,
+    AMO_TiledSurfReg3=  0x01048C4C,
+    AMO_TiledSurfReg4=  0x01048C50,
+    AMO_TiledSurfReg5=  0x01048C54,
+    AMO_TiledSurfReg6=  0x01048C58,
+    AMO_TiledSurfReg7=  0x01048C5C,
+    AMO_LPBModeReg=     0x0100FF00,
+    AMO_LPBFifoSat=     0x0100FF04,
+    AMO_LPBIntFlag=     0x0100FF08,
+    AMO_LPBFmBufA0=     0x0100FF0C,
+    AMO_LPBFmBufA1=     0x0100FF10,
+    AMO_LPBRdWtAdr=     0x0100FF14,
+    AMO_LPBRdWtDat=     0x0100FF18,
+    AMO_LPBIOPort =     0x0100FF1C,
+    AMO_LPBSerPort=     0x0100FF20,
+    AMO_LPBVidInWinSz=  0x0100FF24,
+    AMO_LPBVidDatOffs=  0x0100FF28,
+    AMO_LPBHorScalCtrl= 0x0100FF2C,
+    AMO_LPBVerDeciCtrl= 0x0100FF30,
+    AMO_LPBLnStride=    0x0100FF34,
+    AMO_LPBFmBufAddr2=  0x0100FF38,
+    AMO_LPBVidCapVDCtrl=0x0100FF3C,
+
+    AMO_LPBVidCapFdStAd=0x0100FF60,
+    AMO_LPBVidCapFdMdAd=0x0100FF64,
+    AMO_LPBVidCapFdBtAd=0x0100FF68,
+    AMO_LPBVidCapFdSize=0x0100FF6C,
+    AMO_LPBBilinDecim1= 0x0100FF70,
+    AMO_LPBBilinDecim2= 0x0100FF74,
+    AMO_LPBBilinDecim3= 0x0100FF78,
+    AMO_LPBDspVEUHorSRR=0x0100FF7C,
+    AMO_LPBDspVEUVerSRR=0x0100FF80,
+    AMO_LPBDspVeuDnScDR=0x0100FF84,
+    AMO_LPB_VEUERPReg=  0x0100FF88,
+    AMO_LPB_VBISelReg=  0x0100FF8C,
+    AMO_LPB_VBIBasAdReg=0x0100FF90,
+    AMO_LPB_DatOffsReg= 0x0100FF94,
+    AMO_LPB_VBIVerDcReg=0x0100FF98,
+    AMO_LPB_VBICtrlReg= 0x0100FF9C,
+    AMO_LPB_VIPXferCtrl=0x0100FFA0,
+    AMO_LPB_FIFOWtMark= 0x0100FFA4,
+    AMO_LPB_FIFOCount=  0x0100FFA8,
+    AMO_LPBFdSkipPat=   0x0100FFAC,
+    AMO_LPBCapVEUHorSRR=0x0100FFB0,
+    AMO_LPBCapVEUVerSRR=0x0100FFB4,
+    AMO_LPBCapVeuDnScDR=0x0100FFB8
+
+}AddressMapOffset;   
+/*more to add*/
+
+
+typedef enum {
+  CMD_DrawPrim=0x10,          /*10000*/
+  CMD_DrawIdxPrim=0x11,       /*10001*/
+  CMD_SetRegister=0x12,       /*10010*/
+  CMD_UpdateShadowStat=0x13 , /*10011*/
+  CMD_PageFlip=0x14,          /* 10100*/
+  CMD_BusMasterImgXfer=0x15,  /* 10101*/
+  CMD_ScaledImgXfer=0x16,     /* 10110*/
+  CMD_Macroblock=0x17,         /*10111*/
+  CMD_Wait= 0x18,             /*11000*/
+  CMD_2D_NOP=0x08,            /* 01000*/
+  CMD_2D_RCT=0x09,            /*01001   rectangular fill*/
+  CMD_2D_SCNL=0x0a,           /* 01010   scan line*/
+  CMD_2D_LIN=0x0b,            /*01011   line*/
+  CMD_2D_SMTXT=0x0c,          /*01100*/
+  CMD_2D_BPTXT=0x0d,          /*01101*/
+  CMD_InitFlag=0x1f           /*11111, for S/W initialization control*/
+}Command;
+
+
+typedef enum {
+    VRR_List,
+    VRR_Strip,
+    VRR_Fan,
+    VRR_QuadList
+}VertexReplaceRule;
+
+/***********************
+   Destination
+************************/
+
+typedef enum {
+    DFT_RGB565 = 0,
+    DFT_XRGB8888
+}DestinationFmt;
+
+
+/*************************
+    Z Buffer / Alpha test
+*************************/
+
+typedef enum {
+    ZCF_Never,
+    ZCF_Less,
+    ZCF_Equal,
+    ZCF_LessEqual,
+    ZCF_Greater,
+    ZCF_NotEqual,
+    ZCF_GreaterEqual,
+    ZCF_Always
+}ZCmpFunc;   /* same for Alpha test compare function*/
+
+
+typedef enum {
+  ZDS_16i,    /* .16 fixed*/
+  ZDS_32f     /* 1.8.15 float*/
+}ZDepthSelect;
+
+
+/**********************************
+    BCI Register Addressing Index
+***********************************/
+typedef enum {
+
+    CRI_VTX0_X =    0x00,
+    CRI_VTX0_Y =    0x01,
+    CRI_VTX0_W =    0x02,
+    CRI_VTX0_DIFFU= 0x03,
+    CRI_VTX0_SPECU= 0x04,
+    CRI_VTX0_U =    0x05,
+    CRI_VTX0_V =    0x06,
+    CRI_VTX0_U2 =   0x07,
+    CRI_VTX0_V2 =   0x08,
+    CRI_VTX1_X =    0x09,
+    CRI_VTX1_Y =    0x0a,
+    CRI_VTX1_W =    0x0b,
+    CRI_VTX1_DIFFU= 0x0c,
+    CRI_VTX1_SPECU= 0x0d,
+    CRI_VTX1_U =    0x0e,
+    CRI_VTX1_V =    0x0f,
+    CRI_VTX1_U2 =   0x10,
+    CRI_VTX1_V2 =   0x11,
+    CRI_VTX2_X =    0x12,
+    CRI_VTX2_Y =    0x13,
+    CRI_VTX2_W =    0x14,
+    CRI_VTX2_DIFFU= 0x15,
+    CRI_VTX2_SPECU= 0x16,
+    CRI_VTX2_U =    0x17,
+    CRI_VTX2_V =    0x18,
+    CRI_VTX2_U2 =   0x19,
+    CRI_VTX2_V2 =   0x1a,
+
+    CRI_ZPixelOffset  = 0x1d,
+    CRI_DrawCtrlLocal = 0x1e,
+    CRI_TexPalAddr    = 0x1f,
+    CRI_TexCtrl0      = 0x20,
+    CRI_TexCtrl1      = 0x21,
+    CRI_TexAddr0      = 0x22,
+    CRI_TexAddr1      = 0x23,
+    CRI_TexBlendCtrl0 = 0x24,
+    CRI_TexBlendCtrl1 = 0x25,
+    CRI_TexXprClr     = 0x26,
+    CRI_TexDescr      = 0x27,
+
+    CRI_FogTable00= 0x28,
+    CRI_FogTable04= 0x29,
+    CRI_FogTable08= 0x2a,
+    CRI_FogTable12= 0x2b,
+    CRI_FogTable16= 0x2c,
+    CRI_FogTable20= 0x2d,
+    CRI_FogTable24= 0x2e,
+    CRI_FogTable28= 0x2f,
+    CRI_FogCtrl=    0x30,
+    CRI_StencilCtrl= 0x31,
+    CRI_ZBufCtrl=   0x32,
+    CRI_ZBufOffset= 0x33,
+    CRI_DstCtrl=    0x34,
+    CRI_DrawCtrlGlobal0=   0x35,
+    CRI_DrawCtrlGlobal1=   0x36,
+    CRI_ZRW_WTMK =  0x37,
+    CRI_DST_WTMK =  0x38,
+    CRI_TexBlendColor= 0x39,
+
+    CRI_VertBufAddr= 0x3e,
+    /* new in ms1*/
+    CRI_MauFrameAddr0 = 0x40,
+    CRI_MauFrameAddr1 = 0x41,
+    CRI_MauFrameAddr2 = 0x42,
+    CRI_MauFrameAddr3 = 0x43,
+    CRI_FrameDesc     = 0x44,
+    CRI_IDCT9bitEn    = 0x45,
+    CRI_MV0           = 0x46,
+    CRI_MV1           = 0x47,
+    CRI_MV2           = 0x48,
+    CRI_MV3           = 0x49,
+    CRI_MacroDescr    = 0x4a,  /*kickoff?*/
+    
+    CRI_MeuCtrl = 0x50,
+    CRI_SrcYAddr = 0x51,
+    CRI_DestAddr = 0x52,
+    CRI_FmtrSrcDimen = 0x53,
+    CRI_FmtrDestDimen = 0x54,
+    CRI_SrcCbAddr = 0x55,
+    CRI_SrcCrAddr = 0x56,
+    CRI_SrcCrCbStride = 0x57,
+    
+    CRI_BCI_Power= 0x5f,
+    
+    CRI_PSCtrl=0xA0,
+    CRI_SSClrKeyCtrl=0xA1,
+    CRI_SSCtrl=0xA4,
+    CRI_SSChromUpBound=0xA5,
+    CRI_SSHoriScaleCtrl=0xA6,
+    CRI_SSClrAdj=0xA7,
+    CRI_SSBlendCtrl=0xA8,
+    CRI_PSFBAddr0=0xB0,
+    CRI_PSFBAddr1=0xB1,
+    CRI_PSStride=0xB2,
+    CRI_DB_LPB_Support=0xB3,
+    CRI_SSFBAddr0=0xB4,
+    CRI_SSFBAddr1=0xB5,
+    CRI_SSStride=0xB6,
+    CRI_SSOpaqueCtrl=0xB7,
+    CRI_SSVertScaleCtrl=0xB8,
+    CRI_SSVertInitValue=0xB9,
+    CRI_SSSrcLineCnt=0xBA,
+    CRI_FIFO_RAS_Ctrl=0xBB,
+    CRI_PSWinStartCoord=0xBC,
+    CRI_PSWinSize=0xBD,
+    CRI_SSWinStartCoord=0xBE,
+    CRI_SSWinSize=0xBF,
+    CRI_PSFIFOMon0=0xC0,
+    CRI_SSFIFOMon0=0xC1,
+    CRI_PSFIFOMon1=0xC2,
+    CRI_SSFIFOMon1=0xC3,
+    CRI_PSFBSize=0xC4,
+    CRI_SSFBSize=0xC5,
+    CRI_SSFBAddr2=0xC6,
+    /* 2D register starts at D0*/
+    CRI_CurrXY=0xD0,
+    CRI_DstXYorStep=0xD1 ,
+    CRI_LineErr=0xD2 ,
+    CRI_DrawCmd=0xD3,   /*kick off for image xfer*/
+    CRI_ShortStrkVecXfer=0xD4,
+    CRI_BackClr=0xD5,
+    CRI_ForeClr=0xD6,
+    CRI_BitPlaneWtMask=0xD7,
+    CRI_BitPlaneRdMask=0xD8,
+    CRI_ClrCmp=0xD9 ,
+    CRI_BackAndForeMix=0xDA ,
+    CRI_TopLeftSciss=0xDB ,
+    CRI_BotRightSciss=0xDC ,
+    CRI_PixOrMultiCtrl=0xDD ,
+    CRI_MultiCtrlOrRdSelct=0xDE ,
+    CRI_MinorOrMajorAxisCnt=0xDF ,
+    CRI_GlobalBmpDesc1=0xE0 ,
+    CRI_GlobalBmpDesc2=0xE1 ,
+    CRI_BurstPriBmpDesc1=0xE2 ,
+    CRI_BurstPriBmpDesc2=0xE3 ,
+    CRI_BurstSecBmpDesc1=0xE4 ,
+    CRI_BurstSecBmpDesc2=0xE5,
+    CRI_ImageDataPort=0xF8
+
+}CtrlRegIdx;
+
+/***********************
+        Fog Mode
+************************/
+typedef enum
+{
+  FGM_Z_FOG,  /*Table*/
+  FGM_V_FOG   /*Vertex*/
+} FogMode;
+
+/***********************
+  Texture
+************************/
+typedef enum
+{
+    TAM_Wrap,
+    TAM_Clamp,
+    TAM_Mirror
+} TexAddressModel;
+
+typedef enum
+{
+    TFT_S3TC4Bit,
+    TFT_Pal8Bit565,
+    TFT_Pal8Bit1555,
+    TFT_ARGB8888,
+    TFT_ARGB1555,
+    TFT_ARGB4444,
+    TFT_RGB565,
+    TFT_Pal8Bit4444,
+    TFT_S3TC4A4Bit,  /*like S3TC4Bit but with 4 bit alpha*/
+    TFT_S3TC4CA4Bit, /*like S3TC4Bit, but with 4 bit compressed alpha*/
+    TFT_S3TCL4,
+    TFT_S3TCA4L4,
+    TFT_L8,
+    TFT_A4L4,
+    TFT_I8,
+    TFT_A8
+} TexFmt;
+
+typedef enum
+{
+    TPS_64,
+    TPS_128,
+    TPS_192,
+    TPS_256
+} TexPaletteSize;
+
+    #define MAX_MIPMAP_LOD_BIAS             255
+    #define MIN_MIPMAP_LOD_BIAS             -255
+
+typedef enum
+{
+  TFM_Point,              /*1 TPP*/
+  TFM_Bilin,              /*2 TPP*/
+  TFM_Reserved,
+  TFM_Trilin             /*16 TPP*/
+} TexFilterMode;
+
+
+#define TBC_Decal       0x00850410
+#define TBC_Modul       0x00850011
+#define TBC_DecalAlpha  0x00852A04
+#define TBC_ModulAlpha  0x00110011
+#define TBC_Copy        0x00840410
+#define TBC_CopyAlpha   0x00900405
+#define TBC_NoTexMap    0x00850405
+#define TBC_Blend0      0x00810004
+#define TBC_Blend1      0x00870e02
+#define TBC_BlendAlpha0 0x00040004
+#define TBC_BlendAlpha1 TBC_Blend1
+#define TBC_BlendInt0   0x00040004
+#define TBC_BlendInt1   0x01c20e02
+#define TBC_AddAlpha    0x19910c11
+
+#define TBC_Decal1      0x00870410
+#define TBC_Modul1      0x00870013
+#define TBC_DecalAlpha1 0x00832A00
+#define TBC_ModulAlpha1 0x00130013
+#define TBC_NoTexMap1   0x00870407
+#define TBC_Copy1       0x00870400
+#define TBC_CopyAlpha1  0x00900400
+#define TBC_AddAlpha1   0x19930c13
+
+/*
+ * derived from TexBlendCtrl
+ */
+
+typedef enum
+{
+    TBC_UseSrc,
+    TBC_UseTex,
+    TBC_TexTimesSrc,
+    TBC_BlendTexWithSrc
+} TexBlendCtrlMode;
+
+/***********************
+        Draw Control
+************************/
+typedef enum
+{
+    BCM_Reserved,
+    BCM_None,
+    BCM_CW,
+    BCM_CCW
+} BackfaceCullingMode;
+
+typedef enum
+{
+    SAM_Zero,
+    SAM_One,
+    SAM_DstClr,
+    SAM_1DstClr,
+    SAM_SrcAlpha,
+    SAM_1SrcAlpha,
+    SAM_DstAlpha,
+    SAM_1DstAlpha
+} SrcAlphaBlendMode;
+
+/* -1 from state*/
+typedef enum
+{
+    DAM_Zero,
+    DAM_One,
+    DAM_SrcClr,
+    DAM_1SrcClr,
+    DAM_SrcAlpha,
+    DAM_1SrcAlpha,
+    DAM_DstAlpha,
+    DAM_1DstAlpha
+} DstAlphaBlendMode;
+
+/*
+ * stencil control
+ */
+
+typedef enum
+{
+    STC_COMP_Never,
+    STC_COMP_Less,
+    STC_COMP_Equal,
+    STC_COMP_LessEqual,
+    STC_COMP_Greater,
+    STC_COMP_NotEqual,
+    STC_COMP_GreaterEqual,
+    STC_COMP_Always
+} StencilCompareMode;
+
+typedef enum
+{
+    STC_FAIL_Keep,
+    STC_FAIL_Zero,
+    STC_FAIL_Equal,
+    STC_FAIL_IncClamp,
+    STC_FAIL_DecClamp,
+    STC_FAIL_Invert,
+    STC_FAIL_Inc,
+    STC_FAIL_Dec
+} StencilFailOp;
+
+typedef enum
+{
+    STC_ZPASS_Keep,
+    STC_ZPASS_Zero,
+    STC_ZPASS_Equal,
+    STC_ZPASS_IncClamp,
+    STC_ZPASS_DecClamp,
+    STC_ZPASS_Invert,
+    STC_ZPASS_Inc,
+    STC_ZPASS_Dec
+} StencilZPassOp;
+
+typedef enum
+{
+    STC_ZFAIL_Keep,
+    STC_ZFAIL_Zero,
+    STC_ZFAIL_Equal,
+    STC_ZFAIL_IncClamp,
+    STC_ZFAIL_DecClamp,
+    STC_ZFAIL_Invert,
+    STC_ZFAIL_Inc,
+    STC_ZFAIL_Dec
+} StencilZFailOp;
+
+/***************************************************************
+*** Bitfield Structures for Programming Interface **************
+***************************************************************/
+
+/**************************
+ Command Header Entry
+**************************/
+
+typedef struct {  /*for DrawIndexPrimitive command, vert0Idx is meaningful.*/
+    unsigned int vert0Idx:16;
+    unsigned int vertCnt:8;
+    unsigned int cont:1;
+    unsigned int type:2;   /*00=list, 01=strip, 10=fan, 11=reserved*/
+    unsigned int cmd:5;
+}Reg_DrawIndexPrimitive;
+
+typedef struct {  /*for DrawIndexPrimitive command, vert0Idx is meaningful.*/
+    unsigned int noW:1;
+    unsigned int noCd:1;
+    unsigned int noCs:1;
+    unsigned int noU:1;
+    unsigned int noV:1;
+    unsigned int noU2:1;
+    unsigned int noV2:1;
+
+    unsigned int reserved:9;
+    unsigned int vertCnt:8;
+    unsigned int cont:1;
+    unsigned int type:2;   /* 00=list, 01=strip, 10=fan, 11=reserved*/
+    unsigned int cmd:5;
+}Reg_DrawPrimitive;
+
+
+typedef struct {
+    unsigned int startRegIdx:8;
+    unsigned int reserved:8;
+    unsigned int regCnt:8;
+    unsigned int resvered1:1;
+    unsigned int lowEn:1;
+    unsigned int highEn:1;
+    unsigned int cmd:5;
+}Reg_SetRegister;
+
+typedef struct {
+    unsigned int reserved1:22;
+    unsigned int isPrimary:1;
+    unsigned int MIU_SYNC:1;
+    unsigned int reserved2:3;
+    unsigned int cmd:5;
+}Reg_QueuedPageFlip;
+
+typedef struct {
+    unsigned int reserved1:22;
+    unsigned int DIR:1;
+    unsigned int CTG:1; /*set to 0*/
+    unsigned int BPP:1;
+    unsigned int reserved2:1;
+    unsigned int cmd:5;
+}Reg_MasterImgXfer;
+
+typedef struct {
+    unsigned int PD:4;   /*PM=mono, PS=descriptor specified*/
+    unsigned int PT:1;
+    unsigned int SD:4;
+    unsigned int ST:1;
+    unsigned int DD:3;
+    unsigned int DC:2; /*DC=destination clip*/
+  unsigned int CS:1;  /*cs=color specified*/
+    unsigned int MIX3:8;
+    unsigned int XP:1;
+    unsigned int YP:1;
+    unsigned int LP:1;
+    unsigned int cmd:5;
+}Reg_2D;
+
+typedef struct {
+    unsigned int CodedBlkPattern:6;
+    unsigned int DCT_Type:1;
+    unsigned int MB_Type:2;
+    unsigned int MotionType:2;
+    unsigned int MB_Row:6;
+    unsigned int MB_Column:6;
+    unsigned int mv3:1;
+    unsigned int mv2:1;
+    unsigned int mv1:1;
+    unsigned int mv0:1;
+    unsigned int cmd:5;
+}Reg_MacroBlock;
+
+typedef struct {
+    unsigned int scanLnCnt:11;
+    unsigned int clkCnt:5;
+    unsigned int e3d:1;
+    unsigned int e2d:1;
+    unsigned int mau:1;
+    unsigned int veu:1;
+    unsigned int meuMit:1;
+    unsigned int meuSit:1;
+    unsigned int meuVx:1;
+    unsigned int meuMau:1;
+    unsigned int pageFlip:1;
+    unsigned int scanLn:1;
+    unsigned int clk:1;
+    unsigned int cmd:5;
+}Reg_Wait;
+
+typedef struct{
+    unsigned int reserved:27;
+    unsigned int cmd:5;
+}Reg_ScaledImgXfer  ;
+
+typedef struct{
+    unsigned int eventTag:16;
+    unsigned int reserved2:6;
+    unsigned int ET:1;
+    unsigned int INT:1;
+    unsigned int reserved1:3;
+    unsigned int cmd:5;
+}Reg_UpdtShadowStat;
+
+typedef union {
+    Reg_DrawPrimitive  vert;
+    Reg_DrawIndexPrimitive  vertIdx;
+    Reg_SetRegister    set;
+    Reg_QueuedPageFlip pageFlip;
+    Reg_MasterImgXfer  masterImgXfer;
+    Reg_ScaledImgXfer  scaledImgXfer;
+    Reg_UpdtShadowStat updtShadow;
+    Reg_MacroBlock     macroBlk;
+    Reg_2D             cmd2D;
+    Reg_Wait           wait;
+}CmdHeaderUnion;
+
+
+/*frank 2001/11/14 add BCI write macros*/
+/* Registers not used in the X server
+ */
+
+#define SAVAGE_NOP_ID           0x2094
+#define SAVAGE_NOP_ID_MASK        ((1<<22)-1)
+
+
+/* 3D instructions
+ */
+
+/*          Draw Primitive Control */
+
+
+#define SAVAGE_HW_NO_Z          (1<<0)
+#define SAVAGE_HW_NO_W          (1<<1)
+#define SAVAGE_HW_NO_CD         (1<<2)
+#define SAVAGE_HW_NO_CS         (1<<3)
+#define SAVAGE_HW_NO_UV0        ((1<<4) | (1<<5))
+#define SAVAGE_HW_NO_UV1        ((1<<6) | (1<<7))
+
+#define SAVAGE_HW_TRIANGLE_TYPE     (3UL<<25)
+#define SAVAGE_HW_TRIANGLE_CONT     (1UL<<24)
+#define SAVAGE_HW_TRIANGLE_LIST     (0<<25) 
+#define SAVAGE_HW_TRIANGLE_STRIP    (1<<25) 
+#define SAVAGE_HW_TRIANGLE_FAN      (2<<25) 
+#define SAVAGE_HW_QUAD              (3<<25) 
+
+#define __HW_TEXTURE_CHANGED       0x00002FE
+#define __HW_HAS_SCISSORS_CHANGED  0x00001800
+#define __HW_ALL_CHANGED           0x1FFFFFF           
+/*Frank 2001/11/14 Wait commands*/
+#define WAIT_3D_IDLE    0xC0010000
+#define WAIT_3D_2D_IDLE 0xC0030000
+
+#define SET_REGISTER(index, count) \
+    ((CMD_SetRegister << 27) | (0x6000000) | ((count) << 16) | (index))
+
+/*frank 2001/11/20 */
+#define MAXLOOP 0xFFFFFF
+/*#define MAXFIFO 0x7F00*/
+#define MAXFIFO 0x1FF00
+
+/* get eventtag from shadow status */
+/* here we use eventTag1 because eventTag0 is used by HWXvMC*/
+#define GET_EVENTTAG \
+    (((*(volatile GLuint *)(imesa->MMIO_BASE+0x48c04)) & 0xffff0000L)>>16)
+
+#define SHADOW_WAIT(imesa ) do \
+{ \
+    int loop=0; \
+    imesa->shadowCounter = (imesa->shadowCounter + 1) & 0xffff;\
+    if(imesa->shadowCounter == 0)\
+      imesa->shadowCounter = MAX_SHADOWCOUNTER;\
+    *(volatile GLuint *)imesa->BCIBase = imesa->shadowCounter | 0x98400000L;\
+    while(\
+         (GET_EVENTTAG) != imesa->shadowCounter  &&\
+         (loop++ < MAXLOOP));\
+}while(0);
+
+#define SHADOW_WAIT_IDLE(imesa ) do \
+{ \
+    int loop=0; \
+    imesa->shadowCounter = (imesa->shadowCounter + 1) & 0xffff;\
+    if(imesa->shadowCounter == 0)\
+      imesa->shadowCounter = MAX_SHADOWCOUNTER;\
+/*    *(volatile GLuint *)imesa->BCIBase = WAIT_3D_IDLE;\*/\
+    *(volatile GLuint *)imesa->BCIBase = imesa->shadowCounter | 0x98400000L;\
+    while ( \
+    (GET_EVENTTAG) != imesa->shadowCounter && \
+    (loop++ < MAXLOOP)); \
+}while(0);
+
+#if 0
+#define ALT_STATUS_WORD0 (* (volatile GLuint *)(imesa->MMIO_BASE+0x48c60))
+
+#define PAGE_PENDING(result) do{\
+result=((ALT_STATUS_WORD0 & 0x08000000)?GL_TRUE:GL_FALSE);\
+}while(0)
+
+#define WAIT_FOR_FIFO(count) do{\
+int loop = 0; \
+int slots = MAXFIFO-count; \
+while(((ALT_STATUS_WORD0 &0x001fffff)>slots)&&(loop++<MAXLOOP)); \
+}while(0)
+
+
+#define WAIT_IDLE_EMPTY do{\
+int loop = 0; \
+ if (/*imesa->shadowStatus*/0)\
+   {\
+     SHADOW_WAIT_IDLE(imesa);\
+   }\
+ else\
+   { \
+     while(((ALT_STATUS_WORD0 &0x00ffffff)!=0x00E00000L)&&(loop++<MAXLOOP));\
+   }\
+}while(0)
+
+#define WAIT_IDLE do{\
+int loop = 0; \
+if (imesa->shadowStatus)\
+ while((((*imesa->shadowPointer) & 0x0E000000L)!=0x0E000000L)&&(loop++<MAXLOOP));\
+else\
+while(((ALT_STATUS_WORD0 &0x00E00000)!=0x00E00000L)&&(loop++<MAXLOOP)); \
+}while(0)
+#endif /* 0 */
+
+#define SAVAGE_DRAW_PRIMITIVE(count, typeandvertexSkip, isCont)  \
+        ( ((count)<<16) | (typeandvertexSkip) | (isCont | (1<<31)));
+
+static __inline volatile GLuint * SAVAGE_GET_BCI_POINTER(savageContextPtr imesa, GLuint count)   
+{ 
+  WAIT_FOR_FIFO(count);                                
+  return (volatile GLuint *)(imesa->BCIBase);      
+}
+
+/*use this set bci cmd now!*/
+#define WRITE_CMD(buf,cmd,type) do {\
+    *((type*)buf)=cmd;\
+    buf++;\
+  }while(0)
+#endif
+
+
+
+
+
+
diff --git a/src/mesa/drivers/dri/savage/savage_init.h b/src/mesa/drivers/dri/savage/savage_init.h
new file mode 100644 (file)
index 0000000..c55c62d
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef _SAVAGE_INIT_H_
+#define _SAVAGE_INIT_H_
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include <sys/time.h>
+#include "dri_util.h"
+#include "mtypes.h"
+
+typedef struct {
+   drmHandle handle;
+   drmSize size;
+   char *map;
+} savageRegion, *savageRegionPtr;
+
+typedef struct {
+   savageRegion front;
+   savageRegion back;
+   savageRegion depth;
+   savageRegion aperture;
+
+   int chipset;
+   int width;
+   int height;
+   int mem;
+
+   int cpp;                    /* for front and back buffers */
+   int zpp;
+#if 0 
+   int bitsPerPixel;
+#endif
+   unsigned int frontFormat;
+   unsigned int frontOffset;
+   unsigned int frontPitch;
+   unsigned int frontBitmapDesc;
+
+   unsigned int backOffset;
+   unsigned int backBitmapDesc;
+   unsigned int depthOffset;
+   unsigned int depthBitmapDesc;
+
+   unsigned int backPitch;
+   unsigned int backPitchBits;
+
+   unsigned int textureOffset[SAVAGE_NR_TEX_HEAPS];
+   unsigned int textureSize[SAVAGE_NR_TEX_HEAPS];
+   unsigned int logTextureGranularity[SAVAGE_NR_TEX_HEAPS];
+   drmAddress texVirtual[SAVAGE_NR_TEX_HEAPS];
+  
+  __DRIscreenPrivate *driScrnPriv;
+  drmBufMapPtr  bufs;
+  int use_copy_buf;
+  unsigned int sarea_priv_offset;
+} savageScreenPrivate;
+
+
+#include "savagecontext.h"
+
+extern void savageGetLock( savageContextPtr imesa, GLuint flags );
+extern void savageEmitHwStateLocked( savageContextPtr imesa );
+extern void savageEmitScissorValues( savageContextPtr imesa, int box_nr, int emit );
+extern void savageEmitDrawingRectangle( savageContextPtr imesa );
+extern void savageXMesaSetBackClipRects( savageContextPtr imesa );
+extern void savageXMesaSetFrontClipRects( savageContextPtr imesa );
+
+
+#define GET_DISPATCH_AGE( imesa ) imesa->sarea->last_dispatch
+#define GET_ENQUEUE_AGE( imesa ) imesa->sarea->last_enqueue
+
+
+/* Lock the hardware and validate our state.  
+ */
+#define LOCK_HARDWARE( imesa )                         \
+  do {                                                 \
+    char __ret=0;                                      \
+    DRM_CAS(imesa->driHwLock, imesa->hHWContext,       \
+           (DRM_LOCK_HELD|imesa->hHWContext), __ret);  \
+    if (__ret)                                         \
+        savageGetLock( imesa, 0 );                     \
+  } while (0)
+
+
+
+/* Unlock the hardware using the global current context 
+ */
+#define UNLOCK_HARDWARE(imesa)                                 \
+    DRM_UNLOCK(imesa->driFd, imesa->driHwLock, imesa->hHWContext);
+
+
+/* This is the wrong way to do it, I'm sure.  Otherwise the drm
+ * bitches that I've already got the heavyweight lock.  At worst,
+ * this is 3 ioctls.  The best solution probably only gets me down 
+ * to 2 ioctls in the worst case.
+ */
+#define LOCK_HARDWARE_QUIESCENT( imesa ) do {  \
+   LOCK_HARDWARE( imesa );                     \
+   savageRegetLockQuiescent( imesa );          \
+} while(0)
+
+/* The following definitions are copied from savage_regs.h in the XFree86
+ * driver. They are unlikely to change. If they do we need to keep them in
+ * sync. */
+
+#define S3_SAVAGE3D_SERIES(chip)  ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX))
+
+#define S3_SAVAGE4_SERIES(chip)  ((chip==S3_SAVAGE4)            \
+                                  || (chip==S3_PROSAVAGE)       \
+                                  || (chip==S3_TWISTER)         \
+                                  || (chip==S3_PROSAVAGEDDR))
+
+#define        S3_SAVAGE_MOBILE_SERIES(chip)   ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE))
+
+#define S3_SAVAGE_SERIES(chip)    ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000))
+
+#define S3_MOBILE_TWISTER_SERIES(chip)   ((chip==S3_TWISTER)    \
+                                          ||(chip==S3_PROSAVAGEDDR))
+
+/* Chip tags.  These are used to group the adapters into 
+ * related families.
+ */
+
+enum S3CHIPTAGS {
+    S3_UNKNOWN = 0,
+    S3_SAVAGE3D,
+    S3_SAVAGE_MX,
+    S3_SAVAGE4,
+    S3_PROSAVAGE,
+    S3_TWISTER,
+    S3_PROSAVAGEDDR,
+    S3_SUPERSAVAGE,
+    S3_SAVAGE2000,
+    S3_LAST
+};
+
+#endif
+#endif
diff --git a/src/mesa/drivers/dri/savage/savage_xmesa.c b/src/mesa/drivers/dri/savage/savage_xmesa.c
new file mode 100644 (file)
index 0000000..bc15e0b
--- /dev/null
@@ -0,0 +1,800 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifdef GLX_DIRECT_RENDERING
+
+#include <X11/Xlibint.h>
+#include <stdio.h>
+
+#include "savagecontext.h"
+#include "context.h"
+#include "matrix.h"
+
+#include "simple_list.h"
+
+#include "swrast/swrast.h"
+#include "swrast_setup/swrast_setup.h"
+#include "tnl/tnl.h"
+#include "array_cache/acache.h"
+
+#include "tnl/t_pipeline.h"
+
+#include "drivers/common/driverfuncs.h"
+
+#include "savagedd.h"
+#include "savagestate.h"
+#include "savagetex.h"
+#include "savagespan.h"
+#include "savagetris.h"
+#include "savagevb.h"
+#include "savageioctl.h"
+#include "savage_bci.h"
+
+#include "savage_dri.h"
+
+#include "savagedma.h"
+
+#ifndef SAVAGE_DEBUG
+int SAVAGE_DEBUG = (0
+/*                       | DEBUG_ALWAYS_SYNC  */
+/*               | DEBUG_VERBOSE_RING    */
+/*               | DEBUG_VERBOSE_OUTREG  */
+/*               | DEBUG_VERBOSE_MSG */
+/*               | DEBUG_NO_OUTRING */
+/*               | DEBUG_NO_OUTREG */
+/*               | DEBUG_VERBOSE_API */
+/*               | DEBUG_VERBOSE_2D */
+/*               | DEBUG_VERBOSE_DRI */
+/*               | DEBUG_VALIDATE_RING */
+/*               | DEBUG_VERBOSE_IOCTL */
+                 );
+#endif
+
+
+/*For time caculating test*/
+#if defined(DEBUG_TIME) && DEBUG_TIME
+struct timeval tv_s,tv_f;
+unsigned long time_sum=0;
+struct timeval tv_s1,tv_f1;
+#endif
+
+/* this is first function called in dirver*/
+
+static GLboolean
+savageInitDriver(__DRIscreenPrivate *sPriv)
+{
+  savageScreenPrivate *savageScreen;
+  SAVAGEDRIPtr         gDRIPriv = (SAVAGEDRIPtr)sPriv->pDevPriv;
+
+
+  /* Check the DRI version */
+   {
+      int major, minor, patch;
+      if (XF86DRIQueryVersion(sPriv->display, &major, &minor, &patch)) {
+         if (major != 4 || minor < 0) {
+           __driUtilMessage("savage DRI driver expected DRI version 4.0.x but got version %d.%d.%d", major, minor, patch);
+            return GL_FALSE;
+         }
+      }
+   }
+
+   /* Check that the DDX driver version is compatible */
+   if (sPriv->ddxMajor != 1 ||
+       sPriv->ddxMinor < 0) {
+      __driUtilMessage("savage DRI driver expected DDX driver version 1.0.x but got version %d.%d.%d", sPriv->ddxMajor, sPriv->ddxMinor, sPriv->ddxPatch);
+      return GL_FALSE;
+   }
+
+   /* Check that the DRM driver version is compatible */
+   if (sPriv->drmMajor != 1 ||
+       sPriv->drmMinor < 0) {
+      __driUtilMessage("savage DRI driver expected DRM driver version 1.1.x but got version %d.%d.%d", sPriv->drmMajor, sPriv->drmMinor, sPriv->drmPatch);
+      return GL_FALSE;
+   }
+       
+   /* Allocate the private area */
+   savageScreen = (savageScreenPrivate *)Xmalloc(sizeof(savageScreenPrivate));
+   if (!savageScreen)
+      return GL_FALSE;
+
+   savageScreen->driScrnPriv = sPriv;
+   sPriv->private = (void *)savageScreen;
+
+   savageScreen->chipset=gDRIPriv->chipset; 
+   savageScreen->width=gDRIPriv->width;
+   savageScreen->height=gDRIPriv->height;
+   savageScreen->mem=gDRIPriv->mem;
+   savageScreen->cpp=gDRIPriv->cpp;
+   savageScreen->zpp=gDRIPriv->zpp;
+   savageScreen->frontPitch=gDRIPriv->frontPitch;
+   savageScreen->frontOffset=gDRIPriv->frontOffset;
+   savageScreen->frontBitmapDesc = gDRIPriv->frontBitmapDesc;
+   
+   if (gDRIPriv->cpp == 4) 
+       savageScreen->frontFormat = DV_PF_8888;
+   else
+       savageScreen->frontFormat = DV_PF_565;
+
+   savageScreen->backOffset = gDRIPriv->backOffset; 
+   savageScreen->backBitmapDesc = gDRIPriv->backBitmapDesc; 
+   savageScreen->depthOffset=gDRIPriv->depthOffset;
+   savageScreen->depthBitmapDesc = gDRIPriv->depthBitmapDesc; 
+#if 0   
+   savageScreen->backPitch = gDRIPriv->auxPitch;
+   savageScreen->backPitchBits = gDRIPriv->auxPitchBits;
+#endif   
+   savageScreen->textureOffset[SAVAGE_CARD_HEAP] = 
+                                   gDRIPriv->textureOffset;
+   savageScreen->textureSize[SAVAGE_CARD_HEAP] = 
+                                   gDRIPriv->textureSize;
+   savageScreen->logTextureGranularity[SAVAGE_CARD_HEAP] = 
+                                   gDRIPriv->logTextureGranularity;
+
+   savageScreen->textureOffset[SAVAGE_AGP_HEAP] = 
+                                   gDRIPriv->agpTextures.handle;
+   savageScreen->textureSize[SAVAGE_AGP_HEAP] = 
+                                   gDRIPriv->agpTextures.size;
+   savageScreen->logTextureGranularity[SAVAGE_AGP_HEAP] =
+                                   gDRIPriv->logAgpTextureGranularity;
+   
+   savageScreen->back.handle = gDRIPriv->backbuffer;
+   savageScreen->back.size = gDRIPriv->backbufferSize;
+   savageScreen->back.map = 
+       (drmAddress)(((unsigned int)sPriv->pFB)+gDRIPriv->backOffset);
+   
+   savageScreen->depth.handle = gDRIPriv->depthbuffer;
+   savageScreen->depth.size = gDRIPriv->depthbufferSize;
+
+   savageScreen->depth.map = 
+              (drmAddress)(((unsigned int)sPriv->pFB)+gDRIPriv->depthOffset);
+   
+   savageScreen->sarea_priv_offset = gDRIPriv->sarea_priv_offset;
+
+   savageScreen->texVirtual[SAVAGE_CARD_HEAP] = 
+             (drmAddress)(((unsigned int)sPriv->pFB)+gDRIPriv->textureOffset);
+#if 0
+   savageDDFastPathInit();
+   savageDDTrifuncInit();
+   savageDDSetupInit();
+#endif
+   return GL_TRUE;
+}
+
+/* Accessed by dlsym from dri_mesa_init.c
+ */
+static void
+savageDestroyScreen(__DRIscreenPrivate *sPriv)
+{
+   savageScreenPrivate *savageScreen = (savageScreenPrivate *)sPriv->private;
+
+   
+   Xfree(savageScreen);
+   sPriv->private = NULL;
+}
+
+#if 0
+GLvisual *XMesaCreateVisual(Display *dpy,
+                            __DRIscreenPrivate *driScrnPriv,
+                            const XVisualInfo *visinfo,
+                            const __GLXvisualConfig *config)
+{
+   /* Drivers may change the args to _mesa_create_visual() in order to
+    * setup special visuals.
+    */
+   return _mesa_create_visual( config->rgba,
+                               config->doubleBuffer,
+                               config->stereo,
+                               _mesa_bitcount(visinfo->red_mask),
+                               _mesa_bitcount(visinfo->green_mask),
+                               _mesa_bitcount(visinfo->blue_mask),
+                               config->alphaSize,
+                               0, /* index bits */
+                               config->depthSize,
+                               config->stencilSize,
+                               config->accumRedSize,
+                               config->accumGreenSize,
+                               config->accumBlueSize,
+                               config->accumAlphaSize,
+                               0 /* num samples */ );
+}
+#endif
+
+
+static GLboolean
+savageCreateContext( const __GLcontextModes *mesaVis,
+                    __DRIcontextPrivate *driContextPriv,
+                    void *sharedContextPrivate )
+{
+   GLcontext *ctx, *shareCtx;
+   savageContextPtr imesa;
+   __DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv;
+   struct dd_function_table functions;
+   SAVAGEDRIPtr         gDRIPriv = (SAVAGEDRIPtr)sPriv->pDevPriv;
+   savageScreenPrivate *savageScreen = (savageScreenPrivate *)sPriv->private;
+   drm_savage_sarea_t *saPriv=(drm_savage_sarea_t *)(((char*)sPriv->pSAREA)+
+                                                savageScreen->sarea_priv_offset);
+   int i;
+   imesa = (savageContextPtr)Xcalloc(sizeof(savageContext), 1);
+   if (!imesa) {
+      return GL_FALSE;
+   }
+
+   /* Init default driver functions then plug in savage-specific texture
+    * functions that are needed as early as during context creation. */
+   _mesa_init_driver_functions( &functions );
+   savageDDInitTextureFuncs( &functions );
+
+   /* Allocate the Mesa context */
+   if (sharedContextPrivate)
+      shareCtx = ((savageContextPtr) sharedContextPrivate)->glCtx;
+   else 
+      shareCtx = NULL;
+   ctx = _mesa_create_context(mesaVis, shareCtx, &functions, imesa);
+   if (!ctx) {
+      Xfree(imesa);
+      return GL_FALSE;
+   }
+   driContextPriv->driverPrivate = imesa;
+
+   /*   BEGIN;*/
+   /* Set the maximum texture size small enough that we can guarentee
+    * that both texture units can bind a maximal texture and have them
+    * in memory at once.
+    */
+   if (savageScreen->textureSize[SAVAGE_CARD_HEAP] < 2*1024*1024) {
+      ctx->Const.MaxTextureLevels = 9;
+   } else if (savageScreen->textureSize[SAVAGE_CARD_HEAP] < 8*1024*1024) {
+      ctx->Const.MaxTextureLevels = 10;
+   } else {
+      ctx->Const.MaxTextureLevels = 11;
+   }
+   if (savageScreen->chipset >= S3_SAVAGE4)
+       ctx->Const.MaxTextureUnits = 2;
+   else
+       ctx->Const.MaxTextureUnits = 1;
+
+#if 0
+   ctx->Const.MinLineWidth = 1.0;
+   ctx->Const.MinLineWidthAA = 1.0;
+   ctx->Const.MaxLineWidth = 3.0;
+   ctx->Const.MaxLineWidthAA = 3.0;
+   ctx->Const.LineWidthGranularity = 1.0;
+#endif
+   
+   /* Dri stuff
+    */
+   imesa->hHWContext = driContextPriv->hHWContext;
+   imesa->driFd = sPriv->fd;
+   imesa->driHwLock = &sPriv->pSAREA->lock;
+   
+   imesa->savageScreen = savageScreen;
+   imesa->driScreen = sPriv;
+   imesa->sarea = saPriv;
+   imesa->glBuffer = NULL;
+   
+   /* DMA buffer */
+
+   /*The shadow pointer*/
+   imesa->shadowPointer = 
+     (volatile GLuint *)((((GLuint)(&saPriv->shadow_status)) + 31) & 0xffffffe0L) ;
+   /* here we use eventTag1 because eventTag0 is used by HWXvMC*/
+   imesa->eventTag1 = (volatile GLuint *)(imesa->shadowPointer + 6);
+   /*   imesa->eventTag1=(volatile GLuint *)(imesa->MMIO_BASE+0x48c04);*/
+   imesa->shadowCounter = MAX_SHADOWCOUNTER;
+   imesa->shadowStatus = GL_TRUE;/*Will judge by 2d message */
+
+   if (drmMap(sPriv->fd, 
+             gDRIPriv->registers.handle, 
+             gDRIPriv->registers.size, 
+             (drmAddress *)&(gDRIPriv->registers.map)) != 0) 
+   {
+      Xfree(savageScreen);
+      sPriv->private = NULL;
+      return GL_FALSE;
+   }
+   
+   if (drmMap(sPriv->fd, 
+             gDRIPriv->agpTextures.handle, 
+             gDRIPriv->agpTextures.size, 
+             (drmAddress *)&(gDRIPriv->agpTextures.map)) != 0) 
+   {
+      Xfree(savageScreen);
+      sPriv->private = NULL;
+      return GL_FALSE;
+   }
+
+/* agp texture*/
+   savageScreen->texVirtual[SAVAGE_AGP_HEAP] = 
+                        (drmAddress)(gDRIPriv->agpTextures.map);
+
+   
+
+   gDRIPriv->BCIcmdBuf.map = (drmAddress *)
+                           ((unsigned int)gDRIPriv->registers.map+0x00010000);
+      
+   imesa->MMIO_BASE = (GLuint)gDRIPriv->registers.map;
+   imesa->BCIBase= (GLuint)gDRIPriv->BCIcmdBuf.map;
+
+   savageScreen->aperture.handle = gDRIPriv->aperture.handle;
+   savageScreen->aperture.size   = gDRIPriv->aperture.size;
+   if (drmMap(sPriv->fd, 
+             savageScreen->aperture.handle, 
+             savageScreen->aperture.size, 
+             (drmAddress *)&savageScreen->aperture.map) != 0) 
+   {
+      Xfree(savageScreen);
+      sPriv->private = NULL;
+      return GL_FALSE;
+   } 
+   
+   
+
+
+   
+   for(i=0;i<5;i++)
+   {
+       imesa->apertureBase[i] = ((GLuint)savageScreen->aperture.map + 
+                                 0x01000000 * i );
+       
+   
+   }
+   
+   {
+      volatile unsigned int * tmp;
+      
+      tmp=(volatile unsigned int *)(imesa->MMIO_BASE + 0x850C);
+      
+      
+      tmp=(volatile unsigned int *)(imesa->MMIO_BASE + 0x48C40);
+      
+   
+      tmp=(volatile unsigned int *)(imesa->MMIO_BASE + 0x48C44);
+
+   
+      tmp=(volatile unsigned int *)(imesa->MMIO_BASE + 0x48C48);
+
+   
+   
+   }
+   
+   imesa->aperturePitch = gDRIPriv->aperturePitch;
+   
+   
+   /* change texHeap initialize to support two kind of texture heap*/
+   /* here is some parts of initialization, others in InitDriver() */
+    
+   imesa->lastTexHeap = savageScreen->texVirtual[SAVAGE_AGP_HEAP] ? 2 : 1;
+   
+   /*allocate texHeap for multi-tex*/ 
+   {
+     int i;
+     
+     for(i=0;i<SAVAGE_NR_TEX_HEAPS;i++)
+     {
+       imesa->texHeap[i] = mmInit( 0, savageScreen->textureSize[i] );
+       make_empty_list(&imesa->TexObjList[i]);
+     }
+     
+     make_empty_list(&imesa->SwappedOut);
+   }
+
+   imesa->hw_stencil = GL_FALSE;
+#if HW_STENCIL
+   imesa->hw_stencil = mesaVis->stencilBits && mesaVis->depthBits == 24;
+#endif
+   imesa->depth_scale = (imesa->savageScreen->zpp == 2) ?
+       (1.0F/0x10000):(1.0F/0x1000000);
+
+   /* Utah stuff
+    */
+   imesa->new_state = ~0;
+   imesa->RenderIndex = ~0;
+   imesa->dirty = ~0;
+   imesa->vertex_format = 0;
+   imesa->TextureMode = ctx->Texture.Unit[0].EnvMode;
+   imesa->CurrentTexObj[0] = 0;
+   imesa->CurrentTexObj[1] = 0;
+   imesa->texAge[SAVAGE_CARD_HEAP]=0;
+   imesa->texAge[SAVAGE_AGP_HEAP]=0;
+
+   /* Initialize the software rasterizer and helper modules.
+    */
+   _swrast_CreateContext( ctx );
+   _ac_CreateContext( ctx );
+   _tnl_CreateContext( ctx );
+   
+   _swsetup_CreateContext( ctx );
+
+   /* Install the customized pipeline:
+    */
+#if 0
+   _tnl_destroy_pipeline( ctx );
+   _tnl_install_pipeline( ctx, savage_pipeline );
+#endif
+
+   /* Configure swrast to match hardware characteristics:
+    */
+   _swrast_allow_pixel_fog( ctx, GL_FALSE );
+   _swrast_allow_vertex_fog( ctx, GL_TRUE );
+
+   ctx->DriverCtx = (void *) imesa;
+   imesa->glCtx = ctx;
+   if (savageDMAInit(imesa) == GL_FALSE)
+       return GL_FALSE;  
+   
+   savageDDExtensionsInit( ctx );
+
+   savageDDInitStateFuncs( ctx );
+   savageDDInitSpanFuncs( ctx );
+   savageDDInitDriverFuncs( ctx );
+   savageDDInitIoctlFuncs( ctx );
+   savageInitTriFuncs( ctx );
+
+   savageInitVB( ctx );
+   savageDDInitState( imesa );
+
+   driContextPriv->driverPrivate = (void *) imesa;
+
+   return GL_TRUE;
+}
+
+static void
+savageDestroyContext(__DRIcontextPrivate *driContextPriv)
+{
+   savageContextPtr imesa = (savageContextPtr) driContextPriv->driverPrivate;
+
+   assert (imesa); /* should never be NULL */
+   if (imesa) {
+      savageTextureObjectPtr next_t, t;
+
+      /* update for multi-tex*/ 
+      {
+       int i;
+       for(i=0;i<SAVAGE_NR_TEX_HEAPS;i++)
+          foreach_s (t, next_t, &(imesa->TexObjList[i]))
+        savageDestroyTexObj(imesa, t);
+      }
+      foreach_s (t, next_t, &(imesa->SwappedOut))
+        savageDestroyTexObj(imesa, t);
+      /*free the dma buffer*/
+      savageDMAClose(imesa);
+      _swsetup_DestroyContext(imesa->glCtx );
+      _tnl_DestroyContext( imesa->glCtx );
+      _ac_DestroyContext( imesa->glCtx );
+      _swrast_DestroyContext( imesa->glCtx );
+
+      savageFreeVB( imesa->glCtx );
+
+      /* free the Mesa context */
+      imesa->glCtx->DriverCtx = NULL;
+      _mesa_destroy_context(imesa->glCtx);
+
+      /* no longer use vertex_dma_buf*/
+      Xfree(imesa);
+   }
+}
+
+static GLboolean
+savageCreateBuffer( __DRIscreenPrivate *driScrnPriv,
+                   __DRIdrawablePrivate *driDrawPriv,
+                   const __GLcontextModes *mesaVis,
+                   GLboolean isPixmap)
+{
+   if (isPixmap) {
+      return GL_FALSE; /* not implemented */
+   }
+   else {
+#if HW_STENCIL
+       GLboolean swStencil = mesaVis->stencilBits > 0 && mesaVis->depthBits != 24;
+#else
+       GLboolean swStencil = mesaVis->stencilBits > 0;
+#endif
+      driDrawPriv->driverPrivate = (void *) 
+         _mesa_create_framebuffer(mesaVis,
+                                  GL_FALSE,  /* software depth buffer? */
+                                  swStencil,
+                                  mesaVis->accumRedBits > 0,
+                                  mesaVis->alphaBits > 0 );
+
+      return (driDrawPriv->driverPrivate != NULL);
+   }
+}
+
+static void
+savageDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
+{
+   _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate));
+}
+
+#if 0
+void XMesaSwapBuffers(__DRIdrawablePrivate *driDrawPriv)
+{
+   /* XXX should do swap according to the buffer, not the context! */
+   savageContextPtr imesa = savageCtx; 
+
+   FLUSH_VB( imesa->glCtx, "swap buffers" );
+   savageSwapBuffers(imesa);
+}
+#endif
+
+void savageXMesaSetFrontClipRects( savageContextPtr imesa )
+{
+   __DRIdrawablePrivate *dPriv = imesa->driDrawable;
+
+   imesa->numClipRects = dPriv->numClipRects;
+   imesa->pClipRects = dPriv->pClipRects;
+   imesa->dirty |= SAVAGE_UPLOAD_CLIPRECTS;
+   imesa->drawX = dPriv->x;
+   imesa->drawY = dPriv->y;
+
+   savageEmitDrawingRectangle( imesa );
+}
+
+
+void savageXMesaSetBackClipRects( savageContextPtr imesa )
+{
+   __DRIdrawablePrivate *dPriv = imesa->driDrawable;
+
+   if (dPriv->numBackClipRects == 0) 
+   {
+
+
+      imesa->numClipRects = dPriv->numClipRects;
+      imesa->pClipRects = dPriv->pClipRects;
+      imesa->drawX = dPriv->x;
+      imesa->drawY = dPriv->y;
+   } else {
+
+
+      imesa->numClipRects = dPriv->numBackClipRects;
+      imesa->pClipRects = dPriv->pBackClipRects;
+      imesa->drawX = dPriv->backX;
+      imesa->drawY = dPriv->backY;
+   }
+
+   savageEmitDrawingRectangle( imesa );
+   imesa->dirty |= SAVAGE_UPLOAD_CLIPRECTS;
+
+
+}
+
+
+static void savageXMesaWindowMoved( savageContextPtr imesa ) 
+{
+   if (0)
+      fprintf(stderr, "savageXMesaWindowMoved\n\n");
+
+   switch (imesa->glCtx->Color._DrawDestMask) {
+   case FRONT_LEFT_BIT:
+      savageXMesaSetFrontClipRects( imesa );
+      break;
+   case BACK_LEFT_BIT:
+      savageXMesaSetBackClipRects( imesa );
+      break;
+   default:
+       break;
+   }
+}
+
+
+static GLboolean
+savageUnbindContext(__DRIcontextPrivate *driContextPriv)
+{
+   savageContextPtr savage = (savageContextPtr) driContextPriv->driverPrivate;
+   if (savage)
+      savage->dirty = ~0;
+
+   return GL_TRUE;
+}
+
+static GLboolean
+savageOpenFullScreen(__DRIcontextPrivate *driContextPriv)
+{
+    
+  
+    
+    if (driContextPriv) {
+      savageContextPtr imesa = (savageContextPtr) driContextPriv->driverPrivate;
+      imesa->IsFullScreen = GL_TRUE;
+      imesa->backup_frontOffset = imesa->savageScreen->frontOffset;
+      imesa->backup_backOffset = imesa->savageScreen->backOffset;
+      imesa->backup_frontBitmapDesc = imesa->savageScreen->frontBitmapDesc;
+      imesa->savageScreen->frontBitmapDesc = imesa->savageScreen->backBitmapDesc;      
+      imesa->toggle = TARGET_BACK;
+   }
+
+    return GL_TRUE;
+}
+
+static GLboolean
+savageCloseFullScreen(__DRIcontextPrivate *driContextPriv)
+{
+    
+    if (driContextPriv) {
+      savageContextPtr imesa = (savageContextPtr) driContextPriv->driverPrivate;
+      WAIT_IDLE_EMPTY;
+      imesa->IsFullScreen = GL_FALSE;   
+      imesa->savageScreen->frontOffset = imesa->backup_frontOffset;
+      imesa->savageScreen->backOffset = imesa->backup_backOffset;
+      imesa->savageScreen->frontBitmapDesc = imesa->backup_frontBitmapDesc;
+   }
+    return GL_TRUE;
+}
+
+
+static GLboolean
+savageMakeCurrent(__DRIcontextPrivate *driContextPriv,
+                 __DRIdrawablePrivate *driDrawPriv,
+                 __DRIdrawablePrivate *driReadPriv)
+{
+   if (driContextPriv) {
+      savageContextPtr imesa = (savageContextPtr) driContextPriv->driverPrivate;
+      
+      imesa->driReadable = driReadPriv;
+      imesa->driDrawable = driDrawPriv;
+      imesa->mesa_drawable = driDrawPriv;
+      imesa->dirty = ~0;
+      
+      _mesa_make_current2(imesa->glCtx,
+                          (GLframebuffer *) driDrawPriv->driverPrivate,
+                          (GLframebuffer *) driReadPriv->driverPrivate);
+      
+      savageXMesaWindowMoved( imesa );
+      
+      if (!imesa->glCtx->Viewport.Width)
+        _mesa_set_viewport(imesa->glCtx, 0, 0,
+                            driDrawPriv->w, driDrawPriv->h);
+   }
+   else 
+   {
+      _mesa_make_current(NULL, NULL);
+   }
+   return GL_TRUE;
+}
+
+
+void savageGetLock( savageContextPtr imesa, GLuint flags ) 
+{
+   __DRIdrawablePrivate *dPriv = imesa->driDrawable;
+   __DRIscreenPrivate *sPriv = imesa->driScreen;
+   drm_savage_sarea_t *sarea = imesa->sarea;
+   int me = imesa->hHWContext;
+   int stamp = dPriv->lastStamp; 
+   int heap;
+
+  
+
+   /* We know there has been contention.
+    */
+   drmGetLock(imesa->driFd, imesa->hHWContext, flags); 
+
+
+   /* Note contention for throttling hint
+    */
+   imesa->any_contend = 1;
+
+   /* If the window moved, may need to set a new cliprect now.
+    *
+    * NOTE: This releases and regains the hw lock, so all state
+    * checking must be done *after* this call:
+    */
+   DRI_VALIDATE_DRAWABLE_INFO(sPriv, dPriv);           
+
+
+  
+
+   /* If we lost context, need to dump all registers to hardware.
+    * Note that we don't care about 2d contexts, even if they perform
+    * accelerated commands, so the DRI locking in the X server is even
+    * more broken than usual.
+    */
+   if (sarea->ctxOwner != me) {
+      imesa->dirty |= (SAVAGE_UPLOAD_CTX |
+                      SAVAGE_UPLOAD_CLIPRECTS |
+                      SAVAGE_UPLOAD_TEX0 |
+                      SAVAGE_UPLOAD_TEX1);
+      imesa->Registers.changed.uiRegistersChanged = __HW_ALL_CHANGED;
+      sarea->ctxOwner = me;
+   }
+
+   /* Shared texture managment - if another client has played with
+    * texture space, figure out which if any of our textures have been
+    * ejected, and update our global LRU.
+    */
+   /*frank just for compiling,texAge,texList,AGP*/ 
+   
+   for(heap= 0 ;heap < imesa->lastTexHeap ; heap++)
+   {
+       if (sarea->texAge[heap] != imesa->texAge[heap]) {
+           int sz = 1 << (imesa->savageScreen->logTextureGranularity[heap]);
+           int idx, nr = 0;
+
+      /* Have to go right round from the back to ensure stuff ends up
+       * LRU in our local list...
+       */
+           for (idx = sarea->texList[heap][SAVAGE_NR_TEX_REGIONS].prev ; 
+              idx != SAVAGE_NR_TEX_REGIONS && nr < SAVAGE_NR_TEX_REGIONS ; 
+              idx = sarea->texList[heap][idx].prev, nr++)
+           {
+              if (sarea->texList[heap][idx].age > imesa->texAge[heap])
+              {
+                  savageTexturesGone(imesa, heap ,idx * sz, sz, 
+                                     sarea->texList[heap][idx].in_use);
+              }
+           }
+
+           if (nr == SAVAGE_NR_TEX_REGIONS) 
+           {
+             savageTexturesGone(imesa, heap, 0, 
+                                imesa->savageScreen->textureSize[heap], 0);
+             savageResetGlobalLRU( imesa , heap );
+           }
+
+           imesa->dirty |= SAVAGE_UPLOAD_TEX0IMAGE;
+           imesa->dirty |= SAVAGE_UPLOAD_TEX1IMAGE;
+           imesa->texAge[heap] = sarea->texAge[heap];
+       }
+   } /* end of for loop */ 
+   
+   if (dPriv->lastStamp != stamp)
+      savageXMesaWindowMoved( imesa );
+
+  
+   
+}
+
+
+
+static const struct __DriverAPIRec savageAPI = {
+   savageInitDriver,
+   savageDestroyScreen,
+   savageCreateContext,
+   savageDestroyContext,
+   savageCreateBuffer,
+   savageDestroyBuffer,
+   savageSwapBuffers,
+   savageMakeCurrent,
+   savageUnbindContext,
+   savageOpenFullScreen,
+   savageCloseFullScreen
+};
+
+
+
+/*
+ * This is the bootstrap function for the driver.
+ * The __driCreateScreen name is the symbol that libGL.so fetches.
+ * Return:  pointer to a __DRIscreenPrivate.
+ */
+void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc,
+                        int numConfigs, __GLXvisualConfig *config)
+{
+   __DRIscreenPrivate *psp;
+   psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &savageAPI);
+   return (void *) psp;
+}
+
+
+#endif
diff --git a/src/mesa/drivers/dri/savage/savagecontext.h b/src/mesa/drivers/dri/savage/savagecontext.h
new file mode 100644 (file)
index 0000000..6eaf58e
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+
+#ifndef SAVAGECONTEXT_INC
+#define SAVAGECONTEXT_INC
+
+typedef struct savage_context_t savageContext;
+typedef struct savage_context_t *savageContextPtr;
+typedef struct savage_texture_object_t *savageTextureObjectPtr;
+
+#include <X11/Xlibint.h>
+#include "dri_util.h"
+#include "mtypes.h"
+#include "xf86drm.h"
+#include "drm.h"
+#include "savage_drm.h"
+#include "savage_sarea.h"
+#include "savage_init.h"
+#include "mm.h"
+
+#include "savagetex.h"
+#include "savagedma.h"
+
+/* Reasons to fallback on all primitives.
+ */
+#define SAVAGE_FALLBACK_TEXTURE        0x1
+#define SAVAGE_FALLBACK_DRAW_BUFFER    0x2
+#define SAVAGE_FALLBACK_READ_BUFFER    0x4
+#define SAVAGE_FALLBACK_COLORMASK      0x8  
+#define SAVAGE_FALLBACK_STIPPLE        0x10  
+#define SAVAGE_FALLBACK_SPECULAR       0x20 
+#define SAVAGE_FALLBACK_LOGICOP        0x40
+/*frank 2001/11/12 add the stencil fallbak*/
+#define SAVAGE_FALLBACK_STENCIL        0x80
+#define SAVAGE_FALLBACK_RENDERMODE     0x100
+#define SAVAGE_FALLBACK_BLEND_EQ       0x200
+
+
+#define HW_STENCIL 1
+#define HW_CULL    1
+
+/* for savagectx.new_state - manage GL->driver state changes
+ */
+#define SAVAGE_NEW_TEXTURE 0x1
+
+
+/*define the max numer of vertex in vertex buf*/
+#define SAVAGE_MAX_VERTEXS 0x10000
+
+/* Use the templated vertex formats:
+ */
+#define TAG(x) savage##x
+#include "tnl_dd/t_dd_vertex.h"
+#undef TAG
+
+typedef void (*savage_tri_func)( savageContextPtr, savageVertex *,
+                                savageVertex *, savageVertex * );
+typedef void (*savage_line_func)( savageContextPtr,
+                                 savageVertex *, savageVertex * );
+typedef void (*savage_point_func)( savageContextPtr, savageVertex * );
+
+
+/**************************************************************
+ ****************    enums for chip IDs ************************
+ **************************************************************/
+
+#define CHIP_S3GX3MS1NB             0x8A25
+#define CHIP_S3GX3MS1NBK            0x8A26
+#define CHIP_S3TWISTER              0x8D01
+#define CHIP_S3TWISTERK             0x8D02
+#define CHIP_S3TWISTER_P4M          0x8D04
+#define CHIP_S3PARAMOUNT128         0x8C22              /*SuperSavage 128/MX*/
+#define CHIP_S3TRISTAR128SDR        0x8C2A              /*SuperSavage 128/IX*/
+#define CHIP_S3TRISTAR64SDRM7       0x8C2C              /*SuperSavage/IX M7 Package*/
+#define CHIP_S3TRISTAR64SDR         0x8C2E              /*SuperSavage/IX*/
+#define CHIP_S3TRISTAR64CDDR        0x8C2F              /*SuperSavage/IXC DDR*/
+
+#define IS_SAVAGE(imesa) (imesa->savageScreen->deviceID == CHIP_S3GX3MS1NB ||  \
+                       imesa->savageScreen->deviceID == CHIP_S3GX3MS1NBK || \
+                        imesa->savageScreen->deviceID == CHIP_S3TWISTER || \
+                        imesa->savageScreen->deviceID == CHIP_S3TWISTERK || \
+                        imesa->savageScreen->deviceID == CHIP_S3TWISTER_P4M || \
+                        imesa->savageScreen->deviceID == CHIP_S3PARAMOUNT128 || \
+                        imesa->savageScreen->deviceID == CHIP_S3TRISTAR128SDR || \
+                        imesa->savageScreen->deviceID == CHIP_S3TRISTAR64SDRM7 || \
+                        imesa->savageScreen->deviceID == CHIP_S3TRISTAR64SDR || \
+                       imesa->savageScreen->deviceID == CHIP_S3TRISTAR64CDDR )
+
+
+
+
+struct savage_context_t {
+    GLint refcount;
+
+    GLcontext *glCtx;
+
+    int lastTexHeap;
+    savageTextureObjectPtr CurrentTexObj[2];
+   
+    struct savage_texture_object_t TexObjList[SAVAGE_NR_TEX_HEAPS];
+    struct savage_texture_object_t SwappedOut; 
+  
+    GLuint c_texupload;
+    GLuint c_texusage;
+    GLuint tex_thrash;
+   
+    GLuint TextureMode;
+   
+    
+    /* Hardware state
+     */
+
+    REGISTERS Registers;
+
+    /* Manage our own state */
+    GLuint new_state; 
+    GLuint new_gl_state;
+
+    GLuint BCIBase;  
+    GLuint MMIO_BASE;
+
+    /* DMA command buffer */
+    DMABuffer_t DMABuf;
+
+    /* aperture base */
+    GLuint apertureBase[5];
+    GLuint aperturePitch;
+    /* Manage hardware state */
+    GLuint dirty;
+    memHeap_t *texHeap[SAVAGE_NR_TEX_HEAPS];
+    GLuint bTexEn1;
+    /* One of the few bits of hardware state that can't be calculated
+     * completely on the fly:
+     */
+    GLuint LcsCullMode;
+
+   /* Rasterization state 
+    */
+   GLuint SetupNewInputs;
+   GLuint SetupIndex;
+   GLuint RenderIndex;
+   
+   GLuint hw_primitive;
+   GLenum raster_primitive;
+   GLenum render_primitive;
+
+   GLubyte *verts;
+   GLuint vertex_format;               
+   GLuint vertex_size;
+   GLuint DrawPrimitiveCmd;
+   GLuint DrawPrimitiveMask; 
+
+   /* Fallback rasterization functions 
+    */
+   savage_point_func draw_point;
+   savage_line_func draw_line;
+   savage_tri_func draw_tri;
+
+    /* Funny mesa mirrors
+     */
+    GLuint MonoColor;
+    GLuint ClearColor;
+    GLfloat depth_scale;
+    GLfloat hw_viewport[16];
+    /* DRI stuff */  
+    drmBufPtr  vertex_dma_buffer;
+
+    GLframebuffer *glBuffer;
+   
+    /* Two flags to keep track of fallbacks. */
+    GLuint Fallback;
+
+    GLuint needClip;
+
+    /* These refer to the current draw (front vs. back) buffer:
+     */
+    char *drawMap;             /* draw buffer address in virtual mem */
+    char *readMap;     
+    int drawX;                 /* origin of drawable in draw buffer */
+    int drawY;
+    GLuint numClipRects;               /* cliprects for that buffer */
+    GLint currentClip;
+    XF86DRIClipRectPtr pClipRects;
+
+    /*  use this bit to support single/double buffer */
+    GLuint IsDouble;
+    /*  use this to indicate Fullscreen mode */   
+    GLuint IsFullScreen;
+    GLuint backup_frontOffset;
+    GLuint backup_backOffset;
+    GLuint backup_frontBitmapDesc;
+    GLuint toggle;
+    GLuint backup_streamFIFO;
+    GLuint NotFirstFrame;
+   
+    GLuint lastSwap;
+    GLuint secondLastSwap;
+    GLuint ctxAge;
+    GLuint dirtyAge;
+    GLuint any_contend;                /* throttle me harder */
+
+    GLuint scissor;
+    drm_clip_rect_t draw_rect;
+    drm_clip_rect_t scissor_rect;
+    XF86DRIClipRectRec tmp_boxes[2][SAVAGE_NR_SAREA_CLIPRECTS];
+    /*Texture aging and DMA based aging*/
+    unsigned int texAge[SAVAGE_NR_TEX_HEAPS]; 
+
+    drmContext hHWContext;
+    drmLock *driHwLock;
+    GLuint driFd;
+
+    __DRIdrawablePrivate *driDrawable;
+    __DRIdrawablePrivate *driReadable;
+
+    /**
+     * Drawable used by Mesa for software fallbacks for reading and
+     * writing.  It is set by Mesa's \c SetBuffer callback, and will always be
+     * either \c mga_context_t::driDrawable or \c mga_context_t::driReadable.
+     */
+    __DRIdrawablePrivate *mesa_drawable;
+
+    __DRIscreenPrivate *driScreen;
+    savageScreenPrivate *savageScreen; 
+    drm_savage_sarea_t *sarea;
+
+    GLboolean hw_stencil;
+
+    /*shadow pointer*/
+    volatile GLuint  *shadowPointer;
+    volatile GLuint *eventTag1;
+    GLuint shadowCounter;
+    GLboolean shadowStatus;
+};
+
+#define SAVAGE_CONTEXT(ctx) ((savageContextPtr)(ctx->DriverCtx))
+
+/* To remove all debugging, make sure SAVAGE_DEBUG is defined as a
+ * preprocessor symbol, and equal to zero.  
+ */
+#define SAVAGE_DEBUG 0   
+#ifndef SAVAGE_DEBUG
+#warning "Debugging enabled - expect reduced performance"
+extern int SAVAGE_DEBUG;
+#endif
+
+#define DEBUG_VERBOSE_2D     0x1
+#define DEBUG_VERBOSE_RING   0x8
+#define DEBUG_VERBOSE_OUTREG 0x10
+#define DEBUG_ALWAYS_SYNC    0x40
+#define DEBUG_VERBOSE_MSG    0x80
+#define DEBUG_NO_OUTRING     0x100
+#define DEBUG_NO_OUTREG      0x200
+#define DEBUG_VERBOSE_API    0x400
+#define DEBUG_VALIDATE_RING  0x800
+#define DEBUG_VERBOSE_LRU    0x1000
+#define DEBUG_VERBOSE_DRI    0x2000
+#define DEBUG_VERBOSE_IOCTL  0x4000
+
+#define TARGET_FRONT    0x0
+#define TARGET_BACK     0x1
+#define TARGET_DEPTH    0x2
+
+#define SAVAGEDEBUG 0
+#define _SAVAGE_DEBUG
+/*frank remove the least debug information*/
+#ifdef _SAVAGE_DEBUG
+#define fprintf fprintf
+#else
+#define fprintf(...) 
+#endif
+
+#define SUBPIXEL_X -0.5
+#define SUBPIXEL_Y -0.375
+
+#endif
diff --git a/src/mesa/drivers/dri/savage/savagedd.c b/src/mesa/drivers/dri/savage/savagedd.c
new file mode 100644 (file)
index 0000000..96773e5
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "mtypes.h"
+
+#include <stdio.h>
+
+#include "mm.h"
+#include "savagedd.h"
+#include "savagestate.h"
+#include "savagespan.h"
+#include "savagetex.h"
+#include "savagetris.h"
+#include "savagevb.h"
+#include "savagecontext.h"
+#include "extensions.h"
+
+
+extern int xf86VTSema;
+
+
+/***************************************
+ * Mesa's Driver Functions
+ ***************************************/
+
+
+static const GLubyte *savageDDGetString( GLcontext *ctx, GLenum name )
+{
+   switch (name) {
+   case GL_VENDOR:
+      return (GLubyte *)"S3 Graphics Inc.";
+   case GL_RENDERER:
+      return (GLubyte *)"Mesa DRI SAVAGE Linux_1.1.18";
+   default:
+      return 0;
+   }
+}
+#if 0
+static GLint savageGetParameteri(const GLcontext *ctx, GLint param)
+{
+   switch (param) {
+   case DD_HAVE_HARDWARE_FOG:
+      return 1;
+   default:
+      return 0;
+   }
+}
+#endif
+
+
+static void savageBufferSize(GLframebuffer *buffer, GLuint *width, GLuint *height)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+
+   /* Need to lock to make sure the driDrawable is uptodate.  This
+    * information is used to resize Mesa's software buffers, so it has
+    * to be correct.
+    */
+   LOCK_HARDWARE(imesa);
+   *width = imesa->driDrawable->w;
+   *height = imesa->driDrawable->h;
+   UNLOCK_HARDWARE(imesa);
+}
+
+
+
+
+void savageDDExtensionsInit( GLcontext *ctx )
+{
+   _mesa_enable_extension( ctx, "GL_ARB_multitexture" );
+   _mesa_enable_extension( ctx, "GL_EXT_texture_lod_bias" );
+   _mesa_enable_extension( ctx, "GL_EXT_texture_env_add" );
+}
+
+
+
+
+void savageDDInitDriverFuncs( GLcontext *ctx )
+{
+   ctx->Driver.GetBufferSize = savageBufferSize;
+   ctx->Driver.ResizeBuffers = _swrast_alloc_buffers;
+   ctx->Driver.GetString = savageDDGetString;
+}
diff --git a/src/mesa/drivers/dri/savage/savagedd.h b/src/mesa/drivers/dri/savage/savagedd.h
new file mode 100644 (file)
index 0000000..8d058f3
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef SAVAGEDD_INC
+#define SAVAGEDD_INC
+
+#include "context.h"
+
+void savageDDExtensionsInit( GLcontext *ctx );
+void savageDDInitDriverFuncs( GLcontext *ctx );
+#endif
diff --git a/src/mesa/drivers/dri/savage/savagedma.c b/src/mesa/drivers/dri/savage/savagedma.c
new file mode 100644 (file)
index 0000000..9b0bdc8
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <X11/Xlibint.h>
+#include <stdio.h>
+#include "savageioctl.h"
+#include "savagedma.h"
+#include "savage_bci.h"
+#include <time.h>
+#include <unistd.h>
+
+/* Commit does not depend on whether we use real DMA or fake it via the BCI */
+void savageDMACommit (savageContextPtr imesa, void *endPtr) {
+    DMABufferPtr dmaBuff = &imesa->DMABuf;
+    GLuint end = (GLuint)endPtr;
+
+    /* make sure that enough space was allocated */
+    assert (end <= dmaBuff->allocEnd);
+
+    dmaBuff->allocEnd = dmaBuff->end = end;
+
+    /* TODO: check commands, either here or in flush */
+}
+
+#if SAVAGE_CMD_DMA
+/* flag =
+         0  return -1 if no available page
+        1  wait until a page be available */
+static GLuint getDMAPage (savageContextPtr imesa, int flag) {
+    DMABufferPtr dmaBuff = &imesa->DMABuf;
+    GLuint page;
+    GLuint eventTag1;
+
+    if (dmaBuff->kickFlag == GL_FALSE)
+       return dmaBuff->usingPage;
+
+    page = dmaBuff->usingPage + 1;
+
+    /* overflow */
+    if (page >= (dmaBuff->buf->size * dmaBuff->buf->type)/DMA_PAGE_SIZE)
+       page = 0;
+
+    eventTag1 = GET_EVENTTAG;
+    if ( eventTag1 == page) { /* is kicking off */
+       if (flag == 1)
+           while (GET_EVENTTAG == page); /* FIXME: add a max loop count? */
+       else
+           return -1;
+    }
+
+    /* ok, that's it */
+    dmaBuff->usingPage = page;
+    dmaBuff->start = dmaBuff->end = dmaBuff->allocEnd =
+       (dmaBuff->buf->linear + DMA_PAGE_SIZE * page);
+    dmaBuff->kickFlag = GL_FALSE;
+
+    return page;
+}
+
+/* Allocate space in a real DMA buffer */
+void *savageDMAAlloc (savageContextPtr imesa, GLuint size) {
+    DMABufferPtr dmaBuff = &imesa->DMABuf;
+
+    /* make sure that everything has been filled in and committed */
+    assert (dmaBuff->end == dmaBuff->allocEnd);
+
+    size *= sizeof (GLuint); /* size in bytes */
+    if (dmaBuff->kickFlag == GL_TRUE) {
+       if (size > DMA_PAGE_SIZE)
+           return NULL;
+       getDMAPage (imesa, 1);
+    } else if (dmaBuff->end + size >=
+              dmaBuff->buf->linear + DMA_PAGE_SIZE*(dmaBuff->usingPage+1)) {
+       /* need kick off */
+       savageDMAFlush (imesa);
+       getDMAPage (imesa, 1);
+    }
+    dmaBuff->allocEnd = dmaBuff->end + size;
+    return (void *)dmaBuff->end;
+}
+
+/* Flush DMA buffer via DMA */
+void savageDMAFlush (savageContextPtr imesa) {
+    volatile GLuint* BCIbase;
+    DMABufferPtr dmaBuff = &imesa->DMABuf;
+    GLuint phyAddress;
+    GLuint dmaCount, dmaCount1, remain;
+    int i;
+
+    /* make sure that everything has been filled in and committed */
+    assert (dmaBuff->allocEnd == dmaBuff->end);
+
+    if (dmaBuff->kickFlag == GL_TRUE) /* has been kicked off? */
+      return;
+    if (dmaBuff->start == dmaBuff->end) /* no command? */
+      return;
+
+    /* get bci base */
+    BCIbase = (volatile GLuint *)SAVAGE_GET_BCI_POINTER(imesa,4);
+
+    /* set the eventtag */
+    *BCIbase = (dmaBuff->usingPage & 0xffffL) | (CMD_UpdateShadowStat << 27)
+       | (1 << 22);
+    *BCIbase = 0x96010051;  /* set register x51*/
+    /* set the DMA buffer address */
+    phyAddress = (dmaBuff->buf->phyaddress + dmaBuff->usingPage*DMA_PAGE_SIZE)
+       & MDT_SRCADD_ALIGMENT;
+    if (dmaBuff->buf->location == DRM_SAVAGE_MEM_LOCATION_AGP)
+       *BCIbase = (phyAddress) | MDT_SRC_AGP;
+    else
+        *BCIbase = (phyAddress) | MDT_SRC_PCI;
+
+    /* pad with noops to multiple of 32 bytes */
+    dmaCount = (GLuint)(dmaBuff->end - dmaBuff->start);
+    dmaCount1 = (dmaCount + 31UL) & ~31UL;
+    remain = (dmaCount1 - dmaCount) >> 2;
+    for (i = 0; i < remain; i++) {
+        *((GLuint *)dmaBuff->end) = 0x40000000L;
+        dmaBuff->end+=4;
+    }
+    dmaCount = (dmaCount1 >> 3) - 1;
+    dmaBuff->allocEnd = dmaBuff->end;
+
+    /* kick off */
+    *BCIbase = (0xA8000000L)|dmaCount;
+    dmaBuff->kickFlag = GL_TRUE;
+}
+
+/* Init real DMA */
+int savageDMAInit (savageContextPtr imesa)
+{
+    DMABufferPtr dmaBuff = &imesa->DMABuf;
+    drm_savage_alloc_cont_mem_t * req;
+    int i;
+    long ret;
+
+    req = (drm_savage_alloc_cont_mem_t *)
+       malloc (sizeof(drm_savage_alloc_cont_mem_t));
+    if (!req)
+       return GL_FALSE;
+
+    req->type = DRM_SAVAGE_MEM_PAGE;
+    req->linear = 0;
+
+    /* try agp first */
+    req->phyaddress = imesa->sarea->agp_offset;
+    if (req->phyaddress) {
+       if (drmMap (imesa->driFd,
+                   req->phyaddress,
+                   DRM_SAVAGE_DMA_AGP_SIZE,
+                   (drmAddressPtr)&req->linear) < 0) {
+           fprintf (stderr, "AGP map error.\n");
+           goto dma;
+       }
+       if (0) fprintf (stderr,"Using AGP dma|\n");
+       req->location = DRM_SAVAGE_MEM_LOCATION_AGP;
+       req->size = DRM_SAVAGE_DMA_AGP_SIZE/DRM_SAVAGE_MEM_PAGE;
+    }
+
+  dma:
+    if (!req->linear) {
+       req->size = DMA_BUFFER_SIZE/DRM_SAVAGE_MEM_PAGE;
+       for (i = 0; i < DMA_TRY_COUNT; i++) {
+           if ((ret = savageAllocDMABuffer (imesa, req)) != 0)
+               break;
+           req->size = req->size/2;
+       }
+      
+       if (ret <= 0) {
+           fprintf(stderr, "Can't alloc DMA memory(system and agp)\n");
+           return GL_FALSE;
+       }
+       req->location = DRM_SAVAGE_MEM_LOCATION_PCI;
+    }
+
+    dmaBuff->buf = req;
+
+    dmaBuff->start = dmaBuff->end = dmaBuff->allocEnd = req->linear;
+    dmaBuff->usingPage = 0;
+    dmaBuff->kickFlag = GL_FALSE;
+
+    return GL_TRUE;
+}
+
+/* Close real DMA */
+int savageDMAClose (savageContextPtr imesa)
+{
+    DMABufferPtr dmaBuff = &imesa->DMABuf;
+    drm_savage_alloc_cont_mem_t * req = dmaBuff->buf;
+
+    if(req->location == DRM_SAVAGE_MEM_LOCATION_PCI)
+       savageFreeDMABuffer (imesa, req);
+    else { /* AGP memory */
+       drmUnmap ((drmAddress)req->linear, req->size*req->type);
+       drmRmMap (imesa->driFd, req->phyaddress);
+    }
+    free (req);
+
+    return GL_TRUE;
+}
+#else
+/* Allocate space in faked DMA buffer */
+void *savageDMAAlloc (savageContextPtr imesa, GLuint size) {
+    DMABufferPtr dmaBuff = &imesa->DMABuf;
+
+    /* make sure that everything has been filled in and committed */
+    assert (dmaBuff->end == dmaBuff->allocEnd);
+
+    size *= sizeof (GLuint); /* size in bytes */
+    if (dmaBuff->end + size >= dmaBuff->buf->linear + DMA_PAGE_SIZE) {
+       /* need kick off */
+       savageDMAFlush (imesa);
+    }
+    dmaBuff->allocEnd = dmaBuff->end + size;
+    return (void *)dmaBuff->end;
+}
+
+/* Flush DMA buffer via BCI (faked DMA) */
+void savageDMAFlush(savageContextPtr imesa) {
+    volatile GLuint* BCIbase;
+    DMABufferPtr dmaBuff = &imesa->DMABuf;
+    GLuint *entry;
+
+    /* make sure that everything has been filled in and committed */
+    assert (dmaBuff->allocEnd == dmaBuff->end);
+
+    if (dmaBuff->start == dmaBuff->end) /* no command? */
+      return;
+
+    /* get bci base */
+    BCIbase = (volatile GLuint *)SAVAGE_GET_BCI_POINTER(
+       imesa, (dmaBuff->end - dmaBuff->start) / sizeof (GLuint));
+
+    for (entry = (GLuint *)dmaBuff->start;
+        entry < (GLuint *)dmaBuff->end; ++entry)
+       *BCIbase = *entry;
+
+    dmaBuff->end = dmaBuff->allocEnd = dmaBuff->start;
+}
+
+/* Init faked DMA */
+int savageDMAInit (savageContextPtr imesa) {
+    DMABufferPtr dmaBuff = &imesa->DMABuf;
+    drm_savage_alloc_cont_mem_t * req;
+
+    req = (drm_savage_alloc_cont_mem_t *)
+       malloc (sizeof(drm_savage_alloc_cont_mem_t));
+    if (!req)
+       return GL_FALSE;
+
+    req->linear = (GLuint)malloc (DMA_PAGE_SIZE);
+    if (!req->linear) {
+       free (req);
+       return GL_FALSE;
+    }
+
+    dmaBuff->buf = req;
+
+    dmaBuff->start = dmaBuff->end = dmaBuff->allocEnd = req->linear;
+    dmaBuff->usingPage = 0;
+    dmaBuff->kickFlag = GL_FALSE;
+
+    return GL_TRUE;
+}
+
+/* Close faked DMA */
+int savageDMAClose (savageContextPtr imesa) {
+    DMABufferPtr dmaBuff = &imesa->DMABuf;
+    drm_savage_alloc_cont_mem_t * req = dmaBuff->buf;
+
+    free ((void *)req->linear);
+    free (req);
+
+    return GL_TRUE;
+}
+
+#endif
diff --git a/src/mesa/drivers/dri/savage/savagedma.h b/src/mesa/drivers/dri/savage/savagedma.h
new file mode 100644 (file)
index 0000000..2945685
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef SAVAGEDMA
+#define SAVAGEDMA
+
+/* Whether use DMA to transfer the 3d commands and data */
+#define SAVAGE_CMD_DMA 0
+
+#define DMA_BUFFER_SIZE (4*1024*1024) /*4M*/
+#define MAX_DMA_BUFFER_SIZE (16*1024*1024)
+#define DMA_PAGE_SIZE (4*1024)  /* savage4 , twister, prosavage,...*/
+#define DMA_TRY_COUNT 4
+
+#define MAX_SHADOWCOUNTER (MAX_DMA_BUFFER_SIZE / DMA_PAGE_SIZE)
+typedef struct DMABuffer{
+    drm_savage_alloc_cont_mem_t * buf;
+    GLuint start, end, allocEnd;
+    GLuint usingPage; /*current page */
+    unsigned int kickFlag; /* usingPage is kicked off ?*/
+} DMABuffer_t, * DMABufferPtr;
+
+void *savageDMAAlloc (savageContextPtr imesa, GLuint size);
+void savageDMACommit (savageContextPtr imesa, void *end);
+void savageDMAFlush (savageContextPtr imesa);
+int savageDMAInit (savageContextPtr imesa);
+int savageDMAClose (savageContextPtr);
+#endif
diff --git a/src/mesa/drivers/dri/savage/savageioctl.c b/src/mesa/drivers/dri/savage/savageioctl.c
new file mode 100644 (file)
index 0000000..7f85ef9
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "mtypes.h"
+#include "macros.h"
+#include "dd.h"
+#include "context.h"
+#include "swrast/swrast.h"
+
+#include "mm.h"
+#include "savagecontext.h"
+#include "savageioctl.h"
+#include "savage_bci.h"
+#include "savagedma.h"
+
+#include "drm.h"
+#include <sys/ioctl.h>
+#include <sys/timeb.h>
+
+extern GLuint bcicount;
+#define DEPTH_SCALE_16 ((1<<16)-1)
+#define DEPTH_SCALE_24 ((1<<24)-1)
+
+static void savage_BCI_clear(GLcontext *ctx, drm_savage_clear_t *pclear)
+{
+       savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+       int nbox = imesa->sarea->nbox;
+       drm_clip_rect_t *pbox = imesa->sarea->boxes;
+        int i;
+
+       
+       if (nbox > SAVAGE_NR_SAREA_CLIPRECTS)
+               nbox = SAVAGE_NR_SAREA_CLIPRECTS;
+
+       for (i = 0 ; i < nbox ; i++, pbox++) {
+               unsigned int x = pbox->x1;
+               unsigned int y = pbox->y1;
+               unsigned int width = pbox->x2 - x+1;
+               unsigned int height = pbox->y2 - y+1;
+               unsigned int *bciptr;           
+
+               if (pbox->x1 > pbox->x2 ||
+                   pbox->y1 > pbox->y2 ||
+                   pbox->x2 > imesa->savageScreen->width ||
+                   pbox->y2 > imesa->savageScreen->height)
+                       continue;
+
+               if ( (pclear->flags & SAVAGE_FRONT) && imesa->IsFullScreen) {
+                       bciptr = savageDMAAlloc (imesa, 8);
+                       WRITE_CMD((bciptr) , 0x4BCC8C00,GLuint);
+                       WRITE_CMD((bciptr) , imesa->savageScreen->frontOffset,GLuint);
+                       WRITE_CMD((bciptr) , imesa->savageScreen->frontBitmapDesc,GLuint);
+                       WRITE_CMD((bciptr) , pclear->clear_color,GLuint);
+                       WRITE_CMD((bciptr) , (y <<16) | x,GLuint);
+                       WRITE_CMD((bciptr) , (height << 16) | width,GLuint);
+                       savageDMACommit (imesa, bciptr);
+               }
+               else if ( pclear->flags & (SAVAGE_BACK|SAVAGE_FRONT) ) {
+                       bciptr = savageDMAAlloc (imesa, 8);
+                       WRITE_CMD((bciptr) , 0x4BCC8C00,GLuint);
+                       WRITE_CMD((bciptr) , imesa->savageScreen->backOffset,GLuint);
+                       WRITE_CMD((bciptr) , imesa->savageScreen->backBitmapDesc,GLuint);
+                       WRITE_CMD((bciptr) , pclear->clear_color,GLuint);
+                       WRITE_CMD((bciptr) , (y <<16) | x,GLuint);
+                       WRITE_CMD((bciptr) , (height << 16) | width,GLuint);
+                       savageDMACommit (imesa, bciptr);
+               }
+               
+               if ( pclear->flags & (SAVAGE_DEPTH |SAVAGE_STENCIL) ) {
+                       GLuint writeMask = 0x0;
+#if HW_STENCIL         
+                       if(imesa->hw_stencil)
+                       {        
+                           if(pclear->flags & SAVAGE_STENCIL)
+                           {
+                         
+                                writeMask |= 0xFF000000;
+                           }
+                           if(pclear->flags & SAVAGE_DEPTH)
+                           {
+                                writeMask |= 0x00FFFFFF;
+                           }
+                        }
+#endif
+                       if(imesa->IsFullScreen && imesa->NotFirstFrame &&
+                          imesa->savageScreen->chipset >= S3_SAVAGE4)
+                       {
+                           imesa->Registers.ZBufCtrl.s4.autoZEnable = GL_TRUE;
+                                imesa->Registers.ZBufCtrl.s4.frameID = ~imesa->Registers.ZBufCtrl.s4.frameID;
+                            
+                            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+                       }
+                       else
+                       {
+                           if(imesa->IsFullScreen)
+                               imesa->NotFirstFrame = GL_TRUE;
+                               
+#if HW_STENCIL
+                           if(imesa->hw_stencil)
+                           {
+                               bciptr = savageDMAAlloc (imesa, 10);
+                               if(writeMask != 0xFFFFFFFF)
+                               {
+                                    WRITE_CMD((bciptr) , 0x960100D7,GLuint);
+                                    WRITE_CMD((bciptr) , writeMask,GLuint);  
+                                }
+                            }
+                           else
+#endif              
+                           {
+                               bciptr = savageDMAAlloc (imesa, 6);
+                           }
+
+                           WRITE_CMD((bciptr) , 0x4BCC8C00,GLuint);
+                           WRITE_CMD((bciptr) , imesa->savageScreen->depthOffset,GLuint);
+                           WRITE_CMD((bciptr) , imesa->savageScreen->depthBitmapDesc,GLuint);
+                           WRITE_CMD((bciptr) , pclear->clear_depth,GLuint);
+                           WRITE_CMD((bciptr) , (y <<16) | x,GLuint);
+                           WRITE_CMD((bciptr) , (height << 16) | width,GLuint);
+#if HW_STENCIL                     
+                           if(imesa->hw_stencil)
+                           {
+                               if(writeMask != 0xFFFFFFFF)
+                               {
+                                  WRITE_CMD((bciptr) , 0x960100D7,GLuint);
+                                   WRITE_CMD((bciptr) , 0xFFFFFFFF,GLuint);  
+                               }
+                           }
+#endif
+                           savageDMACommit (imesa, bciptr);
+                       }
+               }
+       }
+       /* FK: Make sure that the clear stuff is emitted. Otherwise a
+          software fallback may get overwritten by a delayed clear. */
+       savageDMAFlush (imesa);
+}
+
+struct timeb a,b;
+
+static void savage_BCI_swap(savageContextPtr imesa)
+{
+    int nbox = imesa->sarea->nbox;
+    drm_clip_rect_t *pbox = imesa->sarea->boxes;
+    int i;
+    volatile unsigned int *bciptr;
+    
+    if (nbox > SAVAGE_NR_SAREA_CLIPRECTS)
+        nbox = SAVAGE_NR_SAREA_CLIPRECTS;
+    savageDMAFlush (imesa);
+    WAIT_IDLE_EMPTY;
+    
+    if(imesa->IsFullScreen)
+    { /* full screen*/
+        unsigned int tmp0;
+        tmp0 = imesa->savageScreen->frontOffset; 
+        imesa->savageScreen->frontOffset = imesa->savageScreen->backOffset;
+        imesa->savageScreen->backOffset = tmp0;
+        
+        if(imesa->toggle == TARGET_BACK)
+            imesa->toggle = TARGET_FRONT;
+        else
+            imesa->toggle = TARGET_BACK; 
+        
+        imesa->drawMap = (char *)imesa->apertureBase[imesa->toggle];
+        imesa->readMap = (char *)imesa->apertureBase[imesa->toggle];
+        
+        imesa->Registers.DestCtrl.ni.offset = imesa->savageScreen->backOffset>>11;
+        imesa->Registers.changed.ni.fDestCtrlChanged = GL_TRUE;
+        imesa->dirty |= SAVAGE_UPLOAD_CTX;
+        bciptr = SAVAGE_GET_BCI_POINTER(imesa,3);
+        *(bciptr) = 0x960100B0;
+        *(bciptr) = (imesa->savageScreen->frontOffset); 
+        *(bciptr) = 0xA0000000;
+    } 
+    
+    else
+    {  /* Use bitblt copy from back to front buffer*/
+        
+        for (i = 0 ; i < nbox; i++, pbox++)
+        {
+            unsigned int w = pbox->x2 - pbox->x1;
+            unsigned int h = pbox->y2 - pbox->y1;
+            
+            if (pbox->x1 > pbox->x2 ||
+                pbox->y1 > pbox->y2 ||
+                pbox->x2 > imesa->savageScreen->width ||
+                pbox->y2 > imesa->savageScreen->height)
+                continue;
+
+            bciptr = SAVAGE_GET_BCI_POINTER(imesa,6);
+            
+            *(bciptr) = 0x4BCC00C0;
+            
+            *(bciptr) = imesa->savageScreen->backOffset;
+            *(bciptr) = imesa->savageScreen->backBitmapDesc;
+            *(bciptr) = (pbox->y1 <<16) | pbox->x1;   /*x0, y0*/
+            *(bciptr) = (pbox->y1 <<16) | pbox->x1;
+            *(bciptr) = (h << 16) | w;
+        }
+        
+    }
+}
+
+
+static void savageDDClear( GLcontext *ctx, GLbitfield mask, GLboolean all,
+                          GLint cx, GLint cy, GLint cw, GLint ch ) 
+{
+  savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+   __DRIdrawablePrivate *dPriv = imesa->driDrawable;
+   const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask);
+   drm_savage_clear_t clear;
+   int i;
+
+   clear.flags = 0;
+   clear.clear_color = imesa->ClearColor;
+
+   if(imesa->savageScreen->zpp == 2)
+       clear.clear_depth = (GLuint) (ctx->Depth.Clear * DEPTH_SCALE_16);
+   else
+       clear.clear_depth = (GLuint) (ctx->Depth.Clear * DEPTH_SCALE_24);
+#if 0
+   FLUSH_BATCH( imesa );
+#endif 
+   if ((mask & DD_FRONT_LEFT_BIT) && ((colorMask&0xffffffUL)==0xffffffUL) ){
+      clear.flags |= SAVAGE_FRONT;
+      mask &= ~DD_FRONT_LEFT_BIT;
+   }
+
+   if ((mask & DD_BACK_LEFT_BIT) && ((colorMask&0xffffffUL)==0xffffffUL) ) {
+      clear.flags |= SAVAGE_BACK;
+      mask &= ~DD_BACK_LEFT_BIT;
+   }
+
+   if ((mask & DD_DEPTH_BIT) && ctx->Depth.Mask) {
+      clear.flags |= SAVAGE_DEPTH;
+      mask &= ~DD_DEPTH_BIT;
+   }
+   
+   if((mask & DD_STENCIL_BIT) && imesa->hw_stencil)
+   {
+       clear.flags |= SAVAGE_STENCIL;
+       mask &= ~DD_STENCIL_BIT;
+   }
+
+   if (clear.flags) {
+       LOCK_HARDWARE( imesa );
+
+       /* flip top to bottom */
+       cy = dPriv->h-cy-ch;
+       cx += imesa->drawX;
+       cy += imesa->drawY;
+
+       for (i = 0 ; i < imesa->numClipRects ; ) {       
+          int nr = MIN2(i + SAVAGE_NR_SAREA_CLIPRECTS, imesa->numClipRects);
+          XF86DRIClipRectRec *box = imesa->pClipRects;  
+          drm_clip_rect_t *b = imesa->sarea->boxes;
+          int n = 0;
+
+          if (!all) {
+              for ( ; i < nr ; i++) {
+                  GLint x = box[i].x1;
+                  GLint y = box[i].y1;
+                  GLint w = box[i].x2 - x;
+                  GLint h = box[i].y2 - y;
+
+                  if (x < cx) w -= cx - x, x = cx; 
+                  if (y < cy) h -= cy - y, y = cy;
+                  if (x + w > cx + cw) w = cx + cw - x;
+                  if (y + h > cy + ch) h = cy + ch - y;
+                  if (w <= 0) continue;
+                  if (h <= 0) continue;
+
+                  b->x1 = x;
+                  b->y1 = y;
+                  b->x2 = x + w;
+                  b->y2 = y + h;
+                  b++;
+                  n++;
+              }
+          } else {
+              for ( ; i < nr ; i++) {
+                  *b++ = *(drm_clip_rect_t *)&box[i];
+                  n++;
+              }
+          }
+
+          imesa->sarea->nbox = n;
+
+          savage_BCI_clear(ctx,&clear);
+       }
+
+       UNLOCK_HARDWARE( imesa );
+       imesa->dirty |= SAVAGE_UPLOAD_CLIPRECTS|SAVAGE_UPLOAD_CTX;
+   }
+
+   if (mask) 
+      _swrast_Clear( ctx, mask, all, cx, cy, cw, ch );
+}
+
+
+
+
+/*
+ * Copy the back buffer to the front buffer. 
+ */
+void savageSwapBuffers( __DRIdrawablePrivate *dPriv )
+{
+   savageContextPtr imesa;
+   XF86DRIClipRectPtr pbox;
+   int nbox;
+   int i;
+
+   GLboolean pending;
+
+   assert(dPriv);
+   assert(dPriv->driContextPriv);
+   assert(dPriv->driContextPriv->driverPrivate);
+
+   imesa = (savageContextPtr) dPriv->driContextPriv->driverPrivate;
+   if (imesa->IsDouble)
+       _mesa_notifySwapBuffers( imesa->glCtx );
+
+   LOCK_HARDWARE( imesa );
+   PAGE_PENDING(pending);
+
+   if(!pending)
+   {
+   pbox = dPriv->pClipRects;
+   nbox = dPriv->numClipRects;
+
+   for (i = 0 ; i < nbox ; )
+   {
+      int nr = MIN2(i + SAVAGE_NR_SAREA_CLIPRECTS, dPriv->numClipRects);
+      XF86DRIClipRectRec *b = (XF86DRIClipRectRec *)imesa->sarea->boxes;
+
+      imesa->sarea->nbox = nr - i;
+
+      for ( ; i < nr ; i++) 
+        *b++ = pbox[i];
+     savage_BCI_swap(imesa) ;
+   }
+   }
+   UNLOCK_HARDWARE( imesa );
+   
+
+}
+
+/* This waits for *everybody* to finish rendering -- overkill.
+ */
+void savageDmaFinish( savageContextPtr imesa  ) 
+{
+    savageDMAFlush(imesa);
+    WAIT_IDLE_EMPTY;
+}
+
+
+void savageRegetLockQuiescent( savageContextPtr imesa  ) 
+{
+    
+
+}
+
+void savageWaitAgeLocked( savageContextPtr imesa, int age  ) 
+{
+}
+
+
+void savageWaitAge( savageContextPtr imesa, int age  ) 
+{
+}
+
+
+
+void savageFlushVertices( savageContextPtr imesa ) 
+{
+
+}
+
+
+void savageFlushVerticesLocked( savageContextPtr imesa )
+{
+
+}
+
+
+int savage_check_copy(int fd)
+{
+    return 0;
+}
+
+static void savageDDFlush( GLcontext *ctx )
+{
+
+}
+
+static void savageDDFinish( GLcontext *ctx  ) 
+{
+}
+
+#define ALT_STATUS_WORD0 (* (volatile GLuint *)(imesa->MMIO_BASE+0x48c60))
+#define STATUS_WORD0 (* (volatile GLuint *)(imesa->MMIO_BASE+0x48c00))
+#define MAXFIFO_S4 0x1FF00
+#define MAXFIFO_S3D 0x7F00
+
+static GLboolean savagePagePending_s4( savageContextPtr imesa ) {
+    return (ALT_STATUS_WORD0 & 0x08000000) ? GL_TRUE : GL_FALSE;
+}
+static GLboolean savagePagePending_s3d( savageContextPtr imesa ) {
+    return GL_FALSE;
+}
+static void savageWaitForFIFO_s4( savageContextPtr imesa, unsigned count ) {
+    int loop = 0;
+    int slots = MAXFIFO_S4-count;
+    while((ALT_STATUS_WORD0 & 0x001fffff) > slots && loop++ < MAXLOOP);
+}
+static void savageWaitForFIFO_s3d( savageContextPtr imesa, unsigned count ) {
+    int loop = 0;
+    int slots = MAXFIFO_S3D-count;
+    while((STATUS_WORD0 & 0x0001ffff) > slots && loop++ < MAXLOOP);
+}
+static void savageWaitIdleEmpty_s4( savageContextPtr imesa ) {
+    int loop = 0;
+    while((ALT_STATUS_WORD0 & 0x00ffffff) != 0x00E00000L && loop++ < MAXLOOP);
+}
+static void savageWaitIdleEmpty_s3d( savageContextPtr imesa ) {
+    int loop = 0;
+    while((STATUS_WORD0 & 0x000fffff) != 0x000E0000L && loop++ < MAXLOOP);
+}
+
+GLboolean (*savagePagePending)( savageContextPtr imesa ) = NULL;
+void (*savageWaitForFIFO)( savageContextPtr imesa, unsigned count ) = NULL;
+void (*savageWaitIdleEmpty)( savageContextPtr imesa ) = NULL;
+
+
+void savageDDInitIoctlFuncs( GLcontext *ctx )
+{
+   ctx->Driver.Clear = savageDDClear;
+   ctx->Driver.Flush = savageDDFlush;
+   ctx->Driver.Finish = savageDDFinish;
+   if (SAVAGE_CONTEXT( ctx )->savageScreen->chipset >= S3_SAVAGE4) {
+       savagePagePending = savagePagePending_s4;
+       savageWaitForFIFO = savageWaitForFIFO_s4;
+       savageWaitIdleEmpty = savageWaitIdleEmpty_s4;
+   } else {
+       savagePagePending = savagePagePending_s3d;
+       savageWaitForFIFO = savageWaitForFIFO_s3d;
+       savageWaitIdleEmpty = savageWaitIdleEmpty_s3d;
+   }
+}
+
+#if SAVAGE_CMD_DMA
+/* Alloc a continuous memory */
+/* return: 0 error when kernel alloc pages(can try a half memory size) 
+           >0 sucess
+          <0 Other error*/
+int  savageAllocDMABuffer(savageContextPtr imesa,  drm_savage_alloc_cont_mem_t *req)
+{
+  int ret;
+  if (req ==NULL)
+    return 0;
+
+  if ((ret=ioctl(imesa->driFd, DRM_IOCTL_SAVAGE_ALLOC_CONTINUOUS_MEM, req)) <=0)    
+    return ret;
+  
+  return 1;
+  
+}
+
+/* get the physics address*/
+GLuint savageGetPhyAddress(savageContextPtr imesa,void * pointer)
+{
+
+  drm_savage_get_physcis_address_t req;
+  int ret;
+
+  req.v_address = (GLuint )pointer;
+  ret = ioctl(imesa->driFd, DRM_IOCTL_SAVAGE_GET_PHYSICS_ADDRESS,&req);
+
+  return req.p_address;
+}
+
+/* free the buffer got by savageAllocDMABuffe*/
+int  savageFreeDMABuffer(savageContextPtr imesa,  drm_savage_alloc_cont_mem_t *req)
+{
+  GLuint ret;
+  if (req ==NULL)
+    return 0;
+  
+  if ((ret=ioctl(imesa->driFd, DRM_IOCTL_SAVAGE_FREE_CONTINUOUS_MEM, req)) <=0)    
+    return ret;
+  return 1;
+  
+}
+#endif
diff --git a/src/mesa/drivers/dri/savage/savageioctl.h b/src/mesa/drivers/dri/savage/savageioctl.h
new file mode 100644 (file)
index 0000000..94b02e3
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef SAVAGE_IOCTL_H
+#define SAVAGE_IOCTL_H
+
+#include "savagecontext.h"
+#include "savagedma.h"
+
+void savageGetGeneralDmaBufferLocked( savageContextPtr mmesa ); 
+
+void savageFlushVertices( savageContextPtr mmesa ); 
+void savageFlushVerticesLocked( savageContextPtr mmesa );
+
+void savageFlushGeneralLocked( savageContextPtr imesa );
+void savageWaitAgeLocked( savageContextPtr imesa, int age );
+void savageWaitAge( savageContextPtr imesa, int age );
+
+void savageDmaFinish( savageContextPtr imesa );
+
+void savageRegetLockQuiescent( savageContextPtr imesa );
+
+void savageDDInitIoctlFuncs( GLcontext *ctx );
+
+void savageSwapBuffers( __DRIdrawablePrivate *dPriv );
+
+int savage_check_copy(int fd);
+
+extern GLboolean (*savagePagePending)( savageContextPtr imesa );
+extern void (*savageWaitForFIFO)( savageContextPtr imesa, unsigned count );
+extern void (*savageWaitIdleEmpty)( savageContextPtr imesa );
+
+#define PAGE_PENDING(result) do { \
+    result = savagePagePending(imesa); \
+} while (0)
+#define WAIT_FOR_FIFO(count) do { \
+    savageWaitForFIFO(imesa, count); \
+} while (0)
+#define WAIT_IDLE_EMPTY do { \
+    savageWaitIdleEmpty(imesa); \
+} while (0)
+
+#if SAVAGE_CMD_DMA
+int  savageAllocDMABuffer(savageContextPtr imesa,  drm_savage_alloc_cont_mem_t *req);
+GLuint savageGetPhyAddress(savageContextPtr imesa,void * pointer);
+int  savageFreeDMABuffer(savageContextPtr, drm_savage_alloc_cont_mem_t*);
+#endif
+
+#define FLUSH_BATCH(imesa) savageDMAFlush(imesa)
+#endif
diff --git a/src/mesa/drivers/dri/savage/savagespan.c b/src/mesa/drivers/dri/savage/savagespan.c
new file mode 100644 (file)
index 0000000..aa13cfc
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "mtypes.h"
+#include "savagedd.h"
+#include "savagespan.h"
+#include "savageioctl.h"
+#include "savage_bci.h"
+#include "savage_3d_reg.h"
+#include "swrast/swrast.h"
+
+#define DBG 0
+
+#define LOCAL_VARS                                     \
+   __DRIdrawablePrivate *dPriv = imesa->mesa_drawable; \
+   savageScreenPrivate *savageScreen = imesa->savageScreen;    \
+   GLuint cpp   = savageScreen->cpp;                   \
+   GLuint pitch = imesa->aperturePitch;                        \
+   GLuint height = dPriv->h;                           \
+   char *buf = (char *)(imesa->drawMap +               \
+                       dPriv->x * cpp +                \
+                       dPriv->y * pitch);              \
+   char *read_buf = (char *)(imesa->readMap +          \
+                            dPriv->x * cpp +           \
+                            dPriv->y * pitch);         \
+   GLuint p = SAVAGE_CONTEXT( ctx )->MonoColor;         \
+   (void) read_buf; (void) buf; (void) p
+
+#define LOCAL_DEPTH_VARS                               \
+   __DRIdrawablePrivate *dPriv = imesa->mesa_drawable; \
+   savageScreenPrivate *savageScreen = imesa->savageScreen;    \
+   GLuint zpp   = savageScreen->zpp;                   \
+   GLuint pitch = imesa->aperturePitch;                        \
+   GLuint height = dPriv->h;                           \
+   char *buf = (char *)(imesa->apertureBase[TARGET_DEPTH] +    \
+                       dPriv->x * zpp +                        \
+                       dPriv->y * pitch)
+
+#define LOCAL_STENCIL_VARS LOCAL_DEPTH_VARS
+
+#define INIT_MONO_PIXEL(p)
+
+#define CLIPPIXEL(_x,_y) (_x >= minx && _x < maxx && \
+                         _y >= miny && _y < maxy)
+
+
+#define CLIPSPAN( _x, _y, _n, _x1, _n1, _i )                           \
+   if ( _y < miny || _y >= maxy ) {                                    \
+      _n1 = 0, _x1 = x;                                                        \
+   } else {                                                            \
+      _n1 = _n;                                                                \
+      _x1 = _x;                                                                \
+      if ( _x1 < minx ) _i += (minx-_x1), n1 -= (minx-_x1), _x1 = minx; \
+      if ( _x1 + _n1 >= maxx ) n1 -= (_x1 + n1 - maxx);                        \
+   }
+
+#define Y_FLIP(_y) (height - _y - 1)
+
+#define HW_LOCK() savageContextPtr imesa = SAVAGE_CONTEXT(ctx); \
+                  WAIT_IDLE_EMPTY;\
+
+#define HW_CLIPLOOP()                                          \
+  do {                                                         \
+    __DRIdrawablePrivate *dPriv = imesa->driDrawable;          \
+    int _nc = dPriv->numClipRects;                             \
+    while (_nc--) {                                            \
+       int minx = dPriv->pClipRects[_nc].x1 - dPriv->x;                \
+       int miny = dPriv->pClipRects[_nc].y1 - dPriv->y;        \
+       int maxx = dPriv->pClipRects[_nc].x2 - dPriv->x;                \
+       int maxy = dPriv->pClipRects[_nc].y2 - dPriv->y;
+
+
+#define HW_ENDCLIPLOOP()                       \
+    }                                          \
+  } while (0)
+
+#if 0
+#define HW_UNLOCK()                            \
+    UNLOCK_HARDWARE(imesa);
+#endif
+#define HW_UNLOCK()    { }
+
+
+/* 16 bit, 565 rgb color spanline and pixel functions
+ */
+#undef INIT_MONO_PIXEL
+#define INIT_MONO_PIXEL(p, color) \
+  p = SAVAGEPACKCOLOR565( color[0], color[1], color[2] )
+
+#define WRITE_RGBA( _x, _y, r, g, b, a )                               \
+do{                                                                    \
+   *(GLushort *)(buf + (_x<<1) + _y*pitch)  = ( (((int)r & 0xf8) << 8) |\
+                                            (((int)g & 0xfc) << 3) |   \
+                                            (((int)b & 0xf8) >> 3));   \
+}while(0)
+#define WRITE_PIXEL( _x, _y, p )  \
+do{                                                            \
+   *(GLushort *)(buf + (_x<<1) + _y*pitch) = p;                        \
+}while(0)
+
+#define READ_RGBA( rgba, _x, _y )                              \
+do {                                                           \
+   GLushort p = *(GLushort *)(read_buf + (_x<<1) + _y*pitch);  \
+   rgba[0] = (((p >> 11) & 0x1f) * 255) >>5;                   \
+   rgba[1] = (((p >>  5) & 0x3f) * 255) >>6;                   \
+   rgba[2] = (((p >>  0) & 0x1f) * 255) >>5;                   \
+   rgba[3] = 255;                                              \
+} while(0)
+
+#define TAG(x) savage##x##_565
+#include "spantmp.h"
+
+
+/* 32 bit, 8888 ARGB color spanline and pixel functions
+ */
+#undef INIT_MONO_PIXEL
+#define INIT_MONO_PIXEL(p, color) \
+  p = SAVAGEPACKCOLOR8888( color[0], color[1], color[2], color[3] )
+
+#define WRITE_RGBA( _x, _y, r, g, b, a )                               \
+   *(GLuint *)(buf + (_x<<2) + _y*pitch)  = ( ((GLuint)a << 24) |      \
+                                           ((GLuint)r << 16) | \
+                                           ((GLuint)g << 8) |  \
+                                           ((GLuint)b ))
+#define WRITE_PIXEL( _x, _y, p )  \
+   *(GLuint *)(buf + (_x<<2) + _y*pitch) = p
+
+#define READ_RGBA( rgba, _x, _y )                              \
+do {                                                           \
+   GLuint p = *(GLuint *)(read_buf + (_x<<2) + _y*pitch);      \
+   rgba[0] = (p >> 16) & 0xFF;                 \
+   rgba[1] = (p >>  8) & 0xFF;                 \
+   rgba[2] = (p >>  0) & 0xFF;                 \
+   rgba[3] = 0xFF;                             \
+} while(0)
+
+#define TAG(x) savage##x##_8888
+#include "spantmp.h"
+
+
+
+
+/* 16 bit depthbuffer functions.
+ */
+#define WRITE_DEPTH( _x, _y, d ) \
+do{                                                    \
+    *(GLushort *)(buf + (_x<<1) + _y*pitch)  = d;      \
+}while(0)
+    
+#define READ_DEPTH( d, _x, _y ) \
+do{                                                    \
+    d = *(GLushort *)(buf + (_x<<1) + _y*pitch);       \
+}while(0)
+       
+/*     d = 0xffff; */
+       
+#define TAG(x) savage##x##_16
+#include "depthtmp.h"
+       
+
+
+
+
+/* 8-bit stencil /24-bit depth depthbuffer functions.
+ */
+#define WRITE_DEPTH( _x, _y, d ) {                     \
+   GLuint tmp = *(GLuint *)(buf + (_x<<2) + _y*pitch); \
+   tmp &= 0xFF000000;                                  \
+   tmp |= d;                                           \
+   *(GLuint *)(buf + (_x<<2) + _y*pitch)  = tmp;               \
+}
+
+#define READ_DEPTH( d, _x, _y )        \
+   d = *(GLuint *)(buf + (_x<<2) + _y*pitch) & 0x00FFFFFF;
+
+/*     d = 0x00ffffff; */
+
+#define TAG(x) savage##x##_8_24
+#include "depthtmp.h"
+
+
+#define WRITE_STENCIL( _x, _y, d ) {                    \
+   GLuint tmp = *(GLuint *)(buf + (_x<<2) + _y*pitch);     \
+   tmp &= 0x00FFFFFF;                                   \
+   tmp |= (((GLuint)d)<<24) & 0xFF000000;               \
+   *(GLuint *)(buf + (_x<<2) + _y*pitch) = tmp;            \
+}
+            
+#define READ_STENCIL( d, _x, _y )               \
+   d = (GLstencil)((*(GLuint *)(buf + (_x<<2) + _y*pitch) & 0xFF000000) >> 24);
+                
+#define TAG(x) savage##x##_8_24
+#include "stenciltmp.h"
+                
+
+/*
+ * This function is called to specify which buffer to read and write
+ * for software rasterization (swrast) fallbacks.  This doesn't necessarily
+ * correspond to glDrawBuffer() or glReadBuffer() calls.
+ */
+static void savageDDSetBuffer(GLcontext *ctx, GLframebuffer *buffer,
+                             GLuint bufferBit)
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+   char *map;
+
+   assert( (bufferBit == FRONT_LEFT_BIT) || (bufferBit == BACK_LEFT_BIT) );
+
+   map = (bufferBit == FRONT_LEFT_BIT)
+       ? (char*)imesa->apertureBase[TARGET_FRONT]
+       : (char*)imesa->apertureBase[TARGET_BACK];
+
+   imesa->drawMap = map;
+   imesa->readMap = map;
+
+   assert( (buffer == imesa->driDrawable->driverPrivate)
+          || (buffer == imesa->driReadable->driverPrivate) );
+
+   imesa->mesa_drawable = (buffer == imesa->driDrawable->driverPrivate)
+       ? imesa->driDrawable : imesa->driReadable;
+}
+
+
+void savageDDInitSpanFuncs( GLcontext *ctx )
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+   struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference(ctx);
+
+   swdd->SetBuffer = savageDDSetBuffer;
+   
+   switch (imesa->savageScreen->cpp) 
+   {
+   case 2:
+      swdd->WriteRGBASpan = savageWriteRGBASpan_565;
+      swdd->WriteRGBSpan = savageWriteRGBSpan_565;
+      swdd->WriteMonoRGBASpan = savageWriteMonoRGBASpan_565;
+      swdd->WriteRGBAPixels = savageWriteRGBAPixels_565;
+      swdd->WriteMonoRGBAPixels = savageWriteMonoRGBAPixels_565;
+      swdd->ReadRGBASpan = savageReadRGBASpan_565;
+      swdd->ReadRGBAPixels = savageReadRGBAPixels_565;
+   
+      break;
+
+   case 4:
+      swdd->WriteRGBASpan = savageWriteRGBASpan_8888;
+      swdd->WriteRGBSpan = savageWriteRGBSpan_8888;
+      swdd->WriteMonoRGBASpan = savageWriteMonoRGBASpan_8888;
+      swdd->WriteRGBAPixels = savageWriteRGBAPixels_8888;
+      swdd->WriteMonoRGBAPixels = savageWriteMonoRGBAPixels_8888;
+      swdd->ReadRGBASpan = savageReadRGBASpan_8888;
+      swdd->ReadRGBAPixels = savageReadRGBAPixels_8888;
+   }
+
+   switch (imesa->savageScreen->zpp)
+   {
+   case 2: 
+       swdd->ReadDepthSpan = savageReadDepthSpan_16;
+       swdd->WriteDepthSpan = savageWriteDepthSpan_16;
+       swdd->ReadDepthPixels = savageReadDepthPixels_16;
+       swdd->WriteDepthPixels = savageWriteDepthPixels_16;
+       
+       break;
+   case 4: 
+       swdd->ReadDepthSpan = savageReadDepthSpan_8_24;
+       swdd->WriteDepthSpan = savageWriteDepthSpan_8_24;
+       swdd->ReadDepthPixels = savageReadDepthPixels_8_24;
+       swdd->WriteDepthPixels = savageWriteDepthPixels_8_24;    
+#if HW_STENCIL
+       swdd->ReadStencilSpan = savageReadStencilSpan_8_24;
+       swdd->WriteStencilSpan = savageWriteStencilSpan_8_24;
+       swdd->ReadStencilPixels = savageReadStencilPixels_8_24;
+       swdd->WriteStencilPixels = savageWriteStencilPixels_8_24;
+#endif       
+       break;   
+   
+   }
+   swdd->WriteCI8Span        =NULL;
+   swdd->WriteCI32Span       =NULL;
+   swdd->WriteMonoCISpan     =NULL;
+   swdd->WriteCI32Pixels     =NULL;
+   swdd->WriteMonoCIPixels   =NULL;
+   swdd->ReadCI32Span        =NULL;
+   swdd->ReadCI32Pixels      =NULL;
+
+   /* Pixel path fallbacks.
+    */
+   ctx->Driver.Accum = _swrast_Accum;
+   ctx->Driver.Bitmap = _swrast_Bitmap;
+   ctx->Driver.CopyPixels = _swrast_CopyPixels;
+   ctx->Driver.DrawPixels = _swrast_DrawPixels;
+   ctx->Driver.ReadPixels = _swrast_ReadPixels;
+}
diff --git a/src/mesa/drivers/dri/savage/savagespan.h b/src/mesa/drivers/dri/savage/savagespan.h
new file mode 100644 (file)
index 0000000..35247b4
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _SAVAGE_SPAN_H
+#define _SAVAGE_SPAN_H
+
+extern void savageDDInitSpanFuncs( GLcontext *ctx );
+
+#endif
diff --git a/src/mesa/drivers/dri/savage/savagestate.c b/src/mesa/drivers/dri/savage/savagestate.c
new file mode 100644 (file)
index 0000000..622e436
--- /dev/null
@@ -0,0 +1,2444 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include <stdio.h>
+
+#include "mtypes.h"
+#include "enums.h"
+#include "macros.h"
+#include "dd.h"
+
+#include "mm.h"
+#include "savagedd.h"
+#include "savagecontext.h"
+
+#include "savagestate.h"
+#include "savagetex.h"
+#include "savagevb.h"
+#include "savagetris.h"
+#include "savageioctl.h"
+#include "savage_bci.h"
+
+#include "swrast/swrast.h"
+#include "array_cache/acache.h"
+#include "tnl/tnl.h"
+#include "swrast_setup/swrast_setup.h"
+
+static void savageBlendFunc_s4(GLcontext *);
+static void savageBlendFunc_s3d(GLcontext *);
+
+static __inline__ GLuint savagePackColor(GLuint format, 
+                                         GLubyte r, GLubyte g, 
+                                         GLubyte b, GLubyte a)
+{
+    switch (format) {
+        case DV_PF_8888:
+            return SAVAGEPACKCOLOR8888(r,g,b,a);
+        case DV_PF_565:
+            return SAVAGEPACKCOLOR565(r,g,b);
+        default:
+            
+            return 0;
+    }
+}
+
+
+static void savageDDAlphaFunc_s4(GLcontext *ctx, GLenum func, GLfloat ref)
+{
+    /* This can be done in BlendFunc*/
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    imesa->dirty |= SAVAGE_UPLOAD_CTX;
+    savageBlendFunc_s4(ctx);
+}
+static void savageDDAlphaFunc_s3d(GLcontext *ctx, GLenum func, GLfloat ref)
+{
+    /* This can be done in BlendFunc*/
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    imesa->dirty |= SAVAGE_UPLOAD_CTX;
+    savageBlendFunc_s3d(ctx);
+}
+
+static void savageDDBlendEquationSeparate(GLcontext *ctx,
+                                         GLenum modeRGB, GLenum modeA)
+{
+    assert( modeRGB == modeA );
+
+    /* BlendEquation sets ColorLogicOpEnabled in an unexpected 
+     * manner.  
+     */
+    FALLBACK( ctx, SAVAGE_FALLBACK_LOGICOP,
+             (ctx->Color.ColorLogicOpEnabled && 
+              ctx->Color.LogicOp != GL_COPY));
+
+   /* Can only do blend addition, not min, max, subtract, etc. */
+   FALLBACK( ctx, SAVAGE_FALLBACK_BLEND_EQ,
+            modeRGB != GL_FUNC_ADD);
+}
+
+
+static void savageBlendFunc_s4(GLcontext *ctx)
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    Reg_DrawLocalCtrl DrawLocalCtrl;
+
+    /* set up draw control register (including blending, alpha
+     * test, dithering, and shading model)
+     */
+
+    /*
+     * And mask removes flushPdDestWrites
+     */
+
+    DrawLocalCtrl.ui = imesa->Registers.DrawLocalCtrl.ui & ~0x40000000;
+
+    /*
+     * blend modes
+     */
+    if(ctx->Color.BlendEnabled){
+        switch (ctx->Color.BlendDstRGB)
+        {
+            case GL_ZERO:
+                DrawLocalCtrl.ni.dstAlphaMode = DAM_Zero;
+                break;
+
+            case GL_ONE:
+                DrawLocalCtrl.ni.dstAlphaMode = DAM_One;
+                DrawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+                break;
+
+            case GL_SRC_COLOR:
+                DrawLocalCtrl.ni.dstAlphaMode = DAM_SrcClr;
+                DrawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+                break;
+
+            case GL_ONE_MINUS_SRC_COLOR:
+                DrawLocalCtrl.ni.dstAlphaMode = DAM_1SrcClr;
+                DrawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+                break;
+
+            case GL_SRC_ALPHA:
+                DrawLocalCtrl.ni.dstAlphaMode = DAM_SrcAlpha;
+                DrawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+                break;
+
+            case GL_ONE_MINUS_SRC_ALPHA:
+                DrawLocalCtrl.ni.dstAlphaMode = DAM_1SrcAlpha;
+                DrawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+                break;
+
+            case GL_DST_ALPHA:
+                if (imesa->glCtx->Visual.alphaBits == 0)
+                {
+                    DrawLocalCtrl.ni.dstAlphaMode = DAM_One;
+                }
+                else
+                {
+                    DrawLocalCtrl.ni.dstAlphaMode = DAM_DstAlpha;
+                }
+                DrawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+                break;
+
+            case GL_ONE_MINUS_DST_ALPHA:
+                if (imesa->glCtx->Visual.alphaBits == 0)
+                {
+                    DrawLocalCtrl.ni.dstAlphaMode = DAM_Zero;
+                }
+                else
+                {
+                    DrawLocalCtrl.ni.dstAlphaMode = DAM_1DstAlpha;
+                    DrawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+                }
+                break;
+        }
+
+        switch (ctx->Color.BlendSrcRGB)
+        {
+            case GL_ZERO:
+                DrawLocalCtrl.ni.srcAlphaMode = SAM_Zero;
+                break;
+
+            case GL_ONE:
+                DrawLocalCtrl.ni.srcAlphaMode = SAM_One;
+                break;
+
+            case GL_DST_COLOR:
+                DrawLocalCtrl.ni.srcAlphaMode = SAM_DstClr;
+                DrawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+                break;
+
+            case GL_ONE_MINUS_DST_COLOR:
+                DrawLocalCtrl.ni.srcAlphaMode = SAM_1DstClr;
+                DrawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+                break;
+
+            case GL_SRC_ALPHA:
+                DrawLocalCtrl.ni.srcAlphaMode = SAM_SrcAlpha;
+                break;
+
+            case GL_ONE_MINUS_SRC_ALPHA:
+                DrawLocalCtrl.ni.srcAlphaMode = SAM_1SrcAlpha;
+                break;
+
+            case GL_DST_ALPHA:
+                if (imesa->glCtx->Visual.alphaBits == 0)
+                {
+                    DrawLocalCtrl.ni.srcAlphaMode = SAM_One;
+                }
+                else
+                {
+                    DrawLocalCtrl.ni.srcAlphaMode = SAM_DstAlpha;
+                    DrawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+                }
+                break;
+
+            case GL_ONE_MINUS_DST_ALPHA:
+                if (imesa->glCtx->Visual.alphaBits == 0)          
+                {
+                    DrawLocalCtrl.ni.srcAlphaMode = SAM_Zero;
+                }
+                else
+                {
+                    DrawLocalCtrl.ni.srcAlphaMode = SAM_1DstAlpha;
+                    DrawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+                }
+                break;
+        }
+    }
+    else
+    {
+        DrawLocalCtrl.ni.dstAlphaMode = DAM_Zero;
+        DrawLocalCtrl.ni.srcAlphaMode = SAM_One;
+    }
+
+    /* alpha test*/
+
+    if(ctx->Color.AlphaEnabled) 
+    {
+        int a;
+       GLubyte alphaRef;
+
+       CLAMPED_FLOAT_TO_UBYTE(alphaRef,ctx->Color.AlphaRef);
+         
+        switch(ctx->Color.AlphaFunc)  { 
+            case GL_NEVER: a = LCS_A_NEVER; break;
+            case GL_ALWAYS: a = LCS_A_ALWAYS; break;
+            case GL_LESS: a = LCS_A_LESS; break; 
+            case GL_LEQUAL: a = LCS_A_LEQUAL; break;
+            case GL_EQUAL: a = LCS_A_EQUAL; break;
+            case GL_GREATER: a = LCS_A_GREATER; break;
+            case GL_GEQUAL: a = LCS_A_GEQUAL; break;
+            case GL_NOTEQUAL: a = LCS_A_NOTEQUAL; break;
+            default:return;
+        }   
+      
+        if (imesa->Registers.DrawCtrl1.ni.alphaTestEn != GL_TRUE)
+        {
+            imesa->Registers.DrawCtrl1.ni.alphaTestEn = GL_TRUE;
+            imesa->Registers.changed.ni.fDrawCtrl1Changed = GL_TRUE;
+        }
+
+        if (imesa->Registers.DrawCtrl1.ni.alphaTestCmpFunc !=
+            (a & 0x0F))
+        {
+            imesa->Registers.DrawCtrl1.ni.alphaTestCmpFunc =
+                a & 0x0F;
+            imesa->Registers.changed.ni.fDrawCtrl1Changed = GL_TRUE;
+        }
+
+        /* looks like rounding control is different on katmai than p2*/
+
+        if (imesa->Registers.DrawCtrl0.ni.alphaRefVal != alphaRef)
+        {
+            imesa->Registers.DrawCtrl0.ni.alphaRefVal = alphaRef;
+            imesa->Registers.changed.ni.fDrawCtrl0Changed = GL_TRUE;
+        }
+    }
+    else
+    {
+        if (imesa->Registers.DrawCtrl1.ni.alphaTestEn != GL_FALSE)
+        {
+            imesa->Registers.DrawCtrl1.ni.alphaTestEn      = GL_FALSE;
+            imesa->Registers.changed.ni.fDrawCtrl1Changed   = GL_TRUE;
+        }
+    }
+
+    /* Set/Reset Z-after-alpha*/
+
+    DrawLocalCtrl.ni.wrZafterAlphaTst = imesa->Registers.DrawCtrl1.ni.alphaTestEn;
+    /*DrawLocalCtrl.ni.zUpdateEn = ~DrawLocalCtrl.ni.wrZafterAlphaTst;*/
+
+    if (imesa->Registers.DrawLocalCtrl.ui != DrawLocalCtrl.ui)
+    {
+        imesa->Registers.DrawLocalCtrl.ui = DrawLocalCtrl.ui;
+        imesa->Registers.changed.ni.fDrawLocalCtrlChanged = GL_TRUE;
+    }
+
+    /* dithering*/
+
+    if ( ctx->Color.DitherFlag )
+    {
+        if (imesa->Registers.DrawCtrl1.ni.ditherEn != GL_TRUE)
+        {
+            imesa->Registers.DrawCtrl1.ni.ditherEn = GL_TRUE;
+            imesa->Registers.changed.ni.fDrawCtrl1Changed = GL_TRUE;
+        }
+    }
+    else
+    {
+        if (imesa->Registers.DrawCtrl1.ni.ditherEn != GL_FALSE)
+        {
+            imesa->Registers.DrawCtrl1.ni.ditherEn = GL_FALSE;
+            imesa->Registers.changed.ni.fDrawCtrl1Changed = GL_TRUE;
+        }
+    }
+}
+static void savageBlendFunc_s3d(GLcontext *ctx)
+{
+  
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    Reg_DrawCtrl DrawCtrl;
+
+    /* set up draw control register (including blending, alpha
+     * test, dithering, and shading model)
+     */
+
+    /*
+     * And mask removes flushPdDestWrites
+     */
+
+    DrawCtrl.ui = imesa->Registers.DrawCtrl.ui & ~0x20000000;
+
+    /*
+     * blend modes
+     */
+    if(ctx->Color.BlendEnabled){
+        switch (ctx->Color.BlendDstRGB)
+        {
+            case GL_ZERO:
+                DrawCtrl.ni.dstAlphaMode = DAM_Zero;
+                break;
+
+            case GL_ONE:
+                DrawCtrl.ni.dstAlphaMode = DAM_One;
+                DrawCtrl.ni.flushPdDestWrites = GL_TRUE;
+                break;
+
+            case GL_SRC_COLOR:
+                DrawCtrl.ni.dstAlphaMode = DAM_SrcClr;
+                DrawCtrl.ni.flushPdDestWrites = GL_TRUE;
+                break;
+
+            case GL_ONE_MINUS_SRC_COLOR:
+                DrawCtrl.ni.dstAlphaMode = DAM_1SrcClr;
+                DrawCtrl.ni.flushPdDestWrites = GL_TRUE;
+                break;
+
+            case GL_SRC_ALPHA:
+                DrawCtrl.ni.dstAlphaMode = DAM_SrcAlpha;
+                DrawCtrl.ni.flushPdDestWrites = GL_TRUE;
+                break;
+
+            case GL_ONE_MINUS_SRC_ALPHA:
+                DrawCtrl.ni.dstAlphaMode = DAM_1SrcAlpha;
+                DrawCtrl.ni.flushPdDestWrites = GL_TRUE;
+                break;
+
+            case GL_DST_ALPHA:
+                if (imesa->glCtx->Visual.alphaBits == 0)
+                {
+                    DrawCtrl.ni.dstAlphaMode = DAM_One;
+                }
+                else
+                {
+                    DrawCtrl.ni.dstAlphaMode = DAM_DstAlpha;
+                }
+                DrawCtrl.ni.flushPdDestWrites = GL_TRUE;
+                break;
+
+            case GL_ONE_MINUS_DST_ALPHA:
+                if (imesa->glCtx->Visual.alphaBits == 0)
+                {
+                    DrawCtrl.ni.dstAlphaMode = DAM_Zero;
+                }
+                else
+                {
+                    DrawCtrl.ni.dstAlphaMode = DAM_1DstAlpha;
+                    DrawCtrl.ni.flushPdDestWrites = GL_TRUE;
+                }
+                break;
+        }
+
+        switch (ctx->Color.BlendSrcRGB)
+        {
+            case GL_ZERO:
+                DrawCtrl.ni.srcAlphaMode = SAM_Zero;
+                break;
+
+            case GL_ONE:
+                DrawCtrl.ni.srcAlphaMode = SAM_One;
+                break;
+
+            case GL_DST_COLOR:
+                DrawCtrl.ni.srcAlphaMode = SAM_DstClr;
+                DrawCtrl.ni.flushPdDestWrites = GL_TRUE;
+                break;
+
+            case GL_ONE_MINUS_DST_COLOR:
+                DrawCtrl.ni.srcAlphaMode = SAM_1DstClr;
+                DrawCtrl.ni.flushPdDestWrites = GL_TRUE;
+                break;
+
+            case GL_SRC_ALPHA:
+                DrawCtrl.ni.srcAlphaMode = SAM_SrcAlpha;
+                break;
+
+            case GL_ONE_MINUS_SRC_ALPHA:
+                DrawCtrl.ni.srcAlphaMode = SAM_1SrcAlpha;
+                break;
+
+            case GL_DST_ALPHA:
+                if (imesa->glCtx->Visual.alphaBits == 0)
+                {
+                    DrawCtrl.ni.srcAlphaMode = SAM_One;
+                }
+                else
+                {
+                    DrawCtrl.ni.srcAlphaMode = SAM_DstAlpha;
+                    DrawCtrl.ni.flushPdDestWrites = GL_TRUE;
+                }
+                break;
+
+            case GL_ONE_MINUS_DST_ALPHA:
+                if (imesa->glCtx->Visual.alphaBits == 0)          
+                {
+                    DrawCtrl.ni.srcAlphaMode = SAM_Zero;
+                }
+                else
+                {
+                    DrawCtrl.ni.srcAlphaMode = SAM_1DstAlpha;
+                    DrawCtrl.ni.flushPdDestWrites = GL_TRUE;
+                }
+                break;
+        }
+    }
+    else
+    {
+        DrawCtrl.ni.dstAlphaMode = DAM_Zero;
+        DrawCtrl.ni.srcAlphaMode = SAM_One;
+    }
+
+    /* alpha test*/
+
+    if(ctx->Color.AlphaEnabled) 
+    {
+        GLint a;
+       GLubyte alphaRef;
+
+       CLAMPED_FLOAT_TO_UBYTE(alphaRef,ctx->Color.AlphaRef);
+         
+        switch(ctx->Color.AlphaFunc)  { 
+            case GL_NEVER: a = LCS_A_NEVER; break;
+            case GL_ALWAYS: a = LCS_A_ALWAYS; break;
+            case GL_LESS: a = LCS_A_LESS; break; 
+            case GL_LEQUAL: a = LCS_A_LEQUAL; break;
+            case GL_EQUAL: a = LCS_A_EQUAL; break;
+            case GL_GREATER: a = LCS_A_GREATER; break;
+            case GL_GEQUAL: a = LCS_A_GEQUAL; break;
+            case GL_NOTEQUAL: a = LCS_A_NOTEQUAL; break;
+            default:return;
+        }   
+
+       DrawCtrl.ni.alphaTestEn = GL_TRUE;
+       DrawCtrl.ni.alphaTestCmpFunc = a & 0x07;
+       DrawCtrl.ni.alphaRefVal = alphaRef;
+    }
+    else
+    {
+       DrawCtrl.ni.alphaTestEn = GL_FALSE;
+    }
+
+    /* Set/Reset Z-after-alpha*/
+
+    if (imesa->Registers.ZBufCtrl.s3d.wrZafterAlphaTst !=
+       DrawCtrl.ni.alphaTestEn)
+    {
+       imesa->Registers.ZBufCtrl.s3d.wrZafterAlphaTst =
+           DrawCtrl.ni.alphaTestEn;
+       imesa->Registers.changed.ni.fZBufCtrlChanged = GL_TRUE;
+    }
+    /*DrawLocalCtrl.ni.zUpdateEn = ~DrawLocalCtrl.ni.wrZafterAlphaTst;*/
+
+    /* dithering*/
+
+    if ( ctx->Color.DitherFlag )
+    {
+       DrawCtrl.ni.ditherEn = GL_TRUE;
+    }
+    else
+    {
+       DrawCtrl.ni.ditherEn = GL_FALSE;
+    }
+
+    if (imesa->Registers.DrawCtrl.ui != DrawCtrl.ui)
+    {
+        imesa->Registers.DrawCtrl.ui = DrawCtrl.ui;
+        imesa->Registers.changed.ni.fDrawCtrlChanged = GL_TRUE;
+    }
+}
+
+static void savageDDBlendFuncSeparate_s4( GLcontext *ctx, GLenum sfactorRGB, 
+                                         GLenum dfactorRGB, GLenum sfactorA,
+                                         GLenum dfactorA )
+{
+    assert (dfactorRGB == dfactorA && sfactorRGB == sfactorA);
+    savageBlendFunc_s4( ctx );
+}
+static void savageDDBlendFuncSeparate_s3d( GLcontext *ctx, GLenum sfactorRGB, 
+                                          GLenum dfactorRGB, GLenum sfactorA,
+                                          GLenum dfactorA )
+{
+    assert (dfactorRGB == dfactorA && sfactorRGB == sfactorA);
+    savageBlendFunc_s3d( ctx );
+}
+
+
+
+static void savageDDDepthFunc_s4(GLcontext *ctx, GLenum func)
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    int zmode;
+#define depthIndex 0
+
+    /* set up z-buffer control register (global)
+     * set up z-buffer offset register (global)
+     * set up z read/write watermarks register (global)
+     */
+
+    switch(func)  { 
+        case GL_NEVER: zmode = LCS_Z_NEVER; break;
+        case GL_ALWAYS: zmode = LCS_Z_ALWAYS; break;
+        case GL_LESS: zmode = LCS_Z_LESS; break; 
+        case GL_LEQUAL: zmode = LCS_Z_LEQUAL; break;
+        case GL_EQUAL: zmode = LCS_Z_EQUAL; break;
+        case GL_GREATER: zmode = LCS_Z_GREATER; break;
+        case GL_GEQUAL: zmode = LCS_Z_GEQUAL; break;
+        case GL_NOTEQUAL: zmode = LCS_Z_NOTEQUAL; break;
+        default:return;
+    } 
+    if (ctx->Depth.Test)
+    {
+
+        if (imesa->Registers.ZBufCtrl.s4.zCmpFunc != (zmode & 0x0F))
+        {
+            imesa->Registers.ZBufCtrl.s4.zCmpFunc = zmode & 0x0F;
+            imesa->Registers.changed.ni.fZBufCtrlChanged  = GL_TRUE;
+        }
+
+        if (imesa->Registers.DrawLocalCtrl.ni.zUpdateEn != ctx->Depth.Mask)
+        {
+            imesa->Registers.DrawLocalCtrl.ni.zUpdateEn = ctx->Depth.Mask;
+            imesa->Registers.changed.ni.fDrawLocalCtrlChanged = GL_TRUE;
+        }
+
+        if (imesa->Registers.DrawLocalCtrl.ni.flushPdZbufWrites == GL_FALSE)
+        {
+            imesa->Registers.DrawLocalCtrl.ni.flushPdZbufWrites = GL_TRUE;
+            imesa->Registers.changed.ni.fDrawLocalCtrlChanged = GL_TRUE;
+#if 1
+            imesa->Registers.ZWatermarks.ni.wLow = 0;
+            imesa->Registers.changed.ni.fZWatermarksChanged = GL_TRUE;
+#endif
+        }
+
+        if (imesa->Registers.ZBufCtrl.s4.zBufEn != GL_TRUE)
+        {
+            imesa->Registers.ZBufCtrl.s4.zBufEn = GL_TRUE;
+            imesa->Registers.changed.ni.fZBufCtrlChanged = GL_TRUE;
+        }
+    }
+    else if (imesa->glCtx->Stencil.Enabled &&
+             !imesa->glCtx->DrawBuffer->UseSoftwareStencilBuffer)
+    {
+#define STENCIL (0x27)
+
+        /* by Jiayo, tempory disable HW stencil in 24 bpp */
+#if HW_STENCIL
+        if(imesa->hw_stencil)
+        {
+            if ((imesa->Registers.ZBufCtrl.ui & STENCIL) != STENCIL)
+            {
+                imesa->Registers.ZBufCtrl.s4.zCmpFunc = GL_ALWAYS & 0x0F;
+                imesa->Registers.ZBufCtrl.s4.zBufEn   = GL_TRUE;
+                imesa->Registers.changed.ni.fZBufCtrlChanged  = GL_TRUE;
+            }
+
+            if (imesa->Registers.DrawLocalCtrl.ni.zUpdateEn != GL_FALSE)
+            {
+                imesa->Registers.DrawLocalCtrl.ni.zUpdateEn = GL_FALSE;
+                imesa->Registers.changed.ni.fDrawLocalCtrlChanged   = GL_TRUE;
+            }
+
+            if (imesa->Registers.DrawLocalCtrl.ni.flushPdZbufWrites == GL_TRUE)
+            {
+                imesa->Registers.DrawLocalCtrl.ni.flushPdZbufWrites = GL_FALSE;
+                imesa->Registers.changed.ni.fDrawLocalCtrlChanged   = GL_TRUE;
+
+                imesa->Registers.ZWatermarks.ni.wLow        = 8;
+                imesa->Registers.changed.ni.fZWatermarksChanged     = GL_TRUE;
+            }
+        }
+#endif /* end #if HW_STENCIL */
+    }
+    else
+    {
+
+        if (imesa->Registers.DrawLocalCtrl.ni.drawUpdateEn == GL_FALSE)
+        {
+            imesa->Registers.ZBufCtrl.s4.zCmpFunc = LCS_Z_ALWAYS & 0x0F;
+            imesa->Registers.ZBufCtrl.s4.zBufEn   = GL_TRUE;
+            imesa->Registers.changed.ni.fZBufCtrlChanged  = GL_TRUE;
+
+            if (imesa->Registers.DrawLocalCtrl.ni.zUpdateEn != GL_FALSE)
+            {
+                imesa->Registers.DrawLocalCtrl.ni.zUpdateEn = GL_FALSE;
+                imesa->Registers.changed.ni.fDrawLocalCtrlChanged   = GL_TRUE;
+            }
+
+            if (imesa->Registers.DrawLocalCtrl.ni.flushPdZbufWrites == GL_TRUE)
+            {
+                imesa->Registers.DrawLocalCtrl.ni.flushPdZbufWrites = GL_FALSE;
+                imesa->Registers.changed.ni.fDrawLocalCtrlChanged   = GL_TRUE;
+
+                imesa->Registers.ZWatermarks.ni.wLow        = 8;
+                imesa->Registers.changed.ni.fZWatermarksChanged     = GL_TRUE;
+
+            }
+        }
+        else
+
+            /* DRAWUPDATE_REQUIRES_Z_ENABLED*/
+        {
+            if (imesa->Registers.ZBufCtrl.s4.zBufEn != GL_FALSE)
+            {
+                imesa->Registers.ZBufCtrl.s4.zBufEn         = GL_FALSE;
+                imesa->Registers.DrawLocalCtrl.ni.zUpdateEn = GL_FALSE;
+                imesa->Registers.changed.ni.fZBufCtrlChanged        = GL_TRUE;
+                imesa->Registers.changed.ni.fDrawLocalCtrlChanged   = GL_TRUE;
+                imesa->Registers.DrawLocalCtrl.ni.flushPdZbufWrites = GL_FALSE;
+                imesa->Registers.ZWatermarks.ni.wLow        = 8;
+                imesa->Registers.changed.ni.fZWatermarksChanged     = GL_TRUE;
+            }
+        }
+    }
+  
+    imesa->dirty |= SAVAGE_UPLOAD_CTX;
+}
+static void savageDDDepthFunc_s3d(GLcontext *ctx, GLenum func)
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    Reg_ZBufCtrl ZBufCtrl;
+    int zmode;
+#define depthIndex 0
+
+    /* set up z-buffer control register (global)
+     * set up z-buffer offset register (global)
+     * set up z read/write watermarks register (global)
+     */
+    ZBufCtrl.ui = imesa->Registers.ZBufCtrl.ui;
+
+    switch(func)  { 
+        case GL_NEVER: zmode = LCS_Z_NEVER; break;
+        case GL_ALWAYS: zmode = LCS_Z_ALWAYS; break;
+        case GL_LESS: zmode = LCS_Z_LESS; break; 
+        case GL_LEQUAL: zmode = LCS_Z_LEQUAL; break;
+        case GL_EQUAL: zmode = LCS_Z_EQUAL; break;
+        case GL_GREATER: zmode = LCS_Z_GREATER; break;
+        case GL_GEQUAL: zmode = LCS_Z_GEQUAL; break;
+        case GL_NOTEQUAL: zmode = LCS_Z_NOTEQUAL; break;
+        default:return;
+    } 
+    if (ctx->Depth.Test)
+    {
+       ZBufCtrl.s3d.zBufEn = GL_TRUE;
+       ZBufCtrl.s3d.zCmpFunc = zmode & 0x0F;
+       ZBufCtrl.s3d.zUpdateEn = ctx->Depth.Mask;
+       
+        if (imesa->Registers.DrawCtrl.ni.flushPdZbufWrites == GL_FALSE)
+        {
+            imesa->Registers.DrawCtrl.ni.flushPdZbufWrites = GL_TRUE;
+            imesa->Registers.changed.ni.fDrawCtrlChanged = GL_TRUE;
+#if 1
+            imesa->Registers.ZWatermarks.ni.wLow = 0;
+            imesa->Registers.changed.ni.fZWatermarksChanged = GL_TRUE;
+#endif
+        }
+    }
+    else
+    {
+       if (ZBufCtrl.s3d.drawUpdateEn == GL_FALSE) {
+           ZBufCtrl.s3d.zCmpFunc = LCS_Z_ALWAYS & 0x0F;
+            ZBufCtrl.s3d.zBufEn = GL_TRUE;
+           ZBufCtrl.s3d.zUpdateEn = GL_FALSE;
+       }
+        else
+
+            /* DRAWUPDATE_REQUIRES_Z_ENABLED*/
+        {
+           ZBufCtrl.s3d.zBufEn = GL_FALSE;
+           ZBufCtrl.s3d.zUpdateEn = GL_FALSE;
+        }
+
+       if (imesa->Registers.DrawCtrl.ni.flushPdZbufWrites == GL_TRUE)
+        {
+           imesa->Registers.DrawCtrl.ni.flushPdZbufWrites = GL_FALSE;
+           imesa->Registers.changed.ni.fDrawCtrlChanged = GL_TRUE;
+
+           imesa->Registers.ZWatermarks.ni.wLow = 8;
+           imesa->Registers.changed.ni.fZWatermarksChanged = GL_TRUE;
+       }
+    }
+  
+    if (imesa->Registers.ZBufCtrl.ui != ZBufCtrl.ui)
+    {
+        imesa->Registers.ZBufCtrl.ui = ZBufCtrl.ui;
+        imesa->Registers.changed.ni.fZBufCtrlChanged = GL_TRUE;
+    }
+
+    imesa->dirty |= SAVAGE_UPLOAD_CTX;
+}
+
+static void savageDDDepthMask_s4(GLcontext *ctx, GLboolean flag)
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+
+    imesa->dirty |= SAVAGE_UPLOAD_CTX;
+    if (flag)
+    {
+        if (imesa->Registers.DrawLocalCtrl.ni.flushPdZbufWrites == GL_FALSE)
+        {
+            imesa->Registers.DrawLocalCtrl.ni.flushPdZbufWrites = GL_TRUE;
+            imesa->Registers.changed.ni.fDrawLocalCtrlChanged = GL_TRUE;
+        }
+    }
+    else
+    {
+        if (imesa->Registers.DrawLocalCtrl.ni.flushPdZbufWrites == GL_TRUE)
+       {
+            imesa->Registers.DrawLocalCtrl.ni.flushPdZbufWrites = GL_FALSE;
+            imesa->Registers.changed.ni.fDrawLocalCtrlChanged   = GL_TRUE;
+        }
+    }
+    savageDDDepthFunc_s4(ctx,ctx->Depth.Func);
+}
+static void savageDDDepthMask_s3d(GLcontext *ctx, GLboolean flag)
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+
+    imesa->dirty |= SAVAGE_UPLOAD_CTX;
+    if (flag)
+    {
+        if (imesa->Registers.DrawCtrl.ni.flushPdZbufWrites == GL_FALSE)
+        {
+            imesa->Registers.DrawCtrl.ni.flushPdZbufWrites = GL_TRUE;
+            imesa->Registers.changed.ni.fDrawCtrlChanged = GL_TRUE;
+        }
+    }
+    else
+    {
+        if (imesa->Registers.DrawCtrl.ni.flushPdZbufWrites == GL_TRUE)
+        {
+            imesa->Registers.DrawCtrl.ni.flushPdZbufWrites = GL_FALSE;
+            imesa->Registers.changed.ni.fDrawCtrlChanged   = GL_TRUE;
+        }
+    }
+    savageDDDepthFunc_s3d(ctx,ctx->Depth.Func);
+}
+
+
+
+
+/* =============================================================
+ * Hardware clipping
+ */
+
+
+ void savageDDScissor( GLcontext *ctx, GLint x, GLint y, 
+                             GLsizei w, GLsizei h )
+{ 
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    imesa->scissor_rect.x1 = MAX2(imesa->drawX+x,imesa->draw_rect.x1);
+    imesa->scissor_rect.y1 = MAX2(imesa->drawY+imesa->driDrawable->h -(y+h),
+                                  imesa->draw_rect.y1);
+    imesa->scissor_rect.x2 = MIN2(imesa->drawX+x+w,imesa->draw_rect.x2);
+    imesa->scissor_rect.y2 = MIN2(imesa->drawY+imesa->driDrawable->h - y,
+                                  imesa->draw_rect.y2);
+    
+
+    imesa->Registers.changed.ni.fScissorsChanged=GL_TRUE;
+
+    imesa->dirty |= SAVAGE_UPLOAD_CLIPRECTS;
+}
+
+
+
+static void savageDDDrawBuffer(GLcontext *ctx, GLenum mode )
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+
+    /*
+     * _DrawDestMask is easier to cope with than <mode>.
+     */
+    switch ( ctx->Color._DrawDestMask ) {
+    case FRONT_LEFT_BIT:
+        imesa->IsDouble = GL_FALSE;
+      
+        if(imesa->IsFullScreen)
+        {
+            imesa->drawMap = (char *)imesa->apertureBase[TARGET_FRONT];
+            imesa->readMap = (char *)imesa->apertureBase[TARGET_FRONT];
+        }
+        else
+        {
+            imesa->drawMap = (char *)imesa->apertureBase[TARGET_BACK];
+            imesa->readMap = (char *)imesa->apertureBase[TARGET_BACK];
+        }
+        imesa->NotFirstFrame = GL_FALSE;
+        imesa->dirty |= SAVAGE_UPLOAD_BUFFERS;
+        savageXMesaSetFrontClipRects( imesa );
+       FALLBACK( ctx, SAVAGE_FALLBACK_DRAW_BUFFER, GL_FALSE );
+       break;
+    case BACK_LEFT_BIT:
+        imesa->IsDouble = GL_TRUE;
+        imesa->drawMap = (char *)imesa->apertureBase[TARGET_BACK];
+        imesa->readMap = (char *)imesa->apertureBase[TARGET_BACK];
+        imesa->NotFirstFrame = GL_FALSE;
+        imesa->dirty |= SAVAGE_UPLOAD_BUFFERS;
+        savageXMesaSetBackClipRects( imesa );
+       FALLBACK( ctx, SAVAGE_FALLBACK_DRAW_BUFFER, GL_FALSE );
+       break;
+    default:
+       FALLBACK( ctx, SAVAGE_FALLBACK_DRAW_BUFFER, GL_TRUE );
+       return;
+    }
+    
+    /* We want to update the s/w rast state too so that r200SetBuffer() (?)
+     * gets called.
+     */
+    _swrast_DrawBuffer(ctx, mode);
+}
+
+static void savageDDReadBuffer(GLcontext *ctx, GLenum mode )
+{
+   /* nothing, until we implement h/w glRead/CopyPixels or CopyTexImage */
+}
+
+#if 0
+static void savageDDSetColor(GLcontext *ctx, 
+                             GLubyte r, GLubyte g,
+                             GLubyte b, GLubyte a )
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    imesa->MonoColor = savagePackColor( imesa->savageScreen->frontFormat, r, g, b, a );
+}
+#endif
+
+/* =============================================================
+ * Window position and viewport transformation
+ */
+
+static void savageCalcViewport( GLcontext *ctx )
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+   const GLfloat *v = ctx->Viewport._WindowMap.m;
+   GLfloat *m = imesa->hw_viewport;
+
+   /* See also mga_translate_vertex.
+    */
+   m[MAT_SX] =   v[MAT_SX];
+   m[MAT_TX] =   v[MAT_TX] + imesa->drawX + SUBPIXEL_X;
+   m[MAT_SY] = - v[MAT_SY];
+   m[MAT_TY] = - v[MAT_TY] + imesa->driDrawable->h + imesa->drawY + SUBPIXEL_Y;
+   m[MAT_SZ] =   v[MAT_SZ] * imesa->depth_scale;
+   m[MAT_TZ] =   v[MAT_TZ] * imesa->depth_scale;
+
+   imesa->SetupNewInputs = ~0;
+}
+
+static void savageViewport( GLcontext *ctx, 
+                           GLint x, GLint y, 
+                           GLsizei width, GLsizei height )
+{
+   savageCalcViewport( ctx );
+}
+
+static void savageDepthRange( GLcontext *ctx, 
+                             GLclampd nearval, GLclampd farval )
+{
+   savageCalcViewport( ctx );
+}
+
+
+/* =============================================================
+ * Miscellaneous
+ */
+
+static void savageDDClearColor(GLcontext *ctx, 
+                              const GLfloat color[4] )
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    GLubyte c[4];
+    CLAMPED_FLOAT_TO_UBYTE(c[0], color[0]);
+    CLAMPED_FLOAT_TO_UBYTE(c[1], color[1]);
+    CLAMPED_FLOAT_TO_UBYTE(c[2], color[2]);
+    CLAMPED_FLOAT_TO_UBYTE(c[3], color[3]);
+
+    imesa->ClearColor = savagePackColor( imesa->savageScreen->frontFormat,
+                                        c[0], c[1], c[2], c[3] );
+}
+
+/* Fallback to swrast for select and feedback.
+ */
+static void savageRenderMode( GLcontext *ctx, GLenum mode )
+{
+   FALLBACK( ctx, SAVAGE_FALLBACK_RENDERMODE, (mode != GL_RENDER) );
+}
+
+
+#if HW_CULL
+
+/* =============================================================
+ * Culling - the savage isn't quite as clean here as the rest of
+ *           its interfaces, but it's not bad.
+ */
+static void savageDDCullFaceFrontFace(GLcontext *ctx, GLenum unused)
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    GLuint cullMode=imesa->LcsCullMode;        
+    switch (ctx->Polygon.CullFaceMode)
+    {
+        case GL_FRONT:
+            switch (ctx->Polygon.FrontFace)
+            {
+                case GL_CW:
+                    cullMode = BCM_CW;
+                    break;
+                case GL_CCW:
+                    cullMode = BCM_CCW;
+                    break;
+            }
+            break;
+
+        case GL_BACK:
+            switch (ctx->Polygon.FrontFace)
+            {
+                case GL_CW:
+                    cullMode = BCM_CCW;
+                    break;
+                case GL_CCW:
+                    cullMode = BCM_CW;
+                    break;
+            }
+            break;
+    }
+    imesa->LcsCullMode = cullMode;    
+}
+#endif /* end #if HW_CULL */
+
+static void savageUpdateCull( GLcontext *ctx )
+{
+#if HW_CULL
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    GLuint cullMode;
+    if (ctx->Polygon.CullFlag &&
+       imesa->raster_primitive == GL_TRIANGLES &&
+       ctx->Polygon.CullFaceMode != GL_FRONT_AND_BACK)
+       cullMode = imesa->LcsCullMode;
+    else
+       cullMode = BCM_None;
+    if (imesa->savageScreen->chipset >= S3_SAVAGE4) {
+       if (imesa->Registers.DrawCtrl1.ni.cullMode != cullMode) {
+           imesa->Registers.DrawCtrl1.ni.cullMode = cullMode;
+           imesa->Registers.changed.ni.fDrawCtrl1Changed = GL_TRUE;
+           imesa->dirty |= SAVAGE_UPLOAD_CTX;
+       }
+    } else {
+       if (imesa->Registers.DrawCtrl.ni.cullMode != cullMode) {
+           imesa->Registers.DrawCtrl.ni.cullMode = cullMode;
+           imesa->Registers.changed.ni.fDrawCtrlChanged = GL_TRUE;
+           imesa->dirty |= SAVAGE_UPLOAD_CTX;
+       }
+    }
+#endif /* end  #if HW_CULL */
+}
+
+
+
+/* =============================================================
+ * Color masks
+ */
+
+/* Mesa calls this from the wrong place - it is called a very large
+ * number of redundant times.
+ *
+ * Colormask can be simulated by multipass or multitexture techniques.
+ */
+static void savageDDColorMask_s4(GLcontext *ctx, 
+                                GLboolean r, GLboolean g, 
+                                GLboolean b, GLboolean a )
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+    GLuint enable;
+
+    if (ctx->Visual.alphaBits)
+    {
+        enable = b | g | r | a;
+    }
+    else
+    {
+        enable = b | g | r;
+    }
+
+    if (enable)
+    {
+        if (imesa->Registers.DrawLocalCtrl.ni.drawUpdateEn == GL_FALSE)
+        {
+            imesa->Registers.DrawLocalCtrl.ni.drawUpdateEn = GL_TRUE;
+            imesa->Registers.changed.ni.fDrawLocalCtrlChanged = GL_TRUE;
+           imesa->dirty |= SAVAGE_UPLOAD_CTX;
+        }
+    }
+    else
+    {
+        if (imesa->Registers.DrawLocalCtrl.ni.drawUpdateEn)
+        {
+            imesa->Registers.DrawLocalCtrl.ni.drawUpdateEn = GL_FALSE;
+            imesa->Registers.changed.ni.fDrawLocalCtrlChanged = GL_TRUE;
+           imesa->dirty |= SAVAGE_UPLOAD_CTX;
+        }
+    }
+    /* TODO: need a software fallback */
+}
+static void savageDDColorMask_s3d(GLcontext *ctx, 
+                                 GLboolean r, GLboolean g, 
+                                 GLboolean b, GLboolean a )
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+    GLuint enable;
+
+    if (ctx->Visual.alphaBits)
+    {
+        enable = b | g | r | a;
+    }
+    else
+    {
+        enable = b | g | r;
+    }
+
+    if (enable)
+    {
+        if (imesa->Registers.ZBufCtrl.s3d.drawUpdateEn == GL_FALSE)
+        {
+            imesa->Registers.ZBufCtrl.s3d.drawUpdateEn = GL_TRUE;
+            imesa->Registers.changed.ni.fZBufCtrlChanged = GL_TRUE;
+           imesa->dirty |= SAVAGE_UPLOAD_CTX;
+        }
+    }
+    else
+    {
+        if (imesa->Registers.ZBufCtrl.s3d.drawUpdateEn)
+        {
+            imesa->Registers.ZBufCtrl.s3d.drawUpdateEn = GL_FALSE;
+            imesa->Registers.changed.ni.fZBufCtrlChanged = GL_TRUE;
+           imesa->dirty |= SAVAGE_UPLOAD_CTX;
+        }
+    }
+    /* TODO: need a software fallback */
+}
+
+/* Seperate specular not fully implemented in hardware...  Needs
+ * some interaction with material state?  Just punt to software
+ * in all cases?
+ * FK: Don't fall back for now. Let's see the failure cases and
+ *     fix them the right way. I don't see how this could be a
+ *     hardware limitation.
+ */
+static void savageUpdateSpecular_s4(GLcontext *ctx) {
+    savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+
+    if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR &&
+       ctx->Light.Enabled) {
+       if (imesa->Registers.DrawLocalCtrl.ni.specShadeEn == GL_FALSE) {
+           imesa->Registers.DrawLocalCtrl.ni.specShadeEn = GL_TRUE;
+           imesa->Registers.changed.ni.fDrawLocalCtrlChanged = GL_TRUE;
+       }        
+       /*FALLBACK (ctx, SAVAGE_FALLBACK_SPECULAR, GL_TRUE);*/
+    } else {
+       if (imesa->Registers.DrawLocalCtrl.ni.specShadeEn == GL_TRUE) {
+           imesa->Registers.DrawLocalCtrl.ni.specShadeEn = GL_FALSE;
+           imesa->Registers.changed.ni.fDrawLocalCtrlChanged = GL_TRUE;
+       }
+       /*FALLBACK (ctx, SAVAGE_FALLBACK_SPECULAR, GL_FALSE);*/
+    }
+}
+static void savageUpdateSpecular_s3d(GLcontext *ctx) {
+    savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+
+    if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR &&
+       ctx->Light.Enabled) {
+       if (imesa->Registers.DrawCtrl.ni.specShadeEn == GL_FALSE) {
+           imesa->Registers.DrawCtrl.ni.specShadeEn = GL_TRUE;
+           imesa->Registers.changed.ni.fDrawCtrlChanged = GL_TRUE;
+       }        
+       FALLBACK (ctx, SAVAGE_FALLBACK_SPECULAR, GL_TRUE);
+    } else {
+       if (imesa->Registers.DrawCtrl.ni.specShadeEn == GL_TRUE) {
+           imesa->Registers.DrawCtrl.ni.specShadeEn = GL_FALSE;
+           imesa->Registers.changed.ni.fDrawCtrlChanged = GL_TRUE;
+       }
+       FALLBACK (ctx, SAVAGE_FALLBACK_SPECULAR, GL_FALSE);
+    }
+}
+
+static void savageDDLightModelfv_s4(GLcontext *ctx, GLenum pname, 
+                                   const GLfloat *param)
+{
+    savageUpdateSpecular_s4 (ctx);
+}
+static void savageDDLightModelfv_s3d(GLcontext *ctx, GLenum pname, 
+                                    const GLfloat *param)
+{
+    savageUpdateSpecular_s3d (ctx);
+}
+
+static void savageDDShadeModel_s4(GLcontext *ctx, GLuint mod)
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+
+    if (mod == GL_SMOOTH)  
+    {    
+        if(imesa->Registers.DrawLocalCtrl.ni.flatShadeEn == GL_TRUE)
+        {
+            imesa->Registers.DrawLocalCtrl.ni.flatShadeEn = GL_FALSE;
+            imesa->Registers.changed.ni.fDrawLocalCtrlChanged = GL_TRUE;
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+        }
+    }
+    else
+    {
+        if(imesa->Registers.DrawLocalCtrl.ni.flatShadeEn == GL_FALSE)
+        {
+            imesa->Registers.DrawLocalCtrl.ni.flatShadeEn = GL_TRUE;
+            imesa->Registers.changed.ni.fDrawLocalCtrlChanged = GL_TRUE;
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+        }
+    }
+}
+static void savageDDShadeModel_s3d(GLcontext *ctx, GLuint mod)
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+
+    if (mod == GL_SMOOTH)  
+    {    
+        if(imesa->Registers.DrawCtrl.ni.flatShadeEn == GL_TRUE)
+        {
+            imesa->Registers.DrawCtrl.ni.flatShadeEn = GL_FALSE;
+            imesa->Registers.changed.ni.fDrawCtrlChanged = GL_TRUE;
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+        }
+    }
+    else
+    {
+        if(imesa->Registers.DrawCtrl.ni.flatShadeEn == GL_FALSE)
+        {
+            imesa->Registers.DrawCtrl.ni.flatShadeEn = GL_TRUE;
+            imesa->Registers.changed.ni.fDrawCtrlChanged = GL_TRUE;
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+        }
+    }
+}
+
+
+/* =============================================================
+ * Fog
+ */
+
+static void savageDDFogfv(GLcontext *ctx, GLenum pname, const GLfloat *param)
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    GLuint  fogClr;
+
+    /*if ((ctx->Fog.Enabled) &&(pname == GL_FOG_COLOR))*/
+    if (ctx->Fog.Enabled)
+    {
+        fogClr = (((GLubyte)(ctx->Fog.Color[0]*255.0F) << 16) |
+                  ((GLubyte)(ctx->Fog.Color[1]*255.0F) << 8) |
+                  ((GLubyte)(ctx->Fog.Color[2]*255.0F) << 0));
+        if (imesa->Registers.FogCtrl.ni.fogEn != GL_TRUE)
+        {
+            imesa->Registers.FogCtrl.ni.fogEn  = GL_TRUE;
+            imesa->Registers.changed.ni.fFogCtrlChanged = GL_TRUE;
+        }
+        /*cheap fog*/
+        if (imesa->Registers.FogCtrl.ni.fogMode != GL_TRUE)
+        {
+            imesa->Registers.FogCtrl.ni.fogMode  = GL_TRUE;
+            imesa->Registers.changed.ni.fFogCtrlChanged = GL_TRUE;
+        }
+        if (imesa->Registers.FogCtrl.ni.fogClr != fogClr)
+        {
+            imesa->Registers.FogCtrl.ni.fogClr = fogClr;    
+            imesa->Registers.changed.ni.fFogCtrlChanged = GL_TRUE;
+        }
+        imesa->dirty |= SAVAGE_UPLOAD_CTX;      
+    }    
+    else
+    {
+        /*No fog*/
+        
+        if (imesa->Registers.FogCtrl.ni.fogEn != 0)
+        {
+            imesa->Registers.FogCtrl.ni.fogEn     = 0;
+            imesa->Registers.FogCtrl.ni.fogMode   = 0;
+            imesa->Registers.changed.ni.fFogCtrlChanged   = GL_TRUE;
+        }
+        return;
+    }
+}
+
+
+#if HW_STENCIL
+static void savageStencilFunc(GLcontext *);
+
+static void savageDDStencilFunc(GLcontext *ctx, GLenum func, GLint ref,
+                                GLuint mask)
+{
+    savageStencilFunc(ctx);
+}
+
+static void savageDDStencilMask(GLcontext *ctx, GLuint mask)
+{
+    savageStencilFunc(ctx);
+}
+
+static void savageDDStencilOp(GLcontext *ctx, GLenum fail, GLenum zfail,
+                              GLenum zpass)
+{
+    savageStencilFunc(ctx);  
+}
+
+static void savageStencilFunc(GLcontext *ctx)
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    Reg_StencilCtrl StencilCtrl;
+    int a=0;
+    
+    StencilCtrl.ui = 0x0; 
+    
+    if (ctx->Stencil.Enabled)
+    {
+         
+        switch (ctx->Stencil.Function[0])
+        {
+            case GL_NEVER: a = LCS_S_NEVER; break;
+            case GL_ALWAYS: a = LCS_S_ALWAYS; break;
+            case GL_LESS: a = LCS_S_LESS; break; 
+            case GL_LEQUAL: a = LCS_S_LEQUAL; break;
+            case GL_EQUAL: a = LCS_S_EQUAL; break;
+            case GL_GREATER: a = LCS_S_GREATER; break;
+            case GL_GEQUAL: a = LCS_S_GEQUAL; break;
+            case GL_NOTEQUAL: a = LCS_S_NOTEQUAL; break;      
+            default:
+                break;
+        }
+
+        StencilCtrl.ni.cmpFunc     = (GLuint)a & 0x0F;
+        StencilCtrl.ni.stencilEn   = GL_TRUE;
+        StencilCtrl.ni.readMask    = ctx->Stencil.ValueMask[0];
+        StencilCtrl.ni.writeMask   = ctx->Stencil.WriteMask[0];
+
+        switch (ctx->Stencil.FailFunc[0])
+        {
+            case GL_KEEP:
+                StencilCtrl.ni.failOp = STC_FAIL_Keep;
+                break;
+            case GL_ZERO:
+                StencilCtrl.ni.failOp = STC_FAIL_Zero;
+                break;
+            case GL_REPLACE:
+                StencilCtrl.ni.failOp = STC_FAIL_Equal;
+                break;
+            case GL_INCR:
+                StencilCtrl.ni.failOp = STC_FAIL_IncClamp;
+                break;
+            case GL_DECR:
+                StencilCtrl.ni.failOp = STC_FAIL_DecClamp;
+                break;
+            case GL_INVERT:
+                StencilCtrl.ni.failOp = STC_FAIL_Invert;
+                break;
+#if GL_EXT_stencil_wrap
+            case GL_INCR_WRAP_EXT:
+                StencilCtrl.ni.failOp = STC_FAIL_Inc;
+                break;
+            case GL_DECR_WRAP_EXT:
+                StencilCtrl.ni.failOp = STC_FAIL_Dec;
+                break;
+#endif
+        }
+
+        switch (ctx->Stencil.ZFailFunc[0])
+        {
+            case GL_KEEP:
+                StencilCtrl.ni.passZfailOp = STC_FAIL_Keep;
+                break;
+            case GL_ZERO:
+                StencilCtrl.ni.passZfailOp = STC_FAIL_Zero;
+                break;
+            case GL_REPLACE:
+                StencilCtrl.ni.passZfailOp = STC_FAIL_Equal;
+                break;
+            case GL_INCR:
+                StencilCtrl.ni.passZfailOp = STC_FAIL_IncClamp;
+                break;
+            case GL_DECR:
+                StencilCtrl.ni.passZfailOp = STC_FAIL_DecClamp;
+                break;
+            case GL_INVERT:
+                StencilCtrl.ni.passZfailOp = STC_FAIL_Invert;
+                break;
+#if GL_EXT_stencil_wrap
+            case GL_INCR_WRAP_EXT:
+                StencilCtrl.ni.passZfailOp = STC_FAIL_Inc;
+                break;
+            case GL_DECR_WRAP_EXT:
+                StencilCtrl.ni.passZfailOp = STC_FAIL_Dec;
+                break;
+#endif
+        }
+
+        switch (ctx->Stencil.ZPassFunc[0])
+        {
+            case GL_KEEP:
+                StencilCtrl.ni.passZpassOp = STC_FAIL_Keep;
+                break;
+            case GL_ZERO:
+                StencilCtrl.ni.passZpassOp = STC_FAIL_Zero;
+                break;
+            case GL_REPLACE:
+                StencilCtrl.ni.passZpassOp = STC_FAIL_Equal;
+                break;
+            case GL_INCR:
+                StencilCtrl.ni.passZpassOp = STC_FAIL_IncClamp;
+                break;
+            case GL_DECR:
+                StencilCtrl.ni.passZpassOp = STC_FAIL_DecClamp;
+                break;
+            case GL_INVERT:
+                StencilCtrl.ni.passZpassOp = STC_FAIL_Invert;
+                break;
+#if GL_EXT_stencil_wrap
+            case GL_INCR_WRAP_EXT:
+                StencilCtrl.ni.passZpassOp = STC_FAIL_Inc;
+                break;
+            case GL_DECR_WRAP_EXT:
+                StencilCtrl.ni.passZpassOp = STC_FAIL_Dec;
+                break;
+#endif
+        }
+
+
+        if (imesa->Registers.StencilCtrl.ui != StencilCtrl.ui)
+        {
+            imesa->Registers.StencilCtrl.ui      = StencilCtrl.ui;
+            imesa->Registers.changed.ni.fStencilCtrlChanged = GL_TRUE;
+        }
+
+        if (imesa->Registers.ZBufCtrl.s4.stencilRefVal != (GLuint) ctx->Stencil.Ref)    {
+            imesa->Registers.ZBufCtrl.s4.stencilRefVal = ctx->Stencil.Ref[0];
+            imesa->Registers.changed.ni.fZBufCtrlChanged       = GL_TRUE;
+        }
+
+        /*
+         * force Z on, HW limitation
+         */
+
+        if (imesa->Registers.ZBufCtrl.s4.zBufEn != GL_TRUE)
+        {
+            imesa->Registers.ZBufCtrl.s4.zCmpFunc       = LCS_Z_ALWAYS & 0x0F;
+            imesa->Registers.ZBufCtrl.s4.zBufEn         = GL_TRUE;
+            imesa->Registers.changed.ni.fZBufCtrlChanged        = GL_TRUE;
+            imesa->Registers.DrawLocalCtrl.ni.zUpdateEn = GL_FALSE;
+            imesa->Registers.changed.ni.fDrawLocalCtrlChanged   = GL_TRUE;
+        }
+        imesa->dirty |= SAVAGE_UPLOAD_CTX;
+    }
+    else
+    {
+        if (imesa->Registers.StencilCtrl.ni.stencilEn != GL_FALSE)
+        {
+            imesa->Registers.StencilCtrl.ni.stencilEn = GL_FALSE;
+            imesa->Registers.changed.ni.fStencilCtrlChanged   = GL_TRUE;
+        }
+    }
+}
+#endif /* end #if HW_STENCIL */
+/* =============================================================
+ */
+
+static void savageDDEnable_s4(GLcontext *ctx, GLenum cap, GLboolean state)
+{
+   
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    unsigned int ui;
+    switch(cap) {
+        case GL_ALPHA_TEST:
+            /* we should consider the disable case*/
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+            savageBlendFunc_s4(ctx);
+            break;
+        case GL_BLEND:
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+            /*Can't find Enable bit in the 3D registers.*/ 
+            /* For some reason enable(GL_BLEND) affects ColorLogicOpEnabled.
+             */
+           FALLBACK (ctx, SAVAGE_FALLBACK_LOGICOP,
+                     (ctx->Color.ColorLogicOpEnabled &&
+                      ctx->Color.LogicOp != GL_COPY));
+            /*add the savageBlendFunc 2001/11/25
+             * if call no such function, then glDisable(GL_BLEND) will do noting,
+             *our chip has no disable bit
+             */ 
+            savageBlendFunc_s4(ctx);
+            break;
+        case GL_DEPTH_TEST:
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+            savageDDDepthFunc_s4(ctx,ctx->Depth.Func);
+            break;
+        case GL_SCISSOR_TEST:
+            imesa->scissor = state;
+            imesa->dirty |= SAVAGE_UPLOAD_CLIPRECTS;
+            break;
+#if 0
+        case GL_LINE_SMOOTH:
+            if (ctx->PB->primitive == GL_LINE) {
+                imesa->dirty |= SAVAGE_UPLOAD_CTX;
+                if (state) {
+                    ui=imesa->Registers.DrawLocalCtrl.ui;
+                    imesa->Registers.DrawLocalCtrl.ni.flatShadeEn=GL_TRUE; 
+                    if(imesa->Registers.DrawLocalCtrl.ui!=ui)
+                        imesa->Registers.changed.ni.fDrawLocalCtrlChanged=GL_TRUE;
+                }
+            }
+            break;
+        case GL_POINT_SMOOTH:
+            if (ctx->PB->primitive == GL_POINT) {
+                imesa->dirty |= SAVAGE_UPLOAD_CTX;
+                if (state) 
+                {
+                    ui=imesa->Registers.DrawLocalCtrl.ui;
+                    imesa->Registers.DrawLocalCtrl.ni.flatShadeEn=GL_FALSE;
+                    if(imesa->Registers.DrawLocalCtrl.ui!=ui)
+                        imesa->Registers.changed.ni.fDrawLocalCtrlChanged=GL_TRUE;
+                }
+            }
+            break;
+        case GL_POLYGON_SMOOTH:
+            if (ctx->PB->primitive == GL_POLYGON) {
+                imesa->dirty |= SAVAGE_UPLOAD_CTX;
+                if (state) {
+                    ui=imesa->Registers.DrawLocalCtrl.ui;        
+                    imesa->Registers.DrawLocalCtrl.ni.flatShadeEn=GL_TRUE;
+                    if(imesa->Registers.DrawLocalCtrl.ui!=ui)
+                        imesa->Registers.changed.ni.fDrawLocalCtrlChanged=GL_TRUE;
+                }  
+            }
+            break;
+#endif
+        case GL_STENCIL_TEST:
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+            if (state)
+            { 
+#if HW_STENCIL
+                if(imesa->hw_stencil)
+                {
+                    ui=imesa->Registers.StencilCtrl.ui;
+#endif /* end if HW_STENCIL */
+                    if(!imesa->hw_stencil)
+                       FALLBACK (ctx, SAVAGE_FALLBACK_STENCIL, GL_TRUE);
+
+#if HW_STENCIL
+                    imesa->Registers.StencilCtrl.ni.stencilEn=GL_TRUE;
+                    if(imesa->Registers.StencilCtrl.ui!=ui)
+                        imesa->Registers.changed.ni.fStencilCtrlChanged=GL_TRUE;
+                }
+#endif /* end if HW_STENCIL */ 
+            }
+           
+            else
+            {
+#if HW_STENCIL
+                if(imesa->hw_stencil)
+                {
+                    if(imesa->Registers.StencilCtrl.ni.stencilEn == GL_TRUE)
+                    {
+                        imesa->Registers.StencilCtrl.ni.stencilEn=GL_FALSE;
+                        imesa->Registers.changed.ni.fStencilCtrlChanged=GL_TRUE;
+                    }
+                }
+               FALLBACK (ctx, SAVAGE_FALLBACK_STENCIL, GL_FALSE);
+#endif      
+            }
+            break;
+        case GL_FOG:
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+            savageDDFogfv(ctx,0,0);    
+            break;
+        case GL_CULL_FACE:
+#if HW_CULL
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+            ui=imesa->Registers.DrawCtrl1.ui;
+            if (state)
+            {
+                savageDDCullFaceFrontFace(ctx,0);
+            }
+            else
+            {
+                imesa->Registers.DrawCtrl1.ni.cullMode=BCM_None;
+            }
+            if(imesa->Registers.DrawCtrl1.ui!=ui)
+                imesa->Registers.changed.ni.fDrawCtrl1Changed=GL_TRUE;
+#endif
+            break;
+        case GL_DITHER:
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+            if (state)
+            {
+                if ( ctx->Color.DitherFlag )
+                {
+                    ui=imesa->Registers.DrawCtrl1.ui;
+                    imesa->Registers.DrawCtrl1.ni.ditherEn=GL_TRUE;
+                    if(imesa->Registers.DrawCtrl1.ui!=ui)
+                        imesa->Registers.changed.ni.fDrawCtrl1Changed=GL_TRUE;
+                }
+            }   
+            if (!ctx->Color.DitherFlag )
+            {
+                ui=imesa->Registers.DrawCtrl1.ui;
+                imesa->Registers.DrawCtrl1.ni.ditherEn=GL_FALSE;
+                if(imesa->Registers.DrawCtrl1.ui!=ui)
+                    imesa->Registers.changed.ni.fDrawCtrl1Changed=GL_TRUE;
+            }
+            break;
+        case GL_LIGHTING:
+           savageUpdateSpecular_s4 (ctx);
+            break;
+        case GL_TEXTURE_1D:      
+        case GL_TEXTURE_3D:      
+            imesa->new_state |= SAVAGE_NEW_TEXTURE;
+            break;
+        case GL_TEXTURE_2D:      
+            imesa->new_state |= SAVAGE_NEW_TEXTURE;
+            break;
+        default:
+            ; 
+    }    
+}
+static void savageDDEnable_s3d(GLcontext *ctx, GLenum cap, GLboolean state)
+{
+   
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    unsigned int ui;
+    switch(cap) {
+        case GL_ALPHA_TEST:
+            /* we should consider the disable case*/
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+            savageBlendFunc_s3d(ctx);
+            break;
+        case GL_BLEND:
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+            /*Can't find Enable bit in the 3D registers.*/ 
+            /* For some reason enable(GL_BLEND) affects ColorLogicOpEnabled.
+             */
+           FALLBACK (ctx, SAVAGE_FALLBACK_LOGICOP,
+                     (ctx->Color.ColorLogicOpEnabled &&
+                      ctx->Color.LogicOp != GL_COPY));
+            /*add the savageBlendFunc 2001/11/25
+             * if call no such function, then glDisable(GL_BLEND) will do noting,
+             *our chip has no disable bit
+             */ 
+            savageBlendFunc_s3d(ctx);
+            break;
+        case GL_DEPTH_TEST:
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+            savageDDDepthFunc_s3d(ctx,ctx->Depth.Func);
+            break;
+        case GL_SCISSOR_TEST:
+            imesa->scissor = state;
+            imesa->dirty |= SAVAGE_UPLOAD_CLIPRECTS;
+            break;
+        case GL_FOG:
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+            savageDDFogfv(ctx,0,0);    
+            break;
+        case GL_CULL_FACE:
+#if HW_CULL
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+            ui=imesa->Registers.DrawCtrl.ui;
+            if (state)
+            {
+                savageDDCullFaceFrontFace(ctx,0);
+            }
+            else
+            {
+                imesa->Registers.DrawCtrl.ni.cullMode=BCM_None;
+            }
+            if(imesa->Registers.DrawCtrl.ui!=ui)
+                imesa->Registers.changed.ni.fDrawCtrlChanged=GL_TRUE;
+#endif
+            break;
+        case GL_DITHER:
+            imesa->dirty |= SAVAGE_UPLOAD_CTX;
+            if (state)
+            {
+                if ( ctx->Color.DitherFlag )
+                {
+                    ui=imesa->Registers.DrawCtrl.ui;
+                    imesa->Registers.DrawCtrl.ni.ditherEn=GL_TRUE;
+                    if(imesa->Registers.DrawCtrl.ui!=ui)
+                        imesa->Registers.changed.ni.fDrawCtrlChanged=GL_TRUE;
+                }
+            }
+            if (!ctx->Color.DitherFlag )
+            {
+                ui=imesa->Registers.DrawCtrl.ui;
+                imesa->Registers.DrawCtrl.ni.ditherEn=GL_FALSE;
+                if(imesa->Registers.DrawCtrl.ui!=ui)
+                    imesa->Registers.changed.ni.fDrawCtrlChanged=GL_TRUE;
+            }
+            break;
+        case GL_LIGHTING:
+           savageUpdateSpecular_s3d (ctx);
+            break;
+        case GL_TEXTURE_1D:      
+        case GL_TEXTURE_3D:      
+            imesa->new_state |= SAVAGE_NEW_TEXTURE;
+            break;
+        case GL_TEXTURE_2D:      
+            imesa->new_state |= SAVAGE_NEW_TEXTURE;
+            break;
+        default:
+            ; 
+    }    
+}
+
+void savageDDUpdateHwState( GLcontext *ctx )
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+   
+    if(imesa->driDrawable)
+    {
+        LOCK_HARDWARE(imesa);
+    }
+    
+    if (imesa->new_state & SAVAGE_NEW_TEXTURE) {
+       savageUpdateTextureState( ctx );
+    }
+    if((imesa->dirty!=0)|| (imesa->new_state!=0))  
+    {
+        savageEmitHwStateLocked(imesa);
+        imesa->new_state = 0;
+    }
+    if(imesa->driDrawable)
+    {
+        UNLOCK_HARDWARE(imesa);
+    }
+}
+
+
+void savageEmitDrawingRectangle( savageContextPtr imesa )
+{
+    __DRIdrawablePrivate *dPriv = imesa->driDrawable;
+    savageScreenPrivate *savageScreen = imesa->savageScreen;
+    XF86DRIClipRectPtr pbox;
+    int nbox;
+   
+
+    int x0 = imesa->drawX;
+    int y0 = imesa->drawY;
+    int x1 = x0 + dPriv->w;
+    int y1 = y0 + dPriv->h;
+
+    pbox = dPriv->pClipRects;  
+    nbox = dPriv->numClipRects;
+       
+
+   
+    /* Coordinate origin of the window - may be offscreen.
+     */
+    /* imesa->BufferSetup[SAVAGE_DESTREG_DR4] = ((y0<<16) | 
+       (((unsigned)x0)&0xFFFF));*/
+  
+    /* Clip to screen.
+     */
+    if (x0 < 0) x0 = 0;
+    if (y0 < 0) y0 = 0;
+    if (x1 > savageScreen->width) x1 = savageScreen->width;
+    if (y1 > savageScreen->height) y1 = savageScreen->height;
+
+
+    if(nbox ==  1)
+    {
+        imesa->draw_rect.x1 = MAX2(x0,pbox->x1);
+        imesa->draw_rect.y1 = MAX2(y0,pbox->y1);
+        imesa->draw_rect.x2 = MIN2(x1,pbox->x2);
+        imesa->draw_rect.y2 = MIN2(y1,pbox->y2);
+    }
+    else
+    {
+        imesa->draw_rect.x1 = x0;
+        imesa->draw_rect.y1 = y0;
+        imesa->draw_rect.x2 = x1;
+        imesa->draw_rect.y2 = y1;
+    }
+   
+    imesa->Registers.changed.ni.fScissorsChanged=GL_TRUE;
+
+    /*   imesa->Registers.changed.ni.fDrawCtrl0Changed=GL_TRUE;
+         imesa->Registers.changed.ni.fDrawCtrl1Changed=GL_TRUE;*/
+
+
+    imesa->dirty |= SAVAGE_UPLOAD_BUFFERS;
+}
+
+
+static void savageDDPrintDirty( const char *msg, GLuint state )
+{
+    fprintf(stderr, "%s (0x%x): %s%s%s%s%s\n",    
+            msg,
+            (unsigned int) state,
+            (state & SAVAGE_UPLOAD_TEX0IMAGE)  ? "upload-tex0, " : "",
+            (state & SAVAGE_UPLOAD_TEX1IMAGE)  ? "upload-tex1, " : "",
+            (state & SAVAGE_UPLOAD_CTX)        ? "upload-ctx, " : "",
+            (state & SAVAGE_UPLOAD_BUFFERS)    ? "upload-bufs, " : "",
+            (state & SAVAGE_UPLOAD_CLIPRECTS)  ? "upload-cliprects, " : ""
+            );
+}
+
+
+
+static void savageUpdateRegister_s4(savageContextPtr imesa)
+{
+    GLuint *pBCIBase;
+    pBCIBase = savageDMAAlloc (imesa, 100);
+    /*
+     *make sure there is enough room for everything
+     */
+    /*savageKickDMA(imesa);*/
+#define PARAMT 1
+#if defined(PARAMT) && PARAMT
+#define GLOBAL_REG SAVAGE_GLOBAL_CHANGED
+#else
+#define GLOBAL_REG (SAVAGE_GLOBAL_CHANGED | SAVAGE_TEXTURE_CHANGED)
+#endif
+    if (imesa->Registers.changed.uiRegistersChanged & GLOBAL_REG)
+    {
+        WRITE_CMD(pBCIBase,WAIT_3D_IDLE,GLuint);
+    }
+
+    if (imesa->Registers.changed.ni.fTexPalAddrChanged)
+    {
+        WRITE_CMD(pBCIBase, SET_REGISTER(SAVAGE_TEXPALADDR_S4, 1),GLuint);
+        WRITE_CMD(pBCIBase, imesa->Registers.TexPalAddr.ui,GLuint);
+    }
+
+    if (imesa->Registers.changed.uiRegistersChanged & 0xFC)
+    {
+        WRITE_CMD(pBCIBase, SET_REGISTER(SAVAGE_TEXCTRL0_S4, 6),GLuint);
+        WRITE_CMD(pBCIBase, imesa->Registers.TexCtrl[0].ui,GLuint);
+        WRITE_CMD(pBCIBase, imesa->Registers.TexCtrl[1].ui,GLuint);
+        WRITE_CMD(pBCIBase, imesa->Registers.TexAddr[0].ui,GLuint);
+        WRITE_CMD(pBCIBase, imesa->Registers.TexAddr[1].ui,GLuint);
+        WRITE_CMD(pBCIBase, imesa->Registers.TexBlendCtrl[0].ui,GLuint);
+        WRITE_CMD(pBCIBase, imesa->Registers.TexBlendCtrl[1].ui,GLuint);
+    }
+
+    if (imesa->Registers.changed.ni.fTexDescrChanged)
+    {
+        WRITE_CMD(pBCIBase, SET_REGISTER(SAVAGE_TEXDESCR_S4, 1),GLuint);
+        WRITE_CMD(pBCIBase, imesa->Registers.TexDescr.ui,GLuint);
+        imesa->Registers.TexDescr.s4.newPal = GL_FALSE;
+    }
+
+    if (imesa->Registers.changed.ni.fFogCtrlChanged)
+    {
+
+        WRITE_CMD(pBCIBase,SET_REGISTER(SAVAGE_FOGCTRL_S4, 1),GLuint);
+        WRITE_CMD(pBCIBase, imesa->Registers.FogCtrl.ui,GLuint);
+    }
+
+    if (imesa->Registers.changed.ni.fDestCtrlChanged)
+    {
+        WRITE_CMD(pBCIBase , SET_REGISTER(SAVAGE_DESTCTRL_S4,1),GLuint);
+       WRITE_CMD( pBCIBase ,imesa->Registers.DestCtrl.ui,GLuint);
+    }
+    
+    if (imesa->Registers.changed.ni.fDrawLocalCtrlChanged)
+    {
+        WRITE_CMD(pBCIBase , SET_REGISTER(SAVAGE_DRAWLOCALCTRL_S4,1),GLuint);
+        WRITE_CMD(pBCIBase , imesa->Registers.DrawLocalCtrl.ui,GLuint);
+    }
+    /*
+     * Scissors updates drawctrl0 and drawctrl 1
+     */
+
+    if (imesa->Registers.changed.ni.fScissorsChanged)
+    {
+        if(imesa->scissor)
+        {
+            imesa->Registers.DrawCtrl0.ni.scissorXStart = imesa->scissor_rect.x1;
+            imesa->Registers.DrawCtrl0.ni.scissorYStart = imesa->scissor_rect.y1;
+            imesa->Registers.DrawCtrl1.ni.scissorXEnd   = imesa->scissor_rect.x2-1;
+            imesa->Registers.DrawCtrl1.ni.scissorYEnd   = imesa->scissor_rect.y2-1;
+        }
+        else
+        {
+            imesa->Registers.DrawCtrl0.ni.scissorXStart = imesa->draw_rect.x1;
+            imesa->Registers.DrawCtrl0.ni.scissorYStart = imesa->draw_rect.y1;
+            imesa->Registers.DrawCtrl1.ni.scissorXEnd   = imesa->draw_rect.x2-1;
+            imesa->Registers.DrawCtrl1.ni.scissorYEnd   = imesa->draw_rect.y2-1;
+        }
+        
+        imesa->Registers.changed.ni.fDrawCtrl0Changed=GL_TRUE;
+        imesa->Registers.changed.ni.fDrawCtrl1Changed=GL_TRUE;
+    }
+    if (imesa->Registers.changed.uiRegistersChanged )
+    {
+        
+        WRITE_CMD(pBCIBase , SET_REGISTER(SAVAGE_DRAWCTRLGLOBAL0_S4,2),GLuint);
+        WRITE_CMD(pBCIBase , imesa->Registers.DrawCtrl0.ui,GLuint);
+        WRITE_CMD(pBCIBase , imesa->Registers.DrawCtrl1.ui,GLuint);
+        
+    }
+
+    if (imesa->Registers.changed.ni.fZBufCtrlChanged)
+    {
+        WRITE_CMD(pBCIBase , SET_REGISTER(SAVAGE_ZBUFCTRL_S4,1),GLuint);
+        WRITE_CMD(pBCIBase , imesa->Registers.ZBufCtrl.ui,GLuint);
+    }
+
+    if (imesa->Registers.changed.ni.fStencilCtrlChanged)
+    {
+        WRITE_CMD(pBCIBase , SET_REGISTER(SAVAGE_STENCILCTRL_S4,1),GLuint);
+        WRITE_CMD(pBCIBase , imesa->Registers.StencilCtrl.ui,GLuint);
+    }
+
+    if (imesa->Registers.changed.ni.fTexBlendColorChanged)
+    {
+        WRITE_CMD(pBCIBase , SET_REGISTER(SAVAGE_TEXBLENDCOLOR_S4,1),GLuint);
+        WRITE_CMD(pBCIBase , imesa->Registers.TexBlendColor.ui,GLuint);
+    }
+
+    if (imesa->Registers.changed.ni.fZWatermarksChanged)
+    {
+        WRITE_CMD(pBCIBase , SET_REGISTER(SAVAGE_ZWATERMARK_S4,1),GLuint);
+        WRITE_CMD(pBCIBase , imesa->Registers.ZWatermarks.ui,GLuint);
+    }
+
+    if (imesa->Registers.changed.ni.fDestTexWatermarksChanged)
+    {
+        WRITE_CMD(pBCIBase , SET_REGISTER(SAVAGE_DESTTEXRWWATERMARK_S4,1),GLuint);
+        WRITE_CMD(pBCIBase , imesa->Registers.DestTexWatermarks.ui,GLuint);
+    }
+
+    imesa->Registers.changed.uiRegistersChanged = 0;
+    imesa->dirty=0;    
+    savageDMACommit (imesa, pBCIBase);
+}
+static void savageUpdateRegister_s3d(savageContextPtr imesa)
+{
+    GLuint *pBCIBase;
+    pBCIBase = savageDMAAlloc (imesa, 100);
+
+    /* Always wait for idle for now.
+     * FIXME: On the Savage3D individual fields in registers can be
+     * local/global. */
+    WRITE_CMD(pBCIBase,WAIT_3D_IDLE,GLuint);
+
+    if (imesa->Registers.changed.ni.fZBufCtrlChanged)
+    {
+        WRITE_CMD(pBCIBase , SET_REGISTER(SAVAGE_ZBUFCTRL_S3D,1),GLuint);
+        WRITE_CMD(pBCIBase , imesa->Registers.ZBufCtrl.ui,GLuint);
+    }
+
+    if (imesa->Registers.changed.ni.fDestCtrlChanged)
+    {
+        WRITE_CMD(pBCIBase , SET_REGISTER(SAVAGE_DESTCTRL_S3D,1),GLuint);
+       WRITE_CMD( pBCIBase ,imesa->Registers.DestCtrl.ui,GLuint);
+    }
+    /* Better leave these alone. They don't seem to be needed and I
+     * don't know exactly what they ary good for. Changing them may
+     * have been responsible for lockups with texturing. */
+/*
+    if (imesa->Registers.changed.ni.fZWatermarksChanged)
+    {
+        WRITE_CMD(pBCIBase , SET_REGISTER(SAVAGE_ZWATERMARK_S3D,1),GLuint);
+        WRITE_CMD(pBCIBase , imesa->Registers.ZWatermarks.ui,GLuint);
+    }
+    if (imesa->Registers.changed.ni.fDestTexWatermarksChanged)
+    {
+        WRITE_CMD(pBCIBase , SET_REGISTER(SAVAGE_DESTTEXRWWATERMARK_S3D,1),GLuint);
+        WRITE_CMD(pBCIBase , imesa->Registers.DestTexWatermarks.ui,GLuint);
+    }
+*/
+    if (imesa->Registers.changed.ni.fDrawCtrlChanged)
+    {
+       /* Same as above. The utah-driver always sets these to true.
+        * Changing them definitely caused lockups with texturing. */
+       imesa->Registers.DrawCtrl.ni.flushPdDestWrites = GL_TRUE;
+       imesa->Registers.DrawCtrl.ni.flushPdZbufWrites = GL_TRUE;
+        WRITE_CMD(pBCIBase , SET_REGISTER(SAVAGE_DRAWCTRL_S3D,1),GLuint);
+        WRITE_CMD(pBCIBase , imesa->Registers.DrawCtrl.ui,GLuint);
+    }
+
+    if (imesa->Registers.changed.ni.fScissorsChanged)
+    {
+        if(imesa->scissor)
+        {
+            imesa->Registers.ScissorsStart.ni.scissorXStart =
+               imesa->scissor_rect.x1;
+            imesa->Registers.ScissorsStart.ni.scissorYStart =
+               imesa->scissor_rect.y1;
+            imesa->Registers.ScissorsEnd.ni.scissorXEnd =
+               imesa->scissor_rect.x2-1;
+            imesa->Registers.ScissorsEnd.ni.scissorYEnd =
+               imesa->scissor_rect.y2-1;
+        }
+        else
+        {
+            imesa->Registers.ScissorsStart.ni.scissorXStart =
+               imesa->draw_rect.x1;
+            imesa->Registers.ScissorsStart.ni.scissorYStart =
+               imesa->draw_rect.y1;
+            imesa->Registers.ScissorsEnd.ni.scissorXEnd =
+               imesa->draw_rect.x2-1;
+            imesa->Registers.ScissorsEnd.ni.scissorYEnd =
+               imesa->draw_rect.y2-1;
+        }
+        
+        imesa->Registers.changed.ni.fScissorsStartChanged=GL_TRUE;
+        imesa->Registers.changed.ni.fScissorsEndChanged=GL_TRUE;
+    }
+    if (imesa->Registers.changed.uiRegistersChanged & 0x00C00000)
+    {
+        WRITE_CMD(pBCIBase , SET_REGISTER(SAVAGE_SCSTART_S3D,2),GLuint);
+        WRITE_CMD(pBCIBase , imesa->Registers.ScissorsStart.ui,GLuint);
+        WRITE_CMD(pBCIBase , imesa->Registers.ScissorsEnd.ui,GLuint);
+    }
+
+    if (imesa->Registers.changed.ni.fTex0CtrlChanged)
+    {
+        WRITE_CMD(pBCIBase, SET_REGISTER(SAVAGE_TEXCTRL_S3D, 1),GLuint);
+        WRITE_CMD(pBCIBase, imesa->Registers.TexCtrl[0].ui,GLuint);
+    }
+
+    if (imesa->Registers.changed.ni.fFogCtrlChanged)
+    {
+        WRITE_CMD(pBCIBase,SET_REGISTER(SAVAGE_FOGCTRL_S3D, 1),GLuint);
+        WRITE_CMD(pBCIBase, imesa->Registers.FogCtrl.ui,GLuint);
+    }
+
+    if (imesa->Registers.changed.ni.fTex0AddrChanged ||
+       imesa->Registers.changed.ni.fTexDescrChanged)
+    {
+        WRITE_CMD(pBCIBase, SET_REGISTER(SAVAGE_TEXADDR_S3D, 1),GLuint);
+        WRITE_CMD(pBCIBase, imesa->Registers.TexAddr[0].ui,GLuint);
+        WRITE_CMD(pBCIBase, SET_REGISTER(SAVAGE_TEXDESCR_S3D, 1),GLuint);
+        WRITE_CMD(pBCIBase, imesa->Registers.TexDescr.ui,GLuint);
+        imesa->Registers.TexDescr.s3d.newPal = GL_FALSE;
+    }
+
+    if (imesa->Registers.changed.ni.fTexPalAddrChanged)
+    {
+        WRITE_CMD(pBCIBase, SET_REGISTER(SAVAGE_TEXPALADDR_S3D, 1),GLuint);
+        WRITE_CMD(pBCIBase, imesa->Registers.TexPalAddr.ui,GLuint);
+    }
+
+    imesa->Registers.changed.uiRegistersChanged = 0;
+    imesa->dirty=0;
+    savageDMACommit (imesa, pBCIBase);
+}
+
+
+
+/* Push the state into the sarea and/or texture memory.
+ */
+void savageEmitHwStateLocked( savageContextPtr imesa )
+{
+    if (SAVAGE_DEBUG & DEBUG_VERBOSE_API)
+        savageDDPrintDirty( "\n\n\nsavageEmitHwStateLocked", imesa->dirty );
+
+    if (imesa->dirty & ~SAVAGE_UPLOAD_CLIPRECTS)
+    {
+        if (imesa->dirty & (SAVAGE_UPLOAD_CTX | SAVAGE_UPLOAD_TEX0  | \
+                            SAVAGE_UPLOAD_TEX1 | SAVAGE_UPLOAD_BUFFERS))
+        {
+   
+            SAVAGE_STATE_COPY(imesa);
+            /* update state to hw*/
+            if (imesa->driDrawable &&imesa->driDrawable->numClipRects ==0 )
+            {
+                return ;
+            }
+           if (imesa->savageScreen->chipset >= S3_SAVAGE4)
+               savageUpdateRegister_s4(imesa);
+           else
+               savageUpdateRegister_s3d(imesa);
+        }
+
+        imesa->sarea->dirty |= (imesa->dirty & 
+                                ~(SAVAGE_UPLOAD_TEX1|SAVAGE_UPLOAD_TEX0));
+        imesa->dirty &= SAVAGE_UPLOAD_CLIPRECTS;
+    }
+}
+
+
+
+static void savageDDInitState_s4( savageContextPtr imesa )
+{
+#if 1
+    *(GLuint *)&imesa->Registers.DestCtrl          = 1<<7;
+#else
+    *(GLuint *)&imesa->Registers.DestCtrl          = 0;
+#endif
+    *(GLuint *)&imesa->Registers.ZBufCtrl          = 0;
+
+    imesa->Registers.ZBufCtrl.s4.zCmpFunc = LCS_Z_LESS;
+    imesa->Registers.ZBufCtrl.s4.wToZEn               = GL_TRUE;
+    /*imesa->Registers.ZBufCtrl.ni.floatZEn          = GL_TRUE;*/
+    *(GLuint *)&imesa->Registers.ZBufOffset        = 0;
+    *(GLuint *)&imesa->Registers.FogCtrl           = 0;
+    imesa->Registers.FogTable.ni.ulEntry[0]           = 0;
+    imesa->Registers.FogTable.ni.ulEntry[1]           = 0;
+    imesa->Registers.FogTable.ni.ulEntry[2]           = 0;
+    imesa->Registers.FogTable.ni.ulEntry[3]           = 0;
+    imesa->Registers.FogTable.ni.ulEntry[4]           = 0;
+    imesa->Registers.FogTable.ni.ulEntry[5]           = 0;
+    imesa->Registers.FogTable.ni.ulEntry[6]           = 0;
+    imesa->Registers.FogTable.ni.ulEntry[7]           = 0;
+    *(GLuint *)&imesa->Registers.TexDescr          = 0;
+    imesa->Registers.TexAddr[0].ui                 = 0;
+    imesa->Registers.TexAddr[1].ui                 = 0;
+    imesa->Registers.TexPalAddr.ui                 = 0;
+    *(GLuint *)&imesa->Registers.TexCtrl[0]        = 0;
+    *(GLuint *)&imesa->Registers.TexCtrl[1]        = 0;
+    imesa->Registers.TexBlendCtrl[0].ui            = TBC_NoTexMap;
+    imesa->Registers.TexBlendCtrl[1].ui            = TBC_NoTexMap1;
+    *(GLuint *)&imesa->Registers.DrawCtrl0         = 0;
+#if 1/*def __GL_HALF_PIXEL_OFFSET*/
+    *(GLuint *)&imesa->Registers.DrawCtrl1         = 0;
+#else
+    *(GLuint *)&imesa->Registers.DrawCtrl1         = 1<<11;
+#endif
+    *(GLuint *)&imesa->Registers.DrawLocalCtrl     = 0;
+    *(GLuint *)&imesa->Registers.StencilCtrl       = 0;
+
+    /* Set DestTexWatermarks_31,30 to 01 always.
+     *Has no effect if dest. flush is disabled.
+     */
+#if 0
+    *(GLuint *)&imesa->Registers.ZWatermarks       = 0x12000C04;
+    *(GLuint *)&imesa->Registers.DestTexWatermarks = 0x40200400;
+#else
+    *(GLuint *)&imesa->Registers.ZWatermarks       = 0x16001808;
+    *(GLuint *)&imesa->Registers.DestTexWatermarks = 0x4f000000;
+#endif
+    imesa->Registers.DrawCtrl0.ni.DPerfAccelEn = GL_TRUE;
+
+    /* clrCmpAlphaBlendCtrl is needed to get alphatest and
+     * alpha blending working properly
+     */
+
+    imesa->Registers.TexCtrl[0].s4.dBias                 = 0x08;
+    imesa->Registers.TexCtrl[1].s4.dBias                 = 0x08;
+    imesa->Registers.TexCtrl[0].s4.texXprEn              = GL_TRUE;
+    imesa->Registers.TexCtrl[1].s4.texXprEn              = GL_TRUE;
+    imesa->Registers.TexCtrl[0].s4.dMax                  = 0x0f;
+    imesa->Registers.TexCtrl[1].s4.dMax                  = 0x0f;
+    imesa->Registers.DrawLocalCtrl.ni.drawUpdateEn     = GL_TRUE;
+    imesa->Registers.DrawLocalCtrl.ni.srcAlphaMode    = SAM_One;
+    imesa->Registers.DrawLocalCtrl.ni.wrZafterAlphaTst = GL_FALSE;
+    imesa->Registers.DrawLocalCtrl.ni.flushPdZbufWrites= GL_TRUE;
+    imesa->Registers.DrawLocalCtrl.ni.flushPdDestWrites= GL_TRUE;
+
+    imesa->Registers.DrawLocalCtrl.ni.zUpdateEn= GL_TRUE;
+    imesa->Registers.DrawCtrl1.ni.ditherEn=GL_TRUE;
+    imesa->Registers.DrawCtrl1.ni.cullMode             = BCM_None;
+
+    imesa->LcsCullMode=BCM_None;
+    imesa->Registers.TexDescr.s4.palSize               = TPS_256;
+}
+static void savageDDInitState_s3d( savageContextPtr imesa )
+{
+#if 1
+    imesa->Registers.DestCtrl.ui           = 1<<7;
+#else
+    imesa->Registers.DestCtrl.ui           = 0;
+#endif
+    imesa->Registers.ZBufCtrl.ui           = 0;
+
+    imesa->Registers.ZBufCtrl.s3d.zCmpFunc = LCS_Z_LESS & 0x07;
+    imesa->Registers.ZBufOffset.ui         = 0;
+    imesa->Registers.FogCtrl.ui            = 0;
+    memset (imesa->Registers.FogTable.ni.ucEntry, 0, 64);
+    imesa->Registers.TexDescr.ui           = 0;
+    imesa->Registers.TexAddr[0].ui         = 0;
+    imesa->Registers.TexPalAddr.ui         = 0;
+    imesa->Registers.TexCtrl[0].ui         = 0;
+#if 1/*def __GL_HALF_PIXEL_OFFSET*/
+    imesa->Registers.DrawCtrl.ui           = 0;
+#else
+    imesa->Registers.DrawCtrl.ui           = 1<<1;
+#endif
+    imesa->Registers.ScissorsStart.ui      = 0;
+    imesa->Registers.ScissorsEnd.ui        = 0;
+
+    /* Set DestTexWatermarks_31,30 to 01 always.
+     *Has no effect if dest. flush is disabled.
+     */
+#if 0
+    imesa->Registers.ZWatermarks.ui       = 0x12000C04;
+    imesa->Registers.DestTexWatermarks.ui = 0x40200400;
+#else
+    imesa->Registers.ZWatermarks.ui       = 0x16001808;
+    imesa->Registers.DestTexWatermarks.ui = 0x4f000000;
+#endif
+
+    /* clrCmpAlphaBlendCtrl is needed to get alphatest and
+     * alpha blending working properly
+     */
+
+    imesa->Registers.TexCtrl[0].s3d.dBias          = 0x08;
+    imesa->Registers.TexCtrl[0].s3d.texXprEn       = GL_TRUE;
+
+    imesa->Registers.ZBufCtrl.s3d.drawUpdateEn     = GL_TRUE;
+    imesa->Registers.ZBufCtrl.s3d.wrZafterAlphaTst = GL_FALSE;
+    imesa->Registers.ZBufCtrl.s3d.zUpdateEn        = GL_TRUE;
+
+    imesa->Registers.DrawCtrl.ni.srcAlphaMode      = SAM_One;
+    imesa->Registers.DrawCtrl.ni.flushPdZbufWrites = GL_TRUE;
+    imesa->Registers.DrawCtrl.ni.flushPdDestWrites = GL_TRUE;
+
+    imesa->Registers.DrawCtrl.ni.ditherEn          = GL_TRUE;
+    imesa->Registers.DrawCtrl.ni.cullMode          = BCM_None;
+
+    imesa->LcsCullMode = BCM_None;
+    imesa->Registers.TexDescr.s3d.palSize          = TPS_256;
+}
+void savageDDInitState( savageContextPtr imesa ) {
+    volatile GLuint* pBCIBase;
+    if (imesa->savageScreen->chipset >= S3_SAVAGE4)
+       savageDDInitState_s4 (imesa);
+    else
+       savageDDInitState_s3d (imesa);
+
+    /*fprintf(stderr,"DBflag:%d\n",imesa->glCtx->Visual->DBflag);*/
+    imesa->Registers.DestCtrl.ni.offset = imesa->savageScreen->backOffset>>11;
+    if(imesa->savageScreen->cpp == 2)
+    {
+        imesa->Registers.DestCtrl.ni.dstPixFmt = 0;
+        imesa->Registers.DestCtrl.ni.dstWidthInTile =
+            (imesa->savageScreen->width+63)>>6;
+    }
+    else
+    {
+        imesa->Registers.DestCtrl.ni.dstPixFmt = 1;
+        imesa->Registers.DestCtrl.ni.dstWidthInTile =
+            (imesa->savageScreen->width+31)>>5;
+    }
+
+    imesa->IsDouble = GL_TRUE;
+
+    imesa->NotFirstFrame = GL_FALSE;
+    imesa->Registers.ZBufOffset.ni.offset=imesa->savageScreen->depthOffset>>11;
+    if(imesa->savageScreen->zpp == 2)
+    {
+        imesa->Registers.ZBufOffset.ni.zBufWidthInTiles = 
+            (imesa->savageScreen->width+63)>>6;
+        imesa->Registers.ZBufOffset.ni.zDepthSelect = 0;
+    }
+    else
+    {   
+        imesa->Registers.ZBufOffset.ni.zBufWidthInTiles = 
+            (imesa->savageScreen->width+31)>>5;
+        imesa->Registers.ZBufOffset.ni.zDepthSelect = 1;      
+    }
+    if (imesa->glCtx->Color._DrawDestMask == BACK_LEFT_BIT) {
+        if(imesa->IsFullScreen)
+        {
+            imesa->toggle = TARGET_BACK;
+
+            imesa->drawMap = (char *)imesa->apertureBase[imesa->toggle];
+            imesa->readMap = (char *)imesa->apertureBase[imesa->toggle];
+        }
+        else
+        {
+            imesa->drawMap = (char *)imesa->apertureBase[TARGET_BACK];
+            imesa->readMap = (char *)imesa->apertureBase[TARGET_BACK];
+        }
+
+    } else {
+      
+        if(imesa->IsFullScreen)
+        {
+            imesa->toggle = TARGET_BACK;
+
+            imesa->drawMap = (char *)imesa->apertureBase[imesa->toggle];
+            imesa->readMap = (char *)imesa->apertureBase[imesa->toggle];
+        }
+        else
+        {
+            imesa->drawMap = (char *)imesa->apertureBase[TARGET_BACK];
+            imesa->readMap = (char *)imesa->apertureBase[TARGET_BACK];
+        }
+    }
+
+#if 0
+    if(imesa->driDrawable)
+    {
+        LOCK_HARDWARE(imesa);
+    }
+    pBCIBase=SAVAGE_GET_BCI_POINTER(imesa,38); 
+    *pBCIBase++ = WAIT_3D_IDLE;
+    pBCIBase[0] = SET_REGISTER(DST,1);
+    pBCIBase[1] = imesa->Registers.DestCtrl.ui;        
+    pBCIBase+=2;
+       
+    pBCIBase[0] = SET_REGISTER(ZBUFCTRL,1);
+    pBCIBase[1] = imesa->Registers.ZBufCtrl.ui;        
+    pBCIBase+=2;
+
+    pBCIBase[0] = SET_REGISTER(ZBUFOFF,1);
+    pBCIBase[1] = imesa->Registers.ZBufOffset.ui;      
+    pBCIBase+=2;
+  
+    pBCIBase[0] = SET_REGISTER(FOGCTRL,1);
+    pBCIBase[1] = imesa->Registers.FogCtrl.ui; 
+    pBCIBase+=2;
+  
+  
+    pBCIBase[0] = SET_REGISTER(FOGTABLE,8);
+    memcpy((GLvoid *)(pBCIBase+1),(GLvoid *)imesa->Registers.FogTable.ni.ulEntry,32);
+    pBCIBase+=9;
+
+    pBCIBase[0] = SET_REGISTER(DRAWLOCALCTRL,1);
+    pBCIBase[1] = imesa->Registers.DrawLocalCtrl.ui;   
+    pBCIBase+=2;
+   
+    pBCIBase[0] = SET_REGISTER(DRAWCTRLGLOBAL0,2);
+    pBCIBase[1] = imesa->Registers.DrawCtrl0.ui;       
+    pBCIBase[2] = imesa->Registers.DrawCtrl1.ui;       
+    pBCIBase+=3;
+
+   
+    pBCIBase[0] = SET_REGISTER(TEXPALADDR,1);
+    pBCIBase[1] = imesa->Registers.TexPalAddr.ui;      
+    pBCIBase+=2;
+
+
+    pBCIBase[0] = SET_REGISTER(TEXCTRL0,6);
+    pBCIBase[1] = imesa->Registers.TexCtrl[0].ui;      
+    pBCIBase[2] = imesa->Registers.TexCtrl[1].ui;      
+   
+    pBCIBase[3] = imesa->Registers.TexAddr[0].ui;      
+    pBCIBase[4] = imesa->Registers.TexAddr[1].ui;      
+    pBCIBase[5] = imesa->Registers.TexBlendCtrl[0].ui; 
+    pBCIBase[6] = imesa->Registers.TexBlendCtrl[1].ui; 
+    pBCIBase+=7;
+   
+    pBCIBase[0] = SET_REGISTER(TEXDESCR,1);
+    pBCIBase[1] = imesa->Registers.TexDescr.ui;        
+    pBCIBase+=2;
+
+
+    pBCIBase[0] = SET_REGISTER(STENCILCTRL,1);
+    pBCIBase[1] = imesa->Registers.StencilCtrl.ui;     
+    pBCIBase+=2;
+
+    pBCIBase[0] = SET_REGISTER(ZWATERMARK,1);
+    pBCIBase[1] = imesa->Registers.ZWatermarks.ui;     
+    pBCIBase+=2;
+
+    pBCIBase[0] = SET_REGISTER(DESTTEXRWWATERMARK,1);
+    pBCIBase[1] = imesa->Registers.DestTexWatermarks.ui;       
+    pBCIBase+=2;
+   
+    if(imesa->driDrawable)
+    {
+        UNLOCK_HARDWARE(imesa);
+    }
+#else
+    if(imesa->driDrawable)
+        LOCK_HARDWARE(imesa);
+
+    /* This is the only reg that is not emitted in savageUpdateRegisters.
+     * FIXME: Should this be set by the Xserver? */
+    pBCIBase = SAVAGE_GET_BCI_POINTER(imesa,3);
+    *pBCIBase++ = WAIT_3D_IDLE;
+    *pBCIBase++ = SET_REGISTER(SAVAGE_ZBUFOFF_S4,1); /* The same on S3D. */
+    *pBCIBase++ = imesa->Registers.ZBufOffset.ui;
+
+    if(imesa->driDrawable)
+        UNLOCK_HARDWARE(imesa);
+    imesa->Registers.changed.uiRegistersChanged = ~0;
+#endif
+}
+
+
+#define INTERESTED (~(NEW_MODELVIEW|NEW_PROJECTION|\
+                      NEW_TEXTURE_MATRIX|\
+                      NEW_USER_CLIP|NEW_CLIENT_STATE))
+
+void savageDDRenderStart(GLcontext *ctx)
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+    __DRIdrawablePrivate *dPriv = imesa->driDrawable;
+    XF86DRIClipRectPtr pbox;
+    GLint nbox;
+
+    /* if the screen is overrided by other application. set the scissor.
+     * In MulitPass, re-render the screen.
+     */
+    pbox = dPriv->pClipRects;
+    nbox = dPriv->numClipRects;
+    if (nbox)
+    {
+        imesa->currentClip = nbox;
+        /* set scissor to the first clip box*/
+        savageDDScissor(ctx,pbox->x1,pbox->y1,pbox->x2,pbox->y2);
+
+        savageUpdateCull(ctx);
+        savageDDUpdateHwState(ctx); /* update to hardware register*/
+    }
+    else /* need not render at all*/
+    {
+        /*ctx->VB->CopyStart = ctx->VB->Count;*/
+    }
+    LOCK_HARDWARE(SAVAGE_CONTEXT(ctx));
+}
+
+
+void savageDDRenderEnd(GLcontext *ctx)
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+       
+    UNLOCK_HARDWARE(SAVAGE_CONTEXT(ctx));
+    if(!imesa->IsDouble)
+    {
+        savageSwapBuffers(imesa->driDrawable);
+    }
+       
+}
+
+static void savageDDInvalidateState( GLcontext *ctx, GLuint new_state )
+{
+   _swrast_InvalidateState( ctx, new_state );
+   _swsetup_InvalidateState( ctx, new_state );
+   _ac_InvalidateState( ctx, new_state );
+   _tnl_InvalidateState( ctx, new_state );
+   SAVAGE_CONTEXT(ctx)->new_gl_state |= new_state;
+}
+
+
+void savageDDInitStateFuncs(GLcontext *ctx)
+{
+    ctx->Driver.UpdateState = savageDDInvalidateState;
+    ctx->Driver.BlendEquationSeparate = savageDDBlendEquationSeparate;
+    ctx->Driver.Fogfv = savageDDFogfv;
+    ctx->Driver.Scissor = savageDDScissor;
+#if HW_CULL
+    ctx->Driver.CullFace = savageDDCullFaceFrontFace;
+    ctx->Driver.FrontFace = savageDDCullFaceFrontFace;
+#else
+    ctx->Driver.CullFace = 0;
+    ctx->Driver.FrontFace = 0;
+#endif /* end #if HW_CULL */
+    ctx->Driver.PolygonMode=NULL;
+    ctx->Driver.PolygonStipple = 0;
+    ctx->Driver.LineStipple = 0;
+    ctx->Driver.LineWidth = 0;
+    ctx->Driver.LogicOpcode = 0;
+    ctx->Driver.DrawBuffer = savageDDDrawBuffer;
+    ctx->Driver.ReadBuffer = savageDDReadBuffer;
+    ctx->Driver.ClearColor = savageDDClearColor;
+
+    ctx->Driver.DepthRange = savageDepthRange;
+    ctx->Driver.Viewport = savageViewport;
+    ctx->Driver.RenderMode = savageRenderMode;
+
+    ctx->Driver.ClearIndex = 0;
+    ctx->Driver.IndexMask = 0;
+
+    if (SAVAGE_CONTEXT( ctx )->savageScreen->chipset >= S3_SAVAGE4) {
+       ctx->Driver.Enable = savageDDEnable_s4;
+       ctx->Driver.AlphaFunc = savageDDAlphaFunc_s4;
+       ctx->Driver.DepthFunc = savageDDDepthFunc_s4;
+       ctx->Driver.DepthMask = savageDDDepthMask_s4;
+       ctx->Driver.BlendFuncSeparate = savageDDBlendFuncSeparate_s4;
+       ctx->Driver.ColorMask = savageDDColorMask_s4;
+       ctx->Driver.ShadeModel = savageDDShadeModel_s4;
+       ctx->Driver.LightModelfv = savageDDLightModelfv_s4;
+#if HW_STENCIL
+       ctx->Driver.StencilFunc = savageDDStencilFunc;
+       ctx->Driver.StencilMask = savageDDStencilMask;
+       ctx->Driver.StencilOp = savageDDStencilOp;
+#else
+       ctx->Driver.StencilFunc = 0;
+       ctx->Driver.StencilMask = 0;
+       ctx->Driver.StencilOp = 0;
+#endif /* end #if HW_STENCIL */
+    } else {
+       ctx->Driver.Enable = savageDDEnable_s3d;
+       ctx->Driver.AlphaFunc = savageDDAlphaFunc_s3d;
+       ctx->Driver.DepthFunc = savageDDDepthFunc_s3d;
+       ctx->Driver.DepthMask = savageDDDepthMask_s3d;
+       ctx->Driver.BlendFuncSeparate = savageDDBlendFuncSeparate_s3d;
+       ctx->Driver.ColorMask = savageDDColorMask_s3d;
+       ctx->Driver.ShadeModel = savageDDShadeModel_s3d;
+       ctx->Driver.LightModelfv = savageDDLightModelfv_s3d;
+       ctx->Driver.StencilFunc = 0;
+       ctx->Driver.StencilMask = 0;
+       ctx->Driver.StencilOp = 0;
+    }
+
+   /* Swrast hooks for imaging extensions:
+    */
+   ctx->Driver.CopyColorTable = _swrast_CopyColorTable;
+   ctx->Driver.CopyColorSubTable = _swrast_CopyColorSubTable;
+   ctx->Driver.CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D;
+   ctx->Driver.CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D;
+}
diff --git a/src/mesa/drivers/dri/savage/savagestate.h b/src/mesa/drivers/dri/savage/savagestate.h
new file mode 100644 (file)
index 0000000..cc30389
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef _SAVAGE_STATE_H
+#define _SAVAGE_STATE_H
+
+#include "savagecontext.h"
+
+extern void savageDDUpdateHwState( GLcontext *ctx );
+extern void savageDDInitState( savageContextPtr imesa );
+extern void savageDDInitStateFuncs( GLcontext *ctx );
+extern void savageDDRenderStart(GLcontext *ctx);
+extern void savageDDRenderEnd(GLcontext *ctx);
+extern void savageDDScissor( GLcontext *ctx, GLint x, GLint y,GLsizei w, GLsizei h );
+
+/*frank 2001/11/13 add macro for sarea state copy*/
+#define SAVAGE_STATE_COPY(ctx) { \
+ctx->sarea->setup[0]=ctx->Registers.DrawLocalCtrl.ui; \
+ctx->sarea->setup[1]=ctx->Registers.TexPalAddr.ui; \
+ctx->sarea->setup[2]=ctx->Registers.TexCtrl[0].ui; \
+ctx->sarea->setup[3]=ctx->Registers.TexCtrl[1].ui; \
+ctx->sarea->setup[4]=ctx->Registers.TexAddr[0].ui; \
+ctx->sarea->setup[5]=ctx->Registers.TexAddr[1].ui; \
+ctx->sarea->setup[6]=ctx->Registers.TexBlendCtrl[0].ui; \
+ctx->sarea->setup[7]=ctx->Registers.TexBlendCtrl[1].ui; \
+ctx->sarea->setup[8]=ctx->Registers.TexXprClr.ui; \
+ctx->sarea->setup[9]=ctx->Registers.TexDescr.ui; \
+ctx->sarea->setup[10]=ctx->Registers.FogTable.ni.ulEntry[0]; \
+ctx->sarea->setup[11]=ctx->Registers.FogTable.ni.ulEntry[1]; \
+ctx->sarea->setup[12]=ctx->Registers.FogTable.ni.ulEntry[2]; \
+ctx->sarea->setup[13]=ctx->Registers.FogTable.ni.ulEntry[3]; \
+ctx->sarea->setup[14]=ctx->Registers.FogTable.ni.ulEntry[4]; \
+ctx->sarea->setup[15]=ctx->Registers.FogTable.ni.ulEntry[5]; \
+ctx->sarea->setup[16]=ctx->Registers.FogTable.ni.ulEntry[6]; \
+ctx->sarea->setup[17]=ctx->Registers.FogTable.ni.ulEntry[7]; \
+ctx->sarea->setup[18]=ctx->Registers.FogCtrl.ui; \
+ctx->sarea->setup[19]=ctx->Registers.StencilCtrl.ui; \
+ctx->sarea->setup[20]=ctx->Registers.ZBufCtrl.ui; \
+ctx->sarea->setup[21]=ctx->Registers.ZBufOffset.ui; \
+ctx->sarea->setup[22]=ctx->Registers.DestCtrl.ui; \
+ctx->sarea->setup[23]=ctx->Registers.DrawCtrl0.ui; \
+ctx->sarea->setup[24]=ctx->Registers.DrawCtrl1.ui; \
+ctx->sarea->setup[25]=ctx->Registers.ZWatermarks.ui; \
+ctx->sarea->setup[26]=ctx->Registers.DestTexWatermarks.ui; \
+ctx->sarea->setup[27]=ctx->Registers.TexBlendColor.ui; \
+}
+#endif
diff --git a/src/mesa/drivers/dri/savage/savagetex.c b/src/mesa/drivers/dri/savage/savagetex.c
new file mode 100644 (file)
index 0000000..94a4b23
--- /dev/null
@@ -0,0 +1,2022 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <GL/gl.h>
+
+#include "mm.h"
+#include "savagecontext.h"
+#include "savagetex.h"
+#include "savagetris.h"
+#include "savageioctl.h"
+#include "simple_list.h"
+#include "enums.h"
+#include "savage_bci.h"
+
+#include "macros.h"
+#include "texformat.h"
+#include "texstore.h"
+#include "texobj.h"
+
+#include "swrast/swrast.h"
+
+/* declarations of static and inline functions */
+__inline GLuint GetTiledCoordinates8(GLuint iBufferWidth, GLint x, GLint y);
+static GLuint GetTiledCoordinates16_4( GLint iBufferWidth,GLint x,GLint y );
+static GLuint GetTiledCoordinates16_8( GLint iBufferWidth,GLint x,GLint y );
+static GLuint GetTiledCoordinates32_4( GLint iBufferWidth, GLint x,   GLint y );
+static GLuint GetTiledCoordinates32_8( GLint iBufferWidth, GLint x,   GLint y );
+__inline GLuint GetTiledCoordinates( GLint iDepth,GLint iBufferWidth,GLint x,GLint y );
+__inline void savageUploadImage(savageTextureObjectPtr t, GLuint level, GLuint startx, GLuint starty, GLuint reloc);
+__inline void  savageTileTex(savageTextureObjectPtr tex, GLuint level);
+
+/* tile sizes depending on texel color depth */
+GLuint gTileWidth[5] =
+{
+    64,    /* 4-bit */ 
+    64,    /* 8-bit */
+    64,    /* 16-bit */
+    0,     /* 24-bit */
+    32     /* 32-bit */
+};
+
+GLuint gTileHeight[5] = 
+{
+    64,   /* 4-bit */
+    32,   /* 8-bit */
+    16,   /* 16-bit */
+    0,    /* 24-bit */
+    16    /* 32-bit */
+};
+
+__inline GLuint GetTiledCoordinates8(GLuint iBufferWidth, GLint x, GLint y)
+{
+    GLint x10, x106, x52;
+    GLint y20, y105, y43;
+    GLuint uWidthInTiles;
+
+    uWidthInTiles = (iBufferWidth + 63) >> 6;
+    x10 = x & 0x3;
+    x52 = (x & 0x3c) >> 2;
+    x106 = (x & 0x7c0) >> 6;
+
+    y20 = y & 0x7;
+    y43 = (y & 0x18) >> 3;
+    y105 = (y & 0x7e0) >> 5;
+    
+    return ( x10         |
+            (y20 << 2)   |
+           (x52 << 5)   |
+           (y43 << 9)   |
+           ((y105 * uWidthInTiles) + x106) << 11 );
+}
+
+/* 4-pixel wide subtiles */
+static GLuint GetTiledCoordinates16_4( GLint iBufferWidth,
+                                              GLint x,
+                                              GLint y )
+{
+    GLint  x106;
+    GLint  x10;
+    GLint  x52;
+    GLint  y104;
+    GLint  y20;
+    GLint  y3;
+    GLuint uiWidthInTiles;
+
+    /*
+    // calculating tiled address
+    */
+
+    uiWidthInTiles = (iBufferWidth + 63) >> 6;
+
+    x10  =  x & 0x3;
+    x52  = (x & 0x3c ) >> 2;
+    x106 = (x & 0x7c0) >> 6;
+
+    y20  =  y & 0x7;
+    y3   = (y & 8    ) >> 3;
+    y104 = (y & 0x7f0) >> 4;
+
+    return( (x10 << 1)  |
+            (y20 << 3)  |
+            (x52 << 6)  |
+            (y3  << 10) |
+            ((y104 * uiWidthInTiles) + x106) << 11 );
+}
+/* 8-pixel wide subtiles */
+static GLuint GetTiledCoordinates16_8( GLint iBufferWidth,
+                                              GLint x,
+                                              GLint y )
+{
+    GLint  x106;
+    GLint  x20;
+    GLint  x53;
+    GLint  y104;
+    GLint  y20;
+    GLint  y3;
+    GLuint uiWidthInTiles;
+
+    /*
+    // calculating tiled address
+    */
+
+    uiWidthInTiles = (iBufferWidth + 63) >> 6;
+
+    x20  =  x & 0x7;
+    x53  = (x & 0x38 ) >> 3;
+    x106 = (x & 0x7c0) >> 6;
+
+    y20  =  y & 0x7;
+    y3   = (y & 8    ) >> 3;
+    y104 = (y & 0x7f0) >> 4;
+
+    return( (x20 << 1)  |
+            (y20 << 4)  |
+            (x53 << 7)  |
+            (y3  << 10) |
+            ((y104 * uiWidthInTiles) + x106) << 11 );
+}
+/* function pointer set to the correct version in savageDDInitTextureFuncs */
+GLuint (*GetTiledCoordinates16) (GLint, GLint, GLint);
+
+/* 4-pixel wide subtiles */
+static GLuint GetTiledCoordinates32_4( GLint iBufferWidth,
+                                              GLint x,
+                                              GLint y )
+{
+    GLint  x10;
+    GLint  y20;
+    GLuint uiWidthInTiles;
+    GLint  x42;
+    GLint  x105;
+    GLint  y3;
+    GLint  y104;
+
+    /*
+    // calculating tiled address
+    */
+
+    uiWidthInTiles = (iBufferWidth + 31) >> 5;
+
+    x10  =  x & 0x3;
+    x42  = (x & 0x1c ) >> 2;
+    x105 = (x & 0x7e0) >> 5;
+
+    y20  =  y & 0x7;
+    y3   = (y & 8    ) >> 3;
+    y104 = (y & 0x7f0) >> 4;
+
+    return( (x10 << 2)  |
+            (y20 << 4)  |
+            (x42 << 7)  |
+            (y3  << 10) |
+            ((y104 * uiWidthInTiles) + x105) << 11 );
+}
+/* 8-pixel wide subtiles */
+static GLuint GetTiledCoordinates32_8( GLint iBufferWidth,
+                                              GLint x,
+                                              GLint y )
+{
+    GLint  x20;
+    GLint  y20;
+    GLuint uiWidthInTiles;
+    GLint  x43;
+    GLint  x105;
+    GLint  y3;
+    GLint  y104;
+
+    /*
+    // calculating tiled address
+    */
+
+    uiWidthInTiles = (iBufferWidth + 31) >> 5;
+
+    x20  =  x & 0x7;
+    x43  = (x & 0x18 ) >> 3;
+    x105 = (x & 0x7e0) >> 5;
+
+    y20  =  y & 0x7;
+    y3   = (y & 8    ) >> 3;
+    y104 = (y & 0x7f0) >> 4;
+
+    return( (x20 << 2)  |
+            (y20 << 5)  |
+            (x43 << 8)  |
+            (y3  << 10) |
+            ((y104 * uiWidthInTiles) + x105) << 11 );
+}
+/* function pointer set to the correct version in savageDDInitTextureFuncs */
+GLuint (*GetTiledCoordinates32) (GLint, GLint, GLint);
+
+__inline GLuint GetTiledCoordinates( GLint iDepth,
+                                            GLint iBufferWidth,
+                                            GLint x,
+                                            GLint y )
+{
+    /*
+    // don't check for 4 since we only have 3 types of fb
+    */
+
+    if (iDepth == 16)
+    {
+        return( GetTiledCoordinates16( iBufferWidth, x, y ) );
+    }
+    else if (iDepth == 32)
+    {
+        return( GetTiledCoordinates32( iBufferWidth, x, y ) );
+    }
+    else
+    {
+        return( GetTiledCoordinates8( iBufferWidth, x, y ) );
+    }
+} 
+
+__inline void savageUploadImage(savageTextureObjectPtr t, GLuint level, GLuint startx, GLuint starty, GLuint reloc)
+{
+    GLuint uMaxTileWidth = gTileWidth[t->texelBytes]; 
+    GLuint x, y, w, row, col;    
+    const struct gl_texture_image *image = t->image[level].image;
+    GLubyte * dst, * src, * pBuffer;
+    GLint xAdd, yAdd;
+    GLuint uRowSeparator, uChunk = MIN_TILE_CHUNK, uWrap;
+
+  
+    pBuffer = (GLubyte *)(t->BufAddr + t->image[level].offset);
+    src = (GLubyte *)image->Data;
+    x = startx;
+    y = starty;
+    w = image->Width;
+
+    if(image->Format ==  GL_COLOR_INDEX)
+    {
+        if(w < MIN_TILE_CHUNK)
+       {
+            w = MIN_TILE_CHUNK;
+        }
+        else
+        {
+           if((w > 64 ) && (image->Height <= 16))
+            {
+                reloc = GL_TRUE;
+                 if(image->Height == 16)
+                {
+                    uChunk = MIN_TILE_CHUNK << 1;
+                }
+           }
+       }  
+
+       if(!reloc & (w > (64 / 2)))
+       {
+           for(row = 0; row < image->Height; row++)
+           {
+               for(col = 0; col < image->Width; col++)    
+               {
+                   dst = pBuffer + GetTiledCoordinates(t->texelBytes << 3, w, x + col, y + row);
+                   memcpy (dst, src, t->texelBytes);
+                   src += t->texelBytes;
+                }
+           }
+       }
+        else
+        {
+           if(reloc & (w > 64))
+           {
+             uWrap = ((w + 63) >> 6) - 1;
+               for(row = 0; row < image->Height; row++)
+               {
+                   for(col = 0; col < image->Width; col++)    
+                   {
+                       xAdd = (col / (4 * 64)) * 64 + col % 64;
+                        yAdd = row + ((col / 64) & 3) * uChunk;
+                       dst = pBuffer + GetTiledCoordinates(t->texelBytes << 3, 64, x + xAdd, y + yAdd);
+                       memcpy (dst, src, t->texelBytes);
+                       src += t->texelBytes;
+                    }
+               }
+           }
+            else
+           {
+               uRowSeparator = 64 * MIN_TILE_CHUNK / w;
+               for(row = 0; row < image->Height; row++)
+               {
+                   xAdd = (w * (row / MIN_TILE_CHUNK)) % 64;
+                    yAdd = row % MIN_TILE_CHUNK + MIN_TILE_CHUNK * (row / uRowSeparator);
+                   for(col = 0; col < image->Width; col++)    
+                   {
+                       dst = pBuffer + GetTiledCoordinates(t->texelBytes << 3, w, x + xAdd, y + yAdd);
+                       memcpy (dst, src, t->texelBytes);
+                       src += t->texelBytes;
+                    }
+               }
+           }
+        }
+    }
+    else
+    {
+        if(w < MIN_TILE_CHUNK)
+       {
+            w = MIN_TILE_CHUNK;
+        }
+        else
+        {
+           if((w > uMaxTileWidth ) && (image->Height <= 8))
+            {
+                reloc = GL_TRUE;
+           }
+       }
+       if(!reloc & (w > uMaxTileWidth / 2))
+       {
+           for(row = 0; row < image->Height; row++)
+           {
+               for(col = 0; col < image->Width; col++)    
+               {
+                   dst = pBuffer + GetTiledCoordinates(t->texelBytes << 3, w, x + col, y + row);
+                   memcpy (dst, src, t->texelBytes);
+                   src += t->texelBytes;
+                }
+           }
+       }
+        else
+        {
+           if(reloc & (w > uMaxTileWidth))
+           {
+               for(row = 0; row < image->Height; row++)
+               {
+                   for(col = 0; col < image->Width; col++)    
+                   {
+                       xAdd = (col / (2 * uMaxTileWidth)) * uMaxTileWidth + col % uMaxTileWidth;
+                        yAdd = row + ((col / uMaxTileWidth) & 1) * MIN_TILE_CHUNK;
+                       dst = pBuffer + GetTiledCoordinates(t->texelBytes << 3, w, x + xAdd, y + yAdd);
+                       memcpy (dst, src, t->texelBytes);
+                       src += t->texelBytes;
+                    }
+               }
+           }
+            else
+           {
+               uRowSeparator = uMaxTileWidth * MIN_TILE_CHUNK / w;
+               for(row = 0; row < image->Height; row++)
+               {
+                    yAdd = row % MIN_TILE_CHUNK + MIN_TILE_CHUNK * (row / uRowSeparator);
+                    xAdd = (w * (row / MIN_TILE_CHUNK)) % uMaxTileWidth;
+                   for(col = 0; col < image->Width; col++)    
+                   {
+                       dst = pBuffer + GetTiledCoordinates(t->texelBytes << 3, w, x + col + xAdd, y + yAdd);
+                       memcpy (dst, src, t->texelBytes);
+                       src += t->texelBytes;
+                    }
+               }
+           }
+        }
+    }
+}        
+
+
+
+__inline void  savageTileTex(savageTextureObjectPtr tex, GLuint level)
+{
+    GLuint uWidth, uHeight;
+    GLint  xOffset, yOffset;
+    GLint  xStart=0, yStart=0;
+    GLint  minSize;
+    GLuint xRepeat, yRepeat;
+    GLuint startCol, startRow;
+    GLuint reloc;
+
+    const struct gl_texture_image *image = tex->image[level].image;
+    
+    reloc = GL_FALSE;
+    uWidth = image->Width2;
+    uHeight = image->Height2;
+
+    if((uWidth > 4) || (uHeight > 4))
+        minSize = MIN_TILE_CHUNK;
+    else
+        minSize = MIPMAP_CHUNK;
+    if(image->Width >= minSize)
+        xRepeat = 1;
+    else
+        xRepeat = minSize / image->Width;
+
+    if(image->Height >= minSize)
+        yRepeat = 1;
+    else
+    {
+        yRepeat = minSize / image->Height;
+        if(minSize == MIN_TILE_CHUNK)
+            reloc = GL_TRUE;
+    }
+  
+    if(((uWidth < 4) && (uHeight < 4)) && (tex->texelBytes >= 2))
+    { 
+        if((uWidth == 2) || (uHeight == 2))
+        {
+            xStart = 4;
+            yStart = 0;
+        }
+
+        else
+        {
+            xStart = 4;
+            yStart = 4;
+        }
+    }
+    for(xOffset = 0; xOffset < xRepeat; xOffset++)
+    {
+        for(yOffset = 0; yOffset < yRepeat; yOffset++)
+        {
+           startCol = image->Width * xOffset + xStart;
+            startRow = image->Height * yOffset + yStart;
+            savageUploadImage(tex,level, startCol, startRow, reloc);
+       }
+    }
+}
+
+static void savageSetTexWrapping(savageTextureObjectPtr tex, GLenum s, GLenum t)
+{
+    tex->texParams.sWrapMode = s;
+    tex->texParams.tWrapMode = t;
+}
+
+static void savageSetTexFilter(savageTextureObjectPtr t, 
+                              GLenum minf, GLenum magf)
+{
+   t->texParams.minFilter = minf;
+   t->texParams.magFilter = magf;
+}
+
+
+/* Need a fallback ?
+ */
+static void savageSetTexBorderColor(savageTextureObjectPtr t, GLubyte color[4])
+{
+/*    t->Setup[SAVAGE_TEXREG_TEXBORDERCOL] =  */
+      t->texParams.boarderColor = SAVAGEPACKCOLOR8888(color[0],color[1],color[2],color[3]); 
+}
+
+
+
+static savageTextureObjectPtr
+savageAllocTexObj( struct gl_texture_object *texObj ) 
+{
+   savageTextureObjectPtr t;
+
+   t = (savageTextureObjectPtr) calloc(1,sizeof(*t));
+   texObj->DriverData = t;
+   if ( t != NULL ) {
+
+      /* Initialize non-image-dependent parts of the state:
+       */
+      t->globj = texObj;
+
+      /* FIXME Something here to set initial values for other parts of
+       * FIXME t->setup?
+       */
+  
+      make_empty_list( t );
+
+      savageSetTexWrapping(t,texObj->WrapS,texObj->WrapT);
+      savageSetTexFilter(t,texObj->MinFilter,texObj->MagFilter);
+      savageSetTexBorderColor(t,texObj->_BorderChan);
+   }
+
+   return t;
+}
+
+/* Called by the _mesa_store_teximage[123]d() functions. */
+static const struct gl_texture_format *
+savageChooseTextureFormat( GLcontext *ctx, GLint internalFormat,
+                          GLenum format, GLenum type )
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+   const GLboolean do32bpt = GL_FALSE;
+   const GLboolean force16bpt = GL_FALSE;
+   const GLboolean isSavage4 = (imesa->savageScreen->chipset >= S3_SAVAGE4);
+   (void) format;
+   (void) type;
+
+   switch ( internalFormat ) {
+   case 4:
+   case GL_RGBA:
+   case GL_COMPRESSED_RGBA:
+      switch ( type ) {
+      case GL_UNSIGNED_INT_10_10_10_2:
+      case GL_UNSIGNED_INT_2_10_10_10_REV:
+        return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555;
+      case GL_UNSIGNED_SHORT_4_4_4_4:
+      case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+        return &_mesa_texformat_argb4444;
+      case GL_UNSIGNED_SHORT_5_5_5_1:
+      case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+        return &_mesa_texformat_argb1555;
+      default:
+         return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
+      }
+
+   case 3:
+   case GL_RGB:
+   case GL_COMPRESSED_RGB:
+      switch ( type ) {
+      case GL_UNSIGNED_SHORT_4_4_4_4:
+      case GL_UNSIGNED_SHORT_4_4_4_4_REV:
+        return &_mesa_texformat_argb4444;
+      case GL_UNSIGNED_SHORT_5_5_5_1:
+      case GL_UNSIGNED_SHORT_1_5_5_5_REV:
+        return &_mesa_texformat_argb1555;
+      case GL_UNSIGNED_SHORT_5_6_5:
+      case GL_UNSIGNED_SHORT_5_6_5_REV:
+        return &_mesa_texformat_rgb565;
+      default:
+         return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
+      }
+
+   case GL_RGBA8:
+   case GL_RGBA12:
+   case GL_RGBA16:
+      return !force16bpt ?
+         &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
+
+   case GL_RGB10_A2:
+      return !force16bpt ?
+         &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555;
+
+   case GL_RGBA4:
+   case GL_RGBA2:
+      return &_mesa_texformat_argb4444;
+
+   case GL_RGB5_A1:
+      return &_mesa_texformat_argb1555;
+
+   case GL_RGB8:
+   case GL_RGB10:
+   case GL_RGB12:
+   case GL_RGB16:
+      return !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565;
+
+   case GL_RGB5:
+   case GL_RGB4:
+   case GL_R3_G3_B2:
+      return &_mesa_texformat_rgb565;
+
+   case GL_ALPHA:
+   case GL_COMPRESSED_ALPHA:
+      return isSavage4 ? &_mesa_texformat_a8 : (
+        do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444);
+   case GL_ALPHA4:
+      return isSavage4 ? &_mesa_texformat_a8 : &_mesa_texformat_argb4444;
+   case GL_ALPHA8:
+   case GL_ALPHA12:
+   case GL_ALPHA16:
+      return isSavage4 ? &_mesa_texformat_a8 : (
+        !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444);
+
+   case 1:
+   case GL_LUMINANCE:
+   case GL_COMPRESSED_LUMINANCE:
+      /* no alpha, but use argb1555 in 16bit case to get pure grey values */
+      return isSavage4 ? &_mesa_texformat_l8 : (
+        do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555);
+   case GL_LUMINANCE4:
+      return isSavage4 ? &_mesa_texformat_l8 : &_mesa_texformat_argb1555;
+   case GL_LUMINANCE8:
+   case GL_LUMINANCE12:
+   case GL_LUMINANCE16:
+      return isSavage4 ? &_mesa_texformat_l8 : (
+        !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb1555);
+
+   case 2:
+   case GL_LUMINANCE_ALPHA:
+   case GL_COMPRESSED_LUMINANCE_ALPHA:
+      /* Savage4 has a al44 texture format. But it's not supported by Mesa. */
+      return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
+   case GL_LUMINANCE4_ALPHA4:
+   case GL_LUMINANCE6_ALPHA2:
+      return &_mesa_texformat_argb4444;
+   case GL_LUMINANCE8_ALPHA8:
+   case GL_LUMINANCE12_ALPHA4:
+   case GL_LUMINANCE12_ALPHA12:
+   case GL_LUMINANCE16_ALPHA16:
+      return !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
+
+   case GL_INTENSITY:
+   case GL_COMPRESSED_INTENSITY:
+      return isSavage4 ? &_mesa_texformat_i8 : (
+        do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444);
+   case GL_INTENSITY4:
+      return isSavage4 ? &_mesa_texformat_i8 : &_mesa_texformat_argb4444;
+   case GL_INTENSITY8:
+   case GL_INTENSITY12:
+   case GL_INTENSITY16:
+      return isSavage4 ? &_mesa_texformat_i8 : (
+        !force16bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444);
+/*
+   case GL_COLOR_INDEX:
+   case GL_COLOR_INDEX1_EXT:
+   case GL_COLOR_INDEX2_EXT:
+   case GL_COLOR_INDEX4_EXT:
+   case GL_COLOR_INDEX8_EXT:
+   case GL_COLOR_INDEX12_EXT:
+   case GL_COLOR_INDEX16_EXT:
+      return &_mesa_texformat_ci8;
+*/
+   default:
+      _mesa_problem(ctx, "unexpected texture format in %s", __FUNCTION__);
+      return NULL;
+   }
+}
+
+static void savageSetTexImages( savageContextPtr imesa,
+                               const struct gl_texture_object *tObj )
+{
+   savageTextureObjectPtr t = (savageTextureObjectPtr) tObj->DriverData;
+   struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
+   GLuint offset, width, pitch, i, textureFormat, log_pitch;
+
+   assert(t);
+   assert(image);
+
+   switch (image->TexFormat->MesaFormat) {
+   case MESA_FORMAT_ARGB8888:
+      textureFormat = TFT_ARGB8888;
+      t->texelBytes = 4;
+      break;
+   case MESA_FORMAT_ARGB1555:
+      textureFormat = TFT_ARGB1555;
+      t->texelBytes = 2;
+      break;
+   case MESA_FORMAT_ARGB4444:
+      textureFormat = TFT_ARGB4444;
+      t->texelBytes = 2;
+      break;
+   case MESA_FORMAT_RGB565:
+      textureFormat = TFT_RGB565;
+      t->texelBytes = 2;
+      break;
+   case MESA_FORMAT_L8:
+      textureFormat = TFT_L8;
+      t->texelBytes = 1;
+      break;
+   case MESA_FORMAT_I8:
+      textureFormat = TFT_I8;
+      t->texelBytes = 1;
+      break;
+   case MESA_FORMAT_A8:
+      textureFormat = TFT_A8;
+      t->texelBytes = 1;
+      break;
+   default:
+      _mesa_problem(imesa->glCtx, "Bad texture format in %s", __FUNCTION__);
+   }
+
+   /* Figure out the size now (and count the levels).  Upload won't be done
+    * until later.
+    */ 
+   width = image->Width * t->texelBytes;
+   for (pitch = 2, log_pitch=1 ; pitch < width ; pitch *= 2 )
+      log_pitch++;
+   
+   t->dirty_images = 0;
+   t->bound = 0;
+
+   offset = 0;
+   for ( i = 0 ; i < SAVAGE_TEX_MAXLEVELS && tObj->Image[0][i] ; i++ ) {
+      t->image[i].image = tObj->Image[0][i];
+      t->image[i].offset = offset;
+      t->image[i].internalFormat = textureFormat;
+      t->dirty_images |= (1<<i);
+      offset += t->image[i].image->Height * pitch;
+      pitch = pitch >> 1;
+   }
+
+   t->totalSize = offset;
+   t->max_level = i-1;
+   t->min_level = 0;
+}
+
+void savageDestroyTexObj(savageContextPtr imesa, savageTextureObjectPtr t)
+{
+   if (!t) return;
+
+   /* This is sad - need to sync *in case* we upload a texture
+    * to this newly free memory...
+    */
+   if (t->MemBlock) {
+      mmFreeMem(t->MemBlock);
+      t->MemBlock = 0;
+
+      if (t->age > imesa->dirtyAge)
+        imesa->dirtyAge = t->age;
+   }
+
+   if (t->globj)
+      t->globj->DriverData = 0;
+
+   if (t->bound)
+      imesa->CurrentTexObj[t->bound - 1] = 0; 
+
+   remove_from_list(t);
+   free(t);
+}
+
+
+static void savageSwapOutTexObj(savageContextPtr imesa, savageTextureObjectPtr t)
+{
+   if (t->MemBlock) {
+      mmFreeMem(t->MemBlock);
+      t->MemBlock = 0;      
+
+      if (t->age > imesa->dirtyAge)
+        imesa->dirtyAge = t->age;
+   }
+
+   t->dirty_images = ~0;
+   move_to_tail(&(imesa->SwappedOut), t);
+}
+
+
+
+/* Upload an image from mesa's internal copy.
+ */
+static void savageUploadTexLevel( savageTextureObjectPtr t, int level )
+{
+   const struct gl_texture_image *image = t->image[level].image;
+
+
+   /* Need triangle (rather than pixel) fallbacks to simulate this using
+    * normal textured triangles.
+    *
+    * DO THIS IN DRIVER STATE MANAGMENT, not hardware state.
+    * 
+    */
+
+   if(image->Border != 0) 
+       fprintf (stderr, "Not supported texture border %d.\n",
+               (int) image->Border);
+
+   savageTileTex(t, level);
+}
+
+
+
+void savagePrintLocalLRU( savageContextPtr imesa , GLuint heap) 
+{
+   savageTextureObjectPtr t;
+   int sz = 1 << (imesa->savageScreen->logTextureGranularity[heap]);
+   
+   foreach( t, &imesa->TexObjList[heap] ) {
+      if (!t->globj)
+        fprintf(stderr, "Placeholder %d at %x sz %x\n", 
+                t->MemBlock->ofs / sz,
+                t->MemBlock->ofs,
+                t->MemBlock->size);      
+      else
+        fprintf(stderr, "Texture (bound %d) at %x sz %x\n", 
+                t->bound,
+                t->MemBlock->ofs,
+                t->MemBlock->size);      
+
+   }
+}
+
+void savagePrintGlobalLRU( savageContextPtr imesa , GLuint heap)
+{
+   int i, j;
+
+   drm_savage_tex_region_t *list = imesa->sarea->texList[heap];
+   
+
+   for (i = 0, j = SAVAGE_NR_TEX_REGIONS ; i < SAVAGE_NR_TEX_REGIONS ; i++) {
+      fprintf(stderr, "list[%d] age %d next %d prev %d\n",
+             j, list[j].age, list[j].next, list[j].prev);
+      j = list[j].next;
+      if (j == SAVAGE_NR_TEX_REGIONS) break;
+   }
+   
+   if (j != SAVAGE_NR_TEX_REGIONS)
+      fprintf(stderr, "Loop detected in global LRU\n");
+       for (i = 0 ; i < SAVAGE_NR_TEX_REGIONS ; i++) 
+       {
+          fprintf(stderr,"list[%d] age %d next %d prev %d\n",
+          i, list[i].age, list[i].next, list[i].prev);
+       }
+}
+
+
+void savageResetGlobalLRU( savageContextPtr imesa, GLuint heap )
+{
+    drm_savage_tex_region_t *list = imesa->sarea->texList[heap];
+   int sz = 1 << imesa->savageScreen->logTextureGranularity[heap];
+   int i;
+
+   /* (Re)initialize the global circular LRU list.  The last element
+    * in the array (SAVAGE_NR_TEX_REGIONS) is the sentinal.  Keeping it
+    * at the end of the array allows it to be addressed rationally
+    * when looking up objects at a particular location in texture
+    * memory.  
+    */
+   for (i = 0 ; (i+1) * sz <= imesa->savageScreen->textureSize[heap]; i++) {
+      list[i].prev = i-1;
+      list[i].next = i+1;
+      list[i].age = 0;
+   }
+
+   i--;
+   list[0].prev = SAVAGE_NR_TEX_REGIONS;
+   list[i].prev = i-1;
+   list[i].next = SAVAGE_NR_TEX_REGIONS;
+   list[SAVAGE_NR_TEX_REGIONS].prev = i;
+   list[SAVAGE_NR_TEX_REGIONS].next = 0;
+   imesa->sarea->texAge[heap] = 0;
+}
+
+
+static void savageUpdateTexLRU( savageContextPtr imesa, savageTextureObjectPtr t ) 
+{
+   int i;
+   int heap = t->heap;
+   int logsz = imesa->savageScreen->logTextureGranularity[heap];
+   int start = t->MemBlock->ofs >> logsz;
+   int end = (t->MemBlock->ofs + t->MemBlock->size - 1) >> logsz;
+   drm_savage_tex_region_t *list = imesa->sarea->texList[heap];
+   
+   imesa->texAge[heap] = ++imesa->sarea->texAge[heap];
+
+   /* Update our local LRU
+    */
+   move_to_head( &(imesa->TexObjList[heap]), t );
+
+   /* Update the global LRU
+    */
+   for (i = start ; i <= end ; i++) {
+
+      list[i].in_use = 1;
+      list[i].age = imesa->texAge[heap];
+
+      /* remove_from_list(i)
+       */
+      list[(unsigned)list[i].next].prev = list[i].prev;
+      list[(unsigned)list[i].prev].next = list[i].next;
+      
+      /* insert_at_head(list, i)
+       */
+      list[i].prev = SAVAGE_NR_TEX_REGIONS;
+      list[i].next = list[SAVAGE_NR_TEX_REGIONS].next;
+      list[(unsigned)list[SAVAGE_NR_TEX_REGIONS].next].prev = i;
+      list[SAVAGE_NR_TEX_REGIONS].next = i;
+   }
+}
+
+
+/* Called for every shared texture region which has increased in age
+ * since we last held the lock.
+ *
+ * Figures out which of our textures have been ejected by other clients,
+ * and pushes a placeholder texture onto the LRU list to represent 
+ * the other client's textures.  
+ */
+void savageTexturesGone( savageContextPtr imesa,
+                      GLuint heap,
+                      GLuint offset, 
+                      GLuint size,
+                      GLuint in_use ) 
+{
+   savageTextureObjectPtr t, tmp;
+   
+   foreach_s ( t, tmp, &imesa->TexObjList[heap] ) {
+
+      if (t->MemBlock->ofs >= offset + size ||
+         t->MemBlock->ofs + t->MemBlock->size <= offset)
+        continue;
+
+      /* It overlaps - kick it off.  Need to hold onto the currently bound
+       * objects, however.
+       */
+      if (t->bound)
+        savageSwapOutTexObj( imesa, t );
+      else
+        savageDestroyTexObj( imesa, t );
+   }
+
+   
+   if (in_use) {
+      t = (savageTextureObjectPtr) calloc(1,sizeof(*t));
+      if (!t) return;
+
+      t->heap = heap;
+      t->MemBlock = mmAllocMem( imesa->texHeap[heap], size, 0, offset);      
+      if(!t->MemBlock)
+      {
+          free(t);
+          return;
+      }
+      insert_at_head( &imesa->TexObjList[heap], t );
+   }
+}
+
+
+
+
+
+/* This is called with the lock held.  May have to eject our own and/or
+ * other client's texture objects to make room for the upload.
+ */
+int savageUploadTexImages( savageContextPtr imesa, savageTextureObjectPtr t )
+{
+   int heap;
+   int i;
+   int ofs;
+   
+   heap = t->heap = SAVAGE_CARD_HEAP;
+
+   /* Do we need to eject LRU texture objects?
+    */
+   if (!t->MemBlock) {
+      while (1)
+      {
+        t->MemBlock = mmAllocMem( imesa->texHeap[heap], t->totalSize, 12, 0 ); 
+        if (t->MemBlock)
+           break;
+        else
+        {
+            heap = t->heap = SAVAGE_AGP_HEAP;
+            t->MemBlock = mmAllocMem( imesa->texHeap[heap], t->totalSize, 12, 0 ); 
+            
+            if (t->MemBlock)
+                break;
+        }
+
+        if (imesa->TexObjList[heap].prev->bound) {
+           fprintf(stderr, "Hit bound texture in upload\n"); 
+           savagePrintLocalLRU( imesa,heap );
+           return -1;
+        }
+
+        if (imesa->TexObjList[heap].prev == &(imesa->TexObjList[heap])) {
+           fprintf(stderr, "Failed to upload texture, sz %d\n", t->totalSize);
+           mmDumpMemInfo( imesa->texHeap[heap] );
+           return -1;
+        }
+        
+        savageDestroyTexObj( imesa, imesa->TexObjList[heap].prev );
+      }
+      ofs = t->MemBlock->ofs;
+      t->texParams.hwPhysAddress = imesa->savageScreen->textureOffset[heap] + ofs;
+      t->BufAddr = (char *)((GLuint) imesa->savageScreen->texVirtual[heap] + ofs);
+      imesa->dirty |= SAVAGE_UPLOAD_CTX;
+   }
+
+   /* Let the world know we've used this memory recently.
+    */
+   savageUpdateTexLRU( imesa, t );
+
+   if (t->dirty_images) {
+      if (SAVAGE_DEBUG & DEBUG_VERBOSE_LRU)
+        fprintf(stderr, "*");
+
+      for (i = t->min_level ; i <= t->max_level ; i++)
+        if (t->dirty_images & (1<<i)) 
+           savageUploadTexLevel( t, i );
+   }
+
+
+   t->dirty_images = 0;
+   return 0;
+}
+
+static void savageTexSetUnit( savageTextureObjectPtr t, GLuint unit )
+{
+   if (t->current_unit == unit) return;
+
+   t->current_unit = unit;
+}
+
+
+
+
+static void savageUpdateTex0State_s4( GLcontext *ctx )
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+   struct gl_texture_object    *tObj;
+   savageTextureObjectPtr t;
+   GLuint format;
+   Reg_TexCtrl TexCtrl;
+   Reg_TexBlendCtrl TexBlendCtrl;
+   Reg_TexDescr TexDescr; 
+
+   /* disable */
+   
+   if (ctx->Texture.Unit[0]._ReallyEnabled == 0) {
+      imesa->Registers.TexDescr.s4.tex0En = GL_FALSE;
+      imesa->Registers.TexBlendCtrl[0].ui = TBC_NoTexMap;
+      imesa->Registers.TexCtrl[0].ui = 0x20f040;
+      imesa->Registers.TexAddr[0].ui = 0;
+      imesa->Registers.changed.ni.fTex0BlendCtrlChanged = GL_TRUE;
+      imesa->Registers.changed.ni.fTex0AddrChanged = GL_TRUE;
+      imesa->Registers.changed.ni.fTexDescrChanged = GL_TRUE;
+      imesa->Registers.changed.ni.fTex0CtrlChanged = GL_TRUE;
+      return;
+   }
+
+   tObj = ctx->Texture.Unit[0]._Current;
+   if (ctx->Texture.Unit[0]._ReallyEnabled != TEXTURE_2D_BIT ||
+       tObj->Image[0][tObj->BaseLevel]->Border > 0) {
+      /* 1D or 3D texturing enabled, or texture border - fallback */
+      FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE);
+      return;
+   }
+
+   /* Do 2D texture setup */
+
+   t = tObj->DriverData;
+   if (!t) {
+      t = savageAllocTexObj( tObj );
+      if (!t)
+         return;
+   }
+
+   if (t->current_unit != 0)
+      savageTexSetUnit( t, 0 );
+    
+   imesa->CurrentTexObj[0] = t;
+   t->bound = 1;
+
+   if (t->dirty_images) {
+       savageSetTexImages(imesa, tObj);
+       savageUploadTexImages(imesa, imesa->CurrentTexObj[0]); 
+   }
+   
+   if (t->MemBlock)
+      savageUpdateTexLRU( imesa, t );
+  
+   TexDescr.ui     = imesa->Registers.TexDescr.ui & ~0x01000000;
+   TexCtrl.ui      = imesa->Registers.TexCtrl[0].ui;
+   TexBlendCtrl.ui = imesa->Registers.TexBlendCtrl[0].ui;
+
+   format = tObj->Image[0][tObj->BaseLevel]->Format;
+
+   switch (ctx->Texture.Unit[0].EnvMode) {
+   case GL_REPLACE:
+      TexCtrl.s4.clrArg1Invert = GL_FALSE;
+      switch(format)
+      {
+          case GL_LUMINANCE:
+          case GL_RGB:
+               TexBlendCtrl.ui = TBC_Decal;
+               break;
+
+          case GL_LUMINANCE_ALPHA:
+          case GL_RGBA:
+          case GL_INTENSITY:
+               TexBlendCtrl.ui = TBC_Copy;
+               break;
+
+          case GL_ALPHA:
+               TexBlendCtrl.ui = TBC_CopyAlpha;
+               break;
+      }
+       __HWEnvCombineSingleUnitScale(imesa, 0, 0, &TexBlendCtrl);
+      break;
+
+    case GL_DECAL:
+        TexCtrl.s4.clrArg1Invert = GL_FALSE;
+        switch (format)
+        {
+            case GL_RGB:
+            case GL_LUMINANCE:
+                TexBlendCtrl.ui = TBC_Decal;
+                break;
+
+            case GL_RGBA:
+            case GL_INTENSITY:
+            case GL_LUMINANCE_ALPHA:
+                TexBlendCtrl.ui = TBC_DecalAlpha;
+                break;
+
+            /*
+             GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_INTENSITY
+             are undefined with GL_DECAL
+            */
+
+            case GL_ALPHA:
+                TexBlendCtrl.ui = TBC_CopyAlpha;
+                break;
+        }
+        __HWEnvCombineSingleUnitScale(imesa, 0, 0, &TexBlendCtrl);
+        break;
+
+    case GL_MODULATE:
+        TexCtrl.s4.clrArg1Invert = GL_FALSE;
+        TexBlendCtrl.ui = TBC_ModulAlpha;
+        __HWEnvCombineSingleUnitScale(imesa, 0, 0, &TexBlendCtrl);
+        break;
+
+    case GL_BLEND:
+
+        switch (format)
+        {
+            case GL_ALPHA:
+                TexBlendCtrl.ui = TBC_ModulAlpha;
+                TexCtrl.s4.clrArg1Invert = GL_FALSE;
+                break;
+
+            case GL_LUMINANCE:
+            case GL_RGB:
+                TexBlendCtrl.ui = TBC_Blend0;
+                TexDescr.s4.tex1En = GL_TRUE;
+                TexDescr.s4.texBLoopEn = GL_TRUE;
+                TexDescr.s4.tex1Width  = TexDescr.s4.tex0Width;
+                TexDescr.s4.tex1Height = TexDescr.s4.tex0Height;
+                TexDescr.s4.tex1Fmt = TexDescr.s4.tex0Fmt;
+
+                if (imesa->Registers.TexAddr[1].ui != imesa->Registers.TexAddr[0].ui)
+                {
+                    imesa->Registers.TexAddr[1].ui = imesa->Registers.TexAddr[0].ui;
+                    imesa->Registers.changed.ni.fTex1AddrChanged = GL_TRUE;
+                }
+
+                if (imesa->Registers.TexBlendCtrl[1].ui != TBC_Blend1)
+                {
+                    imesa->Registers.TexBlendCtrl[1].ui = TBC_Blend1;
+                    imesa->Registers.changed.ni.fTex1BlendCtrlChanged = GL_TRUE;
+                }
+
+                TexCtrl.s4.clrArg1Invert = GL_TRUE;
+                imesa->bTexEn1 = GL_TRUE;
+                break;
+
+            case GL_LUMINANCE_ALPHA:
+            case GL_RGBA:
+                TexBlendCtrl.ui = TBC_BlendAlpha0;
+                TexDescr.s4.tex1En = GL_TRUE;
+                TexDescr.s4.texBLoopEn = GL_TRUE;
+                TexDescr.s4.tex1Width  = TexDescr.s4.tex0Width;
+                TexDescr.s4.tex1Height = TexDescr.s4.tex0Height;
+                TexDescr.s4.tex1Fmt = TexDescr.s4.tex0Fmt;
+
+                if (imesa->Registers.TexAddr[1].ui != imesa->Registers.TexAddr[0].ui)
+                {
+                    imesa->Registers.TexAddr[1].ui = imesa->Registers.TexAddr[0].ui;
+                    imesa->Registers.changed.ni.fTex1AddrChanged = GL_TRUE;
+                }
+
+                if (imesa->Registers.TexBlendCtrl[1].ui != TBC_BlendAlpha1)
+                {
+                    imesa->Registers.TexBlendCtrl[1].ui = TBC_BlendAlpha1;
+                    imesa->Registers.changed.ni.fTex1BlendCtrlChanged = GL_TRUE;
+                }
+
+                TexCtrl.s4.clrArg1Invert = GL_TRUE;
+                imesa->bTexEn1 = GL_TRUE;
+                break;
+
+            case GL_INTENSITY:
+                TexBlendCtrl.ui = TBC_BlendInt0;
+                TexDescr.s4.tex1En = GL_TRUE;
+                TexDescr.s4.texBLoopEn = GL_TRUE;
+                TexDescr.s4.tex1Width  = TexDescr.s4.tex0Width;
+                TexDescr.s4.tex1Height = TexDescr.s4.tex0Height;
+                TexDescr.s4.tex1Fmt = TexDescr.s4.tex0Fmt;
+
+                if (imesa->Registers.TexAddr[1].ui != imesa->Registers.TexAddr[0].ui)
+                {
+                    imesa->Registers.TexAddr[1].ui = imesa->Registers.TexAddr[0].ui;
+                    imesa->Registers.changed.ni.fTex1AddrChanged = GL_TRUE;
+                }
+
+                if (imesa->Registers.TexBlendCtrl[1].ui != TBC_BlendInt1)
+                {
+                    imesa->Registers.TexBlendCtrl[1].ui = TBC_BlendInt1;
+                    imesa->Registers.changed.ni.fTex1BlendCtrlChanged = GL_TRUE;
+                }
+                TexCtrl.s4.clrArg1Invert = GL_TRUE;
+                TexCtrl.s4.alphaArg1Invert = GL_TRUE;
+                imesa->bTexEn1 = GL_TRUE;
+                break;
+        }
+        __HWEnvCombineSingleUnitScale(imesa, 0, 0, &TexBlendCtrl);
+        break;
+
+        /*
+         GL_ADD
+        */
+    case GL_ADD:
+        printf("Add\n");
+        TexCtrl.s4.clrArg1Invert = GL_FALSE;
+        TexBlendCtrl.ui = TBC_AddAlpha;
+        __HWEnvCombineSingleUnitScale(imesa, 0, 0, &TexBlendCtrl);
+        break;
+
+#if GL_ARB_texture_env_combine
+    case GL_COMBINE_ARB:
+        __HWParseTexEnvCombine(imesa, 0, &TexCtrl, &TexBlendCtrl);
+        break;
+#endif
+
+   default:
+      fprintf(stderr, "unknown tex env mode");
+      exit(1);
+      break;                   
+   }
+
+    TexCtrl.s4.uMode = !(t->texParams.sWrapMode & 0x01);
+    TexCtrl.s4.vMode = !(t->texParams.tWrapMode & 0x01);
+
+    switch (t->texParams.minFilter)
+    {
+        case GL_NEAREST:
+            TexCtrl.s4.filterMode   = TFM_Point;
+            TexCtrl.s4.mipmapEnable = GL_FALSE;
+            break;
+
+        case GL_LINEAR:
+            TexCtrl.s4.filterMode   = TFM_Bilin;
+            TexCtrl.s4.mipmapEnable = GL_FALSE;
+            break;
+
+        case GL_NEAREST_MIPMAP_NEAREST:
+            TexCtrl.s4.filterMode   = TFM_Point;
+            TexCtrl.s4.mipmapEnable = GL_TRUE;
+            break;
+
+        case GL_LINEAR_MIPMAP_NEAREST:
+            TexCtrl.s4.filterMode   = TFM_Bilin;
+            TexCtrl.s4.mipmapEnable = GL_TRUE;
+            break;
+
+        case GL_NEAREST_MIPMAP_LINEAR:
+        case GL_LINEAR_MIPMAP_LINEAR:
+            TexCtrl.s4.filterMode   = TFM_Trilin;
+            TexCtrl.s4.mipmapEnable = GL_TRUE;
+            break;
+    }
+
+    if((ctx->Texture.Unit[0].LodBias !=0.0F) && (TexCtrl.s4.dBias != 0))
+    {
+       union {
+           GLfloat f;
+           GLint i;
+       } bias;
+       GLuint  ul;
+       
+       bias.f = ctx->Texture.Unit[0].LodBias;
+       
+       /* if the value is >= 15.9375 determine whether >= 16
+          or <0
+       */
+       if(((bias.i) & 0x7FFFFFFF) >= 0x417F0000)
+       {
+           if((bias.i) & 0x80000000)
+           {
+               ul=0x101;
+           }
+           else
+           {
+               ul=0xff;
+           }
+       }
+       else
+       {
+            ul=(GLuint)(bias.f*16.0);
+        }
+        
+        ul &= 0x1FF;
+        TexCtrl.s4.dBias = ul;
+    }
+
+    TexDescr.s4.tex0En = GL_TRUE;
+    TexDescr.s4.tex0Width  = t->image[0].image->WidthLog2;
+    TexDescr.s4.tex0Height = t->image[0].image->HeightLog2;
+    TexDescr.s4.tex0Fmt = t->image[0].internalFormat;
+    TexCtrl.s4.dMax = t->max_level;
+
+    if (TexDescr.s4.tex1En)
+        TexDescr.s4.texBLoopEn = GL_TRUE;
+
+    if (imesa->Registers.TexAddr[0].ui != (GLuint)t->texParams.hwPhysAddress)
+    {
+        imesa->Registers.TexAddr[0].ui = (GLuint) t->texParams.hwPhysAddress | 0x2;
+        
+        if(t->heap == SAVAGE_AGP_HEAP)
+            imesa->Registers.TexAddr[0].ui |= 0x1;
+            
+        imesa->Registers.changed.ni.fTex0AddrChanged = GL_TRUE;
+    }
+
+    if (imesa->Registers.TexCtrl[0].ui != TexCtrl.ui)
+    {
+        imesa->Registers.TexCtrl[0].ui = TexCtrl.ui;
+        imesa->Registers.changed.ni.fTex0CtrlChanged = GL_TRUE;
+    }
+
+    if (imesa->Registers.TexBlendCtrl[0].ui != TexBlendCtrl.ui)
+    {
+        imesa->Registers.TexBlendCtrl[0].ui = TexBlendCtrl.ui;
+        imesa->Registers.changed.ni.fTex0BlendCtrlChanged = GL_TRUE;
+    }
+
+    if (imesa->Registers.TexDescr.ui != TexDescr.ui)
+    {
+        imesa->Registers.TexDescr.ui = TexDescr.ui;
+        imesa->Registers.changed.ni.fTexDescrChanged = GL_TRUE;
+    }
+
+   return;
+}
+static void savageUpdateTex1State_s4( GLcontext *ctx )
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+   struct gl_texture_object    *tObj;
+   savageTextureObjectPtr t;
+   GLuint format;
+   Reg_TexCtrl           TexCtrl;
+   Reg_TexBlendCtrl      TexBlendCtrl;
+   Reg_TexDescr          TexDescr;
+
+
+   /* disable */
+   if(imesa->bTexEn1)
+   {
+       imesa->bTexEn1 = GL_FALSE;
+       return;
+   }
+
+   if (ctx->Texture.Unit[1]._ReallyEnabled == 0) {
+      imesa->Registers.TexDescr.s4.tex1En = GL_FALSE;
+      imesa->Registers.TexBlendCtrl[1].ui = TBC_NoTexMap1;
+      imesa->Registers.TexCtrl[1].ui = 0x20f040;
+      imesa->Registers.TexAddr[1].ui = 0;
+      imesa->Registers.TexDescr.s4.texBLoopEn = GL_FALSE;
+      imesa->Registers.changed.ni.fTex1BlendCtrlChanged = GL_TRUE;
+      imesa->Registers.changed.ni.fTexDescrChanged = GL_TRUE;
+      imesa->Registers.changed.ni.fTex1BlendCtrlChanged = GL_TRUE;
+      imesa->Registers.changed.ni.fTex1AddrChanged = GL_TRUE;
+      return;
+   }
+
+   tObj = ctx->Texture.Unit[1]._Current;
+
+   if (ctx->Texture.Unit[1]._ReallyEnabled != TEXTURE_2D_BIT ||
+       tObj->Image[0][tObj->BaseLevel]->Border > 0) {
+      /* 1D or 3D texturing enabled, or texture border - fallback */
+      FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE);
+      return;
+   }
+
+   /* Do 2D texture setup */
+
+   t = tObj->DriverData;
+   if (!t) {
+      t = savageAllocTexObj( tObj );
+      if (!t)
+         return;
+   }
+    
+   if (t->current_unit != 1)
+      savageTexSetUnit( t, 1 );
+
+   imesa->CurrentTexObj[1] = t;
+
+   t->bound = 2;
+
+   if (t->dirty_images) {
+       savageSetTexImages(imesa, tObj);
+       savageUploadTexImages(imesa, imesa->CurrentTexObj[1]);
+   }
+   
+   if (t->MemBlock)
+      savageUpdateTexLRU( imesa, t );
+
+   TexDescr.ui = imesa->Registers.TexDescr.ui;
+   TexCtrl.ui = imesa->Registers.TexCtrl[1].ui;
+   TexBlendCtrl.ui = imesa->Registers.TexBlendCtrl[1].ui;
+
+   format = tObj->Image[0][tObj->BaseLevel]->Format;
+
+   switch (ctx->Texture.Unit[1].EnvMode) {
+   case GL_REPLACE:
+        TexCtrl.s4.clrArg1Invert = GL_FALSE;
+        switch (format)
+        {
+            case GL_LUMINANCE:
+            case GL_RGB:
+                TexBlendCtrl.ui = TBC_Decal;
+                break;
+
+            case GL_LUMINANCE_ALPHA:
+            case GL_INTENSITY:
+            case GL_RGBA:
+                TexBlendCtrl.ui = TBC_Copy;
+                break;
+
+            case GL_ALPHA:
+                TexBlendCtrl.ui = TBC_CopyAlpha1;
+                break;
+        }
+        __HWEnvCombineSingleUnitScale(imesa, 0, 1, &TexBlendCtrl);
+      break;
+   case GL_MODULATE:
+       TexCtrl.s4.clrArg1Invert = GL_FALSE;
+       TexBlendCtrl.ui = TBC_ModulAlpha1;
+       __HWEnvCombineSingleUnitScale(imesa, 0, 1, &TexBlendCtrl);
+       break;
+
+/*#if GL_EXT_texture_env_add*/
+    case GL_ADD:
+        TexCtrl.s4.clrArg1Invert = GL_FALSE;
+        TexBlendCtrl.ui = TBC_AddAlpha1;
+        __HWEnvCombineSingleUnitScale(imesa, 0, 1, &TexBlendCtrl);
+        break;
+/*#endif*/
+
+#if GL_ARB_texture_env_combine
+    case GL_COMBINE_ARB:
+        __HWParseTexEnvCombine(imesa, 1, &TexCtrl, &TexBlendCtrl);
+        break;
+#endif
+
+   case GL_DECAL:
+        TexCtrl.s4.clrArg1Invert = GL_FALSE;
+
+        switch (format)
+        {
+            case GL_LUMINANCE:
+            case GL_RGB:
+                TexBlendCtrl.ui = TBC_Decal1;
+                break;
+            case GL_LUMINANCE_ALPHA:
+            case GL_INTENSITY:
+            case GL_RGBA:
+                TexBlendCtrl.ui = TBC_DecalAlpha1;
+                break;
+
+                /*
+                // GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_INTENSITY
+                // are undefined with GL_DECAL
+                */
+            case GL_ALPHA:
+                TexBlendCtrl.ui = TBC_CopyAlpha1;
+                break;
+        }
+        __HWEnvCombineSingleUnitScale(imesa, 0, 1, &TexBlendCtrl);
+        break;
+
+   case GL_BLEND:
+        if (format == GL_LUMINANCE)
+        {
+            /*
+            // This is a hack for GLQuake, invert.
+            */
+            TexCtrl.s4.clrArg1Invert = GL_TRUE;
+            TexBlendCtrl.ui = 0;
+        }
+        __HWEnvCombineSingleUnitScale(imesa, 0, 1, &TexBlendCtrl);
+      break;
+
+   default:
+      fprintf(stderr, "unkown tex 1 env mode\n");
+      exit(1);
+      break;                   
+   }
+
+    TexCtrl.s4.uMode = !(t->texParams.sWrapMode & 0x01);
+    TexCtrl.s4.vMode = !(t->texParams.tWrapMode & 0x01);
+
+    switch (t->texParams.minFilter)
+    {
+        case GL_NEAREST:
+            TexCtrl.s4.filterMode   = TFM_Point;
+            TexCtrl.s4.mipmapEnable = GL_FALSE;
+            break;
+
+        case GL_LINEAR:
+            TexCtrl.s4.filterMode   = TFM_Bilin;
+            TexCtrl.s4.mipmapEnable = GL_FALSE;
+            break;
+
+        case GL_NEAREST_MIPMAP_NEAREST:
+            TexCtrl.s4.filterMode   = TFM_Point;
+            TexCtrl.s4.mipmapEnable = GL_TRUE;
+            break;
+
+        case GL_LINEAR_MIPMAP_NEAREST:
+            TexCtrl.s4.filterMode   = TFM_Bilin;
+            TexCtrl.s4.mipmapEnable = GL_TRUE;
+            break;
+
+        case GL_NEAREST_MIPMAP_LINEAR:
+        case GL_LINEAR_MIPMAP_LINEAR:
+            TexCtrl.s4.filterMode   = TFM_Trilin;
+            TexCtrl.s4.mipmapEnable = GL_TRUE;
+            break;
+    }
+    
+    if((ctx->Texture.Unit[1].LodBias !=0.0F)&&(TexCtrl.s4.dBias != 0))
+    {
+       union {
+           GLfloat f;
+           GLint i;
+       } bias;
+       GLuint  ul;
+       
+       bias.f = ctx->Texture.Unit[1].LodBias;
+       
+       /* if the value is >= 15.9375 determine whether >= 16
+          or <0
+       */
+       if(((bias.i) & 0x7FFFFFFF) >= 0x417F0000)
+       {
+           if((bias.i) & 0x80000000)
+           {
+               ul=0x101;
+           }
+           else
+           {
+               ul=0xff;
+           }
+       }
+       else
+       {
+            ul=(GLuint)(bias.f*16.0);
+        }
+        
+        ul &= 0x1FF;
+        TexCtrl.s4.dBias = ul;
+    }
+
+    TexDescr.s4.tex1En = GL_TRUE;
+    TexDescr.s4.tex1Width  = t->image[0].image->WidthLog2;
+    TexDescr.s4.tex1Height = t->image[0].image->HeightLog2;
+    TexDescr.s4.tex1Fmt = t->image[0].internalFormat;
+    TexCtrl.s4.dMax = t->max_level;
+    TexDescr.s4.texBLoopEn = GL_TRUE;
+
+    if (imesa->Registers.TexAddr[1].ui != (GLuint)t->texParams.hwPhysAddress)
+    {
+        imesa->Registers.TexAddr[1].ui = (GLuint) t->texParams.hwPhysAddress| 2;
+        
+        if(t->heap == SAVAGE_AGP_HEAP)
+           imesa->Registers.TexAddr[1].ui |= 0x1;
+        
+        /*imesa->Registers.TexAddr[1].ui = (GLuint) t->texParams.hwPhysAddress| 3;*/
+        imesa->Registers.changed.ni.fTex1AddrChanged = GL_TRUE;
+    }
+
+    if (imesa->Registers.TexCtrl[1].ui != TexCtrl.ui)
+    {
+        imesa->Registers.TexCtrl[1].ui = TexCtrl.ui;
+        imesa->Registers.changed.ni.fTex1CtrlChanged = GL_TRUE;
+    }
+
+    if (imesa->Registers.TexBlendCtrl[1].ui != TexBlendCtrl.ui)
+    {
+        imesa->Registers.TexBlendCtrl[1].ui = TexBlendCtrl.ui;
+        imesa->Registers.changed.ni.fTex1BlendCtrlChanged = GL_TRUE;
+    }
+
+    if (imesa->Registers.TexDescr.ui != TexDescr.ui)
+    {
+        imesa->Registers.TexDescr.ui = TexDescr.ui;
+        imesa->Registers.changed.ni.fTexDescrChanged = GL_TRUE;
+    }
+
+}
+static void savageUpdateTexState_s3d( GLcontext *ctx )
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    struct gl_texture_object *tObj;
+    savageTextureObjectPtr t;
+    GLuint format;
+    Reg_TexCtrl TexCtrl;
+    Reg_DrawCtrl DrawCtrl;
+    Reg_TexDescr TexDescr; 
+
+    /* disable */
+    if (ctx->Texture.Unit[0]._ReallyEnabled == 0) {
+       imesa->Registers.TexCtrl[0].ui = 0;
+       imesa->Registers.TexCtrl[0].s3d.texEn = GL_FALSE;
+       imesa->Registers.TexCtrl[0].s3d.dBias = 0x08;
+       imesa->Registers.TexCtrl[0].s3d.texXprEn = GL_TRUE;
+       imesa->Registers.TexAddr[0].ui = 0;
+       imesa->Registers.changed.ni.fTex0AddrChanged = GL_TRUE;
+       imesa->Registers.changed.ni.fTex0CtrlChanged = GL_TRUE;
+       return;
+    }
+
+    tObj = ctx->Texture.Unit[0]._Current;
+    if (ctx->Texture.Unit[0]._ReallyEnabled != TEXTURE_2D_BIT ||
+       tObj->Image[0][tObj->BaseLevel]->Border > 0) {
+       /* 1D or 3D texturing enabled, or texture border - fallback */
+       FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE);
+       return;
+    }
+
+    /* Do 2D texture setup */
+    t = tObj->DriverData;
+    if (!t) {
+       t = savageAllocTexObj( tObj );
+       if (!t)
+           return;
+    }
+
+    if (t->current_unit != 0)
+       savageTexSetUnit( t, 0 );
+
+    imesa->CurrentTexObj[0] = t;
+    t->bound = 1;
+
+    if (t->dirty_images) {
+       savageSetTexImages(imesa, tObj);
+       savageUploadTexImages(imesa, imesa->CurrentTexObj[0]); 
+    }
+
+    if (t->MemBlock)
+       savageUpdateTexLRU( imesa, t );
+
+    TexDescr.ui = imesa->Registers.TexDescr.ui;
+    TexCtrl.ui = imesa->Registers.TexCtrl[0].ui;
+    DrawCtrl.ui = imesa->Registers.DrawCtrl.ui;
+
+    format = tObj->Image[0][tObj->BaseLevel]->Format;
+
+    /* FIXME: copied from utah-glx, probably needs some tuning */
+    switch (ctx->Texture.Unit[0].EnvMode) {
+    case GL_DECAL:
+       DrawCtrl.ni.texBlendCtrl = SAVAGETBC_DECAL_S3D;
+       break;
+    case GL_REPLACE:
+       DrawCtrl.ni.texBlendCtrl = SAVAGETBC_COPY_S3D;
+       break;
+    case GL_BLEND: /* FIXIT */
+    case GL_MODULATE:
+       DrawCtrl.ni.texBlendCtrl = SAVAGETBC_MODULATEALPHA_S3D;
+       break;
+    default:
+       fprintf(stderr, "unkown tex env mode\n");
+       /*exit(1);*/
+       break;                  
+    }
+
+    DrawCtrl.ni.flushPdDestWrites = GL_TRUE;
+    DrawCtrl.ni.flushPdZbufWrites = GL_TRUE;
+
+    /* FIXME: this is how the utah-driver works. I doubt it's the ultimate 
+       truth. */
+    TexCtrl.s3d.uWrapEn = 0;
+    TexCtrl.s3d.vWrapEn = 0;
+    if (t->texParams.sWrapMode == GL_CLAMP)
+       TexCtrl.s3d.wrapMode = TAM_Clamp;
+    else
+       TexCtrl.s3d.wrapMode = TAM_Wrap;
+
+    switch (t->texParams.minFilter) {
+    case GL_NEAREST:
+       TexCtrl.s3d.filterMode    = TFM_Point;
+       TexCtrl.s3d.mipmapDisable = GL_TRUE;
+       break;
+
+    case GL_LINEAR:
+       TexCtrl.s3d.filterMode    = TFM_Bilin;
+       TexCtrl.s3d.mipmapDisable = GL_TRUE;
+       break;
+
+    case GL_NEAREST_MIPMAP_NEAREST:
+       TexCtrl.s3d.filterMode    = TFM_Point;
+       TexCtrl.s3d.mipmapDisable = GL_FALSE;
+       break;
+
+    case GL_LINEAR_MIPMAP_NEAREST:
+       TexCtrl.s3d.filterMode    = TFM_Bilin;
+       TexCtrl.s3d.mipmapDisable = GL_FALSE;
+       break;
+
+    case GL_NEAREST_MIPMAP_LINEAR:
+    case GL_LINEAR_MIPMAP_LINEAR:
+       TexCtrl.s3d.filterMode    = TFM_Trilin;
+       TexCtrl.s3d.mipmapDisable = GL_FALSE;
+       break;
+    }
+
+    /* There is no way to specify a maximum mipmap level. We may have to
+       disable mipmapping completely. */
+    /*
+    if (t->max_level < t->image[0].image->WidthLog2 ||
+       t->max_level < t->image[0].image->HeightLog2) {
+       TexCtrl.s3d.mipmapEnable = GL_TRUE;
+       if (TexCtrl.s3d.filterMode == TFM_Trilin)
+           TexCtrl.s3d.filterMode = TFM_Bilin;
+       TexCtrl.s3d.filterMode = TFM_Point;
+    }
+    */
+
+    /* LOD bias makes corruption of small mipmap levels worse on Savage IX
+     * but doesn't show the desired effect with the lodbias mesa demo. */
+    TexCtrl.s3d.dBias = 0;
+
+    TexCtrl.s3d.texEn = GL_TRUE;
+    TexDescr.s3d.texWidth  = t->image[0].image->WidthLog2;
+    TexDescr.s3d.texHeight = t->image[0].image->HeightLog2;
+    assert (t->image[0].internalFormat <= 7);
+    TexDescr.s3d.texFmt = t->image[0].internalFormat;
+
+    if (imesa->Registers.TexAddr[0].ni.addr != (GLuint)t->texParams.hwPhysAddress >> 3)
+    {
+        imesa->Registers.TexAddr[0].ni.addr = (GLuint) t->texParams.hwPhysAddress >> 3;
+
+        if(t->heap == SAVAGE_AGP_HEAP) {
+            imesa->Registers.TexAddr[0].ni.inSysTex = 1;
+            imesa->Registers.TexAddr[0].ni.inAGPTex = 1;
+       } else {
+            imesa->Registers.TexAddr[0].ni.inSysTex = 0;
+            imesa->Registers.TexAddr[0].ni.inAGPTex = 1;
+       }
+
+        imesa->Registers.changed.ni.fTex0AddrChanged = GL_TRUE;
+    }
+
+    if (imesa->Registers.TexCtrl[0].ui != TexCtrl.ui)
+    {
+        imesa->Registers.TexCtrl[0].ui = TexCtrl.ui;
+        imesa->Registers.changed.ni.fTex0CtrlChanged = GL_TRUE;
+    }
+
+    if (imesa->Registers.TexDescr.ui != TexDescr.ui)
+    {
+        imesa->Registers.TexDescr.ui = TexDescr.ui;
+        imesa->Registers.changed.ni.fTexDescrChanged = GL_TRUE;
+    }
+
+    if (imesa->Registers.DrawCtrl.ui != DrawCtrl.ui)
+    {
+        imesa->Registers.DrawCtrl.ui = DrawCtrl.ui;
+        imesa->Registers.changed.ni.fDrawCtrlChanged = GL_TRUE;
+    }
+}
+
+
+
+static void savageUpdateTextureState_s4( GLcontext *ctx )
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+   if (imesa->CurrentTexObj[0]) imesa->CurrentTexObj[0]->bound = 0;
+   if (imesa->CurrentTexObj[1]) imesa->CurrentTexObj[1]->bound = 0;
+   imesa->CurrentTexObj[0] = 0;
+   imesa->CurrentTexObj[1] = 0;   
+   FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_FALSE);
+   savageUpdateTex0State_s4( ctx );
+   savageUpdateTex1State_s4( ctx );
+   imesa->dirty |= (SAVAGE_UPLOAD_CTX |
+                   SAVAGE_UPLOAD_TEX0 | 
+                   SAVAGE_UPLOAD_TEX1);
+}
+static void savageUpdateTextureState_s3d( GLcontext *ctx )
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+    if (imesa->CurrentTexObj[0]) imesa->CurrentTexObj[0]->bound = 0;
+    imesa->CurrentTexObj[0] = 0;
+    if (ctx->Texture.Unit[1]._ReallyEnabled) {
+       FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE);
+    } else {
+       FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_FALSE);
+       savageUpdateTexState_s3d( ctx );
+       imesa->dirty |= (SAVAGE_UPLOAD_CTX |
+                        SAVAGE_UPLOAD_TEX0);
+    }
+}
+static void savageUpdateTextureState_first( GLcontext *ctx)
+{
+    savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+    if (imesa->savageScreen->chipset <= S3_SAVAGE4) {
+       GetTiledCoordinates16 = GetTiledCoordinates16_4;
+       GetTiledCoordinates32 = GetTiledCoordinates32_4;
+    } else {
+       GetTiledCoordinates16 = GetTiledCoordinates16_8;
+       GetTiledCoordinates32 = GetTiledCoordinates32_8;
+    }
+    if (imesa->savageScreen->chipset >= S3_SAVAGE4)
+       savageUpdateTextureState = savageUpdateTextureState_s4;
+    else
+       savageUpdateTextureState = savageUpdateTextureState_s3d;
+    savageUpdateTextureState (ctx);
+}
+void (*savageUpdateTextureState)( GLcontext *ctx ) =
+    savageUpdateTextureState_first;
+
+
+
+/*****************************************
+ * DRIVER functions
+ *****************************************/
+
+static void savageTexEnv( GLcontext *ctx, GLenum target, 
+                       GLenum pname, const GLfloat *param )
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+
+   if (pname == GL_TEXTURE_ENV_MODE) {
+
+      imesa->new_state |= SAVAGE_NEW_TEXTURE;
+
+   } else if (pname == GL_TEXTURE_ENV_COLOR) {
+
+      struct gl_texture_unit *texUnit = 
+        &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+      const GLfloat *fc = texUnit->EnvColor;
+      GLuint r, g, b, a, col;
+      CLAMPED_FLOAT_TO_UBYTE(r, fc[0]);
+      CLAMPED_FLOAT_TO_UBYTE(g, fc[1]);
+      CLAMPED_FLOAT_TO_UBYTE(b, fc[2]);
+      CLAMPED_FLOAT_TO_UBYTE(a, fc[3]);
+
+      col = ((a << 24) | 
+            (r << 16) | 
+            (g <<  8) | 
+            (b <<  0));
+    
+
+   } 
+}
+
+static void savageTexImage2D( GLcontext *ctx, GLenum target, GLint level,
+                             GLint internalFormat,
+                             GLint width, GLint height, GLint border,
+                             GLenum format, GLenum type, const GLvoid *pixels,
+                             const struct gl_pixelstore_attrib *packing,
+                             struct gl_texture_object *texObj,
+                             struct gl_texture_image *texImage )
+{
+   savageTextureObjectPtr t = (savageTextureObjectPtr) texObj->DriverData;
+   if (t) {
+      savageSwapOutTexObj( SAVAGE_CONTEXT(ctx), t );
+   } else {
+      t = savageAllocTexObj(texObj);
+      if (!t) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
+         return;
+      }
+   }
+   _mesa_store_teximage2d( ctx, target, level, internalFormat,
+                          width, height, border, format, type,
+                          pixels, packing, texObj, texImage );
+   t->dirty_images |= (1 << level);
+   SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE;
+}
+
+static void savageTexSubImage2D( GLcontext *ctx, 
+                                GLenum target,
+                                GLint level,   
+                                GLint xoffset, GLint yoffset,
+                                GLsizei width, GLsizei height,
+                                GLenum format, GLenum type,
+                                const GLvoid *pixels,
+                                const struct gl_pixelstore_attrib *packing,
+                                struct gl_texture_object *texObj,
+                                struct gl_texture_image *texImage )
+{
+   savageTextureObjectPtr t = (savageTextureObjectPtr) texObj->DriverData;
+   assert( t ); /* this _should_ be true */
+   if (t) {
+      savageSwapOutTexObj( SAVAGE_CONTEXT(ctx), t );
+   } else {
+      t = savageAllocTexObj(texObj);
+      if (!t) {
+         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
+         return;
+      }
+   }
+   _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width, 
+                            height, format, type, pixels, packing, texObj,
+                            texImage);
+   t->dirty_images |= (1 << level);
+   SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE;
+}
+
+static void savageTexParameter( GLcontext *ctx, GLenum target,
+                             struct gl_texture_object *tObj,
+                             GLenum pname, const GLfloat *params )
+{
+   savageTextureObjectPtr t = (savageTextureObjectPtr) tObj->DriverData;
+   savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+
+   if (!t || target != GL_TEXTURE_2D)
+      return;
+
+   switch (pname) {
+   case GL_TEXTURE_MIN_FILTER:
+   case GL_TEXTURE_MAG_FILTER:
+      savageSetTexFilter(t,tObj->MinFilter,tObj->MagFilter);
+      break;
+
+   case GL_TEXTURE_WRAP_S:
+   case GL_TEXTURE_WRAP_T:
+      savageSetTexWrapping(t,tObj->WrapS,tObj->WrapT);
+      break;
+  
+   case GL_TEXTURE_BORDER_COLOR:
+      savageSetTexBorderColor(t,tObj->_BorderChan);
+      break;
+
+   default:
+      return;
+   }
+
+   imesa->new_state |= SAVAGE_NEW_TEXTURE;
+}
+
+static void savageBindTexture( GLcontext *ctx, GLenum target,
+                              struct gl_texture_object *tObj )
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+   
+
+   if (imesa->CurrentTexObj[ctx->Texture.CurrentUnit]) {
+      imesa->CurrentTexObj[ctx->Texture.CurrentUnit]->bound = 0;
+      imesa->CurrentTexObj[ctx->Texture.CurrentUnit] = 0;  
+   }
+
+   assert( (target != GL_TEXTURE_2D) || (tObj->DriverData != NULL) );
+
+   imesa->new_state |= SAVAGE_NEW_TEXTURE;
+}
+
+static void savageDeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj )
+{
+   savageTextureObjectPtr t = (savageTextureObjectPtr)tObj->DriverData;
+   savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+
+   if (t) {
+
+      if (t->bound) {
+        imesa->CurrentTexObj[t->bound-1] = 0;
+        imesa->new_state |= SAVAGE_NEW_TEXTURE;
+      }
+
+      savageDestroyTexObj(imesa,t);
+      tObj->DriverData=0;
+   }
+   /* Free mipmap images and the texture object itself */
+   _mesa_delete_texture_object(ctx, tObj);
+}
+
+
+static GLboolean savageIsTextureResident( GLcontext *ctx, 
+                                       struct gl_texture_object *t )
+{
+   savageTextureObjectPtr mt;
+
+/*     LOCK_HARDWARE; */
+   mt = (savageTextureObjectPtr)t->DriverData;
+/*     UNLOCK_HARDWARE; */
+
+   return mt && mt->MemBlock;
+}
+
+
+static struct gl_texture_object *
+savageNewTextureObject( GLcontext *ctx, GLuint name, GLenum target )
+{
+    struct gl_texture_object *obj;
+    obj = _mesa_new_texture_object(ctx, name, target);
+    savageAllocTexObj( obj );
+
+    return obj;
+}
+
+void savageDDInitTextureFuncs( struct dd_function_table *functions )
+{
+   functions->TexEnv = savageTexEnv;
+   functions->ChooseTextureFormat = savageChooseTextureFormat;
+   functions->TexImage2D = savageTexImage2D;
+   functions->TexSubImage2D = savageTexSubImage2D;
+   functions->BindTexture = savageBindTexture;
+   functions->NewTextureObject = savageNewTextureObject;
+   functions->DeleteTexture = savageDeleteTexture;
+   functions->IsTextureResident = savageIsTextureResident;
+   functions->TexParameter = savageTexParameter;
+}
diff --git a/src/mesa/drivers/dri/savage/savagetex.h b/src/mesa/drivers/dri/savage/savagetex.h
new file mode 100644 (file)
index 0000000..9ff85e2
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. 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"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef SAVAGETEX_INC
+#define SAVAGETEX_INC
+
+#include "mtypes.h"
+#include "mm.h"
+
+#include "savagecontext.h"
+#include "savage_3d_reg.h"
+
+#define VALID_SAVAGE_TEXTURE_OBJECT(tobj)  (tobj) 
+
+#define SAVAGE_TEX_MAXLEVELS 11
+#define MIN_TILE_CHUNK       8
+#define MIPMAP_CHUNK         4
+
+
+
+/* For shared texture space managment, these texture objects may also
+ * be used as proxies for regions of texture memory containing other
+ * client's textures.  Such proxy textures (not to be confused with GL
+ * proxy textures) are subject to the same LRU aging we use for our
+ * own private textures, and thus we have a mechanism where we can
+ * fairly decide between kicking out our own textures and those of
+ * other clients.
+ *
+ * Non-local texture objects have a valid MemBlock to describe the
+ * region managed by the other client, and can be identified by
+ * 't->globj == 0' 
+ */
+typedef struct  {
+    GLuint sWrapMode;
+    GLuint tWrapMode;
+    GLuint minFilter;
+    GLuint magFilter;
+    GLuint boarderColor;
+    GLuint hwPhysAddress;
+} savage_texture_parameter_t;
+
+struct savage_texture_object_t {
+   struct savage_texture_object_t *next, *prev;
+   struct gl_texture_object *globj;
+   GLuint age;   
+   
+     
+   GLuint texelBytes;
+   GLuint totalSize;
+   GLuint bound;
+   GLuint heap;
+
+   PMemBlock MemBlock;   
+   char *BufAddr;
+   
+   GLuint min_level;
+   GLuint max_level;
+   GLuint dirty_images;
+
+   struct { 
+      const struct gl_texture_image *image;
+      GLuint offset;           /* into BufAddr */
+      GLuint height;
+      GLuint internalFormat;
+   } image[SAVAGE_TEX_MAXLEVELS];
+
+   /* Support for multitexture.
+    */
+   GLuint current_unit;   
+   savage_texture_parameter_t texParams;
+};             
+
+#define SAVAGE_NO_PALETTE        0x0
+#define SAVAGE_USE_PALETTE       0x1
+#define SAVAGE_UPDATE_PALETTE    0x2
+#define SAVAGE_FALLBACK_PALETTE  0x4
+#define __HWEnvCombineSingleUnitScale(imesa, flag0, flag1, TexBlendCtrl)
+#define __HWParseTexEnvCombine(imesa, flag0, TexCtrl, TexBlendCtrl)
+
+
+extern void (*savageUpdateTextureState)( GLcontext *ctx );
+void savageDDInitTextureFuncs( struct dd_function_table *functions );
+
+void savageDestroyTexObj( savageContextPtr imesa, savageTextureObjectPtr t);
+int savageUploadTexImages( savageContextPtr imesa, savageTextureObjectPtr t );
+
+void savageResetGlobalLRU( savageContextPtr imesa , GLuint heap);
+void savageTexturesGone( savageContextPtr imesa, GLuint heap, 
+                      GLuint start, GLuint end, 
+                      GLuint in_use ); 
+
+void savagePrintLocalLRU( savageContextPtr imesa ,GLuint heap);
+void savagePrintGlobalLRU( savageContextPtr imesa ,GLuint heap);
+
+#endif
diff --git a/src/mesa/drivers/dri/savage/savagetris.c b/src/mesa/drivers/dri/savage/savagetris.c
new file mode 100644 (file)
index 0000000..db061d9
--- /dev/null
@@ -0,0 +1,817 @@
+/* $XFree86$ */ /* -*- c-basic-offset: 3 -*- */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+                     VA Linux Systems Inc., Fremont, California.
+
+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"),
+to deal in the Software without restriction, including without limitation
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, and/or sell copies of the Software, and to permit persons to whom
+the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ *   Keith Whitwell <keithw@valinux.com>
+ *   Felix Kuehling <fxkuehl@gmx.de>
+ *
+ */
+
+#include <stdio.h>
+#include <math.h>
+
+#include "glheader.h"
+#include "mtypes.h"
+#include "colormac.h"
+#include "macros.h"
+
+#include "swrast/swrast.h"
+#include "swrast_setup/swrast_setup.h"
+#include "tnl/tnl.h"
+#include "tnl/t_context.h"
+#include "tnl/t_pipeline.h"
+
+#include "savagetris.h"
+#include "savagestate.h"
+#include "savagetex.h"
+#include "savagevb.h"
+#include "savageioctl.h"
+#include "savage_bci.h"
+
+static void savageRasterPrimitive( GLcontext *ctx, GLuint prim );
+static void savageRenderPrimitive( GLcontext *ctx, GLenum prim );
+/***********************************************************************
+ *                    Emit primitives                                  *
+ ***********************************************************************/
+
+static  __inline__ GLuint * savage_send_one_vertex(savageContextPtr imesa, savageVertexPtr v, GLuint * vb, GLuint start, GLuint size)
+{ 
+    GLuint j; 
+    for (j = start ; j < size ; j++) 
+    { 
+        WRITE_CMD(vb, v->ui[j],GLuint); 
+    }
+    return vb; 
+} 
+static void __inline__ savage_draw_triangle( savageContextPtr imesa, 
+                                          savageVertexPtr v0, 
+                                          savageVertexPtr v1, 
+                                          savageVertexPtr v2 ) 
+{ 
+   GLuint vertsize = imesa->vertex_size; 
+#if SAVAGEDEBUG
+   GLuint *vb = savageDMAAlloc (imesa, 3 * vertsize + 1 + 8); 
+#else
+   GLuint *vb = savageDMAAlloc (imesa, 4 * vertsize + 1); 
+#endif
+
+   imesa->DrawPrimitiveCmd &=
+       ~(SAVAGE_HW_TRIANGLE_TYPE| SAVAGE_HW_TRIANGLE_CONT);
+   WRITE_CMD(vb,SAVAGE_DRAW_PRIMITIVE(3, imesa->DrawPrimitiveCmd&imesa->DrawPrimitiveMask, 0),GLuint);
+
+   vb = savage_send_one_vertex(imesa, v0, vb, 0, vertsize);
+   vb = savage_send_one_vertex(imesa, v1, vb, 0, vertsize);
+   vb = savage_send_one_vertex(imesa, v2, vb, 0, vertsize);
+#if SAVAGEDEBUG
+   {
+        GLuint x0,y0,w,h;
+        x0 = (GLuint)imesa->drawX;
+        y0 = (GLuint)imesa->drawY;
+        w  = (GLuint)imesa->driDrawable->w;
+        h  = (GLuint)imesa->driDrawable->h;
+
+       (*vb) = 0x4BCC00C0;
+       vb++;
+       (*vb) = imesa->savageScreen->backOffset;
+       vb++;
+       (*vb) = imesa->savageScreen->backBitmapDesc;
+       vb++;
+       (*vb) = (y0<<16)|x0;
+       vb++;
+       (*vb) = 0x0;
+       vb++;
+       (*vb) = (h<<16)|w;
+       vb++;
+   }
+#endif
+   savageDMACommit (imesa, vb);
+} 
+static __inline__ void savage_draw_point( savageContextPtr imesa, 
+                                         savageVertexPtr tmp ) 
+{ 
+   GLfloat sz = imesa->glCtx->Point._Size * .5;
+   int vertsize = imesa->vertex_size; 
+   GLuint *vb = savageDMAAlloc (imesa, 4 * vertsize + 1); 
+   const GLfloat x = tmp->v.x; 
+   const GLfloat y = tmp->v.y; 
+   
+   imesa->DrawPrimitiveCmd &=
+       ~(SAVAGE_HW_TRIANGLE_TYPE | SAVAGE_HW_TRIANGLE_CONT);   
+   imesa->DrawPrimitiveCmd |= SAVAGE_HW_TRIANGLE_FAN; 
+     
+   WRITE_CMD(vb, SAVAGE_DRAW_PRIMITIVE(4, imesa->DrawPrimitiveCmd&imesa->DrawPrimitiveMask, 0),GLuint);
+
+   WRITE_CMD(vb, x - sz, GLfloat);
+   WRITE_CMD(vb, y - sz, GLfloat);
+   vb = savage_send_one_vertex(imesa, tmp, vb, 2, vertsize);
+
+   WRITE_CMD(vb, x + sz, GLfloat);
+   WRITE_CMD(vb, y - sz, GLfloat);
+   vb = savage_send_one_vertex(imesa, tmp, vb, 2, vertsize);
+
+   WRITE_CMD(vb, x + sz, GLfloat);
+   WRITE_CMD(vb, y + sz, GLfloat);
+   vb = savage_send_one_vertex(imesa, tmp, vb, 2, vertsize);
+   WRITE_CMD(vb, x - sz, GLfloat);
+   WRITE_CMD(vb, y + sz, GLfloat);
+   vb = savage_send_one_vertex(imesa, tmp, vb, 2, vertsize);
+
+   savageDMACommit (imesa, vb);
+} 
+static __inline__ void savage_draw_line( savageContextPtr imesa, 
+                                      savageVertexPtr v0, 
+                                      savageVertexPtr v1 ) 
+{  
+   GLuint vertsize = imesa->vertex_size; 
+   GLuint *vb = savageDMAAlloc (imesa, 4 * vertsize + 1); 
+   GLfloat dx, dy, ix, iy; 
+   GLfloat width = imesa->glCtx->Line._Width;
+
+   imesa->DrawPrimitiveCmd &=
+       ~(SAVAGE_HW_TRIANGLE_TYPE | SAVAGE_HW_TRIANGLE_CONT);
+   imesa->DrawPrimitiveCmd |= SAVAGE_HW_TRIANGLE_FAN; 
+   WRITE_CMD(vb, SAVAGE_DRAW_PRIMITIVE(4, imesa->DrawPrimitiveCmd&imesa->DrawPrimitiveMask, 0),GLuint);
+
+   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;
+   }
+
+   WRITE_CMD(vb, (v0->v.x - ix), GLfloat);
+   WRITE_CMD(vb, (v0->v.y - iy), GLfloat);
+   vb = savage_send_one_vertex(imesa, v0, vb, 2, vertsize);
+
+   WRITE_CMD(vb, (v1->v.x - ix), GLfloat);
+   WRITE_CMD(vb, (v1->v.y - iy), GLfloat);     
+   vb = savage_send_one_vertex(imesa, v1, vb, 2, vertsize);
+
+   WRITE_CMD(vb, (v1->v.x + ix), GLfloat);
+   WRITE_CMD(vb, (v1->v.y + iy), GLfloat);
+   vb = savage_send_one_vertex(imesa, v1, vb, 2, vertsize);
+
+   WRITE_CMD(vb, (v0->v.x + ix), GLfloat);
+   WRITE_CMD(vb, (v0->v.y + iy), GLfloat);
+   vb = savage_send_one_vertex(imesa, v0, vb, 2, vertsize);
+
+   savageDMACommit (imesa, vb);
+} 
+static void __inline__ savage_draw_quad( savageContextPtr imesa, 
+                                        savageVertexPtr v0, 
+                                        savageVertexPtr v1, 
+                                        savageVertexPtr v2, 
+                                        savageVertexPtr v3 ) 
+{ 
+   GLuint vertsize = imesa->vertex_size; 
+   GLuint *vb = savageDMAAlloc (imesa, 6 * vertsize + 1); 
+
+   imesa->DrawPrimitiveCmd &=
+       ~(SAVAGE_HW_TRIANGLE_TYPE | SAVAGE_HW_TRIANGLE_CONT);
+   WRITE_CMD(vb, SAVAGE_DRAW_PRIMITIVE(6, imesa->DrawPrimitiveCmd&imesa->DrawPrimitiveMask, 0),GLuint);
+   vb = savage_send_one_vertex(imesa, v0, vb, 0, vertsize);
+   vb = savage_send_one_vertex(imesa, v1, vb, 0, vertsize);
+   vb = savage_send_one_vertex(imesa, v3, vb, 0, vertsize);
+   vb = savage_send_one_vertex(imesa, v1, vb, 0, vertsize);
+   vb = savage_send_one_vertex(imesa, v2, vb, 0, vertsize);
+   vb = savage_send_one_vertex(imesa, v3, vb, 0, vertsize);
+
+   savageDMACommit (imesa, vb);
+} 
+
+/***********************************************************************
+ *          Macros for t_dd_tritmp.h to draw basic primitives          *
+ ***********************************************************************/
+
+#define TRI( a, b, c )                         \
+do {                                           \
+   if (DO_FALLBACK)                            \
+      imesa->draw_tri( imesa, a, b, c );       \
+   else                                                \
+      savage_draw_triangle( imesa, a, b, c );  \
+} while (0)
+
+#define QUAD( a, b, c, d )                     \
+do {                                           \
+   if (DO_FALLBACK) {                          \
+      imesa->draw_tri( imesa, a, b, d );       \
+      imesa->draw_tri( imesa, b, c, d );       \
+   } else                                      \
+      savage_draw_quad( imesa, a, b, c, d );   \
+} while (0)
+
+#define LINE( v0, v1 )                         \
+do {                                           \
+   if (DO_FALLBACK)                            \
+      imesa->draw_line( imesa, v0, v1 );       \
+   else                                        \
+      savage_draw_line( imesa, v0, v1 );       \
+} while (0)
+
+#define POINT( v0 )                            \
+do {                                           \
+   if (DO_FALLBACK)                            \
+      imesa->draw_point( imesa, v0 );          \
+   else                                        \
+      savage_draw_point( imesa, v0 );          \
+} while (0)
+
+
+/***********************************************************************
+ *              Build render functions from dd templates               *
+ ***********************************************************************/
+
+#define SAVAGE_OFFSET_BIT       0x1
+#define SAVAGE_TWOSIDE_BIT       0x2
+#define SAVAGE_UNFILLED_BIT      0x4
+#define SAVAGE_FALLBACK_BIT      0x8
+#define SAVAGE_MAX_TRIFUNC       0x10
+
+
+static struct {
+   points_func         points;
+   line_func           line;
+   triangle_func       triangle;
+   quad_func           quad;
+} rast_tab[SAVAGE_MAX_TRIFUNC];
+
+
+#define DO_FALLBACK (IND & SAVAGE_FALLBACK_BIT)
+#define DO_OFFSET   (IND & SAVAGE_OFFSET_BIT)
+#define DO_UNFILLED (IND & SAVAGE_UNFILLED_BIT)
+#define DO_TWOSIDE  (IND & SAVAGE_TWOSIDE_BIT)
+#define DO_FLAT      0
+#define DO_TRI       1
+#define DO_QUAD      1
+#define DO_LINE      1
+#define DO_POINTS    1
+#define DO_FULL_QUAD 1
+
+#define HAVE_RGBA   1
+#define HAVE_SPEC   1
+#define HAVE_BACK_COLORS  0
+#define HAVE_HW_FLATSHADE 1
+#define VERTEX savageVertex
+#define TAB rast_tab
+
+#define DEPTH_SCALE imesa->depth_scale
+#define UNFILLED_TRI unfilled_tri
+#define UNFILLED_QUAD unfilled_quad
+#define VERT_X(_v) _v->v.x
+#define VERT_Y(_v) _v->v.y
+#define VERT_Z(_v) _v->v.z
+#define AREA_IS_CCW( a ) (a > 0)
+#define GET_VERTEX(e) (imesa->verts + (e * imesa->vertex_size * sizeof(int)))
+
+#define SAVAGE_COLOR( dst, src )               \
+do {                                           \
+   dst[0] = src[2];                            \
+   dst[1] = src[1];                            \
+   dst[2] = src[0];                            \
+   dst[3] = src[3];                            \
+} while (0)
+
+#define SAVAGE_SPEC( dst, src )                        \
+do {                                           \
+   dst[0] = src[2];                            \
+   dst[1] = src[1];                            \
+   dst[2] = src[0];                            \
+} while (0)
+
+#define VERT_SET_RGBA( v, c )    SAVAGE_COLOR( v->ub4[coloroffset], c )
+#define VERT_COPY_RGBA( v0, v1 ) v0->ui[coloroffset] = v1->ui[coloroffset]
+#define VERT_SAVE_RGBA( idx )    color[idx] = v[idx]->ui[coloroffset]
+#define VERT_RESTORE_RGBA( idx ) v[idx]->ui[coloroffset] = color[idx]
+
+#define VERT_SET_SPEC( v, c )    if (havespec) SAVAGE_SPEC( v->ub4[5], c )
+#define VERT_COPY_SPEC( v0, v1 ) if (havespec) COPY_3V(v0->ub4[5], v1->ub4[5])
+#define VERT_SAVE_SPEC( idx )    if (havespec) spec[idx] = v[idx]->ui[5]
+#define VERT_RESTORE_SPEC( idx ) if (havespec) v[idx]->ui[5] = spec[idx]
+
+#define LOCAL_VARS(n)                                          \
+   savageContextPtr imesa = SAVAGE_CONTEXT(ctx);               \
+   GLuint color[n], spec[n];                                   \
+   GLuint coloroffset = 4/*(rmesa->vertex_size == 4 ? 3 : 4)*/;        \
+   GLboolean havespec = 1/*(rmesa->vertex_size == 4 ? 0 : 1)*/;        \
+   (void) color; (void) spec; (void) coloroffset; (void) havespec;
+
+/***********************************************************************
+ *                Helpers for rendering unfilled primitives            *
+ ***********************************************************************/
+
+#define RASTERIZE(x)
+#define RENDER_PRIMITIVE imesa->render_primitive
+#define IND SAVAGE_FALLBACK_BIT
+#define TAG(x) x
+#include "tnl_dd/t_dd_unfilled.h"
+#undef IND
+
+
+/***********************************************************************
+ *                      Generate GL render functions                   *
+ ***********************************************************************/
+
+
+#define IND (0)
+#define TAG(x) x
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (SAVAGE_OFFSET_BIT)
+#define TAG(x) x##_offset
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (SAVAGE_TWOSIDE_BIT)
+#define TAG(x) x##_twoside
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (SAVAGE_TWOSIDE_BIT|SAVAGE_OFFSET_BIT)
+#define TAG(x) x##_twoside_offset
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (SAVAGE_UNFILLED_BIT)
+#define TAG(x) x##_unfilled
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (SAVAGE_OFFSET_BIT|SAVAGE_UNFILLED_BIT)
+#define TAG(x) x##_offset_unfilled
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (SAVAGE_TWOSIDE_BIT|SAVAGE_UNFILLED_BIT)
+#define TAG(x) x##_twoside_unfilled
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (SAVAGE_TWOSIDE_BIT|SAVAGE_OFFSET_BIT|SAVAGE_UNFILLED_BIT)
+#define TAG(x) x##_twoside_offset_unfilled
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (SAVAGE_FALLBACK_BIT)
+#define TAG(x) x##_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (SAVAGE_OFFSET_BIT|SAVAGE_FALLBACK_BIT)
+#define TAG(x) x##_offset_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (SAVAGE_TWOSIDE_BIT|SAVAGE_FALLBACK_BIT)
+#define TAG(x) x##_twoside_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (SAVAGE_TWOSIDE_BIT|SAVAGE_OFFSET_BIT|SAVAGE_FALLBACK_BIT)
+#define TAG(x) x##_twoside_offset_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (SAVAGE_UNFILLED_BIT|SAVAGE_FALLBACK_BIT)
+#define TAG(x) x##_unfilled_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (SAVAGE_OFFSET_BIT|SAVAGE_UNFILLED_BIT|SAVAGE_FALLBACK_BIT)
+#define TAG(x) x##_offset_unfilled_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (SAVAGE_TWOSIDE_BIT|SAVAGE_UNFILLED_BIT|SAVAGE_FALLBACK_BIT)
+#define TAG(x) x##_twoside_unfilled_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+#define IND (SAVAGE_TWOSIDE_BIT|SAVAGE_OFFSET_BIT|SAVAGE_UNFILLED_BIT| \
+            SAVAGE_FALLBACK_BIT)
+#define TAG(x) x##_twoside_offset_unfilled_fallback
+#include "tnl_dd/t_dd_tritmp.h"
+
+
+static void init_rast_tab( void )
+{
+   init();
+   init_offset();
+   init_twoside();
+   init_twoside_offset();
+   init_unfilled();
+   init_offset_unfilled();
+   init_twoside_unfilled();
+   init_twoside_offset_unfilled();
+   init_fallback();
+   init_offset_fallback();
+   init_twoside_fallback();
+   init_twoside_offset_fallback();
+   init_unfilled_fallback();
+   init_offset_unfilled_fallback();
+   init_twoside_unfilled_fallback();
+   init_twoside_offset_unfilled_fallback();
+}
+
+
+
+/***********************************************************************
+ *                    Rasterization fallback helpers                   *
+ ***********************************************************************/
+
+
+/* This code is hit only when a mix of accelerated and unaccelerated
+ * primitives are being drawn, and only for the unaccelerated
+ * primitives.
+ */
+static void
+savage_fallback_tri( savageContextPtr imesa,
+                    savageVertexPtr v0,
+                    savageVertexPtr v1,
+                    savageVertexPtr v2 )
+{
+   GLcontext *ctx = imesa->glCtx;
+   SWvertex v[3];
+   savage_translate_vertex( ctx, v0, &v[0] );
+   savage_translate_vertex( ctx, v1, &v[1] );
+   savage_translate_vertex( ctx, v2, &v[2] );
+   _swrast_Triangle( ctx, &v[0], &v[1], &v[2] );
+}
+
+
+static void
+savage_fallback_line( savageContextPtr imesa,
+                     savageVertexPtr v0,
+                     savageVertexPtr v1 )
+{
+   GLcontext *ctx = imesa->glCtx;
+   SWvertex v[2];
+   savage_translate_vertex( ctx, v0, &v[0] );
+   savage_translate_vertex( ctx, v1, &v[1] );
+   _swrast_Line( ctx, &v[0], &v[1] );
+}
+
+
+static void
+savage_fallback_point( savageContextPtr imesa,
+                      savageVertexPtr v0 )
+{
+   GLcontext *ctx = imesa->glCtx;
+   SWvertex v[1];
+   savage_translate_vertex( ctx, v0, &v[0] );
+   _swrast_Point( ctx, &v[0] );
+}
+
+
+
+/**********************************************************************/
+/*               Render unclipped begin/end objects                   */
+/**********************************************************************/
+
+#define VERT(x) (savageVertexPtr)(savageVerts + (x * vertsize * sizeof(int)))
+#define RENDER_POINTS( start, count )          \
+   for ( ; start < count ; start++)            \
+      savage_draw_point( imesa, VERT(start) )
+#define RENDER_LINE( v0, v1 ) \
+   savage_draw_line( imesa, VERT(v0), VERT(v1) )
+#define RENDER_TRI( v0, v1, v2 )  \
+   savage_draw_triangle( imesa, VERT(v0), VERT(v1), VERT(v2) )
+#define RENDER_QUAD( v0, v1, v2, v3 ) \
+   savage_draw_quad( imesa, VERT(v0), VERT(v1), VERT(v2), VERT(v3) )
+#define INIT(x) do {                                   \
+   if (0) fprintf(stderr, "%s\n", __FUNCTION__);       \
+   savageRenderPrimitive( ctx, x );                     \
+   /*SAVAGE_CONTEXT(ctx)->render_primitive = x;*/       \
+} while (0)
+#undef LOCAL_VARS
+#define LOCAL_VARS                                             \
+    savageContextPtr imesa = SAVAGE_CONTEXT(ctx);              \
+    const GLuint vertsize = imesa->vertex_size;                        \
+    const char *savageVerts = (char *)imesa->verts;            \
+    const GLuint * const elt = TNL_CONTEXT(ctx)->vb.Elts;      \
+    (void) elt;
+#define RESET_STIPPLE
+#define RESET_OCCLUSION
+#define PRESERVE_VB_DEFS
+#define ELT(x) (x)
+#define TAG(x) savage_##x##_verts
+#include "tnl/t_vb_rendertmp.h"
+#undef ELT
+#undef TAG
+#define TAG(x) savage_##x##_elts
+#define ELT(x) elt[x]
+#include "tnl/t_vb_rendertmp.h"
+
+
+/**********************************************************************/
+/*                    Render clipped primitives                       */
+/**********************************************************************/
+
+static void savageRenderClippedPoly( GLcontext *ctx, const GLuint *elts,
+                                    GLuint n )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+
+   /* Render the new vertices as an unclipped polygon.
+    */
+   {
+      GLuint *tmp = VB->Elts;
+      VB->Elts = (GLuint *)elts;
+      tnl->Driver.Render.PrimTabElts[GL_POLYGON]( ctx, 0, n, PRIM_BEGIN|PRIM_END );
+      VB->Elts = tmp;
+   }
+}
+
+static void savageRenderClippedLine( GLcontext *ctx, GLuint ii, GLuint jj )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   tnl->Driver.Render.Line( ctx, ii, jj );
+}
+/*
+static void savageFastRenderClippedPoly( GLcontext *ctx, const GLuint *elts,
+                                        GLuint n )
+{
+   r128ContextPtr rmesa = R128_CONTEXT( ctx );
+   GLuint vertsize = rmesa->vertex_size;
+   GLuint *vb = r128AllocDmaLow( rmesa, (n-2) * 3 * 4 * vertsize );
+   GLubyte *r128verts = (GLubyte *)rmesa->verts;
+   const GLuint shift = rmesa->vertex_stride_shift;
+   const GLuint *start = (const GLuint *)VERT(elts[0]);
+   int i,j;
+
+   rmesa->num_verts += (n-2) * 3;
+
+   for (i = 2 ; i < n ; i++) {
+      COPY_DWORDS( j, vb, vertsize, (r128VertexPtr) start );
+      COPY_DWORDS( j, vb, vertsize, (r128VertexPtr) VERT(elts[i-1]) );
+      COPY_DWORDS( j, vb, vertsize, (r128VertexPtr) VERT(elts[i]) );
+   }
+}
+*/
+
+
+
+/**********************************************************************/
+/*                    Choose render functions                         */
+/**********************************************************************/
+
+#define _SAVAGE_NEW_RENDER_STATE (_DD_NEW_LINE_STIPPLE |       \
+                                 _DD_NEW_LINE_SMOOTH |         \
+                                 _DD_NEW_POINT_SMOOTH |        \
+                                 _DD_NEW_TRI_SMOOTH |          \
+                                 _DD_NEW_TRI_UNFILLED |        \
+                                 _DD_NEW_TRI_LIGHT_TWOSIDE |   \
+                                 _DD_NEW_TRI_OFFSET)           \
+
+/* original driver didn't have DD_POINT_SMOOTH. really needed? */
+#define POINT_FALLBACK (DD_POINT_SMOOTH)
+#define LINE_FALLBACK (DD_LINE_STIPPLE|DD_LINE_SMOOTH)
+#define TRI_FALLBACK (DD_TRI_SMOOTH)
+#define ANY_FALLBACK_FLAGS (POINT_FALLBACK|LINE_FALLBACK|TRI_FALLBACK)
+#define ANY_RASTER_FLAGS (DD_TRI_LIGHT_TWOSIDE|DD_TRI_OFFSET|DD_TRI_UNFILLED)
+
+
+static void savageChooseRenderState(GLcontext *ctx)
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+   GLuint flags = ctx->_TriangleCaps;
+   GLuint index = 0;
+
+   if (flags & (ANY_RASTER_FLAGS|ANY_FALLBACK_FLAGS)) {
+      imesa->draw_point = savage_draw_point;
+      imesa->draw_line = savage_draw_line;
+      imesa->draw_tri = savage_draw_triangle;
+
+      if (flags & ANY_RASTER_FLAGS) {
+        if (flags & DD_TRI_LIGHT_TWOSIDE) index |= SAVAGE_TWOSIDE_BIT;
+        if (flags & DD_TRI_OFFSET)        index |= SAVAGE_OFFSET_BIT;
+        if (flags & DD_TRI_UNFILLED)      index |= SAVAGE_UNFILLED_BIT;
+      }
+
+      /* Hook in fallbacks for specific primitives.
+       */
+      if (flags & (POINT_FALLBACK|LINE_FALLBACK|TRI_FALLBACK)) {
+        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;
+        index |= SAVAGE_FALLBACK_BIT;
+      }
+   }
+
+   if (index != imesa->RenderIndex) {
+      TNLcontext *tnl = TNL_CONTEXT(ctx);
+      tnl->Driver.Render.Points = rast_tab[index].points;
+      tnl->Driver.Render.Line = rast_tab[index].line;
+      tnl->Driver.Render.Triangle = rast_tab[index].triangle;
+      tnl->Driver.Render.Quad = rast_tab[index].quad;
+
+      if (index == 0) {
+        tnl->Driver.Render.PrimTabVerts = savage_render_tab_verts;
+        tnl->Driver.Render.PrimTabElts = savage_render_tab_elts;
+        tnl->Driver.Render.ClippedLine = rast_tab[index].line;
+        tnl->Driver.Render.ClippedPolygon = savageRenderClippedPoly/*r128FastRenderClippedPoly*/;
+      } else {
+        tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts;
+        tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts;
+        tnl->Driver.Render.ClippedLine = savageRenderClippedLine;
+        tnl->Driver.Render.ClippedPolygon = savageRenderClippedPoly;
+      }
+
+      imesa->RenderIndex = index;
+   }
+}
+
+/**********************************************************************/
+/*                 Validate state at pipeline start                   */
+/**********************************************************************/
+
+static void savageRunPipeline( GLcontext *ctx )
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+
+   if (imesa->new_state)
+      savageDDUpdateHwState( ctx );
+
+   if (!imesa->Fallback && imesa->new_gl_state) {
+      if (imesa->new_gl_state & _SAVAGE_NEW_VERTEX_STATE)
+        savageChooseVertexState( ctx );
+
+      if (imesa->new_gl_state & _SAVAGE_NEW_RENDER_STATE)
+        savageChooseRenderState( ctx );
+
+      imesa->new_gl_state = 0;
+   }
+
+   _tnl_run_pipeline( ctx );
+}
+
+/**********************************************************************/
+/*                 High level hooks for t_vb_render.c                 */
+/**********************************************************************/
+
+static GLenum reduced_prim[GL_POLYGON+1] = {
+   GL_POINTS,
+   GL_LINES,
+   GL_LINES,
+   GL_LINES,
+   GL_TRIANGLES,
+   GL_TRIANGLES,
+   GL_TRIANGLES,
+   GL_TRIANGLES,
+   GL_TRIANGLES,
+   GL_TRIANGLES
+};
+
+/* This is called when Mesa switches between rendering triangle
+ * primitives (such as GL_POLYGON, GL_QUADS, GL_TRIANGLE_STRIP, etc),
+ * and lines, points and bitmaps.
+ *
+ * As the r128 uses triangles to render lines and points, it is
+ * necessary to turn off hardware culling when rendering these
+ * primitives.
+ */
+
+static void savageRasterPrimitive( GLcontext *ctx, GLuint prim )
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+
+   FLUSH_BATCH( imesa );
+
+   /* Update culling */
+   if (imesa->raster_primitive != prim)
+      imesa->dirty |= SAVAGE_UPLOAD_CTX;
+
+   imesa->raster_primitive = prim;
+#if 0
+   if (ctx->Polygon.StippleFlag && mmesa->haveHwStipple)
+   {
+      mmesa->dirty |= MGA_UPLOAD_CONTEXT;
+      mmesa->setup.dwgctl &= ~(0xf<<20);
+      if (mmesa->raster_primitive == GL_TRIANGLES)
+        mmesa->setup.dwgctl |= mmesa->poly_stipple;
+   }
+#endif
+}
+
+static void savageRenderPrimitive( GLcontext *ctx, GLenum prim )
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+   GLuint rprim = reduced_prim[prim];
+
+   imesa->render_primitive = prim;
+
+   if (rprim == GL_TRIANGLES && (ctx->_TriangleCaps & DD_TRI_UNFILLED))
+      return;
+       
+   if (imesa->raster_primitive != rprim) {
+      savageRasterPrimitive( ctx, rprim );
+   }
+}
+
+
+static void savageRenderStart( GLcontext *ctx )
+{
+   /* Check for projective texturing.  Make sure all texcoord
+    * pointers point to something.  (fix in mesa?)
+    */
+   savageCheckTexSizes( ctx );
+
+   if (!SAVAGE_CONTEXT(ctx)->Fallback) {
+      /* Update hardware state and get the lock */
+      savageDDRenderStart( ctx );
+   }
+}
+
+static void savageRenderFinish( GLcontext *ctx )
+{
+   /* Release the lock */
+   savageDDRenderEnd( ctx );
+
+   if (SAVAGE_CONTEXT(ctx)->RenderIndex & SAVAGE_FALLBACK_BIT)
+      _swrast_flush( ctx );
+}
+
+
+/**********************************************************************/
+/*           Transition to/from hardware rasterization.               */
+/**********************************************************************/
+
+void savageFallback( GLcontext *ctx, GLuint bit, GLboolean mode )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+   GLuint oldfallback = imesa->Fallback;
+
+   if (mode) {
+      imesa->Fallback |= bit;
+      if (oldfallback == 0) {
+        /* the first fallback */
+        LOCK_HARDWARE(SAVAGE_CONTEXT(ctx));
+        FLUSH_BATCH( imesa );
+        UNLOCK_HARDWARE(SAVAGE_CONTEXT(ctx));
+        _swsetup_Wakeup( ctx );
+        imesa->RenderIndex = ~0;
+      }
+   }
+   else {
+      imesa->Fallback &= ~bit;
+      if (oldfallback == bit) {
+        /* the last fallback */
+        _swrast_flush( ctx );
+        tnl->Driver.Render.Start = savageRenderStart;
+        tnl->Driver.Render.PrimitiveNotify = savageRenderPrimitive;
+        tnl->Driver.Render.Finish = savageRenderFinish;
+        tnl->Driver.Render.BuildVertices = savageBuildVertices;
+        imesa->new_gl_state |= (_SAVAGE_NEW_RENDER_STATE|
+                                _SAVAGE_NEW_VERTEX_STATE);
+      }
+   }
+}
+
+
+/**********************************************************************/
+/*                            Initialization.                         */
+/**********************************************************************/
+
+void savageInitTriFuncs( GLcontext *ctx )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   static int firsttime = 1;
+
+   if (firsttime) {
+      init_rast_tab();
+      firsttime = 0;
+   }
+
+   tnl->Driver.RunPipeline = savageRunPipeline;
+   tnl->Driver.Render.Start = savageRenderStart;
+   tnl->Driver.Render.Finish = savageRenderFinish;
+   tnl->Driver.Render.PrimitiveNotify = savageRenderPrimitive;
+   tnl->Driver.Render.ResetLineStipple = _swrast_ResetLineStipple;
+   tnl->Driver.Render.BuildVertices = savageBuildVertices;
+
+/*     r128Fallback( ctx, 0x100000, 1 ); */
+}
diff --git a/src/mesa/drivers/dri/savage/savagetris.h b/src/mesa/drivers/dri/savage/savagetris.h
new file mode 100644 (file)
index 0000000..00803e7
--- /dev/null
@@ -0,0 +1,49 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_tris.h,v 1.4 2001/01/08 01:07:24 martin Exp $ */
+/**************************************************************************
+
+Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and
+                     VA Linux Systems Inc., Fremont, California.
+
+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"),
+to deal in the Software without restriction, including without limitation
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, and/or sell copies of the Software, and to permit persons to whom
+the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ *   Keith Whitwell <keithw@valinux.com>
+ *   Felix Kuehling <fxkuehl@gmx.de>
+ *
+ */
+
+#ifndef __R128_TRIS_H__
+#define __R128_TRIS_H__
+
+#include "mtypes.h"
+
+extern void savageInitTriFuncs( GLcontext *ctx );
+
+
+extern void savageFallback( GLcontext *ctx, GLuint bit, GLboolean mode );
+#define FALLBACK( ctx, bit, mode ) savageFallback( ctx, bit, mode )
+
+
+#endif /* __R128_TRIS_H__ */
diff --git a/src/mesa/drivers/dri/savage/savagevb.c b/src/mesa/drivers/dri/savage/savagevb.c
new file mode 100644 (file)
index 0000000..f0f4f4c
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ * Copyright 2000-2001 VA Linux Systems, Inc.
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Keith Whitwell <keithw@valinux.com>
+ *    Felix Kuehling <fxkuehl@gmx.de>
+ */
+/* $XFree86$ */
+
+#include "savagecontext.h"
+#include "savagevb.h"
+#include "savagetris.h"
+#include "savageioctl.h"
+#include "savagecontext.h"
+#include "savage_bci.h"
+
+#include "glheader.h"
+#include "mtypes.h"
+#include "macros.h"
+#include "colormac.h"
+
+#include "tnl/t_context.h"
+#include "swrast_setup/swrast_setup.h"
+#include "swrast/swrast.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#define SAVAGE_TEX1_BIT       0x1
+#define SAVAGE_TEX0_BIT       0x2      
+#define SAVAGE_RGBA_BIT       0x4
+#define SAVAGE_SPEC_BIT       0x8
+#define SAVAGE_FOG_BIT       0x10
+#define SAVAGE_XYZW_BIT       0x20
+#define SAVAGE_PTEX_BIT       0x40
+#define SAVAGE_MAX_SETUP      0x80
+
+static struct {
+   void                (*emit)( GLcontext *, GLuint, GLuint, void *, GLuint );
+   interp_func         interp;
+   copy_pv_func                copy_pv;
+   GLboolean           (*check_tex_sizes)( GLcontext *ctx );
+   GLuint               vertex_size;
+   GLuint               vertex_format;
+} setup_tab[SAVAGE_MAX_SETUP];
+
+/* savage supports vertices without specular color, but this is not supported
+ * by the vbtmp. have to check if/how tiny vertices work. */
+#define TINY_VERTEX_FORMAT      0
+#define NOTEX_VERTEX_FORMAT     (SAVAGE_HW_NO_UV0|SAVAGE_HW_NO_UV1)
+#define TEX0_VERTEX_FORMAT      (SAVAGE_HW_NO_UV1)
+#define TEX1_VERTEX_FORMAT      (0)
+#define PROJ_TEX1_VERTEX_FORMAT 0
+#define TEX2_VERTEX_FORMAT      0
+#define TEX3_VERTEX_FORMAT      0
+#define PROJ_TEX3_VERTEX_FORMAT 0
+
+#define DO_XYZW (IND & SAVAGE_XYZW_BIT)
+#define DO_RGBA (IND & SAVAGE_RGBA_BIT)
+#define DO_SPEC (IND & SAVAGE_SPEC_BIT)
+#define DO_FOG  (IND & SAVAGE_FOG_BIT)
+#define DO_TEX0 (IND & SAVAGE_TEX0_BIT)
+#define DO_TEX1 (IND & SAVAGE_TEX1_BIT)
+#define DO_TEX2 0
+#define DO_TEX3 0
+#define DO_PTEX (IND & SAVAGE_PTEX_BIT)
+
+
+#define VERTEX savageVertex
+#define LOCALVARS savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+#define GET_VIEWPORT_MAT() imesa->hw_viewport
+#define GET_TEXSOURCE(n)  n
+#define GET_VERTEX_FORMAT() (imesa->DrawPrimitiveCmd & \
+                             (SAVAGE_HW_NO_UV0|SAVAGE_HW_NO_UV1))
+#define GET_VERTEX_STORE() imesa->verts
+#define GET_VERTEX_SIZE() (imesa->vertex_size * sizeof(int))
+
+#define HAVE_HW_VIEWPORT    0
+#define HAVE_HW_DIVIDE      0
+#define HAVE_RGBA_COLOR     0
+#define HAVE_TINY_VERTICES  0
+#define HAVE_NOTEX_VERTICES 1
+#define HAVE_TEX0_VERTICES  1
+#define HAVE_TEX1_VERTICES  1
+#define HAVE_TEX2_VERTICES  0
+#define HAVE_TEX3_VERTICES  0
+#define HAVE_PTEX_VERTICES  0
+
+#define UNVIEWPORT_VARS                                        \
+   const GLfloat dx = - imesa->drawX - SUBPIXEL_X;     \
+   const GLfloat dy = (imesa->driDrawable->h +                 \
+                      imesa->drawY + SUBPIXEL_Y);      \
+   const GLfloat sz = 1.0 / imesa->depth_scale
+
+#define UNVIEWPORT_X(x)    x      + dx;
+#define UNVIEWPORT_Y(y)  - y      + dy;
+#define UNVIEWPORT_Z(z)    z * sz;
+
+#define PTEX_FALLBACK() (void)imesa, FALLBACK(ctx, SAVAGE_FALLBACK_TEXTURE, 1)
+
+
+#define INTERP_VERTEX (void)imesa, setup_tab[SAVAGE_CONTEXT(ctx)->SetupIndex].interp
+#define COPY_PV_VERTEX (void)imesa, setup_tab[SAVAGE_CONTEXT(ctx)->SetupIndex].copy_pv
+
+
+/***********************************************************************
+ *         Generate  pv-copying and translation functions              *
+ ***********************************************************************/
+
+#define TAG(x) savage_##x
+#include "tnl_dd/t_dd_vb.c"
+
+/***********************************************************************
+ *             Generate vertex emit and interp functions               *
+ ***********************************************************************/
+
+
+#define IND (SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT)
+#define TAG(x) x##_wg
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT|SAVAGE_SPEC_BIT)
+#define TAG(x) x##_wgs
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT|SAVAGE_TEX0_BIT)
+#define TAG(x) x##_wgt0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT|SAVAGE_TEX0_BIT|SAVAGE_TEX1_BIT)
+#define TAG(x) x##_wgt0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT|SAVAGE_TEX0_BIT|SAVAGE_PTEX_BIT)
+#define TAG(x) x##_wgpt0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT|SAVAGE_SPEC_BIT|SAVAGE_TEX0_BIT)
+#define TAG(x) x##_wgst0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT|SAVAGE_SPEC_BIT|SAVAGE_TEX0_BIT|SAVAGE_TEX1_BIT)
+#define TAG(x) x##_wgst0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT|SAVAGE_SPEC_BIT|SAVAGE_TEX0_BIT|SAVAGE_PTEX_BIT)
+#define TAG(x) x##_wgspt0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT|SAVAGE_FOG_BIT)
+#define TAG(x) x##_wgf
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT|SAVAGE_FOG_BIT|SAVAGE_SPEC_BIT)
+#define TAG(x) x##_wgfs
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT|SAVAGE_FOG_BIT|SAVAGE_TEX0_BIT)
+#define TAG(x) x##_wgft0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT|SAVAGE_FOG_BIT|SAVAGE_TEX0_BIT|SAVAGE_TEX1_BIT)
+#define TAG(x) x##_wgft0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT|SAVAGE_FOG_BIT|SAVAGE_TEX0_BIT|SAVAGE_PTEX_BIT)
+#define TAG(x) x##_wgfpt0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT|SAVAGE_FOG_BIT|SAVAGE_SPEC_BIT|SAVAGE_TEX0_BIT)
+#define TAG(x) x##_wgfst0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT|SAVAGE_FOG_BIT|SAVAGE_SPEC_BIT|SAVAGE_TEX0_BIT|SAVAGE_TEX1_BIT)
+#define TAG(x) x##_wgfst0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT|SAVAGE_FOG_BIT|SAVAGE_SPEC_BIT|SAVAGE_TEX0_BIT|SAVAGE_PTEX_BIT)
+#define TAG(x) x##_wgfspt0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_TEX0_BIT)
+#define TAG(x) x##_t0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_TEX0_BIT|SAVAGE_TEX1_BIT)
+#define TAG(x) x##_t0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_FOG_BIT)
+#define TAG(x) x##_f
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_FOG_BIT|SAVAGE_TEX0_BIT)
+#define TAG(x) x##_ft0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_FOG_BIT|SAVAGE_TEX0_BIT|SAVAGE_TEX1_BIT)
+#define TAG(x) x##_ft0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_RGBA_BIT)
+#define TAG(x) x##_g
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_RGBA_BIT|SAVAGE_SPEC_BIT)
+#define TAG(x) x##_gs
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_RGBA_BIT|SAVAGE_TEX0_BIT)
+#define TAG(x) x##_gt0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_RGBA_BIT|SAVAGE_TEX0_BIT|SAVAGE_TEX1_BIT)
+#define TAG(x) x##_gt0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_RGBA_BIT|SAVAGE_SPEC_BIT|SAVAGE_TEX0_BIT)
+#define TAG(x) x##_gst0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_RGBA_BIT|SAVAGE_SPEC_BIT|SAVAGE_TEX0_BIT|SAVAGE_TEX1_BIT)
+#define TAG(x) x##_gst0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_RGBA_BIT|SAVAGE_FOG_BIT)
+#define TAG(x) x##_gf
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_RGBA_BIT|SAVAGE_FOG_BIT|SAVAGE_SPEC_BIT)
+#define TAG(x) x##_gfs
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_RGBA_BIT|SAVAGE_FOG_BIT|SAVAGE_TEX0_BIT)
+#define TAG(x) x##_gft0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_RGBA_BIT|SAVAGE_FOG_BIT|SAVAGE_TEX0_BIT|SAVAGE_TEX1_BIT)
+#define TAG(x) x##_gft0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_RGBA_BIT|SAVAGE_FOG_BIT|SAVAGE_SPEC_BIT|SAVAGE_TEX0_BIT)
+#define TAG(x) x##_gfst0
+#include "tnl_dd/t_dd_vbtmp.h"
+
+#define IND (SAVAGE_RGBA_BIT|SAVAGE_FOG_BIT|SAVAGE_SPEC_BIT|SAVAGE_TEX0_BIT|SAVAGE_TEX1_BIT)
+#define TAG(x) x##_gfst0t1
+#include "tnl_dd/t_dd_vbtmp.h"
+
+
+static void init_setup_tab( void )
+{
+   init_wg();
+   init_wgs();
+   init_wgt0();
+   init_wgt0t1();
+   init_wgpt0();
+   init_wgst0();
+   init_wgst0t1();
+   init_wgspt0();
+   init_wgf();
+   init_wgfs();
+   init_wgft0();
+   init_wgft0t1();
+   init_wgfpt0();
+   init_wgfst0();
+   init_wgfst0t1();
+   init_wgfspt0();
+   init_t0();
+   init_t0t1();
+   init_f();
+   init_ft0();
+   init_ft0t1();
+   init_g();
+   init_gs();
+   init_gt0();
+   init_gt0t1();
+   init_gst0();
+   init_gst0t1();
+   init_gf();
+   init_gfs();
+   init_gft0();
+   init_gft0t1();
+   init_gfst0();
+   init_gfst0t1();
+}
+
+
+
+
+void savagePrintSetupFlags(char *msg, GLuint flags )
+{
+   fprintf(stderr, "%s: %d %s%s%s%s%s%s\n",
+          msg,
+          (int)flags,
+          (flags & SAVAGE_XYZW_BIT)     ? " xyzw," : "", 
+          (flags & SAVAGE_RGBA_BIT)     ? " rgba," : "",
+          (flags & SAVAGE_SPEC_BIT)     ? " spec," : "",
+          (flags & SAVAGE_FOG_BIT)      ? " fog," : "",
+          (flags & SAVAGE_TEX0_BIT)     ? " tex-0," : "",
+          (flags & SAVAGE_TEX1_BIT)     ? " tex-1," : "");
+}
+
+
+void savageCheckTexSizes( GLcontext *ctx )
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+   /*fprintf(stderr, "%s\n", __FUNCTION__);*/
+
+   if (!setup_tab[imesa->SetupIndex].check_tex_sizes(ctx)) {
+      imesa->SetupIndex |= SAVAGE_PTEX_BIT;
+      imesa->SetupNewInputs = ~0;
+
+      if (!imesa->Fallback &&
+         !(ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED))) {
+        tnl->Driver.Render.Interp = setup_tab[imesa->SetupIndex].interp;
+        tnl->Driver.Render.CopyPV = setup_tab[imesa->SetupIndex].copy_pv;
+      }
+      if (imesa->Fallback)
+        tnl->Driver.Render.Start(ctx);
+   }
+}
+
+
+void savageBuildVertices( GLcontext *ctx, 
+                         GLuint start, 
+                         GLuint count,
+                         GLuint newinputs )
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+   GLuint stride = imesa->vertex_size * sizeof(int);
+   GLubyte *v = ((GLubyte *)imesa->verts + (start * stride));
+
+   newinputs |= imesa->SetupNewInputs;
+   imesa->SetupNewInputs = 0;
+
+   if (!newinputs)
+      return;
+
+   if (newinputs & VERT_BIT_POS) {
+      setup_tab[imesa->SetupIndex].emit( ctx, start, count, v, stride );   
+   } else {
+      GLuint ind = 0;
+
+      if (newinputs & VERT_BIT_COLOR0)
+        ind |= SAVAGE_RGBA_BIT;
+      
+      if (newinputs & VERT_BIT_COLOR1)
+        ind |= SAVAGE_SPEC_BIT;
+
+      if (newinputs & VERT_BIT_TEX0)
+        ind |= SAVAGE_TEX0_BIT;
+
+      if (newinputs & VERT_BIT_TEX1)
+        ind |= SAVAGE_TEX0_BIT|SAVAGE_TEX1_BIT;
+
+      if (newinputs & VERT_BIT_FOG)
+        ind |= SAVAGE_FOG_BIT;
+
+      if (imesa->SetupIndex & SAVAGE_PTEX_BIT)
+        ind = ~0;
+
+      ind &= imesa->SetupIndex;
+
+      if (ind) {
+        setup_tab[ind].emit( ctx, start, count, v, stride );   
+      }
+   }
+}
+
+
+void savageChooseVertexState( GLcontext *ctx )
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   GLuint ind = SAVAGE_XYZW_BIT|SAVAGE_RGBA_BIT;
+
+   if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) 
+      ind |= SAVAGE_SPEC_BIT;
+
+   if (ctx->Fog.Enabled) 
+      ind |= SAVAGE_FOG_BIT;
+   
+   if (ctx->Texture._EnabledUnits & 0x2) {
+      if (ctx->Texture._EnabledUnits & 0x1) {
+        ind |= SAVAGE_TEX1_BIT|SAVAGE_TEX0_BIT;
+      }
+      else {
+        ind |= SAVAGE_TEX0_BIT;
+      }
+   }
+   else if (ctx->Texture._EnabledUnits & 0x1) {
+      ind |= SAVAGE_TEX0_BIT;
+   }
+   
+   imesa->SetupIndex = ind;
+
+   if (ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED)) {
+      tnl->Driver.Render.Interp = savage_interp_extras;
+      tnl->Driver.Render.CopyPV = savage_copy_pv_extras;
+   } else {
+      tnl->Driver.Render.Interp = setup_tab[ind].interp;
+      tnl->Driver.Render.CopyPV = setup_tab[ind].copy_pv;
+   }
+
+   if (setup_tab[ind].vertex_format != GET_VERTEX_FORMAT()) {
+      imesa->DrawPrimitiveCmd = setup_tab[ind].vertex_format;
+      imesa->vertex_size = setup_tab[ind].vertex_size;
+   }
+}
+
+
+
+void savageInitVB( GLcontext *ctx )
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+   GLuint size = TNL_CONTEXT(ctx)->vb.Size;
+
+   imesa->verts = (GLubyte *)ALIGN_MALLOC(size * sizeof(savageVertex), 32);
+
+   {
+      static int firsttime = 1;
+      if (firsttime) {
+        init_setup_tab();
+        firsttime = 0;
+      }
+   }
+
+   imesa->DrawPrimitiveCmd = setup_tab[0].vertex_format;
+   imesa->vertex_size = setup_tab[0].vertex_size;
+
+   if (imesa->savageScreen->chipset >= S3_SAVAGE4)
+       imesa->DrawPrimitiveMask = ~0;
+   else
+       imesa->DrawPrimitiveMask = ~SAVAGE_HW_NO_UV1;
+}
+
+
+void savageFreeVB( GLcontext *ctx )
+{
+   savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+   if (imesa->verts) {
+      ALIGN_FREE(imesa->verts);
+      imesa->verts = 0;
+   }
+}
+
diff --git a/src/mesa/drivers/dri/savage/savagevb.h b/src/mesa/drivers/dri/savage/savagevb.h
new file mode 100644 (file)
index 0000000..9ee2bd9
--- /dev/null
@@ -0,0 +1,62 @@
+/* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgavb.h,v 1.6 2001/04/10 16:07:51 dawes Exp $ */
+/*
+ * Copyright 2000-2001 VA Linux Systems, Inc.
+ * 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"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Keith Whitwell <keithw@valinux.com>
+ *    Felix Kuehling <fxkuehl@gmx.de>
+ */
+
+#ifndef SAVAGEVB_INC
+#define SAVAGEVB_INC
+
+#include "mtypes.h"
+#include "savagecontext.h"
+#include "swrast/swrast.h"
+
+#define _SAVAGE_NEW_VERTEX_STATE (_NEW_TEXTURE |               \
+                                 _DD_NEW_SEPARATE_SPECULAR |   \
+                                 _DD_NEW_TRI_UNFILLED |        \
+                                 _DD_NEW_TRI_LIGHT_TWOSIDE |   \
+                                 _NEW_FOG)
+
+
+extern void savageChooseVertexState( GLcontext *ctx );
+extern void savageCheckTexSizes( GLcontext *ctx );
+extern void savageBuildVertices( GLcontext *ctx, 
+                                GLuint start, 
+                                GLuint count,
+                                GLuint newinputs );
+
+extern void savagePrintSetupFlags(char *msg, GLuint flags );
+
+extern void savageInitVB( GLcontext *ctx );
+extern void savageFreeVB( GLcontext *ctx );
+
+extern void savage_translate_vertex(GLcontext *ctx, 
+                                   const savageVertex *src, 
+                                   SWvertex *dst);
+
+extern void savage_print_vertex( GLcontext *ctx, const savageVertex *v );
+
+#endif