summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac5
-rw-r--r--src/Makefile.am19
-rw-r--r--src/savage_3d_reg.h711
-rw-r--r--src/savage_bci.h612
-rw-r--r--src/savage_init.h157
-rw-r--r--src/savage_xmesa.c1079
-rw-r--r--src/savagecontext.h322
-rw-r--r--src/savagedd.c101
-rw-r--r--src/savagedd.h32
-rw-r--r--src/savageioctl.c662
-rw-r--r--src/savageioctl.h203
-rw-r--r--src/savagerender.c370
-rw-r--r--src/savagespan.c277
-rw-r--r--src/savagespan.h137
-rw-r--r--src/savagestate.c1728
-rw-r--r--src/savagestate.h41
-rw-r--r--src/savagetex.c2100
-rw-r--r--src/savagetex.h83
-rw-r--r--src/savagetris.c1299
-rw-r--r--src/savagetris.h49
-rw-r--r--src/server/savage_dri.h76
21 files changed, 10056 insertions, 7 deletions
diff --git a/configure.ac b/configure.ac
index 2a78cfd..aca1dd3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
# Process this file with autoconf to produce a configure script
AC_PREREQ(2.57)
-AC_INIT([mesa-dri-xxx], 7.0.3, [], mesa-dri-xxx)
+AC_INIT([mesa-dri-savage], 7.0.3, [], mesa-dri-savage)
AM_INIT_AUTOMAKE([dist-bzip2])
@@ -16,7 +16,8 @@ AC_PROG_CC
AC_HEADER_STDC
PKG_CHECK_MODULES([DRM], [libdrm >= 2.3.0])
-PKG_CHECK_MODULES([DRI], [libmesadri = 7.0.3 libmesadricommon = 7.0.3])
+PKG_CHECK_MODULES([DRI], [libmesadri >= 7.0.3 libmesadri < 7.1.0
+ libmesadricommon >= 7.0.3 libmesadricommon < 7.1.0])
AC_OUTPUT([
Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index aa854c5..a5ab717 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,16 @@
AM_CFLAGS = -DIN_DRI_DRIVER -DGLX_DIRECT_RENDERING -DGLX_INDIRECT_RENDERING
-xxx_dri_la_LTLIBRARIES = xxx_dri.la
-xxx_dri_la_CFLAGS = $(AM_CFLAGS) $(DRM_CFLAGS) $(DRI_CFLAGS) -Iserver
-xxx_dri_la_LDFLAGS = -module -noprefix -lm -ldl $(DRM_LIBS) $(DRI_LIBS)
-xxx_dri_ladir = @libdir@/dri
-xxx_dri_la_SOURCES = \
+savage_dri_la_LTLIBRARIES = savage_dri.la
+savage_dri_la_CFLAGS = $(AM_CFLAGS) $(DRM_CFLAGS) $(DRI_CFLAGS) -Iserver
+savage_dri_la_LDFLAGS = -module -noprefix -avoid-version -lm -ldl \
+ $(DRM_LIBS) $(DRI_LIBS)
+savage_dri_ladir = @libdir@/dri
+savage_dri_la_SOURCES = \
+ savage_xmesa.c \
+ savagedd.c \
+ savagestate.c \
+ savagetex.c \
+ savagetris.c \
+ savagerender.c \
+ savageioctl.c \
+ savagespan.c
diff --git a/src/savage_3d_reg.h b/src/savage_3d_reg.h
new file mode 100644
index 0000000..bc81d73
--- /dev/null
+++ b/src/savage_3d_reg.h
@@ -0,0 +1,711 @@
+/*
+ * 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 VIDEO_MEM_ADR 0x02
+#define SYSTEM_MEM_ADR 0x01
+#define AGP_MEM_ADR 0x03
+
+/***********************************************************
+
+ ----------- 3D ENGINE UNIT Registers -------------
+
+ *********************************************************/
+
+typedef union
+{
+ struct
+ {
+ unsigned reserved : 4;
+ unsigned ofs : 28;
+ }ni;
+ u_int32_t ui;
+} savageRegZPixelOffset;
+
+/* This reg exists only on Savage4. */
+typedef union
+{
+ struct
+ {
+ unsigned cmpFunc : 3;
+ unsigned stencilEn : 1;
+ unsigned readMask : 8;
+ unsigned writeMask : 8;
+ unsigned failOp : 3;
+ unsigned passZfailOp : 3;
+ unsigned passZpassOp : 3;
+ unsigned reserved : 3;
+ }ni;
+ u_int32_t ui;
+} savageRegStencilCtrl;
+
+/**************************
+ Texture Registers
+**************************/
+/* The layout of this reg differs between Savage4 and Savage3D. */
+typedef union
+{
+ struct
+ {
+ unsigned tex0Width : 4;
+ unsigned tex0Height : 4;
+ unsigned tex0Fmt : 4;
+ unsigned tex1Width : 4;
+ unsigned tex1Height : 4;
+ unsigned tex1Fmt : 4;
+ unsigned texBLoopEn : 1;
+ unsigned tex0En : 1;
+ unsigned tex1En : 1;
+ unsigned orthProjEn : 1;
+ unsigned reserved : 1;
+ unsigned palSize : 2;
+ unsigned newPal : 1;
+ }ni;
+ u_int32_t ui;
+} savageRegTexDescr_s4;
+typedef union
+{
+ struct
+ {
+ unsigned texWidth : 4;
+ unsigned reserved1 : 4;
+ unsigned texHeight : 4;
+ unsigned reserved2 : 4;
+ /* Savage3D supports only the first 8 texture formats defined in
+ enum TexFmt in savge_bci.h. */
+ unsigned texFmt : 3;
+ unsigned palSize : 2;
+ unsigned reserved3 : 10;
+ unsigned newPal : 1;
+ }ni;
+ u_int32_t ui;
+} savageRegTexDescr_s3d;
+
+/* The layout of this reg is the same on Savage4 and Savage3D,
+ but the Savage4 has two of them, Savage3D has only one. */
+typedef union
+{
+ struct
+ {
+ unsigned inSysTex : 1;
+ unsigned inAGPTex : 1;
+ unsigned reserved : 1;
+ unsigned addr : 29;
+ }ni;
+ u_int32_t ui;
+} savageRegTexAddr;
+
+/* The layout of this reg is the same on Savage4 and Savage3D. */
+typedef union
+{
+ struct
+ {
+ unsigned reserved : 3;
+ unsigned addr : 29;
+ }ni;
+ u_int32_t ui;
+} savageRegTexPalAddr;
+
+/* The layout of this reg on Savage4 and Savage3D are very similar. */
+typedef union
+{
+ struct
+ {
+ unsigned xprClr0 : 16;
+ unsigned xprClr1 : 16; /* this is reserved on Savage3D */
+ }ni;
+ u_int32_t ui;
+} savageRegTexXprClr; /* transparency color in RGB565 format*/
+
+/* The layout of this reg differs between Savage4 and Savage3D.
+ * Savage4 has two of them, Savage3D has only one. */
+typedef union
+{
+ struct
+ {
+ unsigned filterMode : 2;
+ unsigned mipmapEnable : 1;
+ unsigned dBias : 9;
+ unsigned dMax : 4;
+ unsigned uMode : 2;
+ unsigned vMode : 2;
+ unsigned useDFraction : 1;
+ unsigned texXprEn : 1;
+ unsigned clrBlendAlphaSel : 2;
+ unsigned clrArg1CopyAlpha : 1;
+ unsigned clrArg2CopyAlpha : 1;
+ unsigned clrArg1Invert : 1;
+ unsigned clrArg2Invert : 1;
+ unsigned alphaBlendAlphaSel : 2;
+ unsigned alphaArg1Invert : 1;
+ unsigned alphaArg2Invert : 1;
+ }ni;
+ u_int32_t ui;
+} savageRegTexCtrl_s4;
+typedef union
+{
+ struct
+ {
+ unsigned filterMode : 2;
+ unsigned mipmapDisable : 1;
+ unsigned dBias : 9;
+ unsigned uWrapEn : 1;
+ unsigned vWrapEn : 1;
+ unsigned wrapMode : 2;
+ unsigned texEn : 1;
+ unsigned useDFraction : 1;
+ unsigned 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 CCA : 1;
+ unsigned texXprEn : 1;
+ unsigned reserved2 : 11;
+ }ni;
+ u_int32_t ui;
+} savageRegTexCtrl_s3d;
+
+/* This reg exists only on Savage4. */
+typedef union
+{
+ struct
+ {
+ unsigned colorArg1Sel : 2;
+ unsigned colorArg2Sel : 3;
+ unsigned colorInvAlphaEn : 1;
+ unsigned colorInvArg2En : 1;
+ unsigned colorPremodSel : 1;
+ unsigned colorMod1Sel : 1;
+ unsigned colorMod2Sel : 2;
+ unsigned colorAddSel : 2;
+ unsigned colorDoBlend : 1;
+ unsigned colorDo2sCompl : 1;
+ unsigned colorAddBiasEn : 1;
+ unsigned alphaArg1Sel : 2;
+ unsigned alphaArg2Sel : 3;
+ unsigned alphaMod1Sel : 1;
+ unsigned alphaMod2Sel : 2;
+ unsigned alphaAdd0Sel : 1;
+ unsigned alphaDoBlend : 1;
+ unsigned alphaDo2sCompl : 1;
+ unsigned colorStageClamp : 1;
+ unsigned alphaStageClamp : 1;
+ unsigned colorDoDiffMul : 1;
+ unsigned LeftShiftVal : 2;
+ }ni;
+ u_int32_t ui;
+} savageRegTexBlendCtrl;
+
+/* This reg exists only on Savage4. */
+typedef union
+{
+ struct
+ {
+ unsigned blue : 8;
+ unsigned green : 8;
+ unsigned red : 8;
+ unsigned alpha : 8;
+ }ni;
+ u_int32_t ui;
+} savageRegTexBlendColor;
+
+/********************************
+ Tiled Surface Registers
+**********************************/
+
+typedef union
+{
+ struct
+ {
+ unsigned frmBufOffset : 13;
+ unsigned reserved : 12;
+ unsigned widthInTile : 6;
+ unsigned bitPerPixel : 1;
+ }ni;
+ u_int32_t ui;
+} savageRegTiledSurface;
+
+/********************************
+ Draw/Shading Control Registers
+**********************************/
+
+/* This reg exists only on Savage4. */
+typedef union
+{
+ struct
+ {
+ unsigned scissorXStart : 11;
+ unsigned dPerfAccelEn : 1;
+ unsigned scissorYStart : 12;
+ unsigned alphaRefVal : 8;
+ }ni;
+ u_int32_t ui;
+} savageRegDrawCtrl0;
+
+/* This reg exists only on Savage4. */
+typedef union
+{
+ struct
+ {
+ unsigned scissorXEnd : 11;
+ unsigned xyOffsetEn : 1;
+ unsigned scissorYEnd : 12;
+ unsigned ditherEn : 1;
+ unsigned nonNormTexCoord : 1;
+ unsigned cullMode : 2;
+ unsigned alphaTestCmpFunc : 3;
+ unsigned alphaTestEn : 1;
+ }ni;
+ u_int32_t ui;
+} savageRegDrawCtrl1;
+
+/* This reg exists only on Savage4. */
+typedef union
+{
+ struct
+ {
+ unsigned dstAlphaMode : 3;
+
+ /**
+ * This bit enables \c GL_FUNC_SUBTRACT. Like most DirectX oriented
+ * hardware, there's no way to do \c GL_FUNC_REVERSE_SUBTRACT.
+ *
+ * \todo
+ * Add support for \c GL_FUNC_SUBTRACT!
+ */
+ unsigned dstMinusSrc : 1;
+ unsigned srcAlphaMode : 3;
+ unsigned binaryFinalAlpha : 1;
+ unsigned dstAlphaModeHighBit : 1;
+ unsigned srcAlphaModeHighBit : 1;
+ unsigned reserved1 : 15;
+ unsigned wrZafterAlphaTst : 1;
+ unsigned drawUpdateEn : 1;
+ unsigned zUpdateEn : 1;
+ unsigned flatShadeEn : 1;
+ unsigned specShadeEn : 1;
+ unsigned flushPdDestWrites : 1;
+ unsigned flushPdZbufWrites : 1;
+ }ni;
+ u_int32_t ui;
+} savageRegDrawLocalCtrl;
+
+/* This reg exists only on Savage3D. */
+typedef union
+{
+ struct
+ {
+ unsigned ditherEn : 1;
+ unsigned xyOffsetEn : 1;
+ unsigned cullMode : 2;
+ unsigned vertexCountReset : 1;
+ unsigned flatShadeEn : 1;
+ unsigned specShadeEn : 1;
+ unsigned dstAlphaMode : 3;
+ unsigned srcAlphaMode : 3;
+ unsigned reserved1 : 1;
+ unsigned alphaTestCmpFunc : 3;
+ unsigned alphaTestEn : 1;
+ unsigned alphaRefVal : 8;
+ unsigned texBlendCtrl : 3;
+ unsigned flushPdDestWrites : 1;
+ unsigned flushPdZbufWrites : 1;
+
+ /**
+ * Disable perspective correct interpolation for vertex color, vertex
+ * fog, and vertex alpha. For OpenGL, this should \b always be zero.
+ */
+ unsigned interpMode : 1;
+ }ni;
+ u_int32_t ui;
+} savageRegDrawCtrl;
+
+#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
+
+/* This reg exists only on Savage3D. */
+typedef union
+{
+ struct
+ {
+ unsigned scissorXStart : 11;
+ unsigned reserved1 : 5;
+ unsigned scissorYStart : 11;
+ unsigned reserved2 : 5;
+ } ni;
+ u_int32_t ui;
+} savageRegScissorsStart;
+
+/* This reg exists only on Savage3D. */
+typedef union
+{
+ struct
+ {
+ unsigned scissorXEnd : 11;
+ unsigned reserved1 : 5;
+ unsigned scissorYEnd : 11;
+ unsigned reserved2 : 5;
+ } ni;
+ u_int32_t ui;
+} savageRegScissorsEnd;
+
+/********************************
+ Address Registers
+**********************************/
+
+/* 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. */
+typedef union
+{
+ struct
+ {
+ unsigned isSys : 1;
+ unsigned isAGP : 1;
+ unsigned reserved : 1;
+ unsigned addr : 29; /*quad word aligned*/
+ }ni;
+ u_int32_t ui;
+} savageRegVertBufAddr;
+
+/* 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. */
+typedef union
+{
+ struct
+ {
+ unsigned isSys : 1;
+ unsigned isAGP : 1;
+ unsigned reserved : 1;
+ unsigned addr : 29; /*4-quad word aligned*/
+ }ni;
+ u_int32_t ui;
+} savageRegDMABufAddr;
+
+/********************************
+ H/W Debug Registers
+**********************************/
+/* The layout of this reg is the same on Savage4 and Savage3D. */
+typedef union
+{
+ struct
+ {
+ unsigned y01 : 1;
+ unsigned y12 : 1;
+ unsigned y20 : 1;
+ unsigned u01 : 1;
+ unsigned u12 : 1;
+ unsigned u20 : 1;
+ unsigned v01 : 1;
+ unsigned v12 : 1;
+ unsigned v20 : 1;
+ unsigned cullEn : 1;
+ unsigned cullOrient : 1;
+ unsigned loadNewTex : 1;
+ unsigned loadNewPal : 1;
+ unsigned doDSetup : 1;
+ unsigned reserved : 17;
+ unsigned kickOff : 1;
+ }ni;
+ u_int32_t ui;
+} savageRegFlag;
+
+/********************************
+ Z Buffer Registers -- Global
+**********************************/
+
+/* The layout of this reg differs between Savage4 and Savage3D. */
+typedef union
+{
+ struct
+ {
+ unsigned zCmpFunc : 3;
+ unsigned reserved1 : 2;
+ unsigned zBufEn : 1;
+ unsigned reserved2 : 1;
+ unsigned zExpOffset : 8;
+ unsigned reserved3 : 1;
+ unsigned stencilRefVal : 8;
+ unsigned autoZEnable : 1;
+ unsigned frameID : 1;
+ unsigned reserved4 : 4;
+ unsigned floatZEn : 1;
+ unsigned wToZEn : 1;
+ }ni;
+ u_int32_t ui;
+} savageRegZBufCtrl_s4;
+typedef union
+{
+ struct {
+ unsigned zCmpFunc : 3;
+ unsigned drawUpdateEn : 1;
+ unsigned zUpdateEn : 1;
+ unsigned zBufEn : 1;
+
+ /**
+ * We suspect that, in conjunction with
+ * \c savageRegZBufOffset::zDepthSelect, these 2 bits are actually
+ * \c stencilUpdateEn and \c stencilBufEn. If not, then some of
+ * the bits in \c reserved2 may fulfill that purpose.
+ */
+ unsigned reserved1 : 2;
+
+ unsigned zExpOffset : 8;
+ unsigned wrZafterAlphaTst : 1;
+ unsigned reserved2 : 15;
+ }ni;
+ u_int32_t ui;
+} savageRegZBufCtrl_s3d;
+
+/* The layout of this reg on Savage4 and Savage3D is very similar. */
+typedef union
+{
+ struct
+ {
+ /* In the Utah-Driver the offset is defined as 13-bit, 2k-aligned. */
+ unsigned offset : 14;
+ unsigned reserved : 11; /* 12-bits in Utah-driver */
+ unsigned zBufWidthInTiles : 6;
+
+ /**
+ * 0 selects 16-bit depth buffer. On Savage4 hardware, 1 selects
+ * 24-bit depth buffer (with 8-bits for stencil). Though it has never
+ * been tried, we suspect that on Savage3D hardware, 1 selects 15-bit
+ * depth buffer (with 1-bit for stencil).
+ */
+ unsigned zDepthSelect : 1;
+ }ni;
+ u_int32_t ui;
+} savageRegZBufOffset;
+
+/* The layout of this reg is the same on Savage4 and Savage3D. */
+typedef union
+{
+ struct
+ {
+ unsigned rLow : 6;
+ unsigned reserved1 : 2;
+ unsigned rHigh : 6;
+ unsigned reserved2 : 2;
+ unsigned wLow : 6;
+ unsigned reserved3 : 2;
+ unsigned wHigh : 6;
+ unsigned reserved4 : 2;
+ }ni;
+ u_int32_t ui;
+} savageRegZWatermarks;
+
+/********************************
+ Fog Registers -- Global
+**********************************/
+/* The layout of this reg is the same on Savage4 and Savage3D. */
+typedef union
+{
+ struct
+ {
+ unsigned fogClr : 24;
+ unsigned expShift : 3;
+ unsigned reserved : 1;
+ unsigned fogEn : 1;
+ unsigned fogMode : 1;
+ unsigned fogEndShift : 2;
+ }ni;
+ u_int32_t ui;
+} savageRegFogCtrl;
+
+/*not in spec, but tempo for pp and driver*/
+typedef union
+{
+ struct
+ {
+ unsigned fogDensity : 16;
+ unsigned fogStart : 16;
+ }ni;
+ u_int32_t ui;
+} savageRegFogParam;
+
+/**************************************
+ Destination Buffer Registers -- Global
+***************************************/
+
+/* The layout of this reg on Savage4 and Savage3D are very similar. */
+typedef union
+{
+ struct
+ {
+ unsigned dstWidthInTile : 7;
+ unsigned reserved : 1;
+ /* In the Utah-Driver the offset is defined as 13-bit, 2k-aligned. */
+ unsigned offset : 14;
+ unsigned 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 Savage3D.*/
+ unsigned antiAliasMode : 2;
+ unsigned dstPixFmt : 1;
+ }ni;
+ u_int32_t ui;
+} savageRegDestCtrl;
+
+/* The layout of this reg on Savage4 and Savage3D are very similar. */
+typedef union
+{
+ struct
+ {
+ unsigned destReadLow : 6;
+ unsigned destReadHigh : 6;
+ unsigned destWriteLow : 6;
+ unsigned destWriteHigh : 6;
+ unsigned texRead : 4;
+ unsigned 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 destFlush : 2;
+ }ni;
+ u_int32_t ui;
+} savageRegDestTexWatermarks;
+
+/* 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 SAVAGE_FIRST_REG 0x18
+#define SAVAGE_NR_REGS 34
+typedef struct savage_registers_s4_t {
+ u_int32_t unused1[6]; /* 0x18-0x1d */
+ savageRegDrawLocalCtrl drawLocalCtrl; /* 0x1e */
+ savageRegTexPalAddr texPalAddr; /* 0x1f */
+ savageRegTexCtrl_s4 texCtrl[2]; /* 0x20, 0x21 */
+ savageRegTexAddr texAddr[2]; /* 0x22, 0x23 */
+ savageRegTexBlendCtrl texBlendCtrl[2]; /* 0x24, 0x25 */
+ savageRegTexXprClr texXprClr; /* 0x26 */
+ savageRegTexDescr_s4 texDescr; /* 0x27 */
+ u_int8_t fogTable[32]; /* 0x28-0x2f (8dwords) */
+ savageRegFogCtrl fogCtrl; /* 0x30 */
+ savageRegStencilCtrl stencilCtrl; /* 0x31 */
+ savageRegZBufCtrl_s4 zBufCtrl; /* 0x32 */
+ savageRegZBufOffset zBufOffset; /* 0x33 */
+ savageRegDestCtrl destCtrl; /* 0x34 */
+ savageRegDrawCtrl0 drawCtrl0; /* 0x35 */
+ savageRegDrawCtrl1 drawCtrl1; /* 0x36 */
+ savageRegZWatermarks zWatermarks; /* 0x37 */
+ savageRegDestTexWatermarks destTexWatermarks; /* 0x38 */
+ savageRegTexBlendColor texBlendColor; /* 0x39 */
+} savageRegistersS4;
+typedef struct savage_registers_s3d_t {
+ savageRegTexPalAddr texPalAddr; /* 0x18 */
+ savageRegTexXprClr texXprClr; /* 0x19 */
+ savageRegTexAddr texAddr; /* 0x1a */
+ savageRegTexDescr_s3d texDescr; /* 0x1b */
+ savageRegTexCtrl_s3d texCtrl; /* 0x1c */
+ u_int32_t unused1[3]; /* 0x1d-0x1f */
+ u_int8_t fogTable[64]; /* 0x20-0x2f (16dwords) */
+ savageRegFogCtrl fogCtrl; /* 0x30 */
+ savageRegDrawCtrl drawCtrl; /* 0x31 */
+ savageRegZBufCtrl_s3d zBufCtrl; /* 0x32 */
+ savageRegZBufOffset zBufOffset; /* 0x33 */
+ savageRegDestCtrl destCtrl; /* 0x34 */
+ savageRegScissorsStart scissorsStart; /* 0x35 */
+ savageRegScissorsEnd scissorsEnd; /* 0x36 */
+ savageRegZWatermarks zWatermarks; /* 0x37 */
+ savageRegDestTexWatermarks destTexWatermarks; /* 0x38 */
+ u_int32_t unused2; /* 0x39 */
+} savageRegistersS3D;
+typedef union savage_registers_t {
+ savageRegistersS4 s4;
+ savageRegistersS3D s3d;
+ u_int32_t ui[SAVAGE_NR_REGS];
+} savageRegisters;
+
+
+#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))
+
+
+#endif
diff --git a/src/savage_bci.h b/src/savage_bci.h
new file mode 100644
index 0000000..33cfac3
--- /dev/null
+++ b/src/savage_bci.h
@@ -0,0 +1,612 @@
+/*
+ * 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 {
+ CF_Never,
+ CF_Less,
+ CF_Equal,
+ CF_LessEqual,
+ CF_Greater,
+ CF_NotEqual,
+ CF_GreaterEqual,
+ CF_Always
+}ZCmpFunc; /* same for Alpha test and Stencil test compare function */
+
+typedef ZCmpFunc ACmpFunc;
+
+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_Add 0x18110c11
+
+#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
+#define TBC_Add1 0x18130c13
+
+/*
+ * 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
+{
+ STENCIL_Keep,
+ STENCIL_Zero,
+ STENCIL_Equal,
+ STENCIL_IncClamp,
+ STENCIL_DecClamp,
+ STENCIL_Invert,
+ STENCIL_Inc,
+ STENCIL_Dec
+} StencilOp;
+
+/***************************************************************
+*** 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_U0 (1<<4)
+#define SAVAGE_HW_NO_V0 (1<<5)
+#define SAVAGE_HW_NO_UV0 ((1<<4) | (1<<5))
+#define SAVAGE_HW_NO_U1 (1<<6)
+#define SAVAGE_HW_NO_V1 (1<<7)
+#define SAVAGE_HW_NO_UV1 ((1<<6) | (1<<7))
+#define SAVAGE_HW_SKIPFLAGS 0x000000ff
+
+#endif
+
+
+
+
+
+
diff --git a/src/savage_init.h b/src/savage_init.h
new file mode 100644
index 0000000..43fb969
--- /dev/null
+++ b/src/savage_init.h
@@ -0,0 +1,157 @@
+/*
+ * 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_
+
+#include <sys/time.h>
+#include "dri_util.h"
+#include "mtypes.h"
+
+#include "xmlconfig.h"
+
+typedef struct {
+ drm_handle_t handle;
+ drmSize size;
+ char *map;
+} savageRegion, *savageRegionPtr;
+
+typedef struct {
+ int chipset;
+ int width;
+ int height;
+ int mem;
+
+ int cpp; /* for front and back buffers */
+ int zpp;
+
+ int agpMode;
+
+ unsigned int bufferSize;
+
+#if 0
+ int bitsPerPixel;
+#endif
+ unsigned int frontFormat;
+ unsigned int frontOffset;
+ unsigned int backOffset;
+ unsigned int depthOffset;
+
+ unsigned int aperturePitch;
+
+ 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;
+
+ savageRegion aperture;
+ savageRegion agpTextures;
+
+ drmBufMapPtr bufs;
+
+ unsigned int sarea_priv_offset;
+
+ /* Configuration cache with default values for all contexts */
+ driOptionCache optionCache;
+} savageScreenPrivate;
+
+
+#include "savagecontext.h"
+
+extern void savageGetLock( savageContextPtr imesa, GLuint flags );
+extern void savageXMesaSetClipRects(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
diff --git a/src/savage_xmesa.c b/src/savage_xmesa.c
new file mode 100644
index 0000000..43422db
--- /dev/null
+++ b/src/savage_xmesa.c
@@ -0,0 +1,1079 @@
+/*
+ * 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 "savagecontext.h"
+#include "context.h"
+#include "matrix.h"
+#include "framebuffer.h"
+#include "renderbuffer.h"
+#include "simple_list.h"
+
+#include "utils.h"
+
+#include "extensions.h"
+
+#include "swrast/swrast.h"
+#include "swrast_setup/swrast_setup.h"
+#include "tnl/tnl.h"
+#include "vbo/vbo.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 "savageioctl.h"
+#include "savage_bci.h"
+
+#include "savage_dri.h"
+
+#include "drirenderbuffer.h"
+#include "texmem.h"
+
+#define need_GL_ARB_multisample
+#define need_GL_ARB_texture_compression
+#define need_GL_ARB_vertex_buffer_object
+#define need_GL_EXT_secondary_color
+#include "extension_helper.h"
+
+#include "xmlpool.h"
+
+/* Driver-specific options
+ */
+#define SAVAGE_ENABLE_VDMA(def) \
+DRI_CONF_OPT_BEGIN(enable_vdma,bool,def) \
+ DRI_CONF_DESC(en,"Use DMA for vertex transfers") \
+ DRI_CONF_DESC(de,"Benutze DMA für Vertextransfers") \
+DRI_CONF_OPT_END
+#define SAVAGE_ENABLE_FASTPATH(def) \
+DRI_CONF_OPT_BEGIN(enable_fastpath,bool,def) \
+ DRI_CONF_DESC(en,"Use fast path for unclipped primitives") \
+ DRI_CONF_DESC(de,"Schneller Codepfad für ungeschnittene Polygone") \
+DRI_CONF_OPT_END
+#define SAVAGE_SYNC_FRAMES(def) \
+DRI_CONF_OPT_BEGIN(sync_frames,bool,def) \
+ DRI_CONF_DESC(en,"Synchronize with graphics hardware after each frame") \
+ DRI_CONF_DESC(de,"Synchronisiere nach jedem Frame mit Grafikhardware") \
+DRI_CONF_OPT_END
+
+/* Configuration
+ */
+PUBLIC const char __driConfigOptions[] =
+DRI_CONF_BEGIN
+ DRI_CONF_SECTION_QUALITY
+ DRI_CONF_TEXTURE_DEPTH(DRI_CONF_TEXTURE_DEPTH_FB)
+ DRI_CONF_COLOR_REDUCTION(DRI_CONF_COLOR_REDUCTION_DITHER)
+ DRI_CONF_FLOAT_DEPTH(false)
+ DRI_CONF_SECTION_END
+ DRI_CONF_SECTION_PERFORMANCE
+ SAVAGE_ENABLE_VDMA(true)
+ SAVAGE_ENABLE_FASTPATH(true)
+ SAVAGE_SYNC_FRAMES(false)
+ DRI_CONF_MAX_TEXTURE_UNITS(2,1,2)
+ DRI_CONF_TEXTURE_HEAPS(DRI_CONF_TEXTURE_HEAPS_ALL)
+ DRI_CONF_FORCE_S3TC_ENABLE(false)
+ DRI_CONF_SECTION_END
+ DRI_CONF_SECTION_DEBUG
+ DRI_CONF_NO_RAST(false)
+ DRI_CONF_SECTION_END
+DRI_CONF_END;
+static const GLuint __driNConfigOptions = 10;
+
+
+static const struct dri_debug_control debug_control[] =
+{
+ { "fall", DEBUG_FALLBACKS },
+ { "api", DEBUG_VERBOSE_API },
+ { "tex", DEBUG_VERBOSE_TEX },
+ { "verb", DEBUG_VERBOSE_MSG },
+ { "dma", DEBUG_DMA },
+ { "state", DEBUG_STATE },
+ { NULL, 0 }
+};
+#ifndef SAVAGE_DEBUG
+int SAVAGE_DEBUG = 0;
+#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
+
+static const struct dri_extension card_extensions[] =
+{
+ { "GL_ARB_multisample", GL_ARB_multisample_functions },
+ { "GL_ARB_multitexture", NULL },
+ { "GL_ARB_texture_compression", GL_ARB_texture_compression_functions },
+ { "GL_ARB_vertex_buffer_object", GL_ARB_vertex_buffer_object_functions },
+ { "GL_EXT_stencil_wrap", NULL },
+ { "GL_EXT_texture_lod_bias", NULL },
+ { "GL_EXT_secondary_color", GL_EXT_secondary_color_functions },
+ { NULL, NULL }
+};
+
+static const struct dri_extension s4_extensions[] =
+{
+ { "GL_ARB_texture_env_add", NULL },
+ { "GL_ARB_texture_mirrored_repeat", NULL },
+ { NULL, NULL }
+};
+
+extern struct tnl_pipeline_stage _savage_texnorm_stage;
+extern struct tnl_pipeline_stage _savage_render_stage;
+
+static const struct tnl_pipeline_stage *savage_pipeline[] = {
+
+ &_tnl_vertex_transform_stage,
+ &_tnl_normal_transform_stage,
+ &_tnl_lighting_stage,
+ &_tnl_fog_coordinate_stage,
+ &_tnl_texgen_stage,
+ &_tnl_texture_transform_stage,
+ &_savage_texnorm_stage,
+ &_savage_render_stage,
+ &_tnl_render_stage,
+ 0,
+};
+
+
+/* this is first function called in dirver*/
+
+static GLboolean
+savageInitDriver(__DRIscreenPrivate *sPriv)
+{
+ savageScreenPrivate *savageScreen;
+ SAVAGEDRIPtr gDRIPriv = (SAVAGEDRIPtr)sPriv->pDevPriv;
+ PFNGLXSCRENABLEEXTENSIONPROC glx_enable_extension =
+ (PFNGLXSCRENABLEEXTENSIONPROC) (*dri_interface->getProcAddress("glxEnableExtension"));
+
+
+ if (sPriv->devPrivSize != sizeof(SAVAGEDRIRec)) {
+ fprintf(stderr,"\nERROR! sizeof(SAVAGEDRIRec) does not match passed size from device driver\n");
+ 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->agpMode=gDRIPriv->agpMode;
+
+ savageScreen->bufferSize=gDRIPriv->bufferSize;
+
+ if (gDRIPriv->cpp == 4)
+ savageScreen->frontFormat = DV_PF_8888;
+ else
+ savageScreen->frontFormat = DV_PF_565;
+ savageScreen->frontOffset=gDRIPriv->frontOffset;
+ savageScreen->backOffset = gDRIPriv->backOffset;
+ savageScreen->depthOffset=gDRIPriv->depthOffset;
+
+ 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->agpTextureHandle;
+ savageScreen->textureSize[SAVAGE_AGP_HEAP] =
+ gDRIPriv->agpTextureSize;
+ savageScreen->logTextureGranularity[SAVAGE_AGP_HEAP] =
+ gDRIPriv->logAgpTextureGranularity;
+
+ savageScreen->agpTextures.handle = gDRIPriv->agpTextureHandle;
+ savageScreen->agpTextures.size = gDRIPriv->agpTextureSize;
+ if (gDRIPriv->agpTextureSize) {
+ if (drmMap(sPriv->fd,
+ savageScreen->agpTextures.handle,
+ savageScreen->agpTextures.size,
+ (drmAddress *)&(savageScreen->agpTextures.map)) != 0) {
+ Xfree(savageScreen);
+ sPriv->private = NULL;
+ return GL_FALSE;
+ }
+ } else
+ savageScreen->agpTextures.map = NULL;
+
+ savageScreen->texVirtual[SAVAGE_CARD_HEAP] =
+ (drmAddress)(((GLubyte *)sPriv->pFB)+gDRIPriv->textureOffset);
+ savageScreen->texVirtual[SAVAGE_AGP_HEAP] =
+ (drmAddress)(savageScreen->agpTextures.map);
+
+ savageScreen->aperture.handle = gDRIPriv->apertureHandle;
+ savageScreen->aperture.size = gDRIPriv->apertureSize;
+ savageScreen->aperturePitch = gDRIPriv->aperturePitch;
+ if (drmMap(sPriv->fd,
+ savageScreen->aperture.handle,
+ savageScreen->aperture.size,
+ (drmAddress *)&savageScreen->aperture.map) != 0)
+ {
+ Xfree(savageScreen);
+ sPriv->private = NULL;
+ return GL_FALSE;
+ }
+
+ savageScreen->bufs = drmMapBufs(sPriv->fd);
+
+ savageScreen->sarea_priv_offset = gDRIPriv->sarea_priv_offset;
+
+ /* parse information in __driConfigOptions */
+ driParseOptionInfo (&savageScreen->optionCache,
+ __driConfigOptions, __driNConfigOptions);
+
+ if (glx_enable_extension != NULL) {
+ (*glx_enable_extension)(sPriv->psc->screenConfigs,
+ "GLX_SGI_make_current_read");
+ }
+
+#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;
+
+ if (savageScreen->bufs)
+ drmUnmapBufs(savageScreen->bufs);
+
+ /* free all option information */
+ driDestroyOptionInfo (&savageScreen->optionCache);
+
+ 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;
+ savageScreenPrivate *savageScreen = (savageScreenPrivate *)sPriv->private;
+ drm_savage_sarea_t *saPriv=(drm_savage_sarea_t *)(((char*)sPriv->pSAREA)+
+ savageScreen->sarea_priv_offset);
+ int textureSize[SAVAGE_NR_TEX_HEAPS];
+ 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;
+
+ imesa->cmdBuf.size = SAVAGE_CMDBUF_SIZE;
+ imesa->cmdBuf.base = imesa->cmdBuf.write =
+ malloc(SAVAGE_CMDBUF_SIZE * sizeof(drm_savage_cmd_header_t));
+ if (!imesa->cmdBuf.base)
+ return GL_FALSE;
+
+ /* Parse configuration files */
+ driParseConfigFiles (&imesa->optionCache, &savageScreen->optionCache,
+ sPriv->myNum, "savage");
+
+ imesa->float_depth = driQueryOptionb(&imesa->optionCache, "float_depth") &&
+ savageScreen->chipset >= S3_SAVAGE4;
+ imesa->no_rast = driQueryOptionb(&imesa->optionCache, "no_rast");
+
+#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 */
+
+ for(i=0;i<5;i++)
+ {
+ imesa->apertureBase[i] = (GLubyte *)savageScreen->aperture.map +
+ 0x01000000 * i;
+ }
+
+ imesa->aperturePitch = savageScreen->aperturePitch;
+
+ /* change texHeap initialize to support two kind of texture heap*/
+ /* here is some parts of initialization, others in InitDriver() */
+
+ (void) memset( imesa->textureHeaps, 0, sizeof( imesa->textureHeaps ) );
+ make_empty_list( & imesa->swapped );
+
+ textureSize[SAVAGE_CARD_HEAP] = savageScreen->textureSize[SAVAGE_CARD_HEAP];
+ textureSize[SAVAGE_AGP_HEAP] = savageScreen->textureSize[SAVAGE_AGP_HEAP];
+ imesa->lastTexHeap = savageScreen->texVirtual[SAVAGE_AGP_HEAP] ? 2 : 1;
+ switch(driQueryOptioni (&imesa->optionCache, "texture_heaps")) {
+ case DRI_CONF_TEXTURE_HEAPS_CARD: /* only use card memory, if available */
+ if (textureSize[SAVAGE_CARD_HEAP])
+ imesa->lastTexHeap = 1;
+ break;
+ case DRI_CONF_TEXTURE_HEAPS_GART: /* only use gart memory, if available */
+ if (imesa->lastTexHeap == 2 && textureSize[SAVAGE_AGP_HEAP])
+ textureSize[SAVAGE_CARD_HEAP] = 0;
+ break;
+ /*default: Nothing to do, use all available memory. */
+ }
+
+ for (i = 0; i < imesa->lastTexHeap; i++) {
+ imesa->textureHeaps[i] = driCreateTextureHeap(
+ i, imesa,
+ textureSize[i],
+ 11, /* 2^11 = 2k alignment */
+ SAVAGE_NR_TEX_REGIONS,
+ (drmTextureRegionPtr)imesa->sarea->texList[i],
+ &imesa->sarea->texAge[i],
+ &imesa->swapped,
+ sizeof( savageTexObj ),
+ (destroy_texture_object_t *) savageDestroyTexObj );
+ /* If textureSize[i] == 0 textureHeaps[i] is NULL. This can happen
+ * if there is not enough card memory for a card texture heap. */
+ if (imesa->textureHeaps[i])
+ driSetTextureSwapCounterLocation( imesa->textureHeaps[i],
+ & imesa->c_textureSwaps );
+ }
+ imesa->texture_depth = driQueryOptioni (&imesa->optionCache,
+ "texture_depth");
+ if (imesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_FB)
+ imesa->texture_depth = ( savageScreen->cpp == 4 ) ?
+ DRI_CONF_TEXTURE_DEPTH_32 : DRI_CONF_TEXTURE_DEPTH_16;
+
+ if (savageScreen->chipset >= S3_SAVAGE4)
+ ctx->Const.MaxTextureUnits = 2;
+ else
+ ctx->Const.MaxTextureUnits = 1;
+ if (driQueryOptioni(&imesa->optionCache, "texture_units") <
+ ctx->Const.MaxTextureUnits)
+ ctx->Const.MaxTextureUnits =
+ driQueryOptioni(&imesa->optionCache, "texture_units");
+ ctx->Const.MaxTextureImageUnits = ctx->Const.MaxTextureUnits;
+ ctx->Const.MaxTextureCoordUnits = ctx->Const.MaxTextureUnits;
+
+ driCalculateMaxTextureLevels( imesa->textureHeaps,
+ imesa->lastTexHeap,
+ & ctx->Const,
+ 4,
+ 11, /* max 2D texture size is 2048x2048 */
+ 0, /* 3D textures unsupported. */
+ 0, /* cube textures unsupported. */
+ 0, /* texture rectangles unsupported. */
+ 12,
+ GL_FALSE,
+ 0 );
+ if (ctx->Const.MaxTextureLevels <= 6) { /*spec requires at least 64x64*/
+ __driUtilMessage("Not enough texture memory. "
+ "Falling back to indirect rendering.");
+ Xfree(imesa);
+ return GL_FALSE;
+ }
+
+ imesa->hw_stencil = mesaVis->stencilBits && mesaVis->depthBits == 24;
+ imesa->depth_scale = (imesa->savageScreen->zpp == 2) ?
+ (1.0F/0xffff):(1.0F/0xffffff);
+
+ imesa->bufferSize = savageScreen->bufferSize;
+ imesa->dmaVtxBuf.total = 0;
+ imesa->dmaVtxBuf.used = 0;
+ imesa->dmaVtxBuf.flushed = 0;
+
+ imesa->clientVtxBuf.total = imesa->bufferSize / 4;
+ imesa->clientVtxBuf.used = 0;
+ imesa->clientVtxBuf.flushed = 0;
+ imesa->clientVtxBuf.buf = (u_int32_t *)malloc(imesa->bufferSize);
+
+ imesa->vtxBuf = &imesa->clientVtxBuf;
+
+ imesa->firstElt = -1;
+
+ /* Uninitialized vertex format. Force setting the vertex state in
+ * savageRenderStart.
+ */
+ imesa->vertex_size = 0;
+
+ /* Utah stuff
+ */
+ imesa->new_state = ~0;
+ imesa->new_gl_state = ~0;
+ imesa->RenderIndex = ~0;
+ imesa->dirty = ~0;
+ imesa->lostContext = GL_TRUE;
+ imesa->CurrentTexObj[0] = 0;
+ imesa->CurrentTexObj[1] = 0;
+
+ /* Initialize the software rasterizer and helper modules.
+ */
+ _swrast_CreateContext( ctx );
+ _vbo_CreateContext( ctx );
+ _tnl_CreateContext( ctx );
+
+ _swsetup_CreateContext( ctx );
+
+ /* Install the customized pipeline:
+ */
+ _tnl_destroy_pipeline( ctx );
+ _tnl_install_pipeline( ctx, savage_pipeline );
+
+ imesa->enable_fastpath = driQueryOptionb(&imesa->optionCache,
+ "enable_fastpath");
+ /* DRM versions before 2.1.3 would only render triangle lists. ELTS
+ * support was added in 2.2.0. */
+ if (imesa->enable_fastpath && sPriv->drmMinor < 2) {
+ fprintf (stderr,
+ "*** Disabling fast path because your DRM version is buggy "
+ "or doesn't\n*** support ELTS. You need at least Savage DRM "
+ "version 2.2.\n");
+ imesa->enable_fastpath = GL_FALSE;
+ }
+
+ if (!savageScreen->bufs || savageScreen->chipset == S3_SUPERSAVAGE)
+ imesa->enable_vdma = GL_FALSE;
+ else
+ imesa->enable_vdma = driQueryOptionb(&imesa->optionCache, "enable_vdma");
+
+ imesa->sync_frames = driQueryOptionb(&imesa->optionCache, "sync_frames");
+
+ /* Configure swrast to match hardware characteristics:
+ */
+ _tnl_allow_pixel_fog( ctx, GL_FALSE );
+ _tnl_allow_vertex_fog( ctx, GL_TRUE );
+ _swrast_allow_pixel_fog( ctx, GL_FALSE );
+ _swrast_allow_vertex_fog( ctx, GL_TRUE );
+
+ ctx->DriverCtx = (void *) imesa;
+ imesa->glCtx = ctx;
+
+#ifndef SAVAGE_DEBUG
+ SAVAGE_DEBUG = driParseDebugString( getenv( "SAVAGE_DEBUG" ),
+ debug_control );
+#endif
+
+ driInitExtensions( ctx, card_extensions, GL_TRUE );
+ if (savageScreen->chipset >= S3_SAVAGE4)
+ driInitExtensions( ctx, s4_extensions, GL_FALSE );
+ if (ctx->Mesa_DXTn ||
+ driQueryOptionb (&imesa->optionCache, "force_s3tc_enable")) {
+ _mesa_enable_extension( ctx, "GL_S3_s3tc" );
+ if (savageScreen->chipset >= S3_SAVAGE4)
+ /* This extension needs DXT3 and DTX5 support in hardware.
+ * Not available on Savage3D/MX/IX. */
+ _mesa_enable_extension( ctx, "GL_EXT_texture_compression_s3tc" );
+ }
+
+ savageDDInitStateFuncs( ctx );
+ savageDDInitSpanFuncs( ctx );
+ savageDDInitDriverFuncs( ctx );
+ savageDDInitIoctlFuncs( ctx );
+ savageInitTriFuncs( ctx );
+
+ savageDDInitState( imesa );
+
+ driContextPriv->driverPrivate = (void *) imesa;
+
+ return GL_TRUE;
+}
+
+static void
+savageDestroyContext(__DRIcontextPrivate *driContextPriv)
+{
+ savageContextPtr imesa = (savageContextPtr) driContextPriv->driverPrivate;
+ GLuint i;
+
+ assert (imesa); /* should never be NULL */
+ if (imesa) {
+ savageFlushVertices(imesa);
+ savageReleaseIndexedVerts(imesa);
+ savageFlushCmdBuf(imesa, GL_TRUE); /* release DMA buffer */
+ WAIT_IDLE_EMPTY(imesa);
+
+ for (i = 0; i < imesa->lastTexHeap; i++)
+ driDestroyTextureHeap(imesa->textureHeaps[i]);
+
+ free(imesa->cmdBuf.base);
+ free(imesa->clientVtxBuf.buf);
+
+ _swsetup_DestroyContext(imesa->glCtx );
+ _tnl_DestroyContext( imesa->glCtx );
+ _vbo_DestroyContext( imesa->glCtx );
+ _swrast_DestroyContext( 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)
+{
+ savageScreenPrivate *screen = (savageScreenPrivate *) driScrnPriv->private;
+
+ if (isPixmap) {
+ return GL_FALSE; /* not implemented */
+ }
+ else {
+ GLboolean swStencil = mesaVis->stencilBits > 0 && mesaVis->depthBits != 24;
+ struct gl_framebuffer *fb = _mesa_create_framebuffer(mesaVis);
+ /*
+ * XXX: this value needs to be set according to the config file
+ * setting. But we don't get that until we create a rendering
+ * context!!!!
+ */
+ GLboolean float_depth = GL_FALSE;
+
+ {
+ driRenderbuffer *frontRb
+ = driNewRenderbuffer(GL_RGBA,
+ (GLubyte *) screen->aperture.map
+ + 0x01000000 * TARGET_FRONT,
+ screen->cpp,
+ screen->frontOffset, screen->aperturePitch,
+ driDrawPriv);
+ savageSetSpanFunctions(frontRb, mesaVis, float_depth);
+ assert(frontRb->Base.Data);
+ _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontRb->Base);
+ }
+
+ if (mesaVis->doubleBufferMode) {
+ driRenderbuffer *backRb
+ = driNewRenderbuffer(GL_RGBA,
+ (GLubyte *) screen->aperture.map
+ + 0x01000000 * TARGET_BACK,
+ screen->cpp,
+ screen->backOffset, screen->aperturePitch,
+ driDrawPriv);
+ savageSetSpanFunctions(backRb, mesaVis, float_depth);
+ assert(backRb->Base.Data);
+ _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backRb->Base);
+ }
+
+ if (mesaVis->depthBits == 16) {
+ driRenderbuffer *depthRb
+ = driNewRenderbuffer(GL_DEPTH_COMPONENT16,
+ (GLubyte *) screen->aperture.map
+ + 0x01000000 * TARGET_DEPTH,
+ screen->zpp,
+ screen->depthOffset, screen->aperturePitch,
+ driDrawPriv);
+ savageSetSpanFunctions(depthRb, mesaVis, float_depth);
+ _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
+ }
+ else if (mesaVis->depthBits == 24) {
+ driRenderbuffer *depthRb
+ = driNewRenderbuffer(GL_DEPTH_COMPONENT24,
+ (GLubyte *) screen->aperture.map
+ + 0x01000000 * TARGET_DEPTH,
+ screen->zpp,
+ screen->depthOffset, screen->aperturePitch,
+ driDrawPriv);
+ savageSetSpanFunctions(depthRb, mesaVis, float_depth);
+ _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
+ }
+
+ if (mesaVis->stencilBits > 0 && !swStencil) {
+ driRenderbuffer *stencilRb
+ = driNewRenderbuffer(GL_STENCIL_INDEX8_EXT,
+ (GLubyte *) screen->aperture.map
+ + 0x01000000 * TARGET_DEPTH,
+ screen->zpp,
+ screen->depthOffset, screen->aperturePitch,
+ driDrawPriv);
+ savageSetSpanFunctions(stencilRb, mesaVis, float_depth);
+ _mesa_add_renderbuffer(fb, BUFFER_STENCIL, &stencilRb->Base);
+ }
+
+ _mesa_add_soft_renderbuffers(fb,
+ GL_FALSE, /* color */
+ GL_FALSE, /* depth */
+ swStencil,
+ mesaVis->accumRedBits > 0,
+ GL_FALSE, /* alpha */
+ GL_FALSE /* aux */);
+ driDrawPriv->driverPrivate = (void *) fb;
+
+ return (driDrawPriv->driverPrivate != NULL);
+ }
+}
+
+static void
+savageDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
+{
+ _mesa_unreference_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 savageXMesaSetClipRects(savageContextPtr imesa)
+{
+ __DRIdrawablePrivate *dPriv = imesa->driDrawable;
+
+ if ((dPriv->numBackClipRects == 0)
+ || (imesa->glCtx->DrawBuffer->_ColorDrawBufferMask[0] == BUFFER_BIT_FRONT_LEFT)) {
+ 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;
+ }
+
+ savageCalcViewport( imesa->glCtx );
+}
+
+
+static void savageXMesaWindowMoved( savageContextPtr imesa )
+{
+ __DRIdrawablePrivate *const drawable = imesa->driDrawable;
+ __DRIdrawablePrivate *const readable = imesa->driReadable;
+
+ if (0)
+ fprintf(stderr, "savageXMesaWindowMoved\n\n");
+
+ savageXMesaSetClipRects(imesa);
+
+ driUpdateFramebufferSize(imesa->glCtx, drawable);
+ if (drawable != readable) {
+ driUpdateFramebufferSize(imesa->glCtx, readable);
+ }
+}
+
+
+static GLboolean
+savageUnbindContext(__DRIcontextPrivate *driContextPriv)
+{
+ savageContextPtr savage = (savageContextPtr) driContextPriv->driverPrivate;
+ if (savage)
+ savage->dirty = ~0;
+
+ return GL_TRUE;
+}
+
+#if 0
+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);
+ 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;
+}
+#endif
+
+static GLboolean
+savageMakeCurrent(__DRIcontextPrivate *driContextPriv,
+ __DRIdrawablePrivate *driDrawPriv,
+ __DRIdrawablePrivate *driReadPriv)
+{
+ if (driContextPriv) {
+ savageContextPtr imesa
+ = (savageContextPtr) driContextPriv->driverPrivate;
+ struct gl_framebuffer *drawBuffer
+ = (GLframebuffer *) driDrawPriv->driverPrivate;
+ struct gl_framebuffer *readBuffer
+ = (GLframebuffer *) driReadPriv->driverPrivate;
+ driRenderbuffer *frontRb = (driRenderbuffer *)
+ drawBuffer->Attachment[BUFFER_FRONT_LEFT].Renderbuffer;
+ driRenderbuffer *backRb = (driRenderbuffer *)
+ drawBuffer->Attachment[BUFFER_BACK_LEFT].Renderbuffer;
+
+ assert(frontRb->Base.Data);
+ if (imesa->glCtx->Visual.doubleBufferMode) {
+ assert(backRb->Base.Data);
+ }
+
+ imesa->driReadable = driReadPriv;
+ imesa->driDrawable = driDrawPriv;
+ imesa->dirty = ~0;
+
+ _mesa_make_current(imesa->glCtx, drawBuffer, readBuffer);
+
+ savageXMesaWindowMoved( imesa );
+ }
+ else
+ {
+ _mesa_make_current(NULL, NULL, NULL);
+ }
+ return GL_TRUE;
+}
+
+
+void savageGetLock( savageContextPtr imesa, GLuint flags )
+{
+ __DRIdrawablePrivate *const drawable = imesa->driDrawable;
+ __DRIdrawablePrivate *const readable = imesa->driReadable;
+ __DRIscreenPrivate *sPriv = imesa->driScreen;
+ drm_savage_sarea_t *sarea = imesa->sarea;
+ int me = imesa->hHWContext;
+ int stamp = drawable->lastStamp;
+ int heap;
+ unsigned int timestamp = 0;
+
+
+
+ /* 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, drawable);
+ if (drawable != readable) {
+ DRI_VALIDATE_DRAWABLE_INFO(sPriv, readable);
+ }
+
+
+ /* 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_LOCAL |
+ SAVAGE_UPLOAD_GLOBAL |
+ SAVAGE_UPLOAD_FOGTBL |
+ SAVAGE_UPLOAD_TEX0 |
+ SAVAGE_UPLOAD_TEX1 |
+ SAVAGE_UPLOAD_TEXGLOBAL);
+ imesa->lostContext = GL_TRUE;
+ sarea->ctxOwner = me;
+ }
+
+ for (heap = 0; heap < imesa->lastTexHeap; ++heap) {
+ /* If a heap was changed, update its timestamp. Do this before
+ * DRI_AGE_TEXTURES updates the local_age. */
+ if (imesa->textureHeaps[heap] &&
+ imesa->textureHeaps[heap]->global_age[0] >
+ imesa->textureHeaps[heap]->local_age) {
+ if (timestamp == 0)
+ timestamp = savageEmitEventLocked(imesa, 0);
+ imesa->textureHeaps[heap]->timestamp = timestamp;
+ }
+ DRI_AGE_TEXTURES( imesa->textureHeaps[heap] );
+ }
+
+ if (drawable->lastStamp != stamp) {
+ driUpdateFramebufferSize(imesa->glCtx, drawable);
+ savageXMesaWindowMoved( imesa );
+ }
+}
+
+
+
+static const struct __DriverAPIRec savageAPI = {
+ savageInitDriver,
+ savageDestroyScreen,
+ savageCreateContext,
+ savageDestroyContext,
+ savageCreateBuffer,
+ savageDestroyBuffer,
+ savageSwapBuffers,
+ savageMakeCurrent,
+ savageUnbindContext
+};
+
+
+static __GLcontextModes *
+savageFillInModes( unsigned pixel_bits, unsigned depth_bits,
+ unsigned stencil_bits, GLboolean have_back_buffer )
+{
+ __GLcontextModes * modes;
+ __GLcontextModes * m;
+ unsigned num_modes;
+ unsigned depth_buffer_factor;
+ unsigned back_buffer_factor;
+ GLenum fb_format;
+ GLenum fb_type;
+
+ /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy
+ * enough to add support. Basically, if a context is created with an
+ * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping
+ * will never be used.
+ *
+ * FK: What about drivers that don't use page flipping? Could they
+ * just expose GLX_SWAP_COPY_OML?
+ */
+ static const GLenum back_buffer_modes[] = {
+ GLX_NONE, GLX_SWAP_UNDEFINED_OML /*, GLX_SWAP_COPY_OML */
+ };
+
+ u_int8_t depth_bits_array[2];
+ u_int8_t stencil_bits_array[2];
+
+
+ depth_bits_array[0] = depth_bits;
+ depth_bits_array[1] = depth_bits;
+
+ /* Just like with the accumulation buffer, always provide some modes
+ * with a stencil buffer. It will be a sw fallback, but some apps won't
+ * care about that.
+ */
+ stencil_bits_array[0] = 0;
+ stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
+
+ depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 2 : 1;
+ back_buffer_factor = (have_back_buffer) ? 2 : 1;
+
+ num_modes = depth_buffer_factor * back_buffer_factor * 4;
+
+ if ( pixel_bits == 16 ) {
+ fb_format = GL_RGB;
+ fb_type = GL_UNSIGNED_SHORT_5_6_5;
+ }
+ else {
+ fb_format = GL_BGR;
+ fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ }
+
+ modes = (*dri_interface->createContextModes)( num_modes, sizeof( __GLcontextModes ) );
+ m = modes;
+ if ( ! driFillInModes( & m, fb_format, fb_type,
+ depth_bits_array, stencil_bits_array, depth_buffer_factor,
+ back_buffer_modes, back_buffer_factor,
+ GLX_TRUE_COLOR ) ) {
+ fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
+ __func__, __LINE__ );
+ return NULL;
+ }
+
+ if ( ! driFillInModes( & m, fb_format, fb_type,
+ depth_bits_array, stencil_bits_array, depth_buffer_factor,
+ back_buffer_modes, back_buffer_factor,
+ GLX_DIRECT_COLOR ) ) {
+ fprintf( stderr, "[%s:%u] Error creating FBConfig!\n",
+ __func__, __LINE__ );
+ return NULL;
+ }
+
+ /* Mark the visual as slow if there are "fake" stencil bits.
+ */
+ for ( m = modes ; m != NULL ; m = m->next ) {
+ if ( (m->stencilBits != 0) && (m->stencilBits != stencil_bits) ) {
+ m->visualRating = GLX_SLOW_CONFIG;
+ }
+ }
+
+ return modes;
+}
+
+
+/**
+ * This is the bootstrap function for the driver. libGL supplies all of the
+ * requisite information about the system, and the driver initializes itself.
+ * This routine also fills in the linked list pointed to by \c driver_modes
+ * with the \c __GLcontextModes that the driver can support for windows or
+ * pbuffers.
+ *
+ * \return A pointer to a \c __DRIscreenPrivate on success, or \c NULL on
+ * failure.
+ */
+PUBLIC
+void * __driCreateNewScreen_20050727( __DRInativeDisplay *dpy, int scrn, __DRIscreen *psc,
+ const __GLcontextModes * modes,
+ const __DRIversion * ddx_version,
+ const __DRIversion * dri_version,
+ const __DRIversion * drm_version,
+ const __DRIframebuffer * frame_buffer,
+ drmAddress pSAREA, int fd,
+ int internal_api_version,
+ const __DRIinterfaceMethods * interface,
+ __GLcontextModes ** driver_modes )
+
+{
+ __DRIscreenPrivate *psp;
+ static const __DRIversion ddx_expected = { 2, 0, 0 };
+ static const __DRIversion dri_expected = { 4, 0, 0 };
+ static const __DRIversion drm_expected = { 2, 1, 0 };
+
+ dri_interface = interface;
+
+ if ( ! driCheckDriDdxDrmVersions2( "Savage",
+ dri_version, & dri_expected,
+ ddx_version, & ddx_expected,
+ drm_version, & drm_expected ) ) {
+ return NULL;
+ }
+
+ psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL,
+ ddx_version, dri_version, drm_version,
+ frame_buffer, pSAREA, fd,
+ internal_api_version, &savageAPI);
+ if ( psp != NULL ) {
+ SAVAGEDRIPtr dri_priv = (SAVAGEDRIPtr)psp->pDevPriv;
+ *driver_modes = savageFillInModes( dri_priv->cpp*8,
+ (dri_priv->cpp == 2) ? 16 : 24,
+ (dri_priv->cpp == 2) ? 0 : 8,
+ (dri_priv->backOffset != dri_priv->depthOffset) );
+
+ /* Calling driInitExtensions here, with a NULL context pointer, does not actually
+ * enable the extensions. It just makes sure that all the dispatch offsets for all
+ * the extensions that *might* be enables are known. This is needed because the
+ * dispatch offsets need to be known when _mesa_context_create is called, but we can't
+ * enable the extensions until we have a context pointer.
+ *
+ * Hello chicken. Hello egg. How are you two today?
+ */
+ driInitExtensions( NULL, card_extensions, GL_FALSE );
+ }
+
+ return (void *) psp;
+}
diff --git a/src/savagecontext.h b/src/savagecontext.h
new file mode 100644
index 0000000..c4573b0
--- /dev/null
+++ b/src/savagecontext.h
@@ -0,0 +1,322 @@
+/*
+ * 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_init.h"
+#include "savage_3d_reg.h"
+#include "mm.h"
+#include "tnl/t_vertex.h"
+
+#include "texmem.h"
+
+#include "xmlconfig.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_SPECULAR 0x10
+#define SAVAGE_FALLBACK_LOGICOP 0x20
+/*frank 2001/11/12 add the stencil fallbak*/
+#define SAVAGE_FALLBACK_STENCIL 0x40
+#define SAVAGE_FALLBACK_RENDERMODE 0x80
+#define SAVAGE_FALLBACK_BLEND_EQ 0x100
+#define SAVAGE_FALLBACK_NORAST 0x200
+#define SAVAGE_FALLBACK_PROJ_TEXTURE 0x400
+
+
+#define HW_CULL 1
+
+/* for savagectx.new_state - manage GL->driver state changes
+ */
+#define SAVAGE_NEW_TEXTURE 0x1
+#define SAVAGE_NEW_CULL 0x2
+
+/* What needs to be changed for the current vertex dma buffer?
+ * This will go away!
+ */
+#define SAVAGE_UPLOAD_LOCAL 0x1 /* DrawLocalCtrl (S4) or
+ DrawCtrl and ZBufCtrl (S3D) */
+#define SAVAGE_UPLOAD_TEX0 0x2 /* texture unit 0 */
+#define SAVAGE_UPLOAD_TEX1 0x4 /* texture unit 1 (S4 only) */
+#define SAVAGE_UPLOAD_FOGTBL 0x8 /* fog table */
+#define SAVAGE_UPLOAD_GLOBAL 0x10 /* most global regs */
+#define SAVAGE_UPLOAD_TEXGLOBAL 0x20 /* TexBlendColor (S4 only) */
+
+/*define the max numer of vertex in vertex buf*/
+#define SAVAGE_MAX_VERTEXS 0x10000
+
+/* Don't make it too big. We don't want to buffer up a whole frame
+ * that would force the application to wait later. */
+#define SAVAGE_CMDBUF_SIZE 1024
+
+/* 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_vtxbuf_t {
+ GLuint total, used, flushed; /* in 32 bit units */
+ GLuint idx; /* for DMA buffers */
+ u_int32_t *buf;
+};
+
+struct savage_cmdbuf_t {
+ GLuint size; /* size in qwords */
+ drm_savage_cmd_header_t *base; /* initial state starts here */
+ drm_savage_cmd_header_t *start; /* drawing/state commands start here */
+ drm_savage_cmd_header_t *write; /* append stuff here */
+};
+
+struct savage_elt_t {
+ GLuint n; /* number of elts currently allocated */
+ drm_savage_cmd_header_t *cmd; /* the indexed drawing command */
+};
+
+
+struct savage_context_t {
+ GLint refcount;
+
+ GLcontext *glCtx;
+
+ int lastTexHeap;
+ driTexHeap *textureHeaps[SAVAGE_NR_TEX_HEAPS];
+ driTextureObject swapped;
+
+ driTextureObject *CurrentTexObj[2];
+
+ /* Hardware state
+ */
+
+ savageRegisters regs, oldRegs, globalRegMask;
+
+ /* Manage our own state */
+ GLuint new_state;
+ GLuint new_gl_state;
+ GLboolean ptexHack;
+
+ /* Command buffer */
+ struct savage_cmdbuf_t cmdBuf;
+
+ /* Elt book-keeping */
+ struct savage_elt_t elts;
+ GLint firstElt;
+
+ /* Vertex buffers */
+ struct savage_vtxbuf_t dmaVtxBuf, clientVtxBuf;
+ struct savage_vtxbuf_t *vtxBuf;
+
+ /* aperture base */
+ GLubyte *apertureBase[5];
+ GLuint aperturePitch;
+ /* Manage hardware state */
+ GLuint dirty;
+ GLboolean lostContext;
+ GLuint bTexEn1;
+ /* One of the few bits of hardware state that can't be calculated
+ * completely on the fly:
+ */
+ GLuint LcsCullMode;
+ GLuint texEnvColor;
+
+ /* Vertex state
+ */
+ GLuint vertex_size;
+ struct tnl_attr_map vertex_attrs[VERT_ATTRIB_MAX];
+ GLuint vertex_attr_count;
+ char *verts; /* points to tnl->clipspace.vertex_buf */
+
+ /* Rasterization state
+ */
+ GLuint SetupNewInputs;
+ GLuint SetupIndex;
+ GLuint RenderIndex;
+
+ GLuint hw_primitive;
+ GLenum raster_primitive;
+ GLenum render_primitive;
+
+ GLuint skip;
+ GLubyte HwPrim;
+ GLuint HwVertexSize;
+
+ /* 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 */
+ GLuint bufferSize;
+
+ GLframebuffer *glBuffer;
+
+ /* Two flags to keep track of fallbacks. */
+ GLuint Fallback;
+
+ GLuint needClip;
+
+ /* These refer to the current draw (front vs. back) buffer:
+ */
+ int drawX; /* origin of drawable in draw buffer */
+ int drawY;
+ GLuint numClipRects; /* cliprects for that buffer */
+ GLint currentClip;
+ drm_clip_rect_t *pClipRects;
+
+ /* use this bit to support single/double buffer */
+ GLuint IsDouble;
+ /* use this to indicate Fullscreen mode */
+ GLuint IsFullScreen; /* FIXME - open/close fullscreen is gone, is this needed? */
+ GLuint backup_frontOffset;
+ GLuint backup_backOffset;
+ GLuint backup_frontBitmapDesc;
+ GLuint toggle;
+ GLuint backup_streamFIFO;
+ GLuint NotFirstFrame;
+
+ GLboolean inSwap;
+ GLuint lastSwap;
+ GLuint ctxAge;
+ GLuint dirtyAge;
+ GLuint any_contend; /* throttle me harder */
+
+ /* Scissor state needs to be mirrored so buffered commands can be
+ * emitted with the old scissor state when scissor state changes.
+ */
+ struct {
+ GLboolean enabled;
+ GLint x, y;
+ GLsizei w, h;
+ } scissor;
+
+ drm_context_t hHWContext;
+ drm_hw_lock_t *driHwLock;
+ GLuint driFd;
+
+ __DRIdrawablePrivate *driDrawable;
+ __DRIdrawablePrivate *driReadable;
+
+ __DRIscreenPrivate *driScreen;
+ savageScreenPrivate *savageScreen;
+ drm_savage_sarea_t *sarea;
+
+ GLboolean hw_stencil;
+
+ /* Performance counters
+ */
+ GLuint c_textureSwaps;
+
+ /* Configuration cache
+ */
+ driOptionCache optionCache;
+ GLint texture_depth;
+ GLboolean no_rast;
+ GLboolean float_depth;
+ GLboolean enable_fastpath;
+ GLboolean enable_vdma;
+ GLboolean sync_frames;
+};
+
+#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.
+ */
+#ifndef SAVAGE_DEBUG
+extern int SAVAGE_DEBUG;
+#endif
+
+#define DEBUG_FALLBACKS 0x001
+#define DEBUG_VERBOSE_API 0x002
+#define DEBUG_VERBOSE_TEX 0x004
+#define DEBUG_VERBOSE_MSG 0x008
+#define DEBUG_DMA 0x010
+#define DEBUG_STATE 0x020
+
+#define TARGET_FRONT 0x0
+#define TARGET_BACK 0x1
+#define TARGET_DEPTH 0x2
+
+#define SUBPIXEL_X -0.5
+#define SUBPIXEL_Y -0.375
+
+#endif
diff --git a/src/savagedd.c b/src/savagedd.c
new file mode 100644
index 0000000..a5c5310
--- /dev/null
+++ b/src/savagedd.c
@@ -0,0 +1,101 @@
+/*
+ * 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 "framebuffer.h"
+
+#include <stdio.h>
+
+#include "mm.h"
+#include "swrast/swrast.h"
+
+#include "savagedd.h"
+#include "savagestate.h"
+#include "savagespan.h"
+#include "savagetex.h"
+#include "savagetris.h"
+#include "savagecontext.h"
+#include "extensions.h"
+
+#include "utils.h"
+
+
+#define DRIVER_DATE "20061110"
+
+/***************************************
+ * Mesa's Driver Functions
+ ***************************************/
+
+
+static const GLubyte *savageDDGetString( GLcontext *ctx, GLenum name )
+{
+ static char *cardNames[S3_LAST] = {
+ "Unknown",
+ "Savage3D",
+ "Savage/MX/IX",
+ "Savage4",
+ "ProSavage",
+ "Twister",
+ "ProSavageDDR",
+ "SuperSavage",
+ "Savage2000"
+ };
+ static char buffer[128];
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ savageScreenPrivate *screen = imesa->savageScreen;
+ enum S3CHIPTAGS chipset = screen->chipset;
+ unsigned offset;
+
+ if (chipset < S3_SAVAGE3D || chipset >= S3_LAST)
+ chipset = S3_UNKNOWN; /* should not happen */
+
+ switch (name) {
+ case GL_VENDOR:
+ return (GLubyte *)"S3 Graphics Inc.";
+ case GL_RENDERER:
+ offset = driGetRendererString( buffer, cardNames[chipset], DRIVER_DATE,
+ screen->agpMode );
+ return (GLubyte *)buffer;
+ 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
+
+
+void savageDDInitDriverFuncs( GLcontext *ctx )
+{
+ ctx->Driver.GetString = savageDDGetString;
+}
diff --git a/src/savagedd.h b/src/savagedd.h
new file mode 100644
index 0000000..ae167be
--- /dev/null
+++ b/src/savagedd.h
@@ -0,0 +1,32 @@
+/*
+ * 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 savageDDInitDriverFuncs( GLcontext *ctx );
+#endif
diff --git a/src/savageioctl.c b/src/savageioctl.c
new file mode 100644
index 0000000..4eac1fb
--- /dev/null
+++ b/src/savageioctl.c
@@ -0,0 +1,662 @@
+/*
+ * 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 "colormac.h"
+
+#include "mm.h"
+#include "savagecontext.h"
+#include "savageioctl.h"
+#include "savage_bci.h"
+#include "savagestate.h"
+#include "savagespan.h"
+
+#include "drm.h"
+#include <sys/ioctl.h>
+#include <sys/timeb.h>
+
+#define DEPTH_SCALE_16 ((1<<16)-1)
+#define DEPTH_SCALE_24 ((1<<24)-1)
+
+
+void savageGetDMABuffer( savageContextPtr imesa )
+{
+ int idx = 0;
+ int size = 0;
+ drmDMAReq dma;
+ int retcode;
+ drmBufPtr buf;
+
+ assert (imesa->savageScreen->bufs);
+
+ if (SAVAGE_DEBUG & DEBUG_DMA)
+ fprintf(stderr, "Getting dma buffer\n");
+
+ dma.context = imesa->hHWContext;
+ dma.send_count = 0;
+ dma.send_list = NULL;
+ dma.send_sizes = NULL;
+ dma.flags = 0;
+ dma.request_count = 1;
+ dma.request_size = imesa->bufferSize;
+ dma.request_list = &idx;
+ dma.request_sizes = &size;
+ dma.granted_count = 0;
+
+
+ if (SAVAGE_DEBUG & DEBUG_DMA)
+ fprintf(stderr, "drmDMA (get) ctx %d count %d size 0x%x\n",
+ dma.context, dma.request_count,
+ dma.request_size);
+
+ while (1) {
+ retcode = drmDMA(imesa->driFd, &dma);
+
+ if (SAVAGE_DEBUG & DEBUG_DMA)
+ fprintf(stderr, "retcode %d sz %d idx %d count %d\n",
+ retcode,
+ dma.request_sizes[0],
+ dma.request_list[0],
+ dma.granted_count);
+
+ if (retcode == 0 &&
+ dma.request_sizes[0] &&
+ dma.granted_count)
+ break;
+
+ if (SAVAGE_DEBUG & DEBUG_DMA)
+ fprintf(stderr, "\n\nflush");
+ }
+
+ buf = &(imesa->savageScreen->bufs->list[idx]);
+
+ if (SAVAGE_DEBUG & DEBUG_DMA)
+ fprintf(stderr,
+ "drmDMA (get) returns size[0] 0x%x idx[0] %d\n"
+ "dma_buffer now: buf idx: %d size: %d used: %d addr %p\n",
+ dma.request_sizes[0], dma.request_list[0],
+ buf->idx, buf->total,
+ buf->used, buf->address);
+
+ imesa->dmaVtxBuf.total = buf->total / 4;
+ imesa->dmaVtxBuf.used = 0;
+ imesa->dmaVtxBuf.flushed = 0;
+ imesa->dmaVtxBuf.idx = buf->idx;
+ imesa->dmaVtxBuf.buf = (u_int32_t *)buf->address;
+
+ if (SAVAGE_DEBUG & DEBUG_DMA)
+ fprintf(stderr, "finished getbuffer\n");
+}
+
+#if 0
+/* Still keeping this around because it demonstrates page flipping and
+ * automatic z-clear. */
+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;
+ unsigned int height = pbox->y2 - y;
+ u_int32_t *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 ) {
+ bciptr = savageDMAAlloc (imesa, 8);
+ WRITE_CMD((bciptr) , 0x4BCC8C00,u_int32_t);
+ WRITE_CMD((bciptr) , imesa->savageScreen->frontOffset,u_int32_t);
+ WRITE_CMD((bciptr) , imesa->savageScreen->frontBitmapDesc,u_int32_t);
+ WRITE_CMD((bciptr) , pclear->clear_color,u_int32_t);
+ WRITE_CMD((bciptr) , (y <<16) | x,u_int32_t);
+ WRITE_CMD((bciptr) , (height << 16) | width,u_int32_t);
+ savageDMACommit (imesa, bciptr);
+ }
+ if ( pclear->flags & SAVAGE_BACK ) {
+ bciptr = savageDMAAlloc (imesa, 8);
+ WRITE_CMD((bciptr) , 0x4BCC8C00,u_int32_t);
+ WRITE_CMD((bciptr) , imesa->savageScreen->backOffset,u_int32_t);
+ WRITE_CMD((bciptr) , imesa->savageScreen->backBitmapDesc,u_int32_t);
+ WRITE_CMD((bciptr) , pclear->clear_color,u_int32_t);
+ WRITE_CMD((bciptr) , (y <<16) | x,u_int32_t);
+ WRITE_CMD((bciptr) , (height << 16) | width,u_int32_t);
+ savageDMACommit (imesa, bciptr);
+ }
+
+ if ( pclear->flags & (SAVAGE_DEPTH |SAVAGE_STENCIL) ) {
+ u_int32_t writeMask = 0x0;
+ if(imesa->hw_stencil)
+ {
+ if(pclear->flags & SAVAGE_STENCIL)
+ {
+
+ writeMask |= 0xFF000000;
+ }
+ if(pclear->flags & SAVAGE_DEPTH)
+ {
+ writeMask |= 0x00FFFFFF;
+ }
+ }
+ if(imesa->IsFullScreen && imesa->NotFirstFrame &&
+ imesa->savageScreen->chipset >= S3_SAVAGE4)
+ {
+ imesa->regs.s4.zBufCtrl.ni.autoZEnable = GL_TRUE;
+ imesa->regs.s4.zBufCtrl.ni.frameID =
+ ~imesa->regs.s4.zBufCtrl.ni.frameID;
+
+ imesa->dirty |= SAVAGE_UPLOAD_GLOBAL;
+ }
+ else
+ {
+ if(imesa->IsFullScreen)
+ imesa->NotFirstFrame = GL_TRUE;
+
+ if(imesa->hw_stencil)
+ {
+ bciptr = savageDMAAlloc (imesa, 10);
+ if(writeMask != 0xFFFFFFFF)
+ {
+ WRITE_CMD((bciptr) , 0x960100D7,u_int32_t);
+ WRITE_CMD((bciptr) , writeMask,u_int32_t);
+ }
+ }
+ else
+ {
+ bciptr = savageDMAAlloc (imesa, 6);
+ }
+
+ WRITE_CMD((bciptr) , 0x4BCC8C00,u_int32_t);
+ WRITE_CMD((bciptr) , imesa->savageScreen->depthOffset,u_int32_t);
+ WRITE_CMD((bciptr) , imesa->savageScreen->depthBitmapDesc,u_int32_t);
+ WRITE_CMD((bciptr) , pclear->clear_depth,u_int32_t);
+ WRITE_CMD((bciptr) , (y <<16) | x,u_int32_t);
+ WRITE_CMD((bciptr) , (height << 16) | width,u_int32_t);
+ if(imesa->hw_stencil)
+ {
+ if(writeMask != 0xFFFFFFFF)
+ {
+ WRITE_CMD((bciptr) , 0x960100D7,u_int32_t);
+ WRITE_CMD((bciptr) , 0xFFFFFFFF,u_int32_t);
+ }
+ }
+ 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);
+}
+
+static void savage_BCI_swap(savageContextPtr imesa)
+{
+ int nbox = imesa->sarea->nbox;
+ drm_clip_rect_t *pbox = imesa->sarea->boxes;
+ int i;
+ volatile u_int32_t *bciptr;
+
+ if (nbox > SAVAGE_NR_SAREA_CLIPRECTS)
+ nbox = SAVAGE_NR_SAREA_CLIPRECTS;
+ savageDMAFlush (imesa);
+
+ 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;
+
+ driFlipRenderbuffers(imesa->glCtx->DrawBuffer,
+ imesa->toggle != TARGET_FRONT);
+
+ imesa->regs.s4.destCtrl.ni.offset = imesa->savageScreen->backOffset>>11;
+ imesa->dirty |= SAVAGE_UPLOAD_GLOBAL;
+ 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;
+ }
+
+ }
+}
+#endif
+
+
+static GLboolean intersect_rect( drm_clip_rect_t *out,
+ const drm_clip_rect_t *a,
+ const drm_clip_rect_t *b )
+{
+ *out = *a;
+ if (b->x1 > out->x1) out->x1 = b->x1;
+ if (b->y1 > out->y1) out->y1 = b->y1;
+ if (b->x2 < out->x2) out->x2 = b->x2;
+ if (b->y2 < out->y2) out->y2 = b->y2;
+
+ return ((out->x1 < out->x2) && (out->y1 < out->y2));
+}
+
+
+static GLuint savageIntersectClipRects(drm_clip_rect_t *dest,
+ const drm_clip_rect_t *src,
+ GLuint nsrc,
+ const drm_clip_rect_t *clip)
+{
+ GLuint i, ndest;
+
+ for (i = 0, ndest = 0; i < nsrc; ++i, ++src) {
+ if (intersect_rect(dest, src, clip)) {
+ dest++;
+ ndest++;
+ }
+ }
+
+ return ndest;
+}
+
+
+static void savageDDClear( GLcontext *ctx, GLbitfield mask )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+ GLuint colorMask, depthMask, clearColor, clearDepth, flags;
+ GLint cx = ctx->DrawBuffer->_Xmin;
+ GLint cy = ctx->DrawBuffer->_Ymin;
+ GLint cw = ctx->DrawBuffer->_Xmax - cx;
+ GLint ch = ctx->DrawBuffer->_Ymax - cy;
+
+ /* XXX FIX ME: the cx,cy,cw,ch vars are currently ignored! */
+
+ if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
+ fprintf (stderr, "%s\n", __FUNCTION__);
+
+ clearColor = imesa->ClearColor;
+ if (imesa->float_depth) {
+ if (imesa->savageScreen->zpp == 2)
+ clearDepth = savageEncodeFloat16(1.0 - ctx->Depth.Clear);
+ else
+ clearDepth = savageEncodeFloat24(1.0 - ctx->Depth.Clear);
+ } else {
+ if (imesa->savageScreen->zpp == 2)
+ clearDepth = (GLuint) ((1.0 - ctx->Depth.Clear) * DEPTH_SCALE_16);
+ else
+ clearDepth = (GLuint) ((1.0 - ctx->Depth.Clear) * DEPTH_SCALE_24);
+ }
+
+ colorMask = 0;
+ depthMask = 0;
+ switch (imesa->savageScreen->cpp) {
+ case 2:
+ colorMask = PACK_COLOR_565(ctx->Color.ColorMask[0],
+ ctx->Color.ColorMask[1],
+ ctx->Color.ColorMask[2]);
+ break;
+ case 4:
+ colorMask = PACK_COLOR_8888(ctx->Color.ColorMask[3],
+ ctx->Color.ColorMask[2],
+ ctx->Color.ColorMask[1],
+ ctx->Color.ColorMask[0]);
+ break;
+ }
+
+ flags = 0;
+
+ if (mask & BUFFER_BIT_FRONT_LEFT) {
+ flags |= SAVAGE_FRONT;
+ mask &= ~BUFFER_BIT_FRONT_LEFT;
+ }
+
+ if (mask & BUFFER_BIT_BACK_LEFT) {
+ flags |= SAVAGE_BACK;
+ mask &= ~BUFFER_BIT_BACK_LEFT;
+ }
+
+ if ((mask & BUFFER_BIT_DEPTH) && ctx->Depth.Mask) {
+ flags |= SAVAGE_DEPTH;
+ depthMask |=
+ (imesa->savageScreen->zpp == 2) ? 0xffffffff : 0x00ffffff;
+ mask &= ~BUFFER_BIT_DEPTH;
+ }
+
+ if((mask & BUFFER_BIT_STENCIL) && imesa->hw_stencil)
+ {
+ flags |= SAVAGE_DEPTH;
+ depthMask |= 0xff000000;
+ mask &= ~BUFFER_BIT_STENCIL;
+ }
+
+ savageFlushVertices(imesa);
+
+ if (flags) {
+ GLboolean depthCleared = GL_FALSE;
+ if (flags & (SAVAGE_FRONT|SAVAGE_BACK)) {
+ drm_savage_cmd_header_t *cmd;
+ cmd = savageAllocCmdBuf(imesa, sizeof(drm_savage_cmd_header_t));
+ cmd[0].clear0.cmd = SAVAGE_CMD_CLEAR;
+ if ((flags & SAVAGE_DEPTH) &&
+ clearDepth == clearColor && depthMask == colorMask) {
+ cmd[0].clear0.flags = flags;
+ depthCleared = GL_TRUE;
+ } else
+ cmd[0].clear0.flags = flags & (SAVAGE_FRONT|SAVAGE_BACK);
+ cmd[1].clear1.mask = colorMask;
+ cmd[1].clear1.value = clearColor;
+ }
+
+ if ((flags & SAVAGE_DEPTH) && !depthCleared) {
+ drm_savage_cmd_header_t *cmd;
+ cmd = savageAllocCmdBuf(imesa, sizeof(drm_savage_cmd_header_t));
+ cmd[0].clear0.cmd = SAVAGE_CMD_CLEAR;
+ cmd[0].clear0.flags = SAVAGE_DEPTH;
+ cmd[1].clear1.mask = depthMask;
+ cmd[1].clear1.value = clearDepth;
+ }
+ }
+
+ if (mask)
+ _swrast_Clear( ctx, mask );
+}
+
+/*
+ * Copy the back buffer to the front buffer.
+ */
+void savageSwapBuffers( __DRIdrawablePrivate *dPriv )
+{
+ savageContextPtr imesa;
+
+ if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
+ fprintf (stderr, "%s\n================================\n", __FUNCTION__);
+
+ assert(dPriv);
+ assert(dPriv->driContextPriv);
+ assert(dPriv->driContextPriv->driverPrivate);
+
+ imesa = (savageContextPtr) dPriv->driContextPriv->driverPrivate;
+ if (imesa->IsDouble)
+ _mesa_notifySwapBuffers( imesa->glCtx );
+
+ FLUSH_BATCH(imesa);
+
+ if (imesa->sync_frames)
+ imesa->lastSwap = savageEmitEvent( imesa, 0 );
+
+ if (imesa->lastSwap != 0)
+ savageWaitEvent( imesa, imesa->lastSwap );
+
+ {
+ drm_savage_cmd_header_t *cmd = savageAllocCmdBuf(imesa, 0);
+ cmd->cmd.cmd = SAVAGE_CMD_SWAP;
+ imesa->inSwap = GL_TRUE; /* ignore scissors in savageFlushCmdBuf */
+ savageFlushCmdBuf(imesa, GL_FALSE);
+ imesa->inSwap = GL_FALSE;
+ }
+
+ if (!imesa->sync_frames)
+ /* don't sync, but limit the lag to one frame. */
+ imesa->lastSwap = savageEmitEvent( imesa, 0 );
+}
+
+unsigned int savageEmitEventLocked( savageContextPtr imesa, unsigned int flags )
+{
+ drm_savage_event_emit_t event;
+ int ret;
+ event.count = 0;
+ event.flags = flags;
+ ret = drmCommandWriteRead( imesa->driFd, DRM_SAVAGE_BCI_EVENT_EMIT,
+ &event, sizeof(event) );
+ if (ret) {
+ fprintf (stderr, "emit event returned %d\n", ret);
+ exit (1);
+ }
+ return event.count;
+}
+unsigned int savageEmitEvent( savageContextPtr imesa, unsigned int flags )
+{
+ unsigned int ret;
+ LOCK_HARDWARE( imesa );
+ ret = savageEmitEventLocked( imesa, flags );
+ UNLOCK_HARDWARE( imesa );
+ return ret;
+}
+
+
+void savageWaitEvent( savageContextPtr imesa, unsigned int count )
+{
+ drm_savage_event_wait_t event;
+ int ret;
+ event.count = count;
+ event.flags = 0;
+ ret = drmCommandWriteRead( imesa->driFd, DRM_SAVAGE_BCI_EVENT_WAIT,
+ &event, sizeof(event) );
+ if (ret) {
+ fprintf (stderr, "wait event returned %d\n", ret);
+ exit (1);
+ }
+}
+
+
+void savageFlushVertices( savageContextPtr imesa )
+{
+ struct savage_vtxbuf_t *buffer = imesa->vtxBuf;
+
+ if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
+ fprintf (stderr, "%s\n", __FUNCTION__);
+
+ if (!buffer->total)
+ return;
+
+ if (buffer->used > buffer->flushed) {
+ drm_savage_cmd_header_t *cmd;
+ /* State must be updated "per primitive" because hardware
+ * culling must be disabled for unfilled primitives, points
+ * and lines. */
+ savageEmitChangedState (imesa);
+ cmd = savageAllocCmdBuf(imesa, 0);
+ cmd->prim.cmd = buffer == &imesa->dmaVtxBuf ?
+ SAVAGE_CMD_DMA_PRIM : SAVAGE_CMD_VB_PRIM;
+ cmd->prim.prim = imesa->HwPrim;
+ cmd->prim.skip = imesa->skip;
+ cmd->prim.start = buffer->flushed / imesa->HwVertexSize;
+ cmd->prim.count = buffer->used / imesa->HwVertexSize - cmd->prim.start;
+ buffer->flushed = buffer->used;
+ }
+}
+
+void savageFlushCmdBufLocked( savageContextPtr imesa, GLboolean discard )
+{
+ __DRIdrawablePrivate *dPriv = imesa->driDrawable;
+
+ if (!imesa->dmaVtxBuf.total)
+ discard = GL_FALSE;
+
+ /* complete indexed drawing commands */
+ savageFlushElts(imesa);
+
+ if (imesa->cmdBuf.write != imesa->cmdBuf.start || discard) {
+ drm_savage_cmdbuf_t cmdbuf;
+ drm_savage_cmd_header_t *start;
+ int ret;
+
+ /* If we lost the context we must restore the initial state (at
+ * the start of the command buffer). */
+ if (imesa->lostContext) {
+ start = imesa->cmdBuf.base;
+ imesa->lostContext = GL_FALSE;
+ } else
+ start = imesa->cmdBuf.start;
+
+ if ((SAVAGE_DEBUG & DEBUG_DMA) && discard)
+ fprintf (stderr, "Discarding DMA buffer, used=%u\n",
+ imesa->dmaVtxBuf.used);
+
+ cmdbuf.dma_idx = imesa->dmaVtxBuf.idx;
+ cmdbuf.discard = discard;
+ cmdbuf.vb_addr = imesa->clientVtxBuf.buf;
+ cmdbuf.vb_size = imesa->clientVtxBuf.total*4;
+ cmdbuf.vb_stride = imesa->HwVertexSize;
+ cmdbuf.cmd_addr = start;
+ cmdbuf.size = (imesa->cmdBuf.write - start);
+ if (!imesa->inSwap && imesa->scissor.enabled) {
+ drm_clip_rect_t *box = dPriv->pClipRects, *ibox;
+ drm_clip_rect_t scissor;
+ GLuint nbox = dPriv->numClipRects, nibox;
+ /* transform and clip scissor to viewport */
+ scissor.x1 = MAX2(imesa->scissor.x, 0) + dPriv->x;
+ scissor.y1 = MAX2(dPriv->h - imesa->scissor.y - imesa->scissor.h,
+ 0) + dPriv->y;
+ scissor.x2 = MIN2(imesa->scissor.x + imesa->scissor.w,
+ dPriv->w) + dPriv->x;
+ scissor.y2 = MIN2(dPriv->h - imesa->scissor.y,
+ dPriv->h) + dPriv->y;
+ /* intersect cliprects with scissor */
+ ibox = malloc(dPriv->numClipRects*sizeof(drm_clip_rect_t));
+ if (!ibox) {
+ fprintf(stderr, "Out of memory.\n");
+ exit(1);
+ }
+ nibox = savageIntersectClipRects(ibox, box, nbox, &scissor);
+ cmdbuf.nbox = nibox;
+ cmdbuf.box_addr = ibox;
+ } else {
+ cmdbuf.nbox = dPriv->numClipRects;
+ cmdbuf.box_addr = dPriv->pClipRects;
+ }
+
+ ret = drmCommandWrite( imesa->driFd, DRM_SAVAGE_BCI_CMDBUF,
+ &cmdbuf, sizeof(cmdbuf) );
+ if (ret) {
+ fprintf (stderr, "cmdbuf ioctl returned %d\n", ret);
+ exit(1);
+ }
+
+ if (cmdbuf.box_addr != dPriv->pClipRects) {
+ free(cmdbuf.box_addr);
+ }
+
+ /* Save the current state at the start of the command buffer. That
+ * state will only be emitted, if the context was lost since the
+ * last command buffer. */
+ imesa->cmdBuf.write = imesa->cmdBuf.base;
+ savageEmitOldState(imesa);
+ imesa->cmdBuf.start = imesa->cmdBuf.write;
+ }
+
+ if (discard) {
+ assert (!savageHaveIndexedVerts(imesa));
+ imesa->dmaVtxBuf.total = 0;
+ imesa->dmaVtxBuf.used = 0;
+ imesa->dmaVtxBuf.flushed = 0;
+ }
+ if (!savageHaveIndexedVerts(imesa)) {
+ imesa->clientVtxBuf.used = 0;
+ imesa->clientVtxBuf.flushed = 0;
+ }
+}
+
+
+void savageFlushCmdBuf( savageContextPtr imesa, GLboolean discard )
+{
+ if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
+ fprintf (stderr, "%s\n", __FUNCTION__);
+ LOCK_HARDWARE(imesa);
+ savageFlushCmdBufLocked (imesa, discard);
+ UNLOCK_HARDWARE(imesa);
+}
+
+
+static void savageDDFlush( GLcontext *ctx )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
+ fprintf (stderr, "%s\n", __FUNCTION__);
+ savageFlushVertices (imesa);
+ savageFlushCmdBuf(imesa, GL_FALSE);
+}
+
+static void savageDDFinish( GLcontext *ctx )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
+ fprintf (stderr, "%s\n", __FUNCTION__);
+ savageFlushVertices (imesa);
+ savageFlushCmdBuf(imesa, GL_FALSE);
+ WAIT_IDLE_EMPTY(imesa);
+}
+
+void savageDDInitIoctlFuncs( GLcontext *ctx )
+{
+ ctx->Driver.Clear = savageDDClear;
+ ctx->Driver.Flush = savageDDFlush;
+ ctx->Driver.Finish = savageDDFinish;
+}
diff --git a/src/savageioctl.h b/src/savageioctl.h
new file mode 100644
index 0000000..c7ff001
--- /dev/null
+++ b/src/savageioctl.h
@@ -0,0 +1,203 @@
+/*
+ * 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"
+
+void savageFlushVertices( savageContextPtr mmesa );
+
+unsigned int savageEmitEventLocked( savageContextPtr imesa, unsigned int flags );
+unsigned int savageEmitEvent( savageContextPtr imesa, unsigned int flags );
+void savageWaitEvent( savageContextPtr imesa, unsigned int event);
+
+void savageFlushCmdBufLocked( savageContextPtr imesa, GLboolean discard );
+void savageFlushCmdBuf( savageContextPtr imesa, GLboolean discard );
+
+void savageDDInitIoctlFuncs( GLcontext *ctx );
+
+void savageSwapBuffers( __DRIdrawablePrivate *dPriv );
+
+#define WAIT_IDLE_EMPTY(imesa) do { \
+ if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG) \
+ fprintf (stderr, "WAIT_IDLE_EMPTY in %s\n", __FUNCTION__); \
+ savageWaitEvent(imesa, \
+ savageEmitEvent(imesa, SAVAGE_WAIT_2D|SAVAGE_WAIT_3D)); \
+} while (0)
+
+#define WAIT_IDLE_EMPTY_LOCKED(imesa) do { \
+ if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG) \
+ fprintf (stderr, "WAIT_IDLE_EMPTY_LOCKED in %s\n", __FUNCTION__); \
+ savageWaitEvent(imesa, savageEmitEventLocked( \
+ imesa, SAVAGE_WAIT_2D|SAVAGE_WAIT_3D)); \
+} while (0)
+
+#define FLUSH_BATCH(imesa) do { \
+ if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG) \
+ fprintf (stderr, "FLUSH_BATCH in %s\n", __FUNCTION__); \
+ savageFlushVertices(imesa); \
+ savageFlushCmdBuf(imesa, GL_FALSE); \
+} while (0)
+
+extern void savageGetDMABuffer( savageContextPtr imesa );
+
+static __inline
+void savageReleaseIndexedVerts( savageContextPtr imesa )
+{
+ imesa->firstElt = -1;
+}
+
+static __inline
+GLboolean savageHaveIndexedVerts( savageContextPtr imesa )
+{
+ return (imesa->firstElt != -1);
+}
+
+static __inline
+u_int32_t *savageAllocVtxBuf( savageContextPtr imesa, GLuint words )
+{
+ struct savage_vtxbuf_t *buffer = imesa->vtxBuf;
+ u_int32_t *head;
+
+ if (buffer == &imesa->dmaVtxBuf) {
+ if (!buffer->total) {
+ LOCK_HARDWARE(imesa);
+ savageGetDMABuffer(imesa);
+ UNLOCK_HARDWARE(imesa);
+ } else if (buffer->used + words > buffer->total) {
+ if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
+ fprintf (stderr, "... flushing DMA buffer in %s\n",
+ __FUNCTION__);
+ savageReleaseIndexedVerts(imesa);
+ savageFlushVertices(imesa);
+ LOCK_HARDWARE(imesa);
+ savageFlushCmdBufLocked(imesa, GL_TRUE); /* discard DMA buffer */
+ savageGetDMABuffer(imesa);
+ UNLOCK_HARDWARE(imesa);
+ }
+ } else if (buffer->used + words > buffer->total) {
+ if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
+ fprintf (stderr, "... flushing client vertex buffer in %s\n",
+ __FUNCTION__);
+ savageReleaseIndexedVerts(imesa);
+ savageFlushVertices(imesa);
+ LOCK_HARDWARE(imesa);
+ savageFlushCmdBufLocked(imesa, GL_FALSE); /* free clientVtxBuf */
+ UNLOCK_HARDWARE(imesa);
+ }
+
+ head = &buffer->buf[buffer->used];
+
+ buffer->used += words;
+ return head;
+}
+
+static __inline
+u_int32_t *savageAllocIndexedVerts( savageContextPtr imesa, GLuint n )
+{
+ u_int32_t *ret;
+ savageFlushVertices(imesa);
+ ret = savageAllocVtxBuf(imesa, n*imesa->HwVertexSize);
+ imesa->firstElt = imesa->vtxBuf->flushed / imesa->HwVertexSize;
+ imesa->vtxBuf->flushed = imesa->vtxBuf->used;
+ return ret;
+}
+
+/* Flush Elts:
+ * - Complete the drawing command with the correct number of indices.
+ * - Actually allocate entries for the indices in the command buffer.
+ * (This allocation must succeed without wrapping the cmd buffer!)
+ */
+static __inline
+void savageFlushElts( savageContextPtr imesa )
+{
+ if (imesa->elts.cmd) {
+ GLuint qwords = (imesa->elts.n + 3) >> 2;
+ assert(imesa->cmdBuf.write - imesa->cmdBuf.base + qwords
+ <= imesa->cmdBuf.size);
+ imesa->cmdBuf.write += qwords;
+
+ imesa->elts.cmd->idx.count = imesa->elts.n;
+ imesa->elts.cmd = NULL;
+ }
+}
+
+/* Allocate a command buffer entry with <bytes> bytes of arguments:
+ * - implies savageFlushElts
+ */
+static __inline
+drm_savage_cmd_header_t *savageAllocCmdBuf( savageContextPtr imesa, GLuint bytes )
+{
+ drm_savage_cmd_header_t *ret;
+ GLuint qwords = ((bytes + 7) >> 3) + 1; /* round up */
+ assert (qwords < imesa->cmdBuf.size);
+
+ savageFlushElts(imesa);
+
+ if (imesa->cmdBuf.write - imesa->cmdBuf.base + qwords > imesa->cmdBuf.size)
+ savageFlushCmdBuf(imesa, GL_FALSE);
+
+ ret = (drm_savage_cmd_header_t *)imesa->cmdBuf.write;
+ imesa->cmdBuf.write += qwords;
+ return ret;
+}
+
+/* Allocate Elts:
+ * - if it doesn't fit, flush the cmd buffer first
+ * - allocates the drawing command on the cmd buffer if there is no
+ * incomplete indexed drawing command yet
+ * - increments the number of elts. Final allocation is done in savageFlushElts
+ */
+static __inline
+u_int16_t *savageAllocElts( savageContextPtr imesa, GLuint n )
+{
+ u_int16_t *ret;
+ GLuint qwords;
+ assert (savageHaveIndexedVerts(imesa));
+
+ if (imesa->elts.cmd)
+ qwords = (imesa->elts.n + n + 3) >> 2;
+ else
+ qwords = ((n + 3) >> 2) + 1;
+ if (imesa->cmdBuf.write - imesa->cmdBuf.base + qwords > imesa->cmdBuf.size)
+ savageFlushCmdBuf(imesa, GL_FALSE); /* implies savageFlushElts */
+
+ if (!imesa->elts.cmd) {
+ savageFlushVertices(imesa);
+ imesa->elts.cmd = savageAllocCmdBuf(imesa, 0);
+ imesa->elts.cmd->idx.cmd = (imesa->vtxBuf == &imesa->dmaVtxBuf) ?
+ SAVAGE_CMD_DMA_IDX : SAVAGE_CMD_VB_IDX;
+ imesa->elts.cmd->idx.prim = imesa->HwPrim;
+ imesa->elts.cmd->idx.skip = imesa->skip;
+ imesa->elts.n = 0;
+ }
+
+ ret = (u_int16_t *)(imesa->elts.cmd+1) + imesa->elts.n;
+ imesa->elts.n += n;
+ return ret;
+}
+
+#endif
diff --git a/src/savagerender.c b/src/savagerender.c
new file mode 100644
index 0000000..f2f1998
--- /dev/null
+++ b/src/savagerender.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2005 Felix Kuehling
+ * 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 FELIX KUEHLING 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.
+ */
+
+/*
+ * Render unclipped vertex buffers by emitting vertices directly to
+ * dma buffers. Use strip/fan hardware primitives where possible.
+ * Simulate missing primitives with indexed vertices.
+ */
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+#include "imports.h"
+#include "mtypes.h"
+
+#include "tnl/t_context.h"
+
+#include "savagecontext.h"
+#include "savagetris.h"
+#include "savagestate.h"
+#include "savageioctl.h"
+
+/*
+ * Standard render tab for Savage4 and smooth shading on Savage3D
+ */
+#define HAVE_POINTS 0
+#define HAVE_LINES 0
+#define HAVE_LINE_STRIPS 0
+#define HAVE_TRIANGLES 1
+#define HAVE_TRI_STRIPS 1
+#define HAVE_TRI_STRIP_1 0
+#define HAVE_TRI_FANS 1
+#define HAVE_POLYGONS 0
+#define HAVE_QUADS 0
+#define HAVE_QUAD_STRIPS 0
+
+#define HAVE_ELTS 1
+
+#define LOCAL_VARS savageContextPtr imesa = SAVAGE_CONTEXT(ctx)
+#define INIT( prim ) do { \
+ if (0) fprintf(stderr, "%s\n", __FUNCTION__); \
+ savageFlushVertices(imesa); \
+ switch (prim) { \
+ case GL_TRIANGLES: imesa->HwPrim = SAVAGE_PRIM_TRILIST; break; \
+ case GL_TRIANGLE_STRIP: imesa->HwPrim = SAVAGE_PRIM_TRISTRIP; break; \
+ case GL_TRIANGLE_FAN: imesa->HwPrim = SAVAGE_PRIM_TRIFAN; break; \
+ } \
+} while (0)
+#define FLUSH() savageFlushElts(imesa), savageFlushVertices(imesa)
+
+#define GET_CURRENT_VB_MAX_VERTS() \
+ ((imesa->bufferSize/4 - imesa->vtxBuf->used) / imesa->HwVertexSize)
+#define GET_SUBSEQUENT_VB_MAX_VERTS() \
+ (imesa->bufferSize/4 / imesa->HwVertexSize)
+
+#define ALLOC_VERTS( nr ) \
+ savageAllocVtxBuf( imesa, (nr) * imesa->HwVertexSize )
+#define EMIT_VERTS( ctx, j, nr, buf ) \
+ _tnl_emit_vertices_to_buffer(ctx, j, (j)+(nr), buf )
+
+#define ELTS_VARS( buf ) GLushort *dest = buf, firstElt = imesa->firstElt
+#define ELT_INIT( prim ) INIT(prim)
+
+/* (size - used - 1 qword for drawing command) * 4 elts per qword */
+#define GET_CURRENT_VB_MAX_ELTS() \
+ ((imesa->cmdBuf.size - (imesa->cmdBuf.write - imesa->cmdBuf.base) - 1)*4)
+/* (size - space for initial state - 1 qword for drawing command) * 4 elts
+ * imesa is not defined in validate_render :( */
+#define GET_SUBSEQUENT_VB_MAX_ELTS() \
+ ((SAVAGE_CONTEXT(ctx)->cmdBuf.size - \
+ (SAVAGE_CONTEXT(ctx)->cmdBuf.start - \
+ SAVAGE_CONTEXT(ctx)->cmdBuf.base) - 1)*4)
+
+#define ALLOC_ELTS(nr) savageAllocElts(imesa, nr)
+#define EMIT_ELT(offset, x) do { \
+ (dest)[offset] = (GLushort) ((x)+firstElt); \
+} while (0)
+#define EMIT_TWO_ELTS(offset, x, y) do { \
+ *(GLuint *)(dest + offset) = (((y)+firstElt) << 16) | \
+ ((x)+firstElt); \
+} while (0)
+
+#define INCR_ELTS( nr ) dest += nr
+#define ELTPTR dest
+#define RELEASE_ELT_VERTS() \
+ savageReleaseIndexedVerts(imesa)
+
+#define EMIT_INDEXED_VERTS( ctx, start, count ) do { \
+ GLuint *buf = savageAllocIndexedVerts(imesa, count-start); \
+ EMIT_VERTS(ctx, start, count-start, buf); \
+} while (0)
+
+#define TAG(x) savage_##x
+#include "tnl_dd/t_dd_dmatmp.h"
+
+/*
+ * On Savage3D triangle fans and strips are broken with flat
+ * shading. With triangles it wants the color for flat shading in the
+ * first vertex! So we make another template instance which uses
+ * triangles only (with reordered vertices: SAVAGE_PRIM_TRILIST_201).
+ * The reordering is done by the DRM.
+ */
+#undef HAVE_TRI_STRIPS
+#undef HAVE_TRI_FANS
+#define HAVE_TRI_STRIPS 0
+#define HAVE_TRI_FANS 0
+
+#undef INIT
+#define INIT( prim ) do { \
+ if (0) fprintf(stderr, "%s\n", __FUNCTION__); \
+ savageFlushVertices(imesa); \
+ imesa->HwPrim = SAVAGE_PRIM_TRILIST_201; \
+} while(0)
+
+#undef TAG
+#define TAG(x) savage_flat_##x##_s3d
+#include "tnl_dd/t_dd_dmatmp.h"
+
+
+/**********************************************************************/
+/* Render pipeline stage */
+/**********************************************************************/
+
+static GLboolean savage_run_render( GLcontext *ctx,
+ struct tnl_pipeline_stage *stage )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ tnl_render_func *tab, *tab_elts;
+ GLboolean valid;
+ GLuint i;
+
+ if (savageHaveIndexedVerts(imesa))
+ savageReleaseIndexedVerts(imesa);
+
+ if (imesa->savageScreen->chipset < S3_SAVAGE4 &&
+ (ctx->_TriangleCaps & DD_FLATSHADE)) {
+ tab = savage_flat_render_tab_verts_s3d;
+ tab_elts = savage_flat_render_tab_elts_s3d;
+ valid = savage_flat_validate_render_s3d( ctx, VB );
+ } else {
+ tab = savage_render_tab_verts;
+ tab_elts = savage_render_tab_elts;
+ valid = savage_validate_render( ctx, VB );
+ }
+
+ /* Don't handle clipping or vertex manipulations.
+ */
+ if (imesa->RenderIndex != 0 || !valid) {
+ return GL_TRUE;
+ }
+
+ tnl->Driver.Render.Start( ctx );
+ /* Check RenderIndex again. The ptexHack is detected late in RenderStart.
+ * Also check for ptex fallbacks detected late.
+ */
+ if (imesa->RenderIndex != 0 || imesa->Fallback != 0) {
+ return GL_TRUE;
+ }
+
+ /* setup for hardware culling */
+ imesa->raster_primitive = GL_TRIANGLES;
+ imesa->new_state |= SAVAGE_NEW_CULL;
+
+ /* update and emit state */
+ savageDDUpdateHwState(ctx);
+ savageEmitChangedState(imesa);
+
+ if (VB->Elts) {
+ tab = tab_elts;
+ if (!savageHaveIndexedVerts(imesa)) {
+ if (VB->Count > GET_SUBSEQUENT_VB_MAX_VERTS())
+ return GL_TRUE;
+ EMIT_INDEXED_VERTS(ctx, 0, VB->Count);
+ }
+ }
+
+ for (i = 0 ; i < VB->PrimitiveCount ; i++)
+ {
+ GLuint prim = _tnl_translate_prim(&VB->Primitive[i]);
+ GLuint start = VB->Primitive[i].start;
+ GLuint length = VB->Primitive[i].count;
+
+ if (length)
+ tab[prim & PRIM_MODE_MASK]( ctx, start, start+length, prim);
+ }
+
+ tnl->Driver.Render.Finish( ctx );
+
+ return GL_FALSE; /* finished the pipe */
+}
+
+struct tnl_pipeline_stage _savage_render_stage =
+{
+ "savage render",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ savage_run_render /* run */
+};
+
+
+/**********************************************************************/
+/* Pipeline stage for texture coordinate normalization */
+/**********************************************************************/
+struct texnorm_stage_data {
+ GLboolean active;
+ GLvector4f texcoord[MAX_TEXTURE_UNITS];
+};
+
+#define TEXNORM_STAGE_DATA(stage) ((struct texnorm_stage_data *)stage->privatePtr)
+
+
+static GLboolean run_texnorm_stage( GLcontext *ctx,
+ struct tnl_pipeline_stage *stage )
+{
+ struct texnorm_stage_data *store = TEXNORM_STAGE_DATA(stage);
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLuint i;
+
+ if (imesa->Fallback || !store->active)
+ return GL_TRUE;
+
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
+ const GLbitfield reallyEnabled = ctx->Texture.Unit[i]._ReallyEnabled;
+ if (reallyEnabled) {
+ const struct gl_texture_object *texObj = ctx->Texture.Unit[i]._Current;
+ const GLboolean normalizeS = (texObj->WrapS == GL_REPEAT);
+ const GLboolean normalizeT = (reallyEnabled & TEXTURE_2D_BIT) &&
+ (texObj->WrapT == GL_REPEAT);
+ const GLfloat *in = (GLfloat *)VB->TexCoordPtr[i]->data;
+ const GLint instride = VB->TexCoordPtr[i]->stride;
+ GLfloat (*out)[4] = store->texcoord[i].data;
+ GLint j;
+
+ if (!ctx->Texture.Unit[i]._ReallyEnabled ||
+ VB->TexCoordPtr[i]->size == 4)
+ /* Never try to normalize homogenous tex coords! */
+ continue;
+
+ if (normalizeS && normalizeT) {
+ /* take first texcoords as rough estimate of mean value */
+ GLfloat correctionS = -floor(in[0]+0.5);
+ GLfloat correctionT = -floor(in[1]+0.5);
+ for (j = 0; j < VB->Count; ++j) {
+ out[j][0] = in[0] + correctionS;
+ out[j][1] = in[1] + correctionT;
+ in = (GLfloat *)((GLubyte *)in + instride);
+ }
+ } else if (normalizeS) {
+ /* take first texcoords as rough estimate of mean value */
+ GLfloat correctionS = -floor(in[0]+0.5);
+ if (reallyEnabled & TEXTURE_2D_BIT) {
+ for (j = 0; j < VB->Count; ++j) {
+ out[j][0] = in[0] + correctionS;
+ out[j][1] = in[1];
+ in = (GLfloat *)((GLubyte *)in + instride);
+ }
+ } else {
+ for (j = 0; j < VB->Count; ++j) {
+ out[j][0] = in[0] + correctionS;
+ in = (GLfloat *)((GLubyte *)in + instride);
+ }
+ }
+ } else if (normalizeT) {
+ /* take first texcoords as rough estimate of mean value */
+ GLfloat correctionT = -floor(in[1]+0.5);
+ for (j = 0; j < VB->Count; ++j) {
+ out[j][0] = in[0];
+ out[j][1] = in[1] + correctionT;
+ in = (GLfloat *)((GLubyte *)in + instride);
+ }
+ }
+
+ if (normalizeS || normalizeT)
+ VB->AttribPtr[VERT_ATTRIB_TEX0+i] = VB->TexCoordPtr[i] = &store->texcoord[i];
+ }
+ }
+
+ return GL_TRUE;
+}
+
+/* Called the first time stage->run() is invoked.
+ */
+static GLboolean alloc_texnorm_data( GLcontext *ctx,
+ struct tnl_pipeline_stage *stage )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct texnorm_stage_data *store;
+ GLuint i;
+
+ stage->privatePtr = CALLOC(sizeof(*store));
+ store = TEXNORM_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++)
+ _mesa_vector4f_alloc( &store->texcoord[i], 0, VB->Size, 32 );
+
+ return GL_TRUE;
+}
+
+static void validate_texnorm( GLcontext *ctx,
+ struct tnl_pipeline_stage *stage )
+{
+ struct texnorm_stage_data *store = TEXNORM_STAGE_DATA(stage);
+ GLuint flags = 0;
+
+ if (((ctx->Texture.Unit[0]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) &&
+ (ctx->Texture.Unit[0]._Current->WrapS == GL_REPEAT)) ||
+ ((ctx->Texture.Unit[0]._ReallyEnabled & TEXTURE_2D_BIT) &&
+ (ctx->Texture.Unit[0]._Current->WrapT == GL_REPEAT)))
+ flags |= VERT_BIT_TEX0;
+
+ if (((ctx->Texture.Unit[1]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) &&
+ (ctx->Texture.Unit[1]._Current->WrapS == GL_REPEAT)) ||
+ ((ctx->Texture.Unit[1]._ReallyEnabled & TEXTURE_2D_BIT) &&
+ (ctx->Texture.Unit[1]._Current->WrapT == GL_REPEAT)))
+ flags |= VERT_BIT_TEX1;
+
+ store->active = (flags != 0);
+}
+
+static void free_texnorm_data( struct tnl_pipeline_stage *stage )
+{
+ struct texnorm_stage_data *store = TEXNORM_STAGE_DATA(stage);
+ GLuint i;
+
+ if (store) {
+ for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++)
+ if (store->texcoord[i].data)
+ _mesa_vector4f_free( &store->texcoord[i] );
+ FREE( store );
+ stage->privatePtr = 0;
+ }
+}
+
+struct tnl_pipeline_stage _savage_texnorm_stage =
+{
+ "savage texture coordinate normalization stage", /* name */
+ NULL, /* private data */
+ alloc_texnorm_data, /* run -- initially set to init */
+ free_texnorm_data, /* destructor */
+ validate_texnorm,
+ run_texnorm_stage
+};
diff --git a/src/savagespan.c b/src/savagespan.c
new file mode 100644
index 0000000..61ab9e6
--- /dev/null
+++ b/src/savagespan.c
@@ -0,0 +1,277 @@
+/*
+ * 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 \
+ driRenderbuffer *drb = (driRenderbuffer *) rb; \
+ __DRIdrawablePrivate *const dPriv = drb->dPriv; \
+ GLuint cpp = drb->cpp; \
+ GLuint pitch = drb->pitch; \
+ GLuint height = dPriv->h; \
+ GLubyte *buf = drb->Base.Data + dPriv->x * cpp + dPriv->y * pitch; \
+ GLuint p; \
+ (void) p
+
+#define LOCAL_DEPTH_VARS \
+ driRenderbuffer *drb = (driRenderbuffer *) rb; \
+ __DRIdrawablePrivate *const dPriv = drb->dPriv; \
+ GLuint zpp = drb->cpp; \
+ GLuint pitch = drb->pitch; \
+ GLuint height = dPriv->h; \
+ GLubyte *buf = drb->Base.Data + dPriv->x * zpp + dPriv->y * pitch;
+
+#define LOCAL_STENCIL_VARS LOCAL_DEPTH_VARS
+
+#define Y_FLIP(_y) (height - _y - 1)
+
+#define HW_LOCK()
+
+#define HW_UNLOCK()
+
+#define HW_WRITE_LOCK()
+
+#define HW_READ_LOCK()
+
+
+/* 16 bit, 565 rgb color spanline and pixel functions
+ */
+#define SPANTMP_PIXEL_FMT GL_RGB
+#define SPANTMP_PIXEL_TYPE GL_UNSIGNED_SHORT_5_6_5
+
+#define TAG(x) savage##x##_565
+#define TAG2(x,y) savage##x##_565##y
+#include "spantmp2.h"
+
+
+/* 32 bit, 8888 ARGB color spanline and pixel functions
+ */
+#define SPANTMP_PIXEL_FMT GL_BGRA
+#define SPANTMP_PIXEL_TYPE GL_UNSIGNED_INT_8_8_8_8_REV
+
+#define TAG(x) savage##x##_8888
+#define TAG2(x,y) savage##x##_8888##y
+#include "spantmp2.h"
+
+
+#undef HW_WRITE_LOCK
+#define HW_WRITE_LOCK()
+#undef HW_READ_LOCK
+#define HW_READ_LOCK()
+
+
+
+/* 16 bit integer depthbuffer functions
+ * Depth range is reversed. See also savageCalcViewport.
+ */
+#define WRITE_DEPTH( _x, _y, d ) \
+ *(GLushort *)(buf + ((_x)<<1) + (_y)*pitch) = 0xFFFF - d
+
+#define READ_DEPTH( d, _x, _y ) \
+ d = 0xFFFF - *(GLushort *)(buf + ((_x)<<1) + (_y)*pitch)
+
+#define TAG(x) savage##x##_z16
+#include "depthtmp.h"
+
+
+
+
+/* 16 bit float depthbuffer functions
+ */
+#define WRITE_DEPTH( _x, _y, d ) \
+ *(GLushort *)(buf + ((_x)<<1) + (_y)*pitch) = \
+ savageEncodeFloat16( 1.0 - (GLfloat)d/65535.0 )
+
+#define READ_DEPTH( d, _x, _y ) \
+ d = 65535 - \
+ savageDecodeFloat16( *(GLushort *)(buf + ((_x)<<1) + (_y)*pitch) ) * \
+ 65535.0
+
+#define TAG(x) savage##x##_z16f
+#include "depthtmp.h"
+
+
+
+
+/* 8-bit stencil /24-bit integer depth depthbuffer functions.
+ * Depth range is reversed. See also savageCalcViewport.
+ */
+#define WRITE_DEPTH( _x, _y, d ) do { \
+ GLuint tmp = *(GLuint *)(buf + ((_x)<<2) + (_y)*pitch); \
+ tmp &= 0xFF000000; \
+ tmp |= 0x00FFFFFF - d; \
+ *(GLuint *)(buf + (_x<<2) + _y*pitch) = tmp; \
+} while(0)
+
+#define READ_DEPTH( d, _x, _y ) \
+ d = 0x00FFFFFF - (*(GLuint *)(buf + ((_x)<<2) + (_y)*pitch) & 0x00FFFFFF)
+
+#define TAG(x) savage##x##_s8_z24
+#include "depthtmp.h"
+
+
+
+
+/* 24 bit float depthbuffer functions
+ */
+#define WRITE_DEPTH( _x, _y, d ) do { \
+ GLuint tmp = *(GLuint *)(buf + ((_x)<<2) + (_y)*pitch); \
+ tmp &= 0xFF000000; \
+ tmp |= savageEncodeFloat24( 1.0 - (GLfloat)d/16777215.0 ); \
+ *(GLuint *)(buf + (_x<<2) + _y*pitch) = tmp; \
+} while(0)
+
+#define READ_DEPTH( d, _x, _y ) \
+ d = 16777215 - savageDecodeFloat24( \
+ *(GLuint *)(buf + ((_x)<<2) + (_y)*pitch) & 0x00FFFFFF) \
+ * 16777215.0
+
+#define TAG(x) savage##x##_s8_z24f
+#include "depthtmp.h"
+
+
+#define WRITE_STENCIL( _x, _y, d ) do { \
+ GLuint tmp = *(GLuint *)(buf + ((_x)<<2) + (_y)*pitch); \
+ tmp &= 0x00FFFFFF; \
+ tmp |= (((GLuint)d)<<24) & 0xFF000000; \
+ *(GLuint *)(buf + ((_x)<<2) + (_y)*pitch) = tmp; \
+} while(0)
+
+#define READ_STENCIL( d, _x, _y ) \
+ d = (GLstencil)((*(GLuint *)(buf + ((_x)<<2) + (_y)*pitch) & 0xFF000000) >> 24)
+
+#define TAG(x) savage##x##_s8_z24
+#include "stenciltmp.h"
+
+
+
+/*
+ * Wrappers around _swrast_Copy/Draw/ReadPixels that make sure all
+ * primitives are flushed and the hardware is idle before accessing
+ * the frame buffer.
+ */
+static void
+savageCopyPixels( GLcontext *ctx,
+ GLint srcx, GLint srcy, GLsizei width, GLsizei height,
+ GLint destx, GLint desty,
+ GLenum type )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ FLUSH_BATCH(imesa);
+ WAIT_IDLE_EMPTY(imesa);
+ _swrast_CopyPixels(ctx, srcx, srcy, width, height, destx, desty, type);
+}
+static void
+savageDrawPixels( GLcontext *ctx,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ const struct gl_pixelstore_attrib *packing,
+ const GLvoid *pixels )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ FLUSH_BATCH(imesa);
+ WAIT_IDLE_EMPTY(imesa);
+ _swrast_DrawPixels(ctx, x, y, width, height, format, type, packing, pixels);
+}
+static void
+savageReadPixels( GLcontext *ctx,
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ const struct gl_pixelstore_attrib *packing,
+ GLvoid *pixels )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ FLUSH_BATCH(imesa);
+ WAIT_IDLE_EMPTY(imesa);
+ _swrast_ReadPixels(ctx, x, y, width, height, format, type, packing, pixels);
+}
+
+/*
+ * Make sure the hardware is idle when span-rendering.
+ */
+static void savageSpanRenderStart( GLcontext *ctx )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ FLUSH_BATCH(imesa);
+ WAIT_IDLE_EMPTY(imesa);
+}
+
+
+void savageDDInitSpanFuncs( GLcontext *ctx )
+{
+ struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference(ctx);
+ swdd->SpanRenderStart = savageSpanRenderStart;
+
+ /* XXX these should probably be plugged in elsewhere */
+ ctx->Driver.CopyPixels = savageCopyPixels;
+ ctx->Driver.DrawPixels = savageDrawPixels;
+ ctx->Driver.ReadPixels = savageReadPixels;
+}
+
+
+
+/**
+ * Plug in the Get/Put routines for the given driRenderbuffer.
+ */
+void
+savageSetSpanFunctions(driRenderbuffer *drb, const GLvisual *vis,
+ GLboolean float_depth)
+{
+ if (drb->Base.InternalFormat == GL_RGBA) {
+ if (vis->redBits == 5 && vis->greenBits == 6 && vis->blueBits == 5) {
+ savageInitPointers_565(&drb->Base);
+ }
+ else {
+ savageInitPointers_8888(&drb->Base);
+ }
+ }
+ else if (drb->Base.InternalFormat == GL_DEPTH_COMPONENT16) {
+ if (float_depth) {
+ savageInitDepthPointers_z16f(&drb->Base);
+ }
+ else {
+ savageInitDepthPointers_z16(&drb->Base);
+ }
+ }
+ else if (drb->Base.InternalFormat == GL_DEPTH_COMPONENT24) {
+ if (float_depth) {
+ savageInitDepthPointers_s8_z24f(&drb->Base);
+ }
+ else {
+ savageInitDepthPointers_s8_z24(&drb->Base);
+ }
+ }
+ else if (drb->Base.InternalFormat == GL_STENCIL_INDEX8_EXT) {
+ savageInitStencilPointers_s8_z24(&drb->Base);
+ }
+}
diff --git a/src/savagespan.h b/src/savagespan.h
new file mode 100644
index 0000000..f6a312e
--- /dev/null
+++ b/src/savagespan.h
@@ -0,0 +1,137 @@
+/*
+ * 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
+
+#include "drirenderbuffer.h"
+
+
+extern void savageDDInitSpanFuncs( GLcontext *ctx );
+
+extern void
+savageSetSpanFunctions(driRenderbuffer *rb, const GLvisual *vis,
+ GLboolean float_depth);
+
+
+/*
+ * Savage 16-bit float depth format with zExpOffset=16:
+ * 4 bit unsigned exponent, 12 bit mantissa
+ *
+ * The meaning of the mantissa is different from IEEE floatint point
+ * formats. The same number can't be encoded with different exponents.
+ * So no bits are wasted.
+ *
+ * exponent | range encoded by mantissa | accuracy or mantissa
+ * ---------+---------------------------+---------------------
+ * 15 | 2^-1 .. 1 | 2^-13
+ * 14 | 2^-2 .. 2^-1 | 2^-14
+ * 13 | 2^-3 .. 2^-2 | 2^-15
+ * ... | ... |
+ * 2 | 2^-14 .. 2^-13 | 2^-27
+ * 1 | 2^-15 .. 2^-14 | 2^-27
+ * 0 | 2^-16 .. 2^-15 | 2^-28
+ *
+ * Note that there is no encoding for numbers < 2^-16.
+ */
+static __inline GLuint savageEncodeFloat16( GLdouble x )
+{
+ GLint r = (GLint)(x * 0x10000000);
+ GLint exp = 0;
+ if (r < 0x1000)
+ return 0;
+ while (r - 0x1000 > 0x0fff) {
+ r >>= 1;
+ exp++;
+ }
+ return exp > 0xf ? 0xffff : (r - 0x1000) | (exp << 12);
+}
+static __inline GLdouble savageDecodeFloat16( GLuint x )
+{
+ static const GLdouble pow2[16] = {
+ 1.0/(1<<28), 1.0/(1<<27), 1.0/(1<<26), 1.0/(1<<25),
+ 1.0/(1<<24), 1.0/(1<<23), 1.0/(1<<22), 1.0/(1<<21),
+ 1.0/(1<<20), 1.0/(1<<19), 1.0/(1<<18), 1.0/(1<<17),
+ 1.0/(1<<16), 1.0/(1<<15), 1.0/(1<<14), 1.0/(1<<13)
+ };
+ static const GLdouble bias[16] = {
+ 1.0/(1<<16), 1.0/(1<<15), 1.0/(1<<14), 1.0/(1<<13),
+ 1.0/(1<<12), 1.0/(1<<11), 1.0/(1<<10), 1.0/(1<< 9),
+ 1.0/(1<< 8), 1.0/(1<< 7), 1.0/(1<< 6), 1.0/(1<< 5),
+ 1.0/(1<< 4), 1.0/(1<< 3), 1.0/(1<< 2), 1.0/(1<< 1)
+ };
+ GLuint mant = x & 0x0fff;
+ GLuint exp = (x >> 12) & 0xf;
+ return bias[exp] + pow2[exp]*mant;
+}
+
+/*
+ * Savage 24-bit float depth format with zExpOffset=32:
+ * 5 bit unsigned exponent, 19 bit mantissa
+ *
+ * Details analogous to the 16-bit format.
+ */
+static __inline GLuint savageEncodeFloat24( GLdouble x )
+{
+ int64_t r = (int64_t)(x * ((int64_t)1 << (19+32)));
+ GLint exp = 0;
+ if (r < 0x80000)
+ return 0;
+ while (r - 0x80000 > 0x7ffff) {
+ r >>= 1;
+ exp++;
+ }
+ return exp > 0x1f ? 0xffffff : (r - 0x80000) | (exp << 19);
+}
+#define _1 (int64_t)1
+static __inline GLdouble savageDecodeFloat24( GLuint x )
+{
+ static const GLdouble pow2[32] = {
+ 1.0/(_1<<51), 1.0/(_1<<50), 1.0/(_1<<49), 1.0/(_1<<48),
+ 1.0/(_1<<47), 1.0/(_1<<46), 1.0/(_1<<45), 1.0/(_1<<44),
+ 1.0/(_1<<43), 1.0/(_1<<42), 1.0/(_1<<41), 1.0/(_1<<40),
+ 1.0/(_1<<39), 1.0/(_1<<38), 1.0/(_1<<37), 1.0/(_1<<36),
+ 1.0/(_1<<35), 1.0/(_1<<34), 1.0/(_1<<33), 1.0/(_1<<32),
+ 1.0/(_1<<31), 1.0/(_1<<30), 1.0/(_1<<29), 1.0/(_1<<28),
+ 1.0/(_1<<27), 1.0/(_1<<26), 1.0/(_1<<25), 1.0/(_1<<24),
+ 1.0/(_1<<23), 1.0/(_1<<22), 1.0/(_1<<21), 1.0/(_1<<20)
+ };
+ static const GLdouble bias[32] = {
+ 1.0/(_1<<32), 1.0/(_1<<31), 1.0/(_1<<30), 1.0/(_1<<29),
+ 1.0/(_1<<28), 1.0/(_1<<27), 1.0/(_1<<26), 1.0/(_1<<25),
+ 1.0/(_1<<24), 1.0/(_1<<23), 1.0/(_1<<22), 1.0/(_1<<21),
+ 1.0/(_1<<20), 1.0/(_1<<19), 1.0/(_1<<18), 1.0/(_1<<17),
+ 1.0/(_1<<16), 1.0/(_1<<15), 1.0/(_1<<14), 1.0/(_1<<13),
+ 1.0/(_1<<12), 1.0/(_1<<11), 1.0/(_1<<10), 1.0/(_1<< 9),
+ 1.0/(_1<< 8), 1.0/(_1<< 7), 1.0/(_1<< 6), 1.0/(_1<< 5),
+ 1.0/(_1<< 4), 1.0/(_1<< 3), 1.0/(_1<< 2), 1.0/(_1<< 1)
+ };
+ GLuint mant = x & 0x7ffff;
+ GLuint exp = (x >> 19) & 0x1f;
+ return bias[exp] + pow2[exp]*mant;
+}
+#undef _1
+
+
+#endif
diff --git a/src/savagestate.c b/src/savagestate.c
new file mode 100644
index 0000000..741a9dd
--- /dev/null
+++ b/src/savagestate.c
@@ -0,0 +1,1728 @@
+/*
+ * 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 "savagetris.h"
+#include "savageioctl.h"
+#include "savage_bci.h"
+
+#include "swrast/swrast.h"
+#include "vbo/vbo.h"
+#include "tnl/tnl.h"
+#include "swrast_setup/swrast_setup.h"
+
+#include "xmlpool.h"
+
+/* Savage4, ProSavage[DDR], SuperSavage watermarks */
+#define S4_ZRLO 24
+#define S4_ZRHI 24
+#define S4_ZWLO 0
+#define S4_ZWHI 0
+
+#define S4_DRLO 0
+#define S4_DRHI 0
+#define S4_DWLO 0
+#define S4_DWHI 0
+
+#define S4_TR 15
+
+/* Savage3D/MX/IX watermarks */
+#define S3D_ZRLO 8
+#define S3D_ZRHI 24
+#define S3D_ZWLO 0
+#define S3D_ZWHI 24
+
+#define S3D_DRLO 0
+#define S3D_DRHI 0
+#define S3D_DWLO 0
+#define S3D_DWHI 0
+
+#define S3D_TR 15
+
+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)
+{
+ savageBlendFunc_s4(ctx);
+}
+static void savageDDAlphaFunc_s3d(GLcontext *ctx, GLenum func, GLfloat ref)
+{
+ 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);
+ u_int32_t drawLocalCtrl = imesa->regs.s4.drawLocalCtrl.ui;
+ u_int32_t drawCtrl0 = imesa->regs.s4.drawCtrl0.ui;
+ u_int32_t drawCtrl1 = imesa->regs.s4.drawCtrl1.ui;
+
+ /* set up draw control register (including blending, alpha
+ * test, and shading model)
+ */
+
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdDestWrites = GL_FALSE;
+
+ /*
+ * blend modes
+ */
+ if(ctx->Color.BlendEnabled){
+ switch (ctx->Color.BlendDstRGB)
+ {
+ case GL_ZERO:
+ imesa->regs.s4.drawLocalCtrl.ni.dstAlphaMode = DAM_Zero;
+ break;
+
+ case GL_ONE:
+ imesa->regs.s4.drawLocalCtrl.ni.dstAlphaMode = DAM_One;
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+ break;
+
+ case GL_SRC_COLOR:
+ imesa->regs.s4.drawLocalCtrl.ni.dstAlphaMode = DAM_SrcClr;
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+ break;
+
+ case GL_ONE_MINUS_SRC_COLOR:
+ imesa->regs.s4.drawLocalCtrl.ni.dstAlphaMode = DAM_1SrcClr;
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+ break;
+
+ case GL_SRC_ALPHA:
+ imesa->regs.s4.drawLocalCtrl.ni.dstAlphaMode = DAM_SrcAlpha;
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+ break;
+
+ case GL_ONE_MINUS_SRC_ALPHA:
+ imesa->regs.s4.drawLocalCtrl.ni.dstAlphaMode = DAM_1SrcAlpha;
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+ break;
+
+ case GL_DST_ALPHA:
+ if (imesa->glCtx->Visual.alphaBits == 0)
+ {
+ imesa->regs.s4.drawLocalCtrl.ni.dstAlphaMode = DAM_One;
+ }
+ else
+ {
+ imesa->regs.s4.drawLocalCtrl.ni.dstAlphaMode= DAM_DstAlpha;
+ }
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+ break;
+
+ case GL_ONE_MINUS_DST_ALPHA:
+ if (imesa->glCtx->Visual.alphaBits == 0)
+ {
+ imesa->regs.s4.drawLocalCtrl.ni.dstAlphaMode = DAM_Zero;
+ }
+ else
+ {
+ imesa->regs.s4.drawLocalCtrl.ni.dstAlphaMode=DAM_1DstAlpha;
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdDestWrites= GL_TRUE;
+ }
+ break;
+ }
+
+ switch (ctx->Color.BlendSrcRGB)
+ {
+ case GL_ZERO:
+ imesa->regs.s4.drawLocalCtrl.ni.srcAlphaMode = SAM_Zero;
+ break;
+
+ case GL_ONE:
+ imesa->regs.s4.drawLocalCtrl.ni.srcAlphaMode = SAM_One;
+ break;
+
+ case GL_DST_COLOR:
+ imesa->regs.s4.drawLocalCtrl.ni.srcAlphaMode = SAM_DstClr;
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+ break;
+
+ case GL_ONE_MINUS_DST_COLOR:
+ imesa->regs.s4.drawLocalCtrl.ni.srcAlphaMode = SAM_1DstClr;
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdDestWrites = GL_TRUE;
+ break;
+
+ case GL_SRC_ALPHA:
+ imesa->regs.s4.drawLocalCtrl.ni.srcAlphaMode = SAM_SrcAlpha;
+ break;
+
+ case GL_ONE_MINUS_SRC_ALPHA:
+ imesa->regs.s4.drawLocalCtrl.ni.srcAlphaMode = SAM_1SrcAlpha;
+ break;
+
+ case GL_DST_ALPHA:
+ if (imesa->glCtx->Visual.alphaBits == 0)
+ {
+ imesa->regs.s4.drawLocalCtrl.ni.srcAlphaMode = SAM_One;
+ }
+ else
+ {
+ imesa->regs.s4.drawLocalCtrl.ni.srcAlphaMode= SAM_DstAlpha;
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdDestWrites= GL_TRUE;
+ }
+ break;
+
+ case GL_ONE_MINUS_DST_ALPHA:
+ if (imesa->glCtx->Visual.alphaBits == 0)
+ {
+ imesa->regs.s4.drawLocalCtrl.ni.srcAlphaMode = SAM_Zero;
+ }
+ else
+ {
+ imesa->regs.s4.drawLocalCtrl.ni.srcAlphaMode=SAM_1DstAlpha;
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdDestWrites= GL_TRUE;
+ }
+ break;
+ }
+ }
+ else
+ {
+ imesa->regs.s4.drawLocalCtrl.ni.dstAlphaMode = DAM_Zero;
+ imesa->regs.s4.drawLocalCtrl.ni.srcAlphaMode = SAM_One;
+ }
+
+ /* alpha test*/
+
+ if(ctx->Color.AlphaEnabled)
+ {
+ ACmpFunc a;
+ GLubyte alphaRef;
+
+ CLAMPED_FLOAT_TO_UBYTE(alphaRef,ctx->Color.AlphaRef);
+
+ switch(ctx->Color.AlphaFunc) {
+ case GL_NEVER: a = CF_Never; break;
+ case GL_ALWAYS: a = CF_Always; break;
+ case GL_LESS: a = CF_Less; break;
+ case GL_LEQUAL: a = CF_LessEqual; break;
+ case GL_EQUAL: a = CF_Equal; break;
+ case GL_GREATER: a = CF_Greater; break;
+ case GL_GEQUAL: a = CF_GreaterEqual; break;
+ case GL_NOTEQUAL: a = CF_NotEqual; break;
+ default:return;
+ }
+
+ imesa->regs.s4.drawCtrl1.ni.alphaTestEn = GL_TRUE;
+ imesa->regs.s4.drawCtrl1.ni.alphaTestCmpFunc = a;
+ imesa->regs.s4.drawCtrl0.ni.alphaRefVal = alphaRef;
+ }
+ else
+ {
+ imesa->regs.s4.drawCtrl1.ni.alphaTestEn = GL_FALSE;
+ }
+
+ /* Set/Reset Z-after-alpha*/
+
+ imesa->regs.s4.drawLocalCtrl.ni.wrZafterAlphaTst =
+ imesa->regs.s4.drawCtrl1.ni.alphaTestEn;
+ /*imesa->regs.s4.drawLocalCtrl.ni.zUpdateEn =
+ ~drawLocalCtrl.ni.wrZafterAlphaTst;*/
+
+ if (drawLocalCtrl != imesa->regs.s4.drawLocalCtrl.ui)
+ imesa->dirty |= SAVAGE_UPLOAD_LOCAL;
+ if (drawCtrl0 != imesa->regs.s4.drawCtrl0.ui ||
+ drawCtrl1 != imesa->regs.s4.drawCtrl1.ui)
+ imesa->dirty |= SAVAGE_UPLOAD_GLOBAL;
+}
+static void savageBlendFunc_s3d(GLcontext *ctx)
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ u_int32_t drawCtrl = imesa->regs.s3d.drawCtrl.ui;
+ u_int32_t zBufCtrl = imesa->regs.s3d.zBufCtrl.ui;
+
+ /* set up draw control register (including blending, alpha
+ * test, dithering, and shading model)
+ */
+
+ imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites = 0;
+
+ /*
+ * blend modes
+ */
+ if(ctx->Color.BlendEnabled){
+ switch (ctx->Color.BlendDstRGB)
+ {
+ case GL_ZERO:
+ imesa->regs.s3d.drawCtrl.ni.dstAlphaMode = DAM_Zero;
+ break;
+
+ case GL_ONE:
+ imesa->regs.s3d.drawCtrl.ni.dstAlphaMode = DAM_One;
+ imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites = GL_TRUE;
+ break;
+
+ case GL_SRC_COLOR:
+ imesa->regs.s3d.drawCtrl.ni.dstAlphaMode = DAM_SrcClr;
+ imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites = GL_TRUE;
+ break;
+
+ case GL_ONE_MINUS_SRC_COLOR:
+ imesa->regs.s3d.drawCtrl.ni.dstAlphaMode = DAM_1SrcClr;
+ imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites = GL_TRUE;
+ break;
+
+ case GL_SRC_ALPHA:
+ imesa->regs.s3d.drawCtrl.ni.dstAlphaMode = DAM_SrcAlpha;
+ imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites = GL_TRUE;
+ break;
+
+ case GL_ONE_MINUS_SRC_ALPHA:
+ imesa->regs.s3d.drawCtrl.ni.dstAlphaMode = DAM_1SrcAlpha;
+ imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites = GL_TRUE;
+ break;
+
+ case GL_DST_ALPHA:
+ if (imesa->glCtx->Visual.alphaBits == 0)
+ {
+ imesa->regs.s3d.drawCtrl.ni.dstAlphaMode = DAM_One;
+ }
+ else
+ {
+ imesa->regs.s3d.drawCtrl.ni.dstAlphaMode = DAM_DstAlpha;
+ }
+ imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites = GL_TRUE;
+ break;
+
+ case GL_ONE_MINUS_DST_ALPHA:
+ if (imesa->glCtx->Visual.alphaBits == 0)
+ {
+ imesa->regs.s3d.drawCtrl.ni.dstAlphaMode = DAM_Zero;
+ }
+ else
+ {
+ imesa->regs.s3d.drawCtrl.ni.dstAlphaMode = DAM_1DstAlpha;
+ imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites = GL_TRUE;
+ }
+ break;
+ }
+
+ switch (ctx->Color.BlendSrcRGB)
+ {
+ case GL_ZERO:
+ imesa->regs.s3d.drawCtrl.ni.srcAlphaMode = SAM_Zero;
+ break;
+
+ case GL_ONE:
+ imesa->regs.s3d.drawCtrl.ni.srcAlphaMode = SAM_One;
+ break;
+
+ case GL_DST_COLOR:
+ imesa->regs.s3d.drawCtrl.ni.srcAlphaMode = SAM_DstClr;
+ imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites = GL_TRUE;
+ break;
+
+ case GL_ONE_MINUS_DST_COLOR:
+ imesa->regs.s3d.drawCtrl.ni.srcAlphaMode = SAM_1DstClr;
+ imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites = GL_TRUE;
+ break;
+
+ case GL_SRC_ALPHA:
+ imesa->regs.s3d.drawCtrl.ni.srcAlphaMode = SAM_SrcAlpha;
+ break;
+
+ case GL_ONE_MINUS_SRC_ALPHA:
+ imesa->regs.s3d.drawCtrl.ni.srcAlphaMode = SAM_1SrcAlpha;
+ break;
+
+ case GL_DST_ALPHA:
+ if (imesa->glCtx->Visual.alphaBits == 0)
+ {
+ imesa->regs.s3d.drawCtrl.ni.srcAlphaMode = SAM_One;
+ }
+ else
+ {
+ imesa->regs.s3d.drawCtrl.ni.srcAlphaMode = SAM_DstAlpha;
+ imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites = GL_TRUE;
+ }
+ break;
+
+ case GL_ONE_MINUS_DST_ALPHA:
+ if (imesa->glCtx->Visual.alphaBits == 0)
+ {
+ imesa->regs.s3d.drawCtrl.ni.srcAlphaMode = SAM_Zero;
+ }
+ else
+ {
+ imesa->regs.s3d.drawCtrl.ni.srcAlphaMode = SAM_1DstAlpha;
+ imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites = GL_TRUE;
+ }
+ break;
+ }
+ }
+ else
+ {
+ imesa->regs.s3d.drawCtrl.ni.dstAlphaMode = DAM_Zero;
+ imesa->regs.s3d.drawCtrl.ni.srcAlphaMode = SAM_One;
+ }
+
+ /* alpha test*/
+
+ if(ctx->Color.AlphaEnabled)
+ {
+ ACmpFunc a;
+ GLubyte alphaRef;
+
+ CLAMPED_FLOAT_TO_UBYTE(alphaRef,ctx->Color.AlphaRef);
+
+ switch(ctx->Color.AlphaFunc) {
+ case GL_NEVER: a = CF_Never; break;
+ case GL_ALWAYS: a = CF_Always; break;
+ case GL_LESS: a = CF_Less; break;
+ case GL_LEQUAL: a = CF_LessEqual; break;
+ case GL_EQUAL: a = CF_Equal; break;
+ case GL_GREATER: a = CF_Greater; break;
+ case GL_GEQUAL: a = CF_GreaterEqual; break;
+ case GL_NOTEQUAL: a = CF_NotEqual; break;
+ default:return;
+ }
+
+ imesa->regs.s3d.drawCtrl.ni.alphaTestEn = GL_TRUE;
+ imesa->regs.s3d.drawCtrl.ni.alphaTestCmpFunc = a;
+ imesa->regs.s3d.drawCtrl.ni.alphaRefVal = alphaRef;
+ }
+ else
+ {
+ imesa->regs.s3d.drawCtrl.ni.alphaTestEn = GL_FALSE;
+ }
+
+ /* Set/Reset Z-after-alpha*/
+
+ imesa->regs.s3d.zBufCtrl.ni.wrZafterAlphaTst =
+ imesa->regs.s3d.drawCtrl.ni.alphaTestEn;
+
+ if (drawCtrl != imesa->regs.s3d.drawCtrl.ui ||
+ zBufCtrl != imesa->regs.s3d.zBufCtrl.ui)
+ imesa->dirty |= SAVAGE_UPLOAD_LOCAL;
+}
+
+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);
+ ZCmpFunc zmode;
+ u_int32_t drawLocalCtrl = imesa->regs.s4.drawLocalCtrl.ui;
+ u_int32_t zBufCtrl = imesa->regs.s4.zBufCtrl.ui;
+ u_int32_t zWatermarks = imesa->regs.s4.zWatermarks.ui; /* FIXME: in DRM */
+
+ /* set up z-buffer control register (global)
+ * set up z-buffer offset register (global)
+ * set up z read/write watermarks register (global)
+ */
+
+ switch(func) { /* reversed (see savageCalcViewport) */
+ case GL_NEVER: zmode = CF_Never; break;
+ case GL_ALWAYS: zmode = CF_Always; break;
+ case GL_LESS: zmode = CF_Greater; break;
+ case GL_LEQUAL: zmode = CF_GreaterEqual; break;
+ case GL_EQUAL: zmode = CF_Equal; break;
+ case GL_GREATER: zmode = CF_Less; break;
+ case GL_GEQUAL: zmode = CF_LessEqual; break;
+ case GL_NOTEQUAL: zmode = CF_NotEqual; break;
+ default:return;
+ }
+ if (ctx->Depth.Test)
+ {
+
+ imesa->regs.s4.zBufCtrl.ni.zCmpFunc = zmode;
+ imesa->regs.s4.drawLocalCtrl.ni.zUpdateEn = ctx->Depth.Mask;
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdZbufWrites = GL_TRUE;
+ imesa->regs.s4.zBufCtrl.ni.zBufEn = GL_TRUE;
+ }
+ else if (imesa->glCtx->Stencil.Enabled && imesa->hw_stencil)
+ {
+ /* Need to keep Z on for Stencil. */
+ imesa->regs.s4.zBufCtrl.ni.zCmpFunc = CF_Always;
+ imesa->regs.s4.zBufCtrl.ni.zBufEn = GL_TRUE;
+ imesa->regs.s4.drawLocalCtrl.ni.zUpdateEn = GL_FALSE;
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdZbufWrites = GL_FALSE;
+ }
+ else
+ {
+
+ if (imesa->regs.s4.drawLocalCtrl.ni.drawUpdateEn == GL_FALSE)
+ {
+ imesa->regs.s4.zBufCtrl.ni.zCmpFunc = CF_Always;
+ imesa->regs.s4.zBufCtrl.ni.zBufEn = GL_TRUE;
+ }
+ else
+
+ /* DRAWUPDATE_REQUIRES_Z_ENABLED*/
+ {
+ imesa->regs.s4.zBufCtrl.ni.zBufEn = GL_FALSE;
+ }
+ imesa->regs.s4.drawLocalCtrl.ni.zUpdateEn = GL_FALSE;
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdZbufWrites = GL_FALSE;
+ }
+
+ if (drawLocalCtrl != imesa->regs.s4.drawLocalCtrl.ui)
+ imesa->dirty |= SAVAGE_UPLOAD_LOCAL;
+ if (zBufCtrl != imesa->regs.s4.zBufCtrl.ui ||
+ zWatermarks != imesa->regs.s4.zWatermarks.ui)
+ imesa->dirty |= SAVAGE_UPLOAD_GLOBAL;
+}
+static void savageDDDepthFunc_s3d(GLcontext *ctx, GLenum func)
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ ZCmpFunc zmode;
+ u_int32_t drawCtrl = imesa->regs.s3d.drawCtrl.ui;
+ u_int32_t zBufCtrl = imesa->regs.s3d.zBufCtrl.ui;
+ u_int32_t zWatermarks = imesa->regs.s3d.zWatermarks.ui; /* FIXME: in DRM */
+
+ /* set up z-buffer control register (global)
+ * set up z-buffer offset register (global)
+ * set up z read/write watermarks register (global)
+ */
+ switch(func) { /* reversed (see savageCalcViewport) */
+ case GL_NEVER: zmode = CF_Never; break;
+ case GL_ALWAYS: zmode = CF_Always; break;
+ case GL_LESS: zmode = CF_Greater; break;
+ case GL_LEQUAL: zmode = CF_GreaterEqual; break;
+ case GL_EQUAL: zmode = CF_Equal; break;
+ case GL_GREATER: zmode = CF_Less; break;
+ case GL_GEQUAL: zmode = CF_LessEqual; break;
+ case GL_NOTEQUAL: zmode = CF_NotEqual; break;
+ default:return;
+ }
+ if (ctx->Depth.Test)
+ {
+ imesa->regs.s3d.zBufCtrl.ni.zBufEn = GL_TRUE;
+ imesa->regs.s3d.zBufCtrl.ni.zCmpFunc = zmode;
+ imesa->regs.s3d.zBufCtrl.ni.zUpdateEn = ctx->Depth.Mask;
+
+ imesa->regs.s3d.drawCtrl.ni.flushPdZbufWrites = GL_TRUE;
+ }
+ else
+ {
+ if (imesa->regs.s3d.zBufCtrl.ni.drawUpdateEn == GL_FALSE) {
+ imesa->regs.s3d.zBufCtrl.ni.zCmpFunc = CF_Always;
+ imesa->regs.s3d.zBufCtrl.ni.zBufEn = GL_TRUE;
+ }
+ else
+
+ /* DRAWUPDATE_REQUIRES_Z_ENABLED*/
+ {
+ imesa->regs.s3d.zBufCtrl.ni.zBufEn = GL_FALSE;
+ }
+ imesa->regs.s3d.zBufCtrl.ni.zUpdateEn = GL_FALSE;
+ imesa->regs.s3d.drawCtrl.ni.flushPdZbufWrites = GL_FALSE;
+ }
+
+ if (drawCtrl != imesa->regs.s3d.drawCtrl.ui ||
+ zBufCtrl != imesa->regs.s3d.zBufCtrl.ui)
+ imesa->dirty |= SAVAGE_UPLOAD_LOCAL;
+ if (zWatermarks != imesa->regs.s3d.zWatermarks.ui)
+ imesa->dirty |= SAVAGE_UPLOAD_GLOBAL;
+}
+
+static void savageDDDepthMask_s4(GLcontext *ctx, GLboolean flag)
+{
+ savageDDDepthFunc_s4(ctx,ctx->Depth.Func);
+}
+static void savageDDDepthMask_s3d(GLcontext *ctx, GLboolean flag)
+{
+ savageDDDepthFunc_s3d(ctx,ctx->Depth.Func);
+}
+
+
+
+
+/* =============================================================
+ * Hardware clipping
+ */
+
+
+static void savageDDScissor( GLcontext *ctx, GLint x, GLint y,
+ GLsizei w, GLsizei h )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+
+ /* Emit buffered commands with old scissor state. */
+ FLUSH_BATCH(imesa);
+
+ /* Mirror scissors in private context. */
+ imesa->scissor.enabled = ctx->Scissor.Enabled;
+ imesa->scissor.x = x;
+ imesa->scissor.y = y;
+ imesa->scissor.w = w;
+ imesa->scissor.h = h;
+}
+
+
+
+static void savageDDDrawBuffer(GLcontext *ctx, GLenum mode )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ u_int32_t destCtrl = imesa->regs.s4.destCtrl.ui;
+
+ /*
+ * _DrawDestMask is easier to cope with than <mode>.
+ */
+ switch ( ctx->DrawBuffer->_ColorDrawBufferMask[0] ) {
+ case BUFFER_BIT_FRONT_LEFT:
+ imesa->IsDouble = GL_FALSE;
+ imesa->regs.s4.destCtrl.ni.offset = imesa->savageScreen->frontOffset>>11;
+ break;
+ case BUFFER_BIT_BACK_LEFT:
+ imesa->IsDouble = GL_TRUE;
+ imesa->regs.s4.destCtrl.ni.offset = imesa->savageScreen->backOffset>>11;
+ break;
+ default:
+ FALLBACK( ctx, SAVAGE_FALLBACK_DRAW_BUFFER, GL_TRUE );
+ return;
+ }
+
+ imesa->NotFirstFrame = GL_FALSE;
+ savageXMesaSetClipRects(imesa);
+ FALLBACK(ctx, SAVAGE_FALLBACK_DRAW_BUFFER, GL_FALSE);
+
+ if (destCtrl != imesa->regs.s4.destCtrl.ui)
+ imesa->dirty |= SAVAGE_UPLOAD_GLOBAL;
+}
+
+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
+ */
+
+void savageCalcViewport( GLcontext *ctx )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ const GLfloat *v = ctx->Viewport._WindowMap.m;
+ GLfloat *m = imesa->hw_viewport;
+
+ 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;
+ /* Depth range is reversed (far: 0, near: 1) so that float depth
+ * compensates for loss of accuracy of far coordinates. */
+ if (imesa->float_depth && imesa->savageScreen->zpp == 2) {
+ /* The Savage 16-bit floating point depth format can't encode
+ * numbers < 2^-16. Make sure all depth values stay greater
+ * than that. */
+ m[MAT_SZ] = - v[MAT_SZ] * imesa->depth_scale * (65535.0/65536.0);
+ m[MAT_TZ] = 1.0 - v[MAT_TZ] * imesa->depth_scale * (65535.0/65536.0);
+ } else {
+ m[MAT_SZ] = - v[MAT_SZ] * imesa->depth_scale;
+ m[MAT_TZ] = 1.0 - 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;
+ imesa->new_state |= SAVAGE_NEW_CULL;
+}
+#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->regs.s4.drawCtrl1.ni.cullMode != cullMode) {
+ imesa->regs.s4.drawCtrl1.ni.cullMode = cullMode;
+ imesa->dirty |= SAVAGE_UPLOAD_GLOBAL;
+ }
+ } else {
+ if (imesa->regs.s3d.drawCtrl.ni.cullMode != cullMode) {
+ imesa->regs.s3d.drawCtrl.ni.cullMode = cullMode;
+ imesa->dirty |= SAVAGE_UPLOAD_LOCAL;
+ }
+ }
+#endif /* end #if HW_CULL */
+}
+
+
+
+/* =============================================================
+ * Color masks
+ */
+
+/* Savage4 can disable draw updates when all channels are
+ * masked. Savage3D has a bit called drawUpdateEn, but it doesn't seem
+ * to have any effect. If only some channels are masked we need a
+ * software fallback on all chips.
+ */
+static void savageDDColorMask_s4(GLcontext *ctx,
+ GLboolean r, GLboolean g,
+ GLboolean b, GLboolean a )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+ GLboolean passAny, passAll;
+
+ if (ctx->Visual.alphaBits) {
+ passAny = b || g || r || a;
+ passAll = r && g && b && a;
+ } else {
+ passAny = b || g || r;
+ passAll = r && g && b;
+ }
+
+ if (passAny) {
+ if (!imesa->regs.s4.drawLocalCtrl.ni.drawUpdateEn) {
+ imesa->regs.s4.drawLocalCtrl.ni.drawUpdateEn = GL_TRUE;
+ imesa->dirty |= SAVAGE_UPLOAD_LOCAL;
+ }
+ FALLBACK (ctx, SAVAGE_FALLBACK_COLORMASK, !passAll);
+ } else if (imesa->regs.s4.drawLocalCtrl.ni.drawUpdateEn) {
+ imesa->regs.s4.drawLocalCtrl.ni.drawUpdateEn = GL_FALSE;
+ imesa->dirty |= SAVAGE_UPLOAD_LOCAL;
+ }
+}
+static void savageDDColorMask_s3d(GLcontext *ctx,
+ GLboolean r, GLboolean g,
+ GLboolean b, GLboolean a )
+{
+ if (ctx->Visual.alphaBits)
+ FALLBACK (ctx, SAVAGE_FALLBACK_COLORMASK, !(r && g && b && a));
+ else
+ FALLBACK (ctx, SAVAGE_FALLBACK_COLORMASK, !(r && g && b));
+}
+
+static void savageUpdateSpecular_s4(GLcontext *ctx) {
+ savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+ u_int32_t drawLocalCtrl = imesa->regs.s4.drawLocalCtrl.ui;
+
+ if (NEED_SECONDARY_COLOR(ctx)) {
+ imesa->regs.s4.drawLocalCtrl.ni.specShadeEn = GL_TRUE;
+ } else {
+ imesa->regs.s4.drawLocalCtrl.ni.specShadeEn = GL_FALSE;
+ }
+
+ if (drawLocalCtrl != imesa->regs.s4.drawLocalCtrl.ui)
+ imesa->dirty |= SAVAGE_UPLOAD_LOCAL;
+}
+
+static void savageUpdateSpecular_s3d(GLcontext *ctx) {
+ savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+ u_int32_t drawCtrl = imesa->regs.s3d.drawCtrl.ui;
+
+ if (NEED_SECONDARY_COLOR(ctx)) {
+ imesa->regs.s3d.drawCtrl.ni.specShadeEn = GL_TRUE;
+ } else {
+ imesa->regs.s3d.drawCtrl.ni.specShadeEn = GL_FALSE;
+ }
+
+ if (drawCtrl != imesa->regs.s3d.drawCtrl.ui)
+ imesa->dirty |= SAVAGE_UPLOAD_LOCAL;
+}
+
+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 );
+ u_int32_t drawLocalCtrl = imesa->regs.s4.drawLocalCtrl.ui;
+
+ if (mod == GL_SMOOTH)
+ {
+ imesa->regs.s4.drawLocalCtrl.ni.flatShadeEn = GL_FALSE;
+ }
+ else
+ {
+ imesa->regs.s4.drawLocalCtrl.ni.flatShadeEn = GL_TRUE;
+ }
+
+ if (drawLocalCtrl != imesa->regs.s4.drawLocalCtrl.ui)
+ imesa->dirty |= SAVAGE_UPLOAD_LOCAL;
+}
+static void savageDDShadeModel_s3d(GLcontext *ctx, GLuint mod)
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+ u_int32_t drawCtrl = imesa->regs.s3d.drawCtrl.ui;
+
+ if (mod == GL_SMOOTH)
+ {
+ imesa->regs.s3d.drawCtrl.ni.flatShadeEn = GL_FALSE;
+ }
+ else
+ {
+ imesa->regs.s3d.drawCtrl.ni.flatShadeEn = GL_TRUE;
+ }
+
+ if (drawCtrl != imesa->regs.s3d.drawCtrl.ui)
+ imesa->dirty |= SAVAGE_UPLOAD_LOCAL;
+}
+
+
+/* =============================================================
+ * Fog
+ * The fogCtrl register has the same position and the same layout
+ * on savage3d and savage4. No need for two separate functions.
+ */
+
+static void savageDDFogfv(GLcontext *ctx, GLenum pname, const GLfloat *param)
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ GLuint fogClr;
+ u_int32_t fogCtrl = imesa->regs.s4.fogCtrl.ui;
+
+ /*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));
+ imesa->regs.s4.fogCtrl.ni.fogEn = GL_TRUE;
+ /*cheap fog*/
+ imesa->regs.s4.fogCtrl.ni.fogMode = GL_TRUE;
+ imesa->regs.s4.fogCtrl.ni.fogClr = fogClr;
+ }
+ else
+ {
+ /*No fog*/
+
+ imesa->regs.s4.fogCtrl.ni.fogEn = 0;
+ imesa->regs.s4.fogCtrl.ni.fogMode = 0;
+ }
+
+ if (fogCtrl != imesa->regs.s4.fogCtrl.ui)
+ imesa->dirty |= SAVAGE_UPLOAD_GLOBAL;
+}
+
+
+static void
+savageDDStencilFuncSeparate(GLcontext *ctx, GLenum face, GLenum func,
+ GLint ref, GLuint mask)
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ unsigned a=0;
+ const u_int32_t zBufCtrl = imesa->regs.s4.zBufCtrl.ui;
+ const u_int32_t stencilCtrl = imesa->regs.s4.stencilCtrl.ui;
+
+ imesa->regs.s4.zBufCtrl.ni.stencilRefVal = ctx->Stencil.Ref[0] & 0xff;
+ imesa->regs.s4.stencilCtrl.ni.readMask = ctx->Stencil.ValueMask[0] & 0xff;
+
+ switch (ctx->Stencil.Function[0])
+ {
+ case GL_NEVER: a = CF_Never; break;
+ case GL_ALWAYS: a = CF_Always; break;
+ case GL_LESS: a = CF_Less; break;
+ case GL_LEQUAL: a = CF_LessEqual; break;
+ case GL_EQUAL: a = CF_Equal; break;
+ case GL_GREATER: a = CF_Greater; break;
+ case GL_GEQUAL: a = CF_GreaterEqual; break;
+ case GL_NOTEQUAL: a = CF_NotEqual; break;
+ default:
+ break;
+ }
+
+ imesa->regs.s4.stencilCtrl.ni.cmpFunc = a;
+
+ if (zBufCtrl != imesa->regs.s4.zBufCtrl.ui ||
+ stencilCtrl != imesa->regs.s4.stencilCtrl.ui)
+ imesa->dirty |= SAVAGE_UPLOAD_GLOBAL;
+}
+
+static void
+savageDDStencilMaskSeparate(GLcontext *ctx, GLenum face, GLuint mask)
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+
+ if (imesa->regs.s4.stencilCtrl.ni.writeMask != (ctx->Stencil.WriteMask[0] & 0xff)) {
+ imesa->regs.s4.stencilCtrl.ni.writeMask = (ctx->Stencil.WriteMask[0] & 0xff);
+ imesa->dirty |= SAVAGE_UPLOAD_GLOBAL;
+ }
+}
+
+static unsigned get_stencil_op_value( GLenum op )
+{
+ switch (op)
+ {
+ case GL_KEEP: return STENCIL_Keep;
+ case GL_ZERO: return STENCIL_Zero;
+ case GL_REPLACE: return STENCIL_Equal;
+ case GL_INCR: return STENCIL_IncClamp;
+ case GL_DECR: return STENCIL_DecClamp;
+ case GL_INVERT: return STENCIL_Invert;
+ case GL_INCR_WRAP: return STENCIL_Inc;
+ case GL_DECR_WRAP: return STENCIL_Dec;
+ }
+
+ /* Should *never* get here. */
+ return STENCIL_Keep;
+}
+
+static void
+savageDDStencilOpSeparate(GLcontext *ctx, GLenum face, GLenum fail,
+ GLenum zfail, GLenum zpass)
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ const u_int32_t stencilCtrl = imesa->regs.s4.stencilCtrl.ui;
+
+ imesa->regs.s4.stencilCtrl.ni.failOp = get_stencil_op_value( ctx->Stencil.FailFunc[0] );
+ imesa->regs.s4.stencilCtrl.ni.passZfailOp = get_stencil_op_value( ctx->Stencil.ZFailFunc[0] );
+ imesa->regs.s4.stencilCtrl.ni.passZpassOp = get_stencil_op_value( ctx->Stencil.ZPassFunc[0] );
+
+ if (stencilCtrl != imesa->regs.s4.stencilCtrl.ui)
+ imesa->dirty |= SAVAGE_UPLOAD_GLOBAL;
+}
+
+
+/* =============================================================
+ */
+
+static void savageDDEnable_s4(GLcontext *ctx, GLenum cap, GLboolean state)
+{
+
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ switch(cap) {
+ case GL_ALPHA_TEST:
+ /* we should consider the disable case*/
+ savageBlendFunc_s4(ctx);
+ break;
+ case GL_BLEND:
+ /*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);
+ case GL_COLOR_LOGIC_OP:
+ /* Fall through:
+ * For some reason enable(GL_BLEND) affects ColorLogicOpEnabled.
+ */
+ FALLBACK (ctx, SAVAGE_FALLBACK_LOGICOP,
+ (ctx->Color.ColorLogicOpEnabled &&
+ ctx->Color.LogicOp != GL_COPY));
+ break;
+ case GL_DEPTH_TEST:
+ savageDDDepthFunc_s4(ctx,ctx->Depth.Func);
+ break;
+ case GL_SCISSOR_TEST:
+ savageDDScissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
+ ctx->Scissor.Width, ctx->Scissor.Height);
+ break;
+ case GL_STENCIL_TEST:
+ if (!imesa->hw_stencil)
+ FALLBACK (ctx, SAVAGE_FALLBACK_STENCIL, state);
+ else {
+ imesa->regs.s4.stencilCtrl.ni.stencilEn = state;
+ if (ctx->Stencil.Enabled &&
+ imesa->regs.s4.zBufCtrl.ni.zBufEn != GL_TRUE)
+ {
+ /* Stencil buffer requires Z enabled. */
+ imesa->regs.s4.zBufCtrl.ni.zCmpFunc = CF_Always;
+ imesa->regs.s4.zBufCtrl.ni.zBufEn = GL_TRUE;
+ imesa->regs.s4.drawLocalCtrl.ni.zUpdateEn = GL_FALSE;
+ }
+ imesa->dirty |= SAVAGE_UPLOAD_GLOBAL | SAVAGE_UPLOAD_LOCAL;
+ }
+ break;
+ case GL_FOG:
+ savageDDFogfv(ctx,0,0);
+ break;
+ case GL_CULL_FACE:
+#if HW_CULL
+ if (state)
+ {
+ savageDDCullFaceFrontFace(ctx,0);
+ }
+ else
+ {
+ imesa->LcsCullMode = BCM_None;
+ imesa->new_state |= SAVAGE_NEW_CULL;
+ }
+#endif
+ break;
+ case GL_DITHER:
+ if (state)
+ {
+ if ( ctx->Color.DitherFlag )
+ {
+ imesa->regs.s4.drawCtrl1.ni.ditherEn=GL_TRUE;
+ }
+ }
+ if (!ctx->Color.DitherFlag )
+ {
+ imesa->regs.s4.drawCtrl1.ni.ditherEn=GL_FALSE;
+ }
+ imesa->dirty |= SAVAGE_UPLOAD_GLOBAL;
+ 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);
+ switch(cap) {
+ case GL_ALPHA_TEST:
+ /* we should consider the disable case*/
+ savageBlendFunc_s3d(ctx);
+ break;
+ case GL_BLEND:
+ /*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);
+ case GL_COLOR_LOGIC_OP:
+ /* Fall through:
+ * For some reason enable(GL_BLEND) affects ColorLogicOpEnabled.
+ */
+ FALLBACK (ctx, SAVAGE_FALLBACK_LOGICOP,
+ (ctx->Color.ColorLogicOpEnabled &&
+ ctx->Color.LogicOp != GL_COPY));
+ break;
+ case GL_DEPTH_TEST:
+ savageDDDepthFunc_s3d(ctx,ctx->Depth.Func);
+ break;
+ case GL_SCISSOR_TEST:
+ savageDDScissor(ctx, ctx->Scissor.X, ctx->Scissor.Y,
+ ctx->Scissor.Width, ctx->Scissor.Height);
+ break;
+ case GL_STENCIL_TEST:
+ FALLBACK (ctx, SAVAGE_FALLBACK_STENCIL, state);
+ break;
+ case GL_FOG:
+ savageDDFogfv(ctx,0,0);
+ break;
+ case GL_CULL_FACE:
+#if HW_CULL
+ if (state)
+ {
+ savageDDCullFaceFrontFace(ctx,0);
+ }
+ else
+ {
+ imesa->LcsCullMode = BCM_None;
+ imesa->new_state |= SAVAGE_NEW_CULL;
+ }
+#endif
+ break;
+ case GL_DITHER:
+ if (state)
+ {
+ if ( ctx->Color.DitherFlag )
+ {
+ imesa->regs.s3d.drawCtrl.ni.ditherEn=GL_TRUE;
+ }
+ }
+ if (!ctx->Color.DitherFlag )
+ {
+ imesa->regs.s3d.drawCtrl.ni.ditherEn=GL_FALSE;
+ }
+ imesa->dirty |= SAVAGE_UPLOAD_LOCAL;
+ 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->new_state) {
+ savageFlushVertices(imesa);
+ if (imesa->new_state & SAVAGE_NEW_TEXTURE) {
+ savageUpdateTextureState( ctx );
+ }
+ if ((imesa->new_state & SAVAGE_NEW_CULL)) {
+ savageUpdateCull(ctx);
+ }
+ imesa->new_state = 0;
+ }
+}
+
+
+static void savageDDPrintDirty( const char *msg, GLuint state )
+{
+ fprintf(stderr, "%s (0x%x): %s%s%s%s%s%s\n",
+ msg,
+ (unsigned int) state,
+ (state & SAVAGE_UPLOAD_LOCAL) ? "upload-local, " : "",
+ (state & SAVAGE_UPLOAD_TEX0) ? "upload-tex0, " : "",
+ (state & SAVAGE_UPLOAD_TEX1) ? "upload-tex1, " : "",
+ (state & SAVAGE_UPLOAD_FOGTBL) ? "upload-fogtbl, " : "",
+ (state & SAVAGE_UPLOAD_GLOBAL) ? "upload-global, " : "",
+ (state & SAVAGE_UPLOAD_TEXGLOBAL) ? "upload-texglobal, " : ""
+ );
+}
+
+
+/**
+ * Check if global registers were changed
+ */
+static GLboolean savageGlobalRegChanged (savageContextPtr imesa,
+ GLuint first, GLuint last) {
+ GLuint i;
+ for (i = first - SAVAGE_FIRST_REG; i <= last - SAVAGE_FIRST_REG; ++i) {
+ if (((imesa->oldRegs.ui[i] ^ imesa->regs.ui[i]) &
+ imesa->globalRegMask.ui[i]) != 0)
+ return GL_TRUE;
+ }
+ return GL_FALSE;
+}
+static void savageEmitOldRegs (savageContextPtr imesa,
+ GLuint first, GLuint last, GLboolean global) {
+ GLuint n = last-first+1;
+ drm_savage_cmd_header_t *cmd = savageAllocCmdBuf(imesa, n*4);
+ cmd->state.cmd = SAVAGE_CMD_STATE;
+ cmd->state.global = global;
+ cmd->state.count = n;
+ cmd->state.start = first;
+ memcpy(cmd+1, &imesa->oldRegs.ui[first-SAVAGE_FIRST_REG], n*4);
+}
+static void savageEmitContiguousRegs (savageContextPtr imesa,
+ GLuint first, GLuint last) {
+ GLuint i;
+ GLuint n = last-first+1;
+ drm_savage_cmd_header_t *cmd = savageAllocCmdBuf(imesa, n*4);
+ cmd->state.cmd = SAVAGE_CMD_STATE;
+ cmd->state.global = savageGlobalRegChanged(imesa, first, last);
+ cmd->state.count = n;
+ cmd->state.start = first;
+ memcpy(cmd+1, &imesa->regs.ui[first-SAVAGE_FIRST_REG], n*4);
+ /* savageAllocCmdBuf may need to flush the cmd buffer and backup
+ * the current hardware state. It should see the "old" (current)
+ * state that has actually been emitted to the hardware. Therefore
+ * this update is done *after* savageAllocCmdBuf. */
+ for (i = first - SAVAGE_FIRST_REG; i <= last - SAVAGE_FIRST_REG; ++i)
+ imesa->oldRegs.ui[i] = imesa->regs.ui[i];
+ if (SAVAGE_DEBUG & DEBUG_STATE)
+ fprintf (stderr, "Emitting regs 0x%02x-0x%02x\n", first, last);
+}
+static void savageEmitChangedRegs (savageContextPtr imesa,
+ GLuint first, GLuint last) {
+ GLuint i, firstChanged;
+ firstChanged = SAVAGE_NR_REGS;
+ for (i = first - SAVAGE_FIRST_REG; i <= last - SAVAGE_FIRST_REG; ++i) {
+ if (imesa->oldRegs.ui[i] != imesa->regs.ui[i]) {
+ if (firstChanged == SAVAGE_NR_REGS)
+ firstChanged = i;
+ } else {
+ if (firstChanged != SAVAGE_NR_REGS) {
+ savageEmitContiguousRegs (imesa, firstChanged+SAVAGE_FIRST_REG,
+ i-1+SAVAGE_FIRST_REG);
+ firstChanged = SAVAGE_NR_REGS;
+ }
+ }
+ }
+ if (firstChanged != SAVAGE_NR_REGS)
+ savageEmitContiguousRegs (imesa, firstChanged+SAVAGE_FIRST_REG,
+ last);
+}
+static void savageEmitChangedRegChunk (savageContextPtr imesa,
+ GLuint first, GLuint last) {
+ GLuint i;
+ for (i = first - SAVAGE_FIRST_REG; i <= last - SAVAGE_FIRST_REG; ++i) {
+ if (imesa->oldRegs.ui[i] != imesa->regs.ui[i]) {
+ savageEmitContiguousRegs (imesa, first, last);
+ break;
+ }
+ }
+}
+static void savageUpdateRegister_s4(savageContextPtr imesa)
+{
+ /* In case the texture image was changed without changing the
+ * texture address as well, we need to force emitting the texture
+ * address in order to flush texture cashes. */
+ if ((imesa->dirty & SAVAGE_UPLOAD_TEX0) &&
+ imesa->oldRegs.s4.texAddr[0].ui == imesa->regs.s4.texAddr[0].ui)
+ imesa->oldRegs.s4.texAddr[0].ui = 0xffffffff;
+ if ((imesa->dirty & SAVAGE_UPLOAD_TEX1) &&
+ imesa->oldRegs.s4.texAddr[1].ui == imesa->regs.s4.texAddr[1].ui)
+ imesa->oldRegs.s4.texAddr[1].ui = 0xffffffff;
+
+ /* Fix up watermarks */
+ if (imesa->regs.s4.drawLocalCtrl.ni.flushPdDestWrites) {
+ imesa->regs.s4.destTexWatermarks.ni.destWriteLow = 0;
+ imesa->regs.s4.destTexWatermarks.ni.destFlush = 1;
+ } else
+ imesa->regs.s4.destTexWatermarks.ni.destWriteLow = S4_DWLO;
+ if (imesa->regs.s4.drawLocalCtrl.ni.flushPdZbufWrites)
+ imesa->regs.s4.zWatermarks.ni.wLow = 0;
+ else
+ imesa->regs.s4.zWatermarks.ni.wLow = S4_ZWLO;
+
+ savageEmitChangedRegs (imesa, 0x1e, 0x39);
+
+ imesa->dirty=0;
+}
+static void savageUpdateRegister_s3d(savageContextPtr imesa)
+{
+ /* In case the texture image was changed without changing the
+ * texture address as well, we need to force emitting the texture
+ * address in order to flush texture cashes. */
+ if ((imesa->dirty & SAVAGE_UPLOAD_TEX0) &&
+ imesa->oldRegs.s3d.texAddr.ui == imesa->regs.s3d.texAddr.ui)
+ imesa->oldRegs.s3d.texAddr.ui = 0xffffffff;
+
+ /* Fix up watermarks */
+ if (imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites) {
+ imesa->regs.s3d.destTexWatermarks.ni.destWriteLow = 0;
+ imesa->regs.s3d.destTexWatermarks.ni.destFlush = 1;
+ } else
+ imesa->regs.s3d.destTexWatermarks.ni.destWriteLow = S3D_DWLO;
+ if (imesa->regs.s3d.drawCtrl.ni.flushPdZbufWrites)
+ imesa->regs.s3d.zWatermarks.ni.wLow = 0;
+ else
+ imesa->regs.s3d.zWatermarks.ni.wLow = S3D_ZWLO;
+
+
+ /* the savage3d uses two contiguous ranges of BCI registers:
+ * 0x18-0x1c and 0x20-0x38. Some texture registers need to be
+ * emitted in one chunk or we get some funky rendering errors. */
+ savageEmitChangedRegs (imesa, 0x18, 0x19);
+ savageEmitChangedRegChunk (imesa, 0x1a, 0x1c);
+ savageEmitChangedRegs (imesa, 0x20, 0x38);
+
+ imesa->dirty=0;
+}
+
+
+void savageEmitOldState( savageContextPtr imesa )
+{
+ assert(imesa->cmdBuf.write == imesa->cmdBuf.base);
+ if (imesa->savageScreen->chipset >= S3_SAVAGE4) {
+ savageEmitOldRegs (imesa, 0x1e, 0x39, GL_TRUE);
+ } else {
+ savageEmitOldRegs (imesa, 0x18, 0x1c, GL_TRUE);
+ savageEmitOldRegs (imesa, 0x20, 0x38, GL_FALSE);
+ }
+}
+
+
+/* Push the state into the sarea and/or texture memory.
+ */
+void savageEmitChangedState( savageContextPtr imesa )
+{
+ if (SAVAGE_DEBUG & DEBUG_VERBOSE_API)
+ savageDDPrintDirty( "\n\n\nsavageEmitHwStateLocked", imesa->dirty );
+
+ if (imesa->dirty)
+ {
+ if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
+ fprintf (stderr, "... emitting state\n");
+ if (imesa->savageScreen->chipset >= S3_SAVAGE4)
+ savageUpdateRegister_s4(imesa);
+ else
+ savageUpdateRegister_s3d(imesa);
+ }
+
+ imesa->dirty = 0;
+}
+
+
+static void savageDDInitState_s4( savageContextPtr imesa )
+{
+#if 1
+ imesa->regs.s4.destCtrl.ui = 1<<7;
+#endif
+
+ imesa->regs.s4.zBufCtrl.ni.zCmpFunc = CF_Less;
+ imesa->regs.s4.zBufCtrl.ni.wToZEn = GL_TRUE;
+ if (imesa->float_depth) {
+ imesa->regs.s4.zBufCtrl.ni.zExpOffset =
+ imesa->savageScreen->zpp == 2 ? 16 : 32;
+ imesa->regs.s4.zBufCtrl.ni.floatZEn = GL_TRUE;
+ } else {
+ imesa->regs.s4.zBufCtrl.ni.zExpOffset = 0;
+ imesa->regs.s4.zBufCtrl.ni.floatZEn = GL_FALSE;
+ }
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_NoTexMap;
+ imesa->regs.s4.texBlendCtrl[1].ui = TBC_NoTexMap1;
+ imesa->regs.s4.drawCtrl0.ui = 0;
+#if 0
+ imesa->regs.s4.drawCtrl1.ni.xyOffsetEn = 1;
+#endif
+
+ /* Set DestTexWatermarks_31,30 to 01 always.
+ *Has no effect if dest. flush is disabled.
+ */
+#if 0
+ imesa->regs.s4.zWatermarks.ui = 0x12000C04;
+ imesa->regs.s4.destTexWatermarks.ui = 0x40200400;
+#else
+ /*imesa->regs.s4.zWatermarks.ui = 0x16001808;*/
+ imesa->regs.s4.zWatermarks.ni.rLow = S4_ZRLO;
+ imesa->regs.s4.zWatermarks.ni.rHigh = S4_ZRHI;
+ imesa->regs.s4.zWatermarks.ni.wLow = S4_ZWLO;
+ imesa->regs.s4.zWatermarks.ni.wHigh = S4_ZWHI;
+ /*imesa->regs.s4.destTexWatermarks.ui = 0x4f000000;*/
+ imesa->regs.s4.destTexWatermarks.ni.destReadLow = S4_DRLO;
+ imesa->regs.s4.destTexWatermarks.ni.destReadHigh = S4_DRHI;
+ imesa->regs.s4.destTexWatermarks.ni.destWriteLow = S4_DWLO;
+ imesa->regs.s4.destTexWatermarks.ni.destWriteHigh = S4_DWHI;
+ imesa->regs.s4.destTexWatermarks.ni.texRead = S4_TR;
+ imesa->regs.s4.destTexWatermarks.ni.destFlush = 1;
+#endif
+ imesa->regs.s4.drawCtrl0.ni.dPerfAccelEn = GL_TRUE;
+
+ /* clrCmpAlphaBlendCtrl is needed to get alphatest and
+ * alpha blending working properly
+ */
+
+ imesa->regs.s4.texCtrl[0].ni.dBias = 0x08;
+ imesa->regs.s4.texCtrl[1].ni.dBias = 0x08;
+ imesa->regs.s4.texCtrl[0].ni.texXprEn = GL_TRUE;
+ imesa->regs.s4.texCtrl[1].ni.texXprEn = GL_TRUE;
+ imesa->regs.s4.texCtrl[0].ni.dMax = 0x0f;
+ imesa->regs.s4.texCtrl[1].ni.dMax = 0x0f;
+ /* programm a valid tex address, in case texture state is emitted
+ * in wrong order. */
+ if (imesa->lastTexHeap == 2 && imesa->savageScreen->textureSize[1]) {
+ /* AGP textures available */
+ imesa->regs.s4.texAddr[0].ui = imesa->savageScreen->textureOffset[1]|3;
+ imesa->regs.s4.texAddr[1].ui = imesa->savageScreen->textureOffset[1]|3;
+ } else {
+ /* no AGP textures available, use local */
+ imesa->regs.s4.texAddr[0].ui = imesa->savageScreen->textureOffset[0]|2;
+ imesa->regs.s4.texAddr[1].ui = imesa->savageScreen->textureOffset[0]|2;
+ }
+ imesa->regs.s4.drawLocalCtrl.ni.drawUpdateEn = GL_TRUE;
+ imesa->regs.s4.drawLocalCtrl.ni.srcAlphaMode = SAM_One;
+ imesa->regs.s4.drawLocalCtrl.ni.wrZafterAlphaTst = GL_FALSE;
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdZbufWrites= GL_TRUE;
+ imesa->regs.s4.drawLocalCtrl.ni.flushPdDestWrites= GL_TRUE;
+
+ imesa->regs.s4.drawLocalCtrl.ni.zUpdateEn= GL_TRUE;
+ imesa->regs.s4.drawCtrl1.ni.ditherEn = (
+ driQueryOptioni(&imesa->optionCache, "color_reduction") ==
+ DRI_CONF_COLOR_REDUCTION_DITHER) ? GL_TRUE : GL_FALSE;
+ imesa->regs.s4.drawCtrl1.ni.cullMode = BCM_None;
+
+ imesa->regs.s4.zBufCtrl.ni.stencilRefVal = 0x00;
+
+ imesa->regs.s4.stencilCtrl.ni.stencilEn = GL_FALSE;
+ imesa->regs.s4.stencilCtrl.ni.cmpFunc = CF_Always;
+ imesa->regs.s4.stencilCtrl.ni.failOp = STENCIL_Keep;
+ imesa->regs.s4.stencilCtrl.ni.passZfailOp = STENCIL_Keep;
+ imesa->regs.s4.stencilCtrl.ni.passZpassOp = STENCIL_Keep;
+ imesa->regs.s4.stencilCtrl.ni.writeMask = 0xff;
+ imesa->regs.s4.stencilCtrl.ni.readMask = 0xff;
+
+ imesa->LcsCullMode=BCM_None;
+ imesa->regs.s4.texDescr.ni.palSize = TPS_256;
+
+ /* clear the local registers in the global reg mask */
+ imesa->globalRegMask.s4.drawLocalCtrl.ui = 0;
+ imesa->globalRegMask.s4.texPalAddr.ui = 0;
+ imesa->globalRegMask.s4.texCtrl[0].ui = 0;
+ imesa->globalRegMask.s4.texCtrl[1].ui = 0;
+ imesa->globalRegMask.s4.texAddr[0].ui = 0;
+ imesa->globalRegMask.s4.texAddr[1].ui = 0;
+ imesa->globalRegMask.s4.texBlendCtrl[0].ui = 0;
+ imesa->globalRegMask.s4.texBlendCtrl[1].ui = 0;
+ imesa->globalRegMask.s4.texXprClr.ui = 0;
+ imesa->globalRegMask.s4.texDescr.ui = 0;
+}
+static void savageDDInitState_s3d( savageContextPtr imesa )
+{
+#if 1
+ imesa->regs.s3d.destCtrl.ui = 1<<7;
+#endif
+
+ imesa->regs.s3d.zBufCtrl.ni.zCmpFunc = CF_Less;
+#if 0
+ imesa->regs.s3d.drawCtrl.ni.xyOffsetEn = 1;
+#endif
+
+ /* Set DestTexWatermarks_31,30 to 01 always.
+ *Has no effect if dest. flush is disabled.
+ */
+#if 0
+ imesa->regs.s3d.zWatermarks.ui = 0x12000C04;
+ imesa->regs.s3d.destTexWatermarks.ui = 0x40200400;
+#else
+ /*imesa->regs.s3d.zWatermarks.ui = 0x16001808;*/
+ imesa->regs.s3d.zWatermarks.ni.rLow = S3D_ZRLO;
+ imesa->regs.s3d.zWatermarks.ni.rHigh = S3D_ZRHI;
+ imesa->regs.s3d.zWatermarks.ni.wLow = S3D_ZWLO;
+ imesa->regs.s3d.zWatermarks.ni.wHigh = S3D_ZWHI;
+ /*imesa->regs.s3d.destTexWatermarks.ui = 0x4f000000;*/
+ imesa->regs.s3d.destTexWatermarks.ni.destReadLow = S3D_DRLO;
+ imesa->regs.s3d.destTexWatermarks.ni.destReadHigh = S3D_DRHI;
+ imesa->regs.s3d.destTexWatermarks.ni.destWriteLow = S3D_DWLO;
+ imesa->regs.s3d.destTexWatermarks.ni.destWriteHigh = S3D_DWHI;
+ imesa->regs.s3d.destTexWatermarks.ni.texRead = S3D_TR;
+ imesa->regs.s3d.destTexWatermarks.ni.destFlush = 1;
+#endif
+
+ imesa->regs.s3d.texCtrl.ni.dBias = 0x08;
+ imesa->regs.s3d.texCtrl.ni.texXprEn = GL_TRUE;
+ /* texXprEn is needed to get alphatest and alpha blending working
+ * properly. However, this makes texels with color texXprClr
+ * completely transparent in some texture environment modes. I
+ * couldn't find a way to disable this. So choose an arbitrary and
+ * improbable color. (0 is a bad choice, makes all black texels
+ * transparent.) */
+ imesa->regs.s3d.texXprClr.ui = 0x26ae26ae;
+ /* programm a valid tex address, in case texture state is emitted
+ * in wrong order. */
+ if (imesa->lastTexHeap == 2 && imesa->savageScreen->textureSize[1]) {
+ /* AGP textures available */
+ imesa->regs.s3d.texAddr.ui = imesa->savageScreen->textureOffset[1]|3;
+ } else {
+ /* no AGP textures available, use local */
+ imesa->regs.s3d.texAddr.ui = imesa->savageScreen->textureOffset[0]|2;
+ }
+
+ imesa->regs.s3d.zBufCtrl.ni.drawUpdateEn = GL_TRUE;
+ imesa->regs.s3d.zBufCtrl.ni.wrZafterAlphaTst = GL_FALSE;
+ imesa->regs.s3d.zBufCtrl.ni.zUpdateEn = GL_TRUE;
+
+ imesa->regs.s3d.drawCtrl.ni.srcAlphaMode = SAM_One;
+ imesa->regs.s3d.drawCtrl.ni.flushPdZbufWrites = GL_TRUE;
+ imesa->regs.s3d.drawCtrl.ni.flushPdDestWrites = GL_TRUE;
+
+ imesa->regs.s3d.drawCtrl.ni.ditherEn = (
+ driQueryOptioni(&imesa->optionCache, "color_reduction") ==
+ DRI_CONF_COLOR_REDUCTION_DITHER) ? GL_TRUE : GL_FALSE;
+ imesa->regs.s3d.drawCtrl.ni.cullMode = BCM_None;
+
+ imesa->LcsCullMode = BCM_None;
+ imesa->regs.s3d.texDescr.ni.palSize = TPS_256;
+
+ /* clear the local registers in the global reg mask */
+ imesa->globalRegMask.s3d.texPalAddr.ui = 0;
+ imesa->globalRegMask.s3d.texXprClr.ui = 0;
+ imesa->globalRegMask.s3d.texAddr.ui = 0;
+ imesa->globalRegMask.s3d.texDescr.ui = 0;
+ imesa->globalRegMask.s3d.texCtrl.ui = 0;
+
+ imesa->globalRegMask.s3d.fogCtrl.ui = 0;
+
+ /* drawCtrl is local with some exceptions */
+ imesa->globalRegMask.s3d.drawCtrl.ui = 0;
+ imesa->globalRegMask.s3d.drawCtrl.ni.cullMode = 0x3;
+ imesa->globalRegMask.s3d.drawCtrl.ni.alphaTestCmpFunc = 0x7;
+ imesa->globalRegMask.s3d.drawCtrl.ni.alphaTestEn = 0x1;
+ imesa->globalRegMask.s3d.drawCtrl.ni.alphaRefVal = 0xff;
+
+ /* zBufCtrl is local with some exceptions */
+ imesa->globalRegMask.s3d.zBufCtrl.ui = 0;
+ imesa->globalRegMask.s3d.zBufCtrl.ni.zCmpFunc = 0x7;
+ imesa->globalRegMask.s3d.zBufCtrl.ni.zBufEn = 0x1;
+}
+void savageDDInitState( savageContextPtr imesa ) {
+ memset (imesa->regs.ui, 0, SAVAGE_NR_REGS*sizeof(u_int32_t));
+ memset (imesa->globalRegMask.ui, 0xff, SAVAGE_NR_REGS*sizeof(u_int32_t));
+ if (imesa->savageScreen->chipset >= S3_SAVAGE4)
+ savageDDInitState_s4 (imesa);
+ else
+ savageDDInitState_s3d (imesa);
+
+ /*fprintf(stderr,"DBflag:%d\n",imesa->glCtx->Visual->DBflag);*/
+ /* zbufoffset and destctrl have the same position and layout on
+ * savage4 and savage3d. */
+ if (imesa->glCtx->Visual.doubleBufferMode) {
+ imesa->IsDouble = GL_TRUE;
+ imesa->toggle = TARGET_BACK;
+ imesa->regs.s4.destCtrl.ni.offset =
+ imesa->savageScreen->backOffset>>11;
+ } else {
+ imesa->IsDouble = GL_FALSE;
+ imesa->toggle = TARGET_FRONT;
+ imesa->regs.s4.destCtrl.ni.offset =
+ imesa->savageScreen->frontOffset>>11;
+ }
+ if(imesa->savageScreen->cpp == 2) {
+ imesa->regs.s4.destCtrl.ni.dstPixFmt = 0;
+ imesa->regs.s4.destCtrl.ni.dstWidthInTile =
+ (imesa->savageScreen->width+63)>>6;
+ } else {
+ imesa->regs.s4.destCtrl.ni.dstPixFmt = 1;
+ imesa->regs.s4.destCtrl.ni.dstWidthInTile =
+ (imesa->savageScreen->width+31)>>5;
+ }
+ imesa->NotFirstFrame = GL_FALSE;
+
+ imesa->regs.s4.zBufOffset.ni.offset=imesa->savageScreen->depthOffset>>11;
+ if(imesa->savageScreen->zpp == 2) {
+ imesa->regs.s4.zBufOffset.ni.zBufWidthInTiles =
+ (imesa->savageScreen->width+63)>>6;
+ imesa->regs.s4.zBufOffset.ni.zDepthSelect = 0;
+ } else {
+ imesa->regs.s4.zBufOffset.ni.zBufWidthInTiles =
+ (imesa->savageScreen->width+31)>>5;
+ imesa->regs.s4.zBufOffset.ni.zDepthSelect = 1;
+ }
+
+ memcpy (imesa->oldRegs.ui, imesa->regs.ui, SAVAGE_NR_REGS*sizeof(u_int32_t));
+
+ /* Emit the initial state to the (empty) command buffer. */
+ assert (imesa->cmdBuf.write == imesa->cmdBuf.base);
+ savageEmitOldState(imesa);
+ imesa->cmdBuf.start = imesa->cmdBuf.write;
+}
+
+
+#define INTERESTED (~(NEW_MODELVIEW|NEW_PROJECTION|\
+ NEW_TEXTURE_MATRIX|\
+ NEW_USER_CLIP|NEW_CLIENT_STATE))
+
+static void savageDDInvalidateState( GLcontext *ctx, GLuint new_state )
+{
+ _swrast_InvalidateState( ctx, new_state );
+ _swsetup_InvalidateState( ctx, new_state );
+ _vbo_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.DrawBuffer = savageDDDrawBuffer;
+ ctx->Driver.ReadBuffer = savageDDReadBuffer;
+ ctx->Driver.ClearColor = savageDDClearColor;
+
+ ctx->Driver.DepthRange = savageDepthRange;
+ ctx->Driver.Viewport = savageViewport;
+ ctx->Driver.RenderMode = savageRenderMode;
+
+ 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;
+ ctx->Driver.StencilFuncSeparate = savageDDStencilFuncSeparate;
+ ctx->Driver.StencilMaskSeparate = savageDDStencilMaskSeparate;
+ ctx->Driver.StencilOpSeparate = savageDDStencilOpSeparate;
+ } 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.StencilFuncSeparate = NULL;
+ ctx->Driver.StencilMaskSeparate = NULL;
+ ctx->Driver.StencilOpSeparate = NULL;
+ }
+}
diff --git a/src/savagestate.h b/src/savagestate.h
new file mode 100644
index 0000000..5fe718d
--- /dev/null
+++ b/src/savagestate.h
@@ -0,0 +1,41 @@
+/*
+ * 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"
+
+void savageCalcViewport( GLcontext *ctx );
+void savageEmitOldState( savageContextPtr imesa );
+void savageEmitChangedState( savageContextPtr imesa );
+
+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);
+
+#endif
diff --git a/src/savagetex.c b/src/savagetex.c
new file mode 100644
index 0000000..719e50f
--- /dev/null
+++ b/src/savagetex.c
@@ -0,0 +1,2100 @@
+/*
+ * 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 "convolve.h"
+#include "colormac.h"
+
+#include "swrast/swrast.h"
+
+#include "xmlpool.h"
+
+#define TILE_INDEX_DXT1 0
+#define TILE_INDEX_8 1
+#define TILE_INDEX_16 2
+#define TILE_INDEX_DXTn 3
+#define TILE_INDEX_32 4
+
+/* On Savage4 the texure LOD-bias needs an offset of ~ 0.3 to get
+ * somewhere close to software rendering.
+ */
+#define SAVAGE4_LOD_OFFSET 10
+
+/* Tile info for S3TC formats counts in 4x4 blocks instead of texels.
+ * In DXT1 each block is encoded in 64 bits. In DXT3 and 5 each block is
+ * encoded in 128 bits. */
+
+/* Size 1, 2 and 4 images are packed into the last subtile. Each image
+ * is repeated to fill a 4x4 pixel area. The figure below shows the
+ * layout of those 4x4 pixel areas in the 8x8 subtile.
+ *
+ * 4 2
+ * x 1
+ *
+ * Yuck! 8-bit texture formats use 4x8 subtiles. See below.
+ */
+static const savageTileInfo tileInfo_pro[5] = {
+ {16, 16, 16, 8, 1, 2, {0x18, 0x10}}, /* DXT1 */
+ {64, 32, 16, 4, 4, 8, {0x30, 0x20}}, /* 8-bit */
+ {64, 16, 8, 2, 8, 8, {0x48, 0x08}}, /* 16-bit */
+ {16, 8, 16, 4, 1, 2, {0x30, 0x20}}, /* DXT3, DXT5 */
+ {32, 16, 4, 2, 8, 8, {0x90, 0x10}}, /* 32-bit */
+};
+
+/* Size 1, 2 and 4 images are packed into the last two subtiles. Each
+ * image is repeated to fill a 4x4 pixel area. The figures below show
+ * the layout of those 4x4 pixel areas in the two 4x8 subtiles.
+ *
+ * second last subtile: 4 last subtile: 2
+ * x 1
+ */
+static const savageTileInfo tileInfo_s3d_s4[5] = {
+ {16, 16, 16, 8, 1, 2, {0x18, 0x10}}, /* DXT1 */
+ {64, 32, 16, 4, 4, 8, {0x30, 0x20}}, /* 8-bit */
+ {64, 16, 16, 2, 4, 8, {0x60, 0x40}}, /* 16-bit */
+ {16, 8, 16, 4, 1, 2, {0x30, 0x20}}, /* DXT3, DXT5 */
+ {32, 16, 8, 2, 4, 8, {0xc0, 0x80}}, /* 32-bit */
+};
+
+/** \brief Template for subtile uploads.
+ * \param h height in pixels
+ * \param w width in bytes
+ */
+#define SUBTILE_FUNC(w,h) \
+static __inline GLubyte *savageUploadSubtile_##w##x##h \
+(GLubyte *dest, GLubyte *src, GLuint srcStride) \
+{ \
+ GLuint y; \
+ for (y = 0; y < h; ++y) { \
+ memcpy (dest, src, w); \
+ src += srcStride; \
+ dest += w; \
+ } \
+ return dest; \
+}
+
+SUBTILE_FUNC(2, 8) /* 4 bits per pixel, 4 pixels wide */
+SUBTILE_FUNC(4, 8)
+SUBTILE_FUNC(8, 8)
+SUBTILE_FUNC(16, 8)
+SUBTILE_FUNC(32, 8) /* 4 bytes per pixel, 8 pixels wide */
+
+SUBTILE_FUNC(8, 2) /* DXT1 */
+SUBTILE_FUNC(16, 2) /* DXT3 and DXT5 */
+
+/** \brief Upload a complete tile from src (srcStride) to dest
+ *
+ * \param tileInfo Pointer to tiling information
+ * \param wInSub Width of source/dest image in subtiles
+ * \param hInSub Height of source/dest image in subtiles
+ * \param bpp Bytes per pixel
+ * \param src Pointer to source data
+ * \param srcStride Byte stride of rows in the source data
+ * \param dest Pointer to destination
+ *
+ * Writes linearly to the destination memory in order to exploit write
+ * combining.
+ *
+ * For a complete tile wInSub and hInSub are set to the same values as
+ * in tileInfo. If the source image is smaller than a whole tile in
+ * one or both dimensions then they are set to the values of the
+ * source image. This only works as long as the source image is bigger
+ * than 8x8 pixels.
+ */
+static void savageUploadTile (const savageTileInfo *tileInfo,
+ GLuint wInSub, GLuint hInSub, GLuint bpp,
+ GLubyte *src, GLuint srcStride, GLubyte *dest) {
+ GLuint subStride = tileInfo->subWidth * bpp;
+ GLubyte *srcSRow = src, *srcSTile = src;
+ GLubyte *(*subtileFunc) (GLubyte *, GLubyte *, GLuint);
+ GLuint sx, sy;
+ switch (subStride) {
+ case 2: subtileFunc = savageUploadSubtile_2x8; break;
+ case 4: subtileFunc = savageUploadSubtile_4x8; break;
+ case 8: subtileFunc = tileInfo->subHeight == 8 ?
+ savageUploadSubtile_8x8 : savageUploadSubtile_8x2; break;
+ case 16: subtileFunc = tileInfo->subHeight == 8 ?
+ savageUploadSubtile_16x8 : savageUploadSubtile_16x2; break;
+ case 32: subtileFunc = savageUploadSubtile_32x8; break;
+ default: assert(0);
+ }
+ for (sy = 0; sy < hInSub; ++sy) {
+ srcSTile = srcSRow;
+ for (sx = 0; sx < wInSub; ++sx) {
+ src = srcSTile;
+ dest = subtileFunc (dest, src, srcStride);
+ srcSTile += subStride;
+ }
+ srcSRow += srcStride * tileInfo->subHeight;
+ }
+}
+
+/** \brief Upload a image that is smaller than 8 pixels in either dimension.
+ *
+ * \param tileInfo Pointer to tiling information
+ * \param width Width of the image
+ * \param height Height of the image
+ * \param bpp Bytes per pixel
+ * \param src Pointer to source data
+ * \param dest Pointer to destination
+ *
+ * This function handles all the special cases that need to be taken
+ * care off. The caller may need to call this function multiple times
+ * with the destination offset in different ways since small texture
+ * images must be repeated in order to fill a whole tile (or 4x4 for
+ * the last 3 levels).
+ *
+ * FIXME: Repeating inside this function would be more efficient.
+ */
+static void savageUploadTiny (const savageTileInfo *tileInfo,
+ GLuint pixWidth, GLuint pixHeight,
+ GLuint width, GLuint height, GLuint bpp,
+ GLubyte *src, GLubyte *dest) {
+ GLuint size = MAX2(pixWidth, pixHeight);
+
+ if (width > tileInfo->subWidth) { /* assert: height <= subtile height */
+ GLuint wInSub = width / tileInfo->subWidth;
+ GLuint srcStride = width * bpp;
+ GLuint subStride = tileInfo->subWidth * bpp;
+ GLuint subSkip = (tileInfo->subHeight - height) * subStride;
+ GLubyte *srcSTile = src;
+ GLuint sx, y;
+ for (sx = 0; sx < wInSub; ++sx) {
+ src = srcSTile;
+ for (y = 0; y < height; ++y) {
+ memcpy (dest, src, subStride);
+ src += srcStride;
+ dest += subStride;
+ }
+ dest += subSkip;
+ srcSTile += subStride;
+ }
+ } else if (size > 4) { /* a tile or less wide, except the last 3 levels */
+ GLuint srcStride = width * bpp;
+ GLuint subStride = tileInfo->subWidth * bpp;
+ /* if the subtile width is 4 we have to skip every other subtile */
+ GLuint subSkip = tileInfo->subWidth <= 4 ?
+ subStride * tileInfo->subHeight : 0;
+ GLuint skipRemainder = tileInfo->subHeight - 1;
+ GLuint y;
+ for (y = 0; y < height; ++y) {
+ memcpy (dest, src, srcStride);
+ src += srcStride;
+ dest += subStride;
+ if ((y & skipRemainder) == skipRemainder)
+ dest += subSkip;
+ }
+ } else { /* the last 3 mipmap levels */
+ GLuint offset = (size <= 2 ? tileInfo->tinyOffset[size-1] : 0);
+ GLuint subStride = tileInfo->subWidth * bpp;
+ GLuint y;
+ dest += offset;
+ for (y = 0; y < height; ++y) {
+ memcpy (dest, src, bpp*width);
+ src += width * bpp;
+ dest += subStride;
+ }
+ }
+}
+
+/** \brief Upload an image from mesa's internal copy.
+ */
+static void savageUploadTexLevel( savageTexObjPtr t, int level )
+{
+ const struct gl_texture_image *image = t->base.tObj->Image[0][level];
+ const savageTileInfo *tileInfo = t->tileInfo;
+ GLuint pixWidth = image->Width2, pixHeight = image->Height2;
+ GLuint bpp = t->texelBytes;
+ GLuint width, height;
+
+ /* FIXME: 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);
+
+ if (t->hwFormat == TFT_S3TC4A4Bit || t->hwFormat == TFT_S3TC4CA4Bit ||
+ t->hwFormat == TFT_S3TC4Bit) {
+ width = (pixWidth+3) / 4;
+ height = (pixHeight+3) / 4;
+ } else {
+ width = pixWidth;
+ height = pixHeight;
+ }
+
+ if (pixWidth >= 8 && pixHeight >= 8) {
+ GLuint *dirtyPtr = t->image[level].dirtyTiles;
+ GLuint dirtyMask = 1;
+
+ if (width >= tileInfo->width && height >= tileInfo->height) {
+ GLuint wInTiles = width / tileInfo->width;
+ GLuint hInTiles = height / tileInfo->height;
+ GLubyte *srcTRow = image->Data, *src;
+ GLubyte *dest = (GLubyte *)(t->bufAddr + t->image[level].offset);
+ GLuint x, y;
+ for (y = 0; y < hInTiles; ++y) {
+ src = srcTRow;
+ for (x = 0; x < wInTiles; ++x) {
+ if (*dirtyPtr & dirtyMask) {
+ savageUploadTile (tileInfo,
+ tileInfo->wInSub, tileInfo->hInSub,
+ bpp, src, width * bpp, dest);
+ }
+ src += tileInfo->width * bpp;
+ dest += 2048; /* tile size is always 2k */
+ if (dirtyMask == 1<<31) {
+ dirtyMask = 1;
+ dirtyPtr++;
+ } else
+ dirtyMask <<= 1;
+ }
+ srcTRow += width * tileInfo->height * bpp;
+ }
+ } else if (width >= tileInfo->width) {
+ GLuint wInTiles = width / tileInfo->width;
+ GLubyte *src = image->Data;
+ GLubyte *dest = (GLubyte *)(t->bufAddr + t->image[level].offset);
+ GLuint tileStride = tileInfo->width * bpp * height;
+ savageContextPtr imesa = (savageContextPtr)t->base.heap->driverContext;
+ GLuint x;
+ /* Savage3D-based chips seem so use a constant tile stride
+ * of 2048 for vertically incomplete tiles, but only if
+ * the color depth is 32bpp. Nobody said this was supposed
+ * to be logical!
+ */
+ if (bpp == 4 && imesa->savageScreen->chipset < S3_SAVAGE4)
+ tileStride = 2048;
+ for (x = 0; x < wInTiles; ++x) {
+ if (*dirtyPtr & dirtyMask) {
+ savageUploadTile (tileInfo,
+ tileInfo->wInSub,
+ height / tileInfo->subHeight,
+ bpp, src, width * bpp, dest);
+ }
+ src += tileInfo->width * bpp;
+ dest += tileStride;
+ if (dirtyMask == 1<<31) {
+ dirtyMask = 1;
+ dirtyPtr++;
+ } else
+ dirtyMask <<= 1;
+ }
+ } else {
+ savageUploadTile (tileInfo, width / tileInfo->subWidth,
+ height / tileInfo->subHeight, bpp,
+ image->Data, width * bpp,
+ (GLubyte *)(t->bufAddr+t->image[level].offset));
+ }
+ } else {
+ GLuint minHeight, minWidth, hRepeat, vRepeat, x, y;
+ if (t->hwFormat == TFT_S3TC4A4Bit || t->hwFormat == TFT_S3TC4CA4Bit ||
+ t->hwFormat == TFT_S3TC4Bit)
+ minWidth = minHeight = 1;
+ else
+ minWidth = minHeight = 4;
+ if (width > minWidth || height > minHeight) {
+ minWidth = tileInfo->subWidth;
+ minHeight = tileInfo->subHeight;
+ }
+ hRepeat = width >= minWidth ? 1 : minWidth / width;
+ vRepeat = height >= minHeight ? 1 : minHeight / height;
+ for (y = 0; y < vRepeat; ++y) {
+ GLuint offset = y * tileInfo->subWidth*height * bpp;
+ for (x = 0; x < hRepeat; ++x) {
+ savageUploadTiny (tileInfo, pixWidth, pixHeight,
+ width, height, bpp, image->Data,
+ (GLubyte *)(t->bufAddr +
+ t->image[level].offset+offset));
+ offset += width * bpp;
+ }
+ }
+ }
+}
+
+/** \brief Compute the destination size of a texture image
+ */
+static GLuint savageTexImageSize (GLuint width, GLuint height, GLuint bpp) {
+ /* full subtiles */
+ if (width >= 8 && height >= 8)
+ return width * height * bpp;
+ /* special case for the last three mipmap levels: the hardware computes
+ * the offset internally */
+ else if (width <= 4 && height <= 4)
+ return 0;
+ /* partially filled sub tiles waste memory
+ * on Savage3D and Savage4 with subtile width 4 every other subtile is
+ * skipped if width < 8 so we can assume a uniform subtile width of 8 */
+ else if (width >= 8)
+ return width * 8 * bpp;
+ else if (height >= 8)
+ return 8 * height * bpp;
+ else
+ return 64 * bpp;
+}
+
+/** \brief Compute the destination size of a compressed texture image
+ */
+static GLuint savageCompressedTexImageSize (GLuint width, GLuint height,
+ GLuint bpp) {
+ width = (width+3) / 4;
+ height = (height+3) / 4;
+ /* full subtiles */
+ if (width >= 2 && height >= 2)
+ return width * height * bpp;
+ /* special case for the last three mipmap levels: the hardware computes
+ * the offset internally */
+ else if (width <= 1 && height <= 1)
+ return 0;
+ /* partially filled sub tiles waste memory
+ * on Savage3D and Savage4 with subtile width 4 every other subtile is
+ * skipped if width < 8 so we can assume a uniform subtile width of 8 */
+ else if (width >= 2)
+ return width * 2 * bpp;
+ else if (height >= 2)
+ return 2 * height * bpp;
+ else
+ return 4 * bpp;
+}
+
+/** \brief Compute the number of (partial) tiles of a texture image
+ */
+static GLuint savageTexImageTiles (GLuint width, GLuint height,
+ const savageTileInfo *tileInfo)
+{
+ return (width + tileInfo->width - 1) / tileInfo->width *
+ (height + tileInfo->height - 1) / tileInfo->height;
+}
+
+/** \brief Mark dirty tiles
+ *
+ * Some care must be taken because tileInfo may not be set or not
+ * up-to-date. So we check if tileInfo is initialized and if the number
+ * of tiles in the bit vector matches the number of tiles computed from
+ * the current tileInfo.
+ */
+static void savageMarkDirtyTiles (savageTexObjPtr t, GLuint level,
+ GLuint totalWidth, GLuint totalHeight,
+ GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height)
+{
+ GLuint wInTiles, hInTiles;
+ GLuint x0, y0, x1, y1;
+ GLuint x, y;
+ if (!t->tileInfo)
+ return;
+ wInTiles = (totalWidth + t->tileInfo->width - 1) / t->tileInfo->width;
+ hInTiles = (totalHeight + t->tileInfo->height - 1) / t->tileInfo->height;
+ if (wInTiles * hInTiles != t->image[level].nTiles)
+ return;
+
+ x0 = xoffset / t->tileInfo->width;
+ y0 = yoffset / t->tileInfo->height;
+ x1 = (xoffset + width - 1) / t->tileInfo->width;
+ y1 = (yoffset + height - 1) / t->tileInfo->height;
+
+ for (y = y0; y <= y1; ++y) {
+ GLuint *ptr = t->image[level].dirtyTiles + (y * wInTiles + x0) / 32;
+ GLuint mask = 1 << (y * wInTiles + x0) % 32;
+ for (x = x0; x <= x1; ++x) {
+ *ptr |= mask;
+ if (mask == (1<<31)) {
+ ptr++;
+ mask = 1;
+ } else {
+ mask <<= 1;
+ }
+ }
+ }
+}
+
+/** \brief Mark all tiles as dirty
+ */
+static void savageMarkAllTiles (savageTexObjPtr t, GLuint level)
+{
+ GLuint words = (t->image[level].nTiles + 31) / 32;
+ if (words)
+ memset(t->image[level].dirtyTiles, ~0, words*sizeof(GLuint));
+}
+
+
+static void savageSetTexWrapping(savageTexObjPtr tex, GLenum s, GLenum t)
+{
+ tex->setup.sWrapMode = s;
+ tex->setup.tWrapMode = t;
+}
+
+static void savageSetTexFilter(savageTexObjPtr t, GLenum minf, GLenum magf)
+{
+ t->setup.minFilter = minf;
+ t->setup.magFilter = magf;
+}
+
+
+/* Need a fallback ?
+ */
+static void savageSetTexBorderColor(savageTexObjPtr t, GLubyte color[4])
+{
+/* t->Setup[SAVAGE_TEXREG_TEXBORDERCOL] = */
+ /*t->setup.borderColor = SAVAGEPACKCOLOR8888(color[0],color[1],color[2],color[3]); */
+}
+
+
+
+static savageTexObjPtr
+savageAllocTexObj( struct gl_texture_object *texObj )
+{
+ savageTexObjPtr t;
+
+ t = (savageTexObjPtr) calloc(1,sizeof(*t));
+ texObj->DriverData = t;
+ if ( t != NULL ) {
+ GLuint i;
+
+ /* Initialize non-image-dependent parts of the state:
+ */
+ t->base.tObj = texObj;
+ t->base.dirty_images[0] = 0;
+ t->dirtySubImages = 0;
+ t->tileInfo = NULL;
+
+ /* Initialize dirty tiles bit vectors
+ */
+ for (i = 0; i < SAVAGE_TEX_MAXLEVELS; ++i)
+ t->image[i].nTiles = 0;
+
+ /* FIXME Something here to set initial values for other parts of
+ * FIXME t->setup?
+ */
+
+ make_empty_list( &t->base );
+
+ savageSetTexWrapping(t,texObj->WrapS,texObj->WrapT);
+ savageSetTexFilter(t,texObj->MinFilter,texObj->MagFilter);
+ savageSetTexBorderColor(t,texObj->_BorderChan);
+ }
+
+ return t;
+}
+
+/* Mesa texture formats for alpha-images on Savage3D/IX/MX
+ *
+ * Promoting texture images to ARGB888 or ARGB4444 doesn't work
+ * because we can't tell the hardware to ignore the color components
+ * and only use the alpha component. So we define our own texture
+ * formats that promote to ARGB8888 or ARGB4444 and set the color
+ * components to white. This way we get the correct result.
+ */
+
+static GLboolean
+_savage_texstore_a1114444(TEXSTORE_PARAMS);
+
+static GLboolean
+_savage_texstore_a1118888(TEXSTORE_PARAMS);
+
+static struct gl_texture_format _savage_texformat_a1114444 = {
+ MESA_FORMAT_ARGB4444, /* MesaFormat */
+ GL_RGBA, /* BaseFormat */
+ GL_UNSIGNED_NORMALIZED_ARB, /* DataType */
+ 4, /* RedBits */
+ 4, /* GreenBits */
+ 4, /* BlueBits */
+ 4, /* AlphaBits */
+ 0, /* LuminanceBits */
+ 0, /* IntensityBits */
+ 0, /* IndexBits */
+ 0, /* DepthBits */
+ 0, /* StencilBits */
+ 2, /* TexelBytes */
+ _savage_texstore_a1114444, /* StoreTexImageFunc */
+ NULL, NULL, NULL, NULL, NULL, NULL /* FetchTexel* filled in by
+ * savageDDInitTextureFuncs */
+};
+static struct gl_texture_format _savage_texformat_a1118888 = {
+ MESA_FORMAT_ARGB8888, /* MesaFormat */
+ GL_RGBA, /* BaseFormat */
+ GL_UNSIGNED_NORMALIZED_ARB, /* DataType */
+ 8, /* RedBits */
+ 8, /* GreenBits */
+ 8, /* BlueBits */
+ 8, /* AlphaBits */
+ 0, /* LuminanceBits */
+ 0, /* IntensityBits */
+ 0, /* IndexBits */
+ 0, /* DepthBits */
+ 0, /* StencilBits */
+ 4, /* TexelBytes */
+ _savage_texstore_a1118888, /* StoreTexImageFunc */
+ NULL, NULL, NULL, NULL, NULL, NULL /* FetchTexel* filled in by
+ * savageDDInitTextureFuncs */
+};
+
+
+static GLboolean
+_savage_texstore_a1114444(TEXSTORE_PARAMS)
+{
+ const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
+ baseInternalFormat,
+ baseInternalFormat,
+ srcWidth, srcHeight, srcDepth,
+ srcFormat, srcType, srcAddr,
+ srcPacking);
+ const GLchan *src = tempImage;
+ GLint img, row, col;
+
+ ASSERT(dstFormat == &_savage_texformat_a1114444);
+ ASSERT(baseInternalFormat == GL_ALPHA);
+
+ if (!tempImage)
+ return GL_FALSE;
+ _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
+ for (img = 0; img < srcDepth; img++) {
+ GLubyte *dstRow = (GLubyte *) dstAddr
+ + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
+ + dstYoffset * dstRowStride
+ + dstXoffset * dstFormat->TexelBytes;
+ for (row = 0; row < srcHeight; row++) {
+ GLushort *dstUI = (GLushort *) dstRow;
+ for (col = 0; col < srcWidth; col++) {
+ dstUI[col] = PACK_COLOR_4444( CHAN_TO_UBYTE(src[0]),
+ 255, 255, 255 );
+ src += 1;
+ }
+ dstRow += dstRowStride;
+ }
+ }
+ _mesa_free((void *) tempImage);
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+_savage_texstore_a1118888(TEXSTORE_PARAMS)
+{
+ const GLchan *tempImage = _mesa_make_temp_chan_image(ctx, dims,
+ baseInternalFormat,
+ baseInternalFormat,
+ srcWidth, srcHeight, srcDepth,
+ srcFormat, srcType, srcAddr,
+ srcPacking);
+ const GLchan *src = tempImage;
+ GLint img, row, col;
+
+ ASSERT(dstFormat == &_savage_texformat_a1118888);
+ ASSERT(baseInternalFormat == GL_ALPHA);
+
+ if (!tempImage)
+ return GL_FALSE;
+ _mesa_adjust_image_for_convolution(ctx, dims, &srcWidth, &srcHeight);
+ for (img = 0; img < srcDepth; img++) {
+ GLubyte *dstRow = (GLubyte *) dstAddr
+ + dstImageOffsets[dstZoffset + img] * dstFormat->TexelBytes
+ + dstYoffset * dstRowStride
+ + dstXoffset * dstFormat->TexelBytes;
+ for (row = 0; row < srcHeight; row++) {
+ GLuint *dstUI = (GLuint *) dstRow;
+ for (col = 0; col < srcWidth; col++) {
+ dstUI[col] = PACK_COLOR_8888( CHAN_TO_UBYTE(src[0]),
+ 255, 255, 255 );
+ src += 1;
+ }
+ dstRow += dstRowStride;
+ }
+ }
+ _mesa_free((void *) tempImage);
+
+ return GL_TRUE;
+}
+
+
+/* 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 =
+ ( imesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_32 );
+ const GLboolean force16bpt =
+ ( imesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_FORCE_16 );
+ const GLboolean isSavage4 = (imesa->savageScreen->chipset >= S3_SAVAGE4);
+ (void) format;
+
+ 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 ? &_savage_texformat_a1118888 : &_savage_texformat_a1114444);
+ case GL_ALPHA4:
+ return isSavage4 ? &_mesa_texformat_a8 : &_savage_texformat_a1114444;
+ case GL_ALPHA8:
+ case GL_ALPHA12:
+ case GL_ALPHA16:
+ return isSavage4 ? &_mesa_texformat_a8 : (
+ !force16bpt ? &_savage_texformat_a1118888 : &_savage_texformat_a1114444);
+
+ 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;
+#if 0
+ /* TFT_I8 produces garbage on ProSavageDDR and subsequent texture
+ * disable keeps rendering garbage. Disabled for now. */
+ 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);
+#else
+ case GL_INTENSITY:
+ case GL_COMPRESSED_INTENSITY:
+ return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444;
+ case GL_INTENSITY4:
+ return &_mesa_texformat_argb4444;
+ case GL_INTENSITY8:
+ case GL_INTENSITY12:
+ case GL_INTENSITY16:
+ return !force16bpt ? &_mesa_texformat_argb8888 :
+ &_mesa_texformat_argb4444;
+#endif
+
+ case GL_RGB_S3TC:
+ case GL_RGB4_S3TC:
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ return &_mesa_texformat_rgb_dxt1;
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ return &_mesa_texformat_rgba_dxt1;
+
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ return &_mesa_texformat_rgba_dxt3;
+
+ case GL_RGBA_S3TC:
+ case GL_RGBA4_S3TC:
+ if (!isSavage4)
+ /* Not the best choice but Savage3D/MX/IX don't support DXT3 or DXT5. */
+ return &_mesa_texformat_rgba_dxt1;
+ /* fall through */
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ return &_mesa_texformat_rgba_dxt5;
+
+/*
+ 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 )
+{
+ savageTexObjPtr t = (savageTexObjPtr) tObj->DriverData;
+ struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
+ GLuint offset, i, textureFormat, tileIndex, size;
+ GLint firstLevel, lastLevel;
+
+ assert(t);
+ assert(image);
+
+ switch (image->TexFormat->MesaFormat) {
+ case MESA_FORMAT_ARGB8888:
+ textureFormat = TFT_ARGB8888;
+ t->texelBytes = tileIndex = 4;
+ break;
+ case MESA_FORMAT_ARGB1555:
+ textureFormat = TFT_ARGB1555;
+ t->texelBytes = tileIndex = 2;
+ break;
+ case MESA_FORMAT_ARGB4444:
+ textureFormat = TFT_ARGB4444;
+ t->texelBytes = tileIndex = 2;
+ break;
+ case MESA_FORMAT_RGB565:
+ textureFormat = TFT_RGB565;
+ t->texelBytes = tileIndex = 2;
+ break;
+ case MESA_FORMAT_L8:
+ textureFormat = TFT_L8;
+ t->texelBytes = tileIndex = 1;
+ break;
+ case MESA_FORMAT_I8:
+ textureFormat = TFT_I8;
+ t->texelBytes = tileIndex = 1;
+ break;
+ case MESA_FORMAT_A8:
+ textureFormat = TFT_A8;
+ t->texelBytes = tileIndex = 1;
+ break;
+ case MESA_FORMAT_RGB_DXT1:
+ textureFormat = TFT_S3TC4Bit;
+ tileIndex = TILE_INDEX_DXT1;
+ t->texelBytes = 8;
+ break;
+ case MESA_FORMAT_RGBA_DXT1:
+ textureFormat = TFT_S3TC4Bit;
+ tileIndex = TILE_INDEX_DXT1;
+ t->texelBytes = 8;
+ break;
+ case MESA_FORMAT_RGBA_DXT3:
+ textureFormat = TFT_S3TC4A4Bit;
+ tileIndex = TILE_INDEX_DXTn;
+ t->texelBytes = 16;
+ break;
+ case MESA_FORMAT_RGBA_DXT5:
+ textureFormat = TFT_S3TC4CA4Bit;
+ tileIndex = TILE_INDEX_DXTn;
+ t->texelBytes = 16;
+ break;
+ default:
+ _mesa_problem(imesa->glCtx, "Bad texture format in %s", __FUNCTION__);
+ return;
+ }
+ t->hwFormat = textureFormat;
+
+ /* Select tiling format depending on the chipset and texture format */
+ if (imesa->savageScreen->chipset <= S3_SAVAGE4)
+ t->tileInfo = &tileInfo_s3d_s4[tileIndex];
+ else
+ t->tileInfo = &tileInfo_pro[tileIndex];
+
+ /* Compute which mipmap levels we really want to send to the hardware.
+ */
+ driCalculateTextureFirstLastLevel( &t->base );
+ firstLevel = t->base.firstLevel;
+ lastLevel = t->base.lastLevel;
+
+ /* Figure out the size now (and count the levels). Upload won't be
+ * done until later. If the number of tiles changes, it means that
+ * this function is called for the first time on this tex object or
+ * the image or the destination color format changed. So all tiles
+ * are marked as dirty.
+ */
+ offset = 0;
+ size = 1;
+ for ( i = firstLevel ; i <= lastLevel && tObj->Image[0][i] ; i++ ) {
+ GLuint nTiles;
+ nTiles = savageTexImageTiles (image->Width2, image->Height2, t->tileInfo);
+ if (t->image[i].nTiles != nTiles) {
+ GLuint words = (nTiles + 31) / 32;
+ if (t->image[i].nTiles != 0) {
+ free(t->image[i].dirtyTiles);
+ }
+ t->image[i].dirtyTiles = malloc(words*sizeof(GLuint));
+ memset(t->image[i].dirtyTiles, ~0, words*sizeof(GLuint));
+ }
+ t->image[i].nTiles = nTiles;
+
+ t->image[i].offset = offset;
+
+ image = tObj->Image[0][i];
+ if (t->texelBytes >= 8)
+ size = savageCompressedTexImageSize (image->Width2, image->Height2,
+ t->texelBytes);
+ else
+ size = savageTexImageSize (image->Width2, image->Height2,
+ t->texelBytes);
+ offset += size;
+ }
+
+ t->base.lastLevel = i-1;
+ t->base.totalSize = offset;
+ /* the last three mipmap levels don't add to the offset. They are packed
+ * into 64 pixels. */
+ if (size == 0)
+ t->base.totalSize += (t->texelBytes >= 8 ? 4 : 64) * t->texelBytes;
+ /* 2k-aligned (really needed?) */
+ t->base.totalSize = (t->base.totalSize + 2047UL) & ~2047UL;
+}
+
+void savageDestroyTexObj(savageContextPtr imesa, savageTexObjPtr t)
+{
+ GLuint i;
+
+ /* Free dirty tiles bit vectors */
+ for (i = 0; i < SAVAGE_TEX_MAXLEVELS; ++i) {
+ if (t->image[i].nTiles)
+ free (t->image[i].dirtyTiles);
+ }
+
+ /* See if it was the driver's current object.
+ */
+ if ( imesa != NULL )
+ {
+ for ( i = 0 ; i < imesa->glCtx->Const.MaxTextureUnits ; i++ )
+ {
+ if ( &t->base == imesa->CurrentTexObj[ i ] ) {
+ assert( t->base.bound & (1 << i) );
+ imesa->CurrentTexObj[ i ] = NULL;
+ }
+ }
+ }
+}
+
+/* Upload a texture's images to one of the texture heaps. May have to
+ * eject our own and/or other client's texture objects to make room
+ * for the upload.
+ */
+static void savageUploadTexImages( savageContextPtr imesa, savageTexObjPtr t )
+{
+ const GLint numLevels = t->base.lastLevel - t->base.firstLevel + 1;
+ GLuint i;
+
+ assert(t);
+
+ LOCK_HARDWARE(imesa);
+
+ /* Do we need to eject LRU texture objects?
+ */
+ if (!t->base.memBlock) {
+ GLint heap;
+ GLuint ofs;
+
+ heap = driAllocateTexture(imesa->textureHeaps, imesa->lastTexHeap,
+ (driTextureObject *)t);
+ if (heap == -1) {
+ UNLOCK_HARDWARE(imesa);
+ return;
+ }
+
+ ofs = t->base.memBlock->ofs;
+ t->setup.physAddr = imesa->savageScreen->textureOffset[heap] + ofs;
+ t->bufAddr = (GLubyte *)imesa->savageScreen->texVirtual[heap] + ofs;
+ imesa->dirty |= SAVAGE_UPLOAD_GLOBAL; /* FIXME: really needed? */
+ }
+
+ /* Let the world know we've used this memory recently.
+ */
+ driUpdateTextureLRU( &t->base );
+ UNLOCK_HARDWARE(imesa);
+
+ if (t->base.dirty_images[0] || t->dirtySubImages) {
+ if (SAVAGE_DEBUG & DEBUG_VERBOSE_TEX)
+ fprintf(stderr, "Texture upload: |");
+
+ /* Heap timestamps are only reliable with Savage DRM 2.3.x or
+ * later. Earlier versions had only 16 bit time stamps which
+ * would wrap too frequently. */
+ if (imesa->savageScreen->driScrnPriv->drmMinor >= 3) {
+ unsigned int heap = t->base.heap->heapId;
+ LOCK_HARDWARE(imesa);
+ savageWaitEvent (imesa, imesa->textureHeaps[heap]->timestamp);
+ } else {
+ savageFlushVertices (imesa);
+ LOCK_HARDWARE(imesa);
+ savageFlushCmdBufLocked (imesa, GL_FALSE);
+ WAIT_IDLE_EMPTY_LOCKED(imesa);
+ }
+
+ for (i = 0 ; i < numLevels ; i++) {
+ const GLint j = t->base.firstLevel + i; /* the texObj's level */
+ if (t->base.dirty_images[0] & (1 << j)) {
+ savageMarkAllTiles(t, j);
+ if (SAVAGE_DEBUG & DEBUG_VERBOSE_TEX)
+ fprintf (stderr, "*");
+ } else if (SAVAGE_DEBUG & DEBUG_VERBOSE_TEX) {
+ if (t->dirtySubImages & (1 << j))
+ fprintf (stderr, ".");
+ else
+ fprintf (stderr, " ");
+ }
+ if ((t->base.dirty_images[0] | t->dirtySubImages) & (1 << j))
+ savageUploadTexLevel( t, j );
+ }
+
+ UNLOCK_HARDWARE(imesa);
+ t->base.dirty_images[0] = 0;
+ t->dirtySubImages = 0;
+
+ if (SAVAGE_DEBUG & DEBUG_VERBOSE_TEX)
+ fprintf(stderr, "|\n");
+ }
+}
+
+
+static void
+savage4_set_wrap_mode( savageContextPtr imesa, unsigned unit,
+ GLenum s_mode, GLenum t_mode )
+{
+ switch( s_mode ) {
+ case GL_REPEAT:
+ imesa->regs.s4.texCtrl[ unit ].ni.uMode = TAM_Wrap;
+ break;
+ case GL_CLAMP:
+ case GL_CLAMP_TO_EDGE:
+ imesa->regs.s4.texCtrl[ unit ].ni.uMode = TAM_Clamp;
+ break;
+ case GL_MIRRORED_REPEAT:
+ imesa->regs.s4.texCtrl[ unit ].ni.uMode = TAM_Mirror;
+ break;
+ }
+
+ switch( t_mode ) {
+ case GL_REPEAT:
+ imesa->regs.s4.texCtrl[ unit ].ni.vMode = TAM_Wrap;
+ break;
+ case GL_CLAMP:
+ case GL_CLAMP_TO_EDGE:
+ imesa->regs.s4.texCtrl[ unit ].ni.vMode = TAM_Clamp;
+ break;
+ case GL_MIRRORED_REPEAT:
+ imesa->regs.s4.texCtrl[ unit ].ni.vMode = TAM_Mirror;
+ break;
+ }
+}
+
+
+/**
+ * Sets the hardware bits for the specified GL texture filter modes.
+ *
+ * \todo
+ * Does the Savage4 have the ability to select the magnification filter?
+ */
+static void
+savage4_set_filter_mode( savageContextPtr imesa, unsigned unit,
+ GLenum minFilter, GLenum magFilter )
+{
+ (void) magFilter;
+
+ switch (minFilter) {
+ case GL_NEAREST:
+ imesa->regs.s4.texCtrl[ unit ].ni.filterMode = TFM_Point;
+ imesa->regs.s4.texCtrl[ unit ].ni.mipmapEnable = GL_FALSE;
+ break;
+
+ case GL_LINEAR:
+ imesa->regs.s4.texCtrl[ unit ].ni.filterMode = TFM_Bilin;
+ imesa->regs.s4.texCtrl[ unit ].ni.mipmapEnable = GL_FALSE;
+ break;
+
+ case GL_NEAREST_MIPMAP_NEAREST:
+ imesa->regs.s4.texCtrl[ unit ].ni.filterMode = TFM_Point;
+ imesa->regs.s4.texCtrl[ unit ].ni.mipmapEnable = GL_TRUE;
+ break;
+
+ case GL_LINEAR_MIPMAP_NEAREST:
+ imesa->regs.s4.texCtrl[ unit ].ni.filterMode = TFM_Bilin;
+ imesa->regs.s4.texCtrl[ unit ].ni.mipmapEnable = GL_TRUE;
+ break;
+
+ case GL_NEAREST_MIPMAP_LINEAR:
+ case GL_LINEAR_MIPMAP_LINEAR:
+ imesa->regs.s4.texCtrl[ unit ].ni.filterMode = TFM_Trilin;
+ imesa->regs.s4.texCtrl[ unit ].ni.mipmapEnable = GL_TRUE;
+ break;
+ }
+}
+
+
+static void savageUpdateTex0State_s4( GLcontext *ctx )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ struct gl_texture_object *tObj;
+ struct gl_texture_image *image;
+ savageTexObjPtr t;
+ GLuint format;
+
+ /* disable */
+ imesa->regs.s4.texDescr.ni.tex0En = GL_FALSE;
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_NoTexMap;
+ imesa->regs.s4.texCtrl[0].ui = 0x20f040;
+ if (ctx->Texture.Unit[0]._ReallyEnabled == 0)
+ return;
+
+ tObj = ctx->Texture.Unit[0]._Current;
+ if ((ctx->Texture.Unit[0]._ReallyEnabled & ~(TEXTURE_1D_BIT|TEXTURE_2D_BIT))
+ || tObj->Image[0][tObj->BaseLevel]->Border > 0) {
+ /* 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;
+ }
+
+ imesa->CurrentTexObj[0] = &t->base;
+ t->base.bound |= 1;
+
+ if (t->base.dirty_images[0] || t->dirtySubImages) {
+ savageSetTexImages(imesa, tObj);
+ savageUploadTexImages(imesa, t);
+ }
+
+ driUpdateTextureLRU( &t->base );
+
+ format = tObj->Image[0][tObj->BaseLevel]->_BaseFormat;
+
+ switch (ctx->Texture.Unit[0].EnvMode) {
+ case GL_REPLACE:
+ imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE;
+ switch(format)
+ {
+ case GL_LUMINANCE:
+ case GL_RGB:
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_Decal;
+ break;
+
+ case GL_LUMINANCE_ALPHA:
+ case GL_RGBA:
+ case GL_INTENSITY:
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_Copy;
+ break;
+
+ case GL_ALPHA:
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_CopyAlpha;
+ break;
+ }
+ __HWEnvCombineSingleUnitScale(imesa, 0, 0,
+ &imesa->regs.s4.texBlendCtrl[0]);
+ break;
+
+ case GL_DECAL:
+ imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE;
+ switch (format)
+ {
+ case GL_RGB:
+ case GL_LUMINANCE:
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_Decal;
+ break;
+
+ case GL_RGBA:
+ case GL_INTENSITY:
+ case GL_LUMINANCE_ALPHA:
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_DecalAlpha;
+ break;
+
+ /*
+ GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_INTENSITY
+ are undefined with GL_DECAL
+ */
+
+ case GL_ALPHA:
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_CopyAlpha;
+ break;
+ }
+ __HWEnvCombineSingleUnitScale(imesa, 0, 0,
+ &imesa->regs.s4.texBlendCtrl[0]);
+ break;
+
+ case GL_MODULATE:
+ imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE;
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_ModulAlpha;
+ __HWEnvCombineSingleUnitScale(imesa, 0, 0,
+ &imesa->regs.s4.texBlendCtrl[0]);
+ break;
+
+ case GL_BLEND:
+ imesa->regs.s4.texBlendColor.ui = imesa->texEnvColor;
+
+ switch (format)
+ {
+ case GL_ALPHA:
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_ModulAlpha;
+ imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE;
+ break;
+
+ case GL_LUMINANCE:
+ case GL_RGB:
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_Blend0;
+ imesa->regs.s4.texDescr.ni.tex1En = GL_TRUE;
+ imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE;
+ imesa->regs.s4.texDescr.ni.tex1Width =
+ imesa->regs.s4.texDescr.ni.tex0Width;
+ imesa->regs.s4.texDescr.ni.tex1Height =
+ imesa->regs.s4.texDescr.ni.tex0Height;
+ imesa->regs.s4.texDescr.ni.tex1Fmt =
+ imesa->regs.s4.texDescr.ni.tex0Fmt;
+
+ imesa->regs.s4.texAddr[1].ui = imesa->regs.s4.texAddr[0].ui;
+ imesa->regs.s4.texBlendCtrl[1].ui = TBC_Blend1;
+
+ imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_TRUE;
+ imesa->bTexEn1 = GL_TRUE;
+ break;
+
+ case GL_LUMINANCE_ALPHA:
+ case GL_RGBA:
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_BlendAlpha0;
+ imesa->regs.s4.texDescr.ni.tex1En = GL_TRUE;
+ imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE;
+ imesa->regs.s4.texDescr.ni.tex1Width =
+ imesa->regs.s4.texDescr.ni.tex0Width;
+ imesa->regs.s4.texDescr.ni.tex1Height =
+ imesa->regs.s4.texDescr.ni.tex0Height;
+ imesa->regs.s4.texDescr.ni.tex1Fmt =
+ imesa->regs.s4.texDescr.ni.tex0Fmt;
+
+ imesa->regs.s4.texAddr[1].ui = imesa->regs.s4.texAddr[0].ui;
+ imesa->regs.s4.texBlendCtrl[1].ui = TBC_BlendAlpha1;
+
+ imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_TRUE;
+ imesa->bTexEn1 = GL_TRUE;
+ break;
+
+ case GL_INTENSITY:
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_BlendInt0;
+ imesa->regs.s4.texDescr.ni.tex1En = GL_TRUE;
+ imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE;
+ imesa->regs.s4.texDescr.ni.tex1Width =
+ imesa->regs.s4.texDescr.ni.tex0Width;
+ imesa->regs.s4.texDescr.ni.tex1Height =
+ imesa->regs.s4.texDescr.ni.tex0Height;
+ imesa->regs.s4.texDescr.ni.tex1Fmt =
+ imesa->regs.s4.texDescr.ni.tex0Fmt;
+
+ imesa->regs.s4.texAddr[1].ui = imesa->regs.s4.texAddr[0].ui;
+ imesa->regs.s4.texBlendCtrl[1].ui = TBC_BlendInt1;
+
+ imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_TRUE;
+ imesa->regs.s4.texCtrl[0].ni.alphaArg1Invert = GL_TRUE;
+ imesa->bTexEn1 = GL_TRUE;
+ break;
+ }
+ __HWEnvCombineSingleUnitScale(imesa, 0, 0,
+ &imesa->regs.s4.texBlendCtrl[0]);
+ break;
+
+ case GL_ADD:
+ imesa->regs.s4.texCtrl[0].ni.clrArg1Invert = GL_FALSE;
+ switch (format)
+ {
+ case GL_ALPHA:
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_ModulAlpha;
+ break;
+
+ case GL_LUMINANCE:
+ case GL_RGB:
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_Add;
+ break;
+
+ case GL_LUMINANCE_ALPHA:
+ case GL_RGBA:
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_Add;
+ break;
+
+ case GL_INTENSITY:
+ imesa->regs.s4.texBlendCtrl[0].ui = TBC_AddAlpha;
+ break;
+ }
+ __HWEnvCombineSingleUnitScale(imesa, 0, 0,
+ &imesa->regs.s4.texBlendCtrl[0]);
+ break;
+
+#if GL_ARB_texture_env_combine
+ case GL_COMBINE_ARB:
+ __HWParseTexEnvCombine(imesa, 0, &imesa->regs.s4.texCtrl[0],
+ &imesa->regs.s4.texBlendCtrl[0]);
+ break;
+#endif
+
+ default:
+ fprintf(stderr, "unknown tex env mode");
+ exit(1);
+ break;
+ }
+
+ savage4_set_wrap_mode( imesa, 0, t->setup.sWrapMode, t->setup.tWrapMode );
+ savage4_set_filter_mode( imesa, 0, t->setup.minFilter, t->setup.magFilter );
+
+ if((ctx->Texture.Unit[0].LodBias !=0.0F) ||
+ (imesa->regs.s4.texCtrl[0].ni.dBias != 0))
+ {
+ int bias = (int)(ctx->Texture.Unit[0].LodBias * 32.0) +
+ SAVAGE4_LOD_OFFSET;
+ if (bias < -256)
+ bias = -256;
+ else if (bias > 255)
+ bias = 255;
+ imesa->regs.s4.texCtrl[0].ni.dBias = bias & 0x1ff;
+ }
+
+ image = tObj->Image[0][tObj->BaseLevel];
+ imesa->regs.s4.texDescr.ni.tex0En = GL_TRUE;
+ imesa->regs.s4.texDescr.ni.tex0Width = image->WidthLog2;
+ imesa->regs.s4.texDescr.ni.tex0Height = image->HeightLog2;
+ imesa->regs.s4.texDescr.ni.tex0Fmt = t->hwFormat;
+ imesa->regs.s4.texCtrl[0].ni.dMax = t->base.lastLevel - t->base.firstLevel;
+
+ if (imesa->regs.s4.texDescr.ni.tex1En)
+ imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE;
+
+ imesa->regs.s4.texAddr[0].ui = (u_int32_t) t->setup.physAddr | 0x2;
+ if(t->base.heap->heapId == SAVAGE_AGP_HEAP)
+ imesa->regs.s4.texAddr[0].ui |= 0x1;
+
+ return;
+}
+static void savageUpdateTex1State_s4( GLcontext *ctx )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ struct gl_texture_object *tObj;
+ struct gl_texture_image *image;
+ savageTexObjPtr t;
+ GLuint format;
+
+ /* disable */
+ if(imesa->bTexEn1)
+ {
+ imesa->bTexEn1 = GL_FALSE;
+ return;
+ }
+
+ imesa->regs.s4.texDescr.ni.tex1En = GL_FALSE;
+ imesa->regs.s4.texBlendCtrl[1].ui = TBC_NoTexMap1;
+ imesa->regs.s4.texCtrl[1].ui = 0x20f040;
+ imesa->regs.s4.texDescr.ni.texBLoopEn = GL_FALSE;
+ if (ctx->Texture.Unit[1]._ReallyEnabled == 0)
+ return;
+
+ tObj = ctx->Texture.Unit[1]._Current;
+
+ if ((ctx->Texture.Unit[1]._ReallyEnabled & ~(TEXTURE_1D_BIT|TEXTURE_2D_BIT))
+ || tObj->Image[0][tObj->BaseLevel]->Border > 0) {
+ /* 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;
+ }
+
+ imesa->CurrentTexObj[1] = &t->base;
+
+ t->base.bound |= 2;
+
+ if (t->base.dirty_images[0] || t->dirtySubImages) {
+ savageSetTexImages(imesa, tObj);
+ savageUploadTexImages(imesa, t);
+ }
+
+ driUpdateTextureLRU( &t->base );
+
+ format = tObj->Image[0][tObj->BaseLevel]->_BaseFormat;
+
+ switch (ctx->Texture.Unit[1].EnvMode) {
+ case GL_REPLACE:
+ imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE;
+ switch (format)
+ {
+ case GL_LUMINANCE:
+ case GL_RGB:
+ imesa->regs.s4.texBlendCtrl[1].ui = TBC_Decal;
+ break;
+
+ case GL_LUMINANCE_ALPHA:
+ case GL_INTENSITY:
+ case GL_RGBA:
+ imesa->regs.s4.texBlendCtrl[1].ui = TBC_Copy;
+ break;
+
+ case GL_ALPHA:
+ imesa->regs.s4.texBlendCtrl[1].ui = TBC_CopyAlpha1;
+ break;
+ }
+ __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl);
+ break;
+ case GL_MODULATE:
+ imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE;
+ imesa->regs.s4.texBlendCtrl[1].ui = TBC_ModulAlpha1;
+ __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl);
+ break;
+
+ case GL_ADD:
+ imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE;
+ switch (format)
+ {
+ case GL_ALPHA:
+ imesa->regs.s4.texBlendCtrl[1].ui = TBC_ModulAlpha1;
+ break;
+
+ case GL_LUMINANCE:
+ case GL_RGB:
+ imesa->regs.s4.texBlendCtrl[1].ui = TBC_Add1;
+ break;
+
+ case GL_LUMINANCE_ALPHA:
+ case GL_RGBA:
+ imesa->regs.s4.texBlendCtrl[1].ui = TBC_Add1;
+ break;
+
+ case GL_INTENSITY:
+ imesa->regs.s4.texBlendCtrl[1].ui = TBC_AddAlpha1;
+ break;
+ }
+ __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl);
+ break;
+
+#if GL_ARB_texture_env_combine
+ case GL_COMBINE_ARB:
+ __HWParseTexEnvCombine(imesa, 1, &texCtrl, &imesa->regs.s4.texBlendCtrl);
+ break;
+#endif
+
+ case GL_DECAL:
+ imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_FALSE;
+
+ switch (format)
+ {
+ case GL_LUMINANCE:
+ case GL_RGB:
+ imesa->regs.s4.texBlendCtrl[1].ui = TBC_Decal1;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ case GL_INTENSITY:
+ case GL_RGBA:
+ imesa->regs.s4.texBlendCtrl[1].ui = TBC_DecalAlpha1;
+ break;
+
+ /*
+ // GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_ALPHA, GL_INTENSITY
+ // are undefined with GL_DECAL
+ */
+ case GL_ALPHA:
+ imesa->regs.s4.texBlendCtrl[1].ui = TBC_CopyAlpha1;
+ break;
+ }
+ __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl);
+ break;
+
+ case GL_BLEND:
+ if (format == GL_LUMINANCE)
+ {
+ /*
+ // This is a hack for GLQuake, invert.
+ */
+ imesa->regs.s4.texCtrl[1].ni.clrArg1Invert = GL_TRUE;
+ imesa->regs.s4.texBlendCtrl[1].ui = 0;
+ }
+ __HWEnvCombineSingleUnitScale(imesa, 0, 1, &imesa->regs.s4.texBlendCtrl);
+ break;
+
+ default:
+ fprintf(stderr, "unknown tex 1 env mode\n");
+ exit(1);
+ break;
+ }
+
+ savage4_set_wrap_mode( imesa, 1, t->setup.sWrapMode, t->setup.tWrapMode );
+ savage4_set_filter_mode( imesa, 1, t->setup.minFilter, t->setup.magFilter );
+
+ if((ctx->Texture.Unit[1].LodBias !=0.0F) ||
+ (imesa->regs.s4.texCtrl[1].ni.dBias != 0))
+ {
+ int bias = (int)(ctx->Texture.Unit[1].LodBias * 32.0) +
+ SAVAGE4_LOD_OFFSET;
+ if (bias < -256)
+ bias = -256;
+ else if (bias > 255)
+ bias = 255;
+ imesa->regs.s4.texCtrl[1].ni.dBias = bias & 0x1ff;
+ }
+
+ image = tObj->Image[0][tObj->BaseLevel];
+ imesa->regs.s4.texDescr.ni.tex1En = GL_TRUE;
+ imesa->regs.s4.texDescr.ni.tex1Width = image->WidthLog2;
+ imesa->regs.s4.texDescr.ni.tex1Height = image->HeightLog2;
+ imesa->regs.s4.texDescr.ni.tex1Fmt = t->hwFormat;
+ imesa->regs.s4.texCtrl[1].ni.dMax = t->base.lastLevel - t->base.firstLevel;
+ imesa->regs.s4.texDescr.ni.texBLoopEn = GL_TRUE;
+
+ imesa->regs.s4.texAddr[1].ui = (u_int32_t) t->setup.physAddr | 2;
+ if(t->base.heap->heapId == SAVAGE_AGP_HEAP)
+ imesa->regs.s4.texAddr[1].ui |= 0x1;
+}
+static void savageUpdateTexState_s3d( GLcontext *ctx )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ struct gl_texture_object *tObj;
+ struct gl_texture_image *image;
+ savageTexObjPtr t;
+ GLuint format;
+
+ /* disable */
+ imesa->regs.s3d.texCtrl.ui = 0;
+ imesa->regs.s3d.texCtrl.ni.texEn = GL_FALSE;
+ imesa->regs.s3d.texCtrl.ni.dBias = 0x08;
+ imesa->regs.s3d.texCtrl.ni.texXprEn = GL_TRUE;
+ if (ctx->Texture.Unit[0]._ReallyEnabled == 0)
+ return;
+
+ tObj = ctx->Texture.Unit[0]._Current;
+ if ((ctx->Texture.Unit[0]._ReallyEnabled & ~(TEXTURE_1D_BIT|TEXTURE_2D_BIT))
+ || tObj->Image[0][tObj->BaseLevel]->Border > 0) {
+ /* 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;
+ }
+
+ imesa->CurrentTexObj[0] = &t->base;
+ t->base.bound |= 1;
+
+ if (t->base.dirty_images[0] || t->dirtySubImages) {
+ savageSetTexImages(imesa, tObj);
+ savageUploadTexImages(imesa, t);
+ }
+
+ driUpdateTextureLRU( &t->base );
+
+ format = tObj->Image[0][tObj->BaseLevel]->_BaseFormat;
+
+ /* FIXME: copied from utah-glx, probably needs some tuning */
+ switch (ctx->Texture.Unit[0].EnvMode) {
+ case GL_DECAL:
+ imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = SAVAGETBC_DECALALPHA_S3D;
+ break;
+ case GL_REPLACE:
+ switch (format) {
+ case GL_ALPHA: /* FIXME */
+ imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = 1;
+ break;
+ case GL_LUMINANCE_ALPHA:
+ case GL_RGBA:
+ imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = 4;
+ break;
+ case GL_RGB:
+ case GL_LUMINANCE:
+ imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = SAVAGETBC_DECAL_S3D;
+ break;
+ case GL_INTENSITY:
+ imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = SAVAGETBC_COPY_S3D;
+ }
+ break;
+ case GL_BLEND: /* hardware can't do GL_BLEND */
+ FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE);
+ return;
+ case GL_MODULATE:
+ imesa->regs.s3d.drawCtrl.ni.texBlendCtrl = SAVAGETBC_MODULATEALPHA_S3D;
+ break;
+ default:
+ fprintf(stderr, "unknown tex env mode\n");
+ /*exit(1);*/
+ break;
+ }
+
+ /* The Savage3D can't handle different wrapping modes in s and t.
+ * If they are not the same, fall back to software. */
+ if (t->setup.sWrapMode != t->setup.tWrapMode) {
+ FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_TRUE);
+ return;
+ }
+ imesa->regs.s3d.texCtrl.ni.uWrapEn = 0;
+ imesa->regs.s3d.texCtrl.ni.vWrapEn = 0;
+ imesa->regs.s3d.texCtrl.ni.wrapMode =
+ (t->setup.sWrapMode == GL_REPEAT) ? TAM_Wrap : TAM_Clamp;
+
+ switch (t->setup.minFilter) {
+ case GL_NEAREST:
+ imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Point;
+ imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_TRUE;
+ break;
+
+ case GL_LINEAR:
+ imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Bilin;
+ imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_TRUE;
+ break;
+
+ case GL_NEAREST_MIPMAP_NEAREST:
+ imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Point;
+ imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_FALSE;
+ break;
+
+ case GL_LINEAR_MIPMAP_NEAREST:
+ imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Bilin;
+ imesa->regs.s3d.texCtrl.ni.mipmapDisable = GL_FALSE;
+ break;
+
+ case GL_NEAREST_MIPMAP_LINEAR:
+ case GL_LINEAR_MIPMAP_LINEAR:
+ imesa->regs.s3d.texCtrl.ni.filterMode = TFM_Trilin;
+ imesa->regs.s3d.texCtrl.ni.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.ni.mipmapEnable = GL_TRUE;
+ if (texCtrl.ni.filterMode == TFM_Trilin)
+ texCtrl.ni.filterMode = TFM_Bilin;
+ texCtrl.ni.filterMode = TFM_Point;
+ }
+ */
+
+ if((ctx->Texture.Unit[0].LodBias !=0.0F) ||
+ (imesa->regs.s3d.texCtrl.ni.dBias != 0))
+ {
+ int bias = (int)(ctx->Texture.Unit[0].LodBias * 16.0);
+ if (bias < -256)
+ bias = -256;
+ else if (bias > 255)
+ bias = 255;
+ imesa->regs.s3d.texCtrl.ni.dBias = bias & 0x1ff;
+ }
+
+ image = tObj->Image[0][tObj->BaseLevel];
+ imesa->regs.s3d.texCtrl.ni.texEn = GL_TRUE;
+ imesa->regs.s3d.texDescr.ni.texWidth = image->WidthLog2;
+ imesa->regs.s3d.texDescr.ni.texHeight = image->HeightLog2;
+ assert (t->hwFormat <= 7);
+ imesa->regs.s3d.texDescr.ni.texFmt = t->hwFormat;
+
+ imesa->regs.s3d.texAddr.ui = (u_int32_t) t->setup.physAddr | 2;
+ if(t->base.heap->heapId == SAVAGE_AGP_HEAP)
+ imesa->regs.s3d.texAddr.ui |= 0x1;
+}
+
+
+static void savageTimestampTextures( savageContextPtr imesa )
+{
+ /* Timestamp current texture objects for texture heap aging.
+ * Only useful with long-lived 32-bit event tags available
+ * with Savage DRM 2.3.x or later. */
+ if ((imesa->CurrentTexObj[0] || imesa->CurrentTexObj[1]) &&
+ imesa->savageScreen->driScrnPriv->drmMinor >= 3) {
+ unsigned int e;
+ FLUSH_BATCH(imesa);
+ e = savageEmitEvent(imesa, SAVAGE_WAIT_3D);
+ if (imesa->CurrentTexObj[0])
+ imesa->CurrentTexObj[0]->timestamp = e;
+ if (imesa->CurrentTexObj[1])
+ imesa->CurrentTexObj[1]->timestamp = e;
+ }
+}
+
+
+static void savageUpdateTextureState_s4( GLcontext *ctx )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+
+ /* When a texture is about to change or be disabled, timestamp the
+ * old texture(s). We'll have to wait for this time stamp before
+ * uploading anything to the same texture heap.
+ */
+ if ((imesa->CurrentTexObj[0] && ctx->Texture.Unit[0]._ReallyEnabled &&
+ ctx->Texture.Unit[0]._Current->DriverData != imesa->CurrentTexObj[0]) ||
+ (imesa->CurrentTexObj[1] && ctx->Texture.Unit[1]._ReallyEnabled &&
+ ctx->Texture.Unit[1]._Current->DriverData != imesa->CurrentTexObj[1]) ||
+ (imesa->CurrentTexObj[0] && !ctx->Texture.Unit[0]._ReallyEnabled) ||
+ (imesa->CurrentTexObj[1] && !ctx->Texture.Unit[1]._ReallyEnabled))
+ savageTimestampTextures(imesa);
+
+ if (imesa->CurrentTexObj[0]) imesa->CurrentTexObj[0]->bound &= ~1;
+ if (imesa->CurrentTexObj[1]) imesa->CurrentTexObj[1]->bound &= ~2;
+ imesa->CurrentTexObj[0] = 0;
+ imesa->CurrentTexObj[1] = 0;
+ savageUpdateTex0State_s4( ctx );
+ savageUpdateTex1State_s4( ctx );
+ imesa->dirty |= (SAVAGE_UPLOAD_TEX0 |
+ SAVAGE_UPLOAD_TEX1);
+}
+static void savageUpdateTextureState_s3d( GLcontext *ctx )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+
+ /* When a texture is about to change or be disabled, timestamp the
+ * old texture(s). We'll have to wait for this time stamp before
+ * uploading anything to the same texture heap.
+ */
+ if ((imesa->CurrentTexObj[0] && ctx->Texture.Unit[0]._ReallyEnabled &&
+ ctx->Texture.Unit[0]._Current->DriverData != imesa->CurrentTexObj[0]) ||
+ (imesa->CurrentTexObj[0] && !ctx->Texture.Unit[0]._ReallyEnabled))
+ savageTimestampTextures(imesa);
+
+ if (imesa->CurrentTexObj[0]) imesa->CurrentTexObj[0]->bound &= ~1;
+ imesa->CurrentTexObj[0] = 0;
+ savageUpdateTexState_s3d( ctx );
+ imesa->dirty |= (SAVAGE_UPLOAD_TEX0);
+}
+void savageUpdateTextureState( GLcontext *ctx)
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+ FALLBACK (ctx, SAVAGE_FALLBACK_TEXTURE, GL_FALSE);
+ FALLBACK(ctx, SAVAGE_FALLBACK_PROJ_TEXTURE, GL_FALSE);
+ if (imesa->savageScreen->chipset >= S3_SAVAGE4)
+ savageUpdateTextureState_s4 (ctx);
+ else
+ savageUpdateTextureState_s3d (ctx);
+}
+
+
+
+/*****************************************
+ * 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;
+ 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]);
+
+ imesa->texEnvColor = ((a << 24) | (r << 16) |
+ (g << 8) | (b << 0));
+
+
+ }
+}
+
+/* Update the heap's time stamp, so the new image is not uploaded
+ * while the old one is still in use. If the texture that is going to
+ * be changed is currently bound, we need to timestamp the texture
+ * first. */
+static void savageTexImageChanged (savageTexObjPtr t) {
+ if (t->base.heap) {
+ if (t->base.bound)
+ savageTimestampTextures(
+ (savageContextPtr)t->base.heap->driverContext);
+ if (t->base.timestamp > t->base.heap->timestamp)
+ t->base.heap->timestamp = t->base.timestamp;
+ }
+}
+
+static void savageTexImage1D( GLcontext *ctx, GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, 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 )
+{
+ savageTexObjPtr t = (savageTexObjPtr) texObj->DriverData;
+ if (t) {
+ savageTexImageChanged (t);
+ } else {
+ t = savageAllocTexObj(texObj);
+ if (!t) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
+ return;
+ }
+ }
+ _mesa_store_teximage1d( ctx, target, level, internalFormat,
+ width, border, format, type,
+ pixels, packing, texObj, texImage );
+ t->base.dirty_images[0] |= (1 << level);
+ SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE;
+}
+
+static void savageTexSubImage1D( GLcontext *ctx,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLsizei width,
+ GLenum format, GLenum type,
+ const GLvoid *pixels,
+ const struct gl_pixelstore_attrib *packing,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage )
+{
+ savageTexObjPtr t = (savageTexObjPtr) texObj->DriverData;
+ assert( t ); /* this _should_ be true */
+ if (t) {
+ savageTexImageChanged (t);
+ savageMarkDirtyTiles(t, level, texImage->Width2, 1,
+ xoffset, 0, width, 1);
+ } else {
+ t = savageAllocTexObj(texObj);
+ if (!t) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D");
+ return;
+ }
+ t->base.dirty_images[0] |= (1 << level);
+ }
+ _mesa_store_texsubimage1d(ctx, target, level, xoffset, width,
+ format, type, pixels, packing, texObj,
+ texImage);
+ t->dirtySubImages |= (1 << level);
+ SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE;
+}
+
+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 )
+{
+ savageTexObjPtr t = (savageTexObjPtr) texObj->DriverData;
+ if (t) {
+ savageTexImageChanged (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->base.dirty_images[0] |= (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 )
+{
+ savageTexObjPtr t = (savageTexObjPtr) texObj->DriverData;
+ assert( t ); /* this _should_ be true */
+ if (t) {
+ savageTexImageChanged (t);
+ savageMarkDirtyTiles(t, level, texImage->Width2, texImage->Height2,
+ xoffset, yoffset, width, height);
+ } else {
+ t = savageAllocTexObj(texObj);
+ if (!t) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D");
+ return;
+ }
+ t->base.dirty_images[0] |= (1 << level);
+ }
+ _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width,
+ height, format, type, pixels, packing, texObj,
+ texImage);
+ t->dirtySubImages |= (1 << level);
+ SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE;
+}
+
+static void
+savageCompressedTexImage2D( GLcontext *ctx, GLenum target, GLint level,
+ GLint internalFormat,
+ GLint width, GLint height, GLint border,
+ GLsizei imageSize, const GLvoid *data,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage )
+{
+ savageTexObjPtr t = (savageTexObjPtr) texObj->DriverData;
+ if (t) {
+ savageTexImageChanged (t);
+ } else {
+ t = savageAllocTexObj(texObj);
+ if (!t) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D");
+ return;
+ }
+ }
+ _mesa_store_compressed_teximage2d( ctx, target, level, internalFormat,
+ width, height, border, imageSize,
+ data, texObj, texImage );
+ t->base.dirty_images[0] |= (1 << level);
+ SAVAGE_CONTEXT(ctx)->new_state |= SAVAGE_NEW_TEXTURE;
+}
+
+static void
+savageCompressedTexSubImage2D( GLcontext *ctx,
+ GLenum target,
+ GLint level,
+ GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height,
+ GLenum format, GLsizei imageSize,
+ const GLvoid *data,
+ struct gl_texture_object *texObj,
+ struct gl_texture_image *texImage )
+{
+ savageTexObjPtr t = (savageTexObjPtr) texObj->DriverData;
+ assert( t ); /* this _should_ be true */
+ if (t) {
+ savageTexImageChanged (t);
+ savageMarkDirtyTiles(t, level, texImage->Width2, texImage->Height2,
+ xoffset, yoffset, width, height);
+ } else {
+ t = savageAllocTexObj(texObj);
+ if (!t) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D");
+ return;
+ }
+ t->base.dirty_images[0] |= (1 << level);
+ }
+ _mesa_store_compressed_texsubimage2d(ctx, target, level, xoffset, yoffset,
+ width, height, format, imageSize,
+ data, texObj, texImage);
+ t->dirtySubImages |= (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 )
+{
+ savageTexObjPtr t = (savageTexObjPtr) tObj->DriverData;
+ savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+
+ if (!t || (target != GL_TEXTURE_1D && 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 );
+
+ assert( (target != GL_TEXTURE_1D && target != GL_TEXTURE_2D) ||
+ (tObj->DriverData != NULL) );
+
+ imesa->new_state |= SAVAGE_NEW_TEXTURE;
+}
+
+static void savageDeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj )
+{
+ driTextureObject *t = (driTextureObject *)tObj->DriverData;
+ savageContextPtr imesa = SAVAGE_CONTEXT( ctx );
+
+ if (t) {
+ if (t->bound)
+ savageTimestampTextures(imesa);
+
+ driDestroyTextureObject(t);
+ }
+ /* Free mipmap images and the texture object itself */
+ _mesa_delete_texture_object(ctx, tObj);
+}
+
+
+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->TexImage1D = savageTexImage1D;
+ functions->TexSubImage1D = savageTexSubImage1D;
+ functions->TexImage2D = savageTexImage2D;
+ functions->TexSubImage2D = savageTexSubImage2D;
+ functions->CompressedTexImage2D = savageCompressedTexImage2D;
+ functions->CompressedTexSubImage2D = savageCompressedTexSubImage2D;
+ functions->BindTexture = savageBindTexture;
+ functions->NewTextureObject = savageNewTextureObject;
+ functions->DeleteTexture = savageDeleteTexture;
+ functions->IsTextureResident = driIsTextureResident;
+ functions->TexParameter = savageTexParameter;
+
+ /* Texel fetching with our custom texture formats works just like
+ * the standard argb formats. */
+ _savage_texformat_a1114444.FetchTexel1D = _mesa_texformat_argb4444.FetchTexel1D;
+ _savage_texformat_a1114444.FetchTexel2D = _mesa_texformat_argb4444.FetchTexel2D;
+ _savage_texformat_a1114444.FetchTexel3D = _mesa_texformat_argb4444.FetchTexel3D;
+ _savage_texformat_a1114444.FetchTexel1Df= _mesa_texformat_argb4444.FetchTexel1Df;
+ _savage_texformat_a1114444.FetchTexel2Df= _mesa_texformat_argb4444.FetchTexel2Df;
+ _savage_texformat_a1114444.FetchTexel3Df= _mesa_texformat_argb4444.FetchTexel3Df;
+
+ _savage_texformat_a1118888.FetchTexel1D = _mesa_texformat_argb8888.FetchTexel1D;
+ _savage_texformat_a1118888.FetchTexel2D = _mesa_texformat_argb8888.FetchTexel2D;
+ _savage_texformat_a1118888.FetchTexel3D = _mesa_texformat_argb8888.FetchTexel3D;
+ _savage_texformat_a1118888.FetchTexel1Df= _mesa_texformat_argb8888.FetchTexel1Df;
+ _savage_texformat_a1118888.FetchTexel2Df= _mesa_texformat_argb8888.FetchTexel2Df;
+ _savage_texformat_a1118888.FetchTexel3Df= _mesa_texformat_argb8888.FetchTexel3Df;
+}
diff --git a/src/savagetex.h b/src/savagetex.h
new file mode 100644
index 0000000..f1ee722
--- /dev/null
+++ b/src/savagetex.h
@@ -0,0 +1,83 @@
+/*
+ * 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 "savagecontext.h"
+#include "texmem.h"
+
+#define SAVAGE_TEX_MAXLEVELS 12
+
+/** \brief Texture tiling information */
+typedef struct savage_tileinfo_t {
+ GLuint width, height; /**< tile width and height */
+ GLuint wInSub, hInSub; /**< tile width and height in subtiles */
+ GLuint subWidth, subHeight; /**< subtile width and height */
+ GLuint tinyOffset[2]; /**< internal offsets size 1 and 2 images */
+} savageTileInfo, *savageTileInfoPtr;
+
+typedef struct {
+ GLuint offset;
+ GLuint nTiles;
+ GLuint *dirtyTiles; /* bit vector of dirty tiles (still unused) */
+} savageTexImage;
+
+typedef struct {
+ driTextureObject base;
+
+ GLubyte *bufAddr;
+
+ GLuint age;
+ savageTexImage image[SAVAGE_TEX_MAXLEVELS];
+ GLuint dirtySubImages;
+
+ struct {
+ GLuint sWrapMode, tWrapMode;
+ GLuint minFilter, magFilter;
+ GLuint physAddr;
+ } setup;
+
+ GLuint hwFormat;
+ GLuint texelBytes;
+ const savageTileInfo *tileInfo;
+} savageTexObj, *savageTexObjPtr;
+
+#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)
+
+
+void savageUpdateTextureState( GLcontext *ctx );
+void savageDDInitTextureFuncs( struct dd_function_table *functions );
+
+void savageDestroyTexObj( savageContextPtr imesa, savageTexObjPtr t );
+
+#endif
diff --git a/src/savagetris.c b/src/savagetris.c
new file mode 100644
index 0000000..3dd821a
--- /dev/null
+++ b/src/savagetris.c
@@ -0,0 +1,1299 @@
+/* $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 "savageioctl.h"
+#include "savage_bci.h"
+
+static void savageRasterPrimitive( GLcontext *ctx, GLuint prim );
+static void savageRenderPrimitive( GLcontext *ctx, GLenum prim );
+
+
+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
+};
+
+
+/***********************************************************************
+ * Emit primitives *
+ ***********************************************************************/
+
+#if defined (USE_X86_ASM)
+#define EMIT_VERT( j, vb, vertex_size, start, v ) \
+do { int __tmp; \
+ vb += start; \
+ __asm__ __volatile__( "rep ; movsl" \
+ : "=%c" (j), "=D" (vb), "=S" (__tmp) \
+ : "0" (vertex_size-start), \
+ "D" ((long)vb), \
+ "S" ((long)&(v)->ui[start])); \
+} while (0)
+#else
+#define EMIT_VERT( j, vb, vertex_size, start, v ) \
+do { \
+ for ( j = start ; j < vertex_size ; j++ ) \
+ vb[j] = (v)->ui[j]; \
+ vb += vertex_size; \
+} while (0)
+#endif
+
+static void __inline__ savage_draw_triangle (savageContextPtr imesa,
+ savageVertexPtr v0,
+ savageVertexPtr v1,
+ savageVertexPtr v2) {
+ GLuint vertsize = imesa->HwVertexSize;
+ u_int32_t *vb = savageAllocVtxBuf (imesa, 3*vertsize);
+ GLuint j;
+
+ EMIT_VERT (j, vb, vertsize, 0, v0);
+ EMIT_VERT (j, vb, vertsize, 0, v1);
+ EMIT_VERT (j, vb, vertsize, 0, v2);
+}
+
+static void __inline__ savage_draw_quad (savageContextPtr imesa,
+ savageVertexPtr v0,
+ savageVertexPtr v1,
+ savageVertexPtr v2,
+ savageVertexPtr v3) {
+ GLuint vertsize = imesa->HwVertexSize;
+ u_int32_t *vb = savageAllocVtxBuf (imesa, 6*vertsize);
+ GLuint j;
+
+ EMIT_VERT (j, vb, vertsize, 0, v0);
+ EMIT_VERT (j, vb, vertsize, 0, v1);
+ EMIT_VERT (j, vb, vertsize, 0, v3);
+ EMIT_VERT (j, vb, vertsize, 0, v1);
+ EMIT_VERT (j, vb, vertsize, 0, v2);
+ EMIT_VERT (j, vb, vertsize, 0, v3);
+}
+
+static __inline__ void savage_draw_point (savageContextPtr imesa,
+ savageVertexPtr tmp) {
+ GLuint vertsize = imesa->HwVertexSize;
+ u_int32_t *vb = savageAllocVtxBuf (imesa, 6*vertsize);
+ const GLfloat x = tmp->v.x;
+ const GLfloat y = tmp->v.y;
+ const GLfloat sz = imesa->glCtx->Point._Size * .5;
+ GLuint j;
+
+ *(float *)&vb[0] = x - sz;
+ *(float *)&vb[1] = y - sz;
+ EMIT_VERT (j, vb, vertsize, 2, tmp);
+
+ *(float *)&vb[0] = x + sz;
+ *(float *)&vb[1] = y - sz;
+ EMIT_VERT (j, vb, vertsize, 2, tmp);
+
+ *(float *)&vb[0] = x + sz;
+ *(float *)&vb[1] = y + sz;
+ EMIT_VERT (j, vb, vertsize, 2, tmp);
+
+ *(float *)&vb[0] = x + sz;
+ *(float *)&vb[1] = y + sz;
+ EMIT_VERT (j, vb, vertsize, 2, tmp);
+
+ *(float *)&vb[0] = x - sz;
+ *(float *)&vb[1] = y + sz;
+ EMIT_VERT (j, vb, vertsize, 2, tmp);
+
+ *(float *)&vb[0] = x - sz;
+ *(float *)&vb[1] = y - sz;
+ EMIT_VERT (j, vb, vertsize, 2, tmp);
+}
+
+static __inline__ void savage_draw_line (savageContextPtr imesa,
+ savageVertexPtr v0,
+ savageVertexPtr v1 ) {
+ GLuint vertsize = imesa->HwVertexSize;
+ u_int32_t *vb = savageAllocVtxBuf (imesa, 6*vertsize);
+ GLfloat width = imesa->glCtx->Line._Width;
+ GLfloat dx, dy, ix, iy;
+ GLuint j;
+
+ dx = v0->v.x - v1->v.x;
+ dy = v0->v.y - v1->v.y;
+
+ ix = width * .5; iy = 0;
+ if (dx * dx > dy * dy) {
+ iy = ix; ix = 0;
+ }
+
+ *(float *)&vb[0] = v0->v.x - ix;
+ *(float *)&vb[1] = v0->v.y - iy;
+ EMIT_VERT (j, vb, vertsize, 2, v0);
+
+ *(float *)&vb[0] = v1->v.x + ix;
+ *(float *)&vb[1] = v1->v.y + iy;
+ EMIT_VERT (j, vb, vertsize, 2, v1);
+
+ *(float *)&vb[0] = v0->v.x + ix;
+ *(float *)&vb[1] = v0->v.y + iy;
+ EMIT_VERT (j, vb, vertsize, 2, v0);
+
+ *(float *)&vb[0] = v0->v.x - ix;
+ *(float *)&vb[1] = v0->v.y - iy;
+ EMIT_VERT (j, vb, vertsize, 2, v0);
+
+ *(float *)&vb[0] = v1->v.x - ix;
+ *(float *)&vb[1] = v1->v.y - iy;
+ EMIT_VERT (j, vb, vertsize, 2, v1);
+
+ *(float *)&vb[0] = v1->v.x + ix;
+ *(float *)&vb[1] = v1->v.y + iy;
+ EMIT_VERT (j, vb, vertsize, 2, v1);
+}
+
+/* Fallback drawing functions for the ptex hack. Code duplication
+ * (especially lines and points) isn't beautiful, but I didn't feel
+ * like inventing yet another template. :-/
+ */
+#define PTEX_VERTEX( j, tmp, vertex_size, start, v) \
+do { \
+ GLfloat rhw = 1.0 / v->f[vertex_size]; \
+ for ( j = start ; j < vertex_size ; j++ ) \
+ tmp.f[j] = v->f[j]; \
+ tmp.f[3] *= v->f[vertex_size]; \
+ tmp.f[vertex_size-2] *= rhw; \
+ tmp.f[vertex_size-1] *= rhw; \
+} while (0)
+
+static void __inline__ savage_ptex_tri (savageContextPtr imesa,
+ savageVertexPtr v0,
+ savageVertexPtr v1,
+ savageVertexPtr v2) {
+ GLuint vertsize = imesa->HwVertexSize;
+ u_int32_t *vb = savageAllocVtxBuf (imesa, 3*vertsize);
+ savageVertex tmp;
+ GLuint j;
+
+ PTEX_VERTEX (j, tmp, vertsize, 0, v0); EMIT_VERT (j, vb, vertsize, 0, &tmp);
+ PTEX_VERTEX (j, tmp, vertsize, 0, v1); EMIT_VERT (j, vb, vertsize, 0, &tmp);
+ PTEX_VERTEX (j, tmp, vertsize, 0, v2); EMIT_VERT (j, vb, vertsize, 0, &tmp);
+}
+
+static __inline__ void savage_ptex_line (savageContextPtr imesa,
+ savageVertexPtr v0,
+ savageVertexPtr v1 ) {
+ GLuint vertsize = imesa->HwVertexSize;
+ u_int32_t *vb = savageAllocVtxBuf (imesa, 6*vertsize);
+ GLfloat width = imesa->glCtx->Line._Width;
+ GLfloat dx, dy, ix, iy;
+ savageVertex tmp0, tmp1;
+ GLuint j;
+
+ PTEX_VERTEX (j, tmp0, vertsize, 2, v0);
+ PTEX_VERTEX (j, tmp1, vertsize, 2, v1);
+
+ dx = v0->v.x - v1->v.x;
+ dy = v0->v.y - v1->v.y;
+
+ ix = width * .5; iy = 0;
+ if (dx * dx > dy * dy) {
+ iy = ix; ix = 0;
+ }
+
+ *(float *)&vb[0] = v0->v.x - ix;
+ *(float *)&vb[1] = v0->v.y - iy;
+ EMIT_VERT (j, vb, vertsize, 2, &tmp0);
+
+ *(float *)&vb[0] = v1->v.x + ix;
+ *(float *)&vb[1] = v1->v.y + iy;
+ EMIT_VERT (j, vb, vertsize, 2, &tmp1);
+
+ *(float *)&vb[0] = v0->v.x + ix;
+ *(float *)&vb[1] = v0->v.y + iy;
+ EMIT_VERT (j, vb, vertsize, 2, &tmp0);
+
+ *(float *)&vb[0] = v0->v.x - ix;
+ *(float *)&vb[1] = v0->v.y - iy;
+ EMIT_VERT (j, vb, vertsize, 2, &tmp0);
+
+ *(float *)&vb[0] = v1->v.x - ix;
+ *(float *)&vb[1] = v1->v.y - iy;
+ EMIT_VERT (j, vb, vertsize, 2, &tmp1);
+
+ *(float *)&vb[0] = v1->v.x + ix;
+ *(float *)&vb[1] = v1->v.y + iy;
+ EMIT_VERT (j, vb, vertsize, 2, &tmp1);
+}
+
+static __inline__ void savage_ptex_point (savageContextPtr imesa,
+ savageVertexPtr v0) {
+ GLuint vertsize = imesa->HwVertexSize;
+ u_int32_t *vb = savageAllocVtxBuf (imesa, 6*vertsize);
+ const GLfloat x = v0->v.x;
+ const GLfloat y = v0->v.y;
+ const GLfloat sz = imesa->glCtx->Point._Size * .5;
+ savageVertex tmp;
+ GLuint j;
+
+ PTEX_VERTEX (j, tmp, vertsize, 2, v0);
+
+ *(float *)&vb[0] = x - sz;
+ *(float *)&vb[1] = y - sz;
+ EMIT_VERT (j, vb, vertsize, 2, &tmp);
+
+ *(float *)&vb[0] = x + sz;
+ *(float *)&vb[1] = y - sz;
+ EMIT_VERT (j, vb, vertsize, 2, &tmp);
+
+ *(float *)&vb[0] = x + sz;
+ *(float *)&vb[1] = y + sz;
+ EMIT_VERT (j, vb, vertsize, 2, &tmp);
+
+ *(float *)&vb[0] = x + sz;
+ *(float *)&vb[1] = y + sz;
+ EMIT_VERT (j, vb, vertsize, 2, &tmp);
+
+ *(float *)&vb[0] = x - sz;
+ *(float *)&vb[1] = y + sz;
+ EMIT_VERT (j, vb, vertsize, 2, &tmp);
+
+ *(float *)&vb[0] = x - sz;
+ *(float *)&vb[1] = y - sz;
+ EMIT_VERT (j, vb, vertsize, 2, &tmp);
+}
+
+/***********************************************************************
+ * Macros for t_dd_tritmp.h to draw basic primitives *
+ ***********************************************************************/
+
+#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 {
+ tnl_points_func points;
+ tnl_line_func line;
+ tnl_triangle_func triangle;
+ tnl_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 REVERSE_DEPTH 1
+#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 VERT_SET_RGBA( v, c ) \
+do { \
+ savage_color_t *color = (savage_color_t *)&((v)->ub4[coloroffset]); \
+ UNCLAMPED_FLOAT_TO_UBYTE(color->red, (c)[0]); \
+ UNCLAMPED_FLOAT_TO_UBYTE(color->green, (c)[1]); \
+ UNCLAMPED_FLOAT_TO_UBYTE(color->blue, (c)[2]); \
+ UNCLAMPED_FLOAT_TO_UBYTE(color->alpha, (c)[3]); \
+} while (0)
+#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 ) \
+do { \
+ if (specoffset) { \
+ savage_color_t *spec = (savage_color_t *)&((v)->ub4[specoffset]); \
+ UNCLAMPED_FLOAT_TO_UBYTE(spec->red, (c)[0]); \
+ UNCLAMPED_FLOAT_TO_UBYTE(spec->green, (c)[1]); \
+ UNCLAMPED_FLOAT_TO_UBYTE(spec->blue, (c)[2]); \
+ } \
+} while (0)
+#define VERT_COPY_SPEC( v0, v1 ) \
+ if (specoffset) COPY_3V(v0->ub4[specoffset], v1->ub4[specoffset])
+#define VERT_SAVE_SPEC( idx ) \
+ if (specoffset) spec[idx] = v[idx]->ui[specoffset]
+#define VERT_RESTORE_SPEC( idx ) \
+ if (specoffset) v[idx]->ui[specoffset] = spec[idx]
+
+#define LOCAL_VARS(n) \
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx); \
+ GLuint color[n], spec[n]; \
+ GLuint coloroffset = \
+ ((imesa->skip & SAVAGE_SKIP_W) ? 3 : 4); \
+ GLboolean specoffset = \
+ ((imesa->skip & SAVAGE_SKIP_C1) ? 0 : coloroffset+1); \
+ (void) color; (void) spec; (void) coloroffset; (void) specoffset;
+
+/***********************************************************************
+ * Helpers for rendering unfilled primitives *
+ ***********************************************************************/
+
+#define RASTERIZE(x) if (imesa->raster_primitive != reduced_prim[x]) \
+ savageRasterPrimitive( ctx, 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];
+ FLUSH_BATCH(imesa);
+ WAIT_IDLE_EMPTY(imesa);
+ _swsetup_Translate( ctx, v0, &v[0] );
+ _swsetup_Translate( ctx, v1, &v[1] );
+ _swsetup_Translate( 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];
+ FLUSH_BATCH(imesa);
+ WAIT_IDLE_EMPTY(imesa);
+ _swsetup_Translate( ctx, v0, &v[0] );
+ _swsetup_Translate( 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];
+ FLUSH_BATCH(imesa);
+ WAIT_IDLE_EMPTY(imesa);
+ _swsetup_Translate( 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_STIPPLE | \
+ _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_STIPPLE|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;
+
+ /* Hook in fallback functions for the ptex hack. Do this first, so
+ * that a real fallback will overwrite them with the respective
+ * savage_fallback_... function.
+ */
+ if (imesa->ptexHack) {
+ /* Do textures make sense with points? */
+ imesa->draw_point = savage_ptex_point;
+ imesa->draw_line = savage_ptex_line;
+ imesa->draw_tri = savage_ptex_tri;
+ index |= SAVAGE_FALLBACK_BIT;
+ } else {
+ imesa->draw_point = savage_draw_point;
+ imesa->draw_line = savage_draw_line;
+ imesa->draw_tri = savage_draw_triangle;
+ }
+
+ if (flags & (ANY_RASTER_FLAGS|ANY_FALLBACK_FLAGS)) {
+ 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 & ANY_FALLBACK_FLAGS) {
+ if (flags & POINT_FALLBACK) imesa->draw_point = savage_fallback_point;
+ if (flags & LINE_FALLBACK) imesa->draw_line = savage_fallback_line;
+ if (flags & TRI_FALLBACK) imesa->draw_tri = savage_fallback_tri;
+ index |= SAVAGE_FALLBACK_BIT;
+ if (SAVAGE_DEBUG & DEBUG_FALLBACKS) {
+ fprintf (stderr, "Per-primitive fallback, TriangleCaps=0x%x\n",
+ ctx->_TriangleCaps);
+ }
+ }
+ }
+
+ 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->no_rast)
+ FALLBACK(ctx, SAVAGE_FALLBACK_NORAST, GL_TRUE);
+
+ if (imesa->new_state)
+ savageDDUpdateHwState( ctx );
+
+ if (!imesa->Fallback) {
+ if (imesa->new_gl_state & _SAVAGE_NEW_RENDER_STATE)
+ savageChooseRenderState( ctx );
+
+ /* choose the correct primitive type for tnl rendering */
+ if (imesa->savageScreen->chipset < S3_SAVAGE4 &&
+ (ctx->_TriangleCaps & DD_FLATSHADE)) {
+ if (imesa->HwPrim != SAVAGE_PRIM_TRILIST_201)
+ savageFlushVertices(imesa);
+ imesa->HwPrim = SAVAGE_PRIM_TRILIST_201;
+ } else {
+ if (imesa->HwPrim != SAVAGE_PRIM_TRILIST)
+ savageFlushVertices(imesa);
+ imesa->HwPrim = SAVAGE_PRIM_TRILIST;
+ }
+
+ imesa->new_gl_state = 0;
+ }
+
+ _tnl_run_pipeline( ctx );
+
+ if (imesa->no_rast)
+ FALLBACK(ctx, SAVAGE_FALLBACK_NORAST, GL_FALSE);
+}
+
+/**********************************************************************/
+/* High level hooks for t_vb_render.c */
+/**********************************************************************/
+
+/* 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 );
+
+ /* Update culling */
+ if (imesa->raster_primitive != prim) {
+ imesa->raster_primitive = prim;
+ imesa->new_state |= SAVAGE_NEW_CULL;
+ savageDDUpdateHwState (ctx);
+ }
+
+#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 );
+ }
+}
+
+/* Check if projective texture coordinates are used and if we can fake
+ * them. Fallback to swrast we can't. Returns GL_TRUE if projective
+ * texture coordinates must be faked, GL_FALSE otherwise.
+ */
+static GLboolean savageCheckPTexHack( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ DECLARE_RENDERINPUTS(index_bitset);
+
+ RENDERINPUTS_COPY( index_bitset, tnl->render_inputs_bitset );
+
+ if (RENDERINPUTS_TEST( index_bitset, _TNL_ATTRIB_TEX0 ) && VB->TexCoordPtr[0]->size == 4) {
+ if (!RENDERINPUTS_TEST_RANGE( index_bitset, _TNL_ATTRIB_TEX1, _TNL_LAST_TEX ))
+ return GL_TRUE; /* apply ptex hack */
+ else
+ FALLBACK(ctx, SAVAGE_FALLBACK_PROJ_TEXTURE, GL_TRUE);
+ }
+ if (RENDERINPUTS_TEST( index_bitset, _TNL_ATTRIB_TEX1 ) && VB->TexCoordPtr[1]->size == 4)
+ FALLBACK(ctx, SAVAGE_FALLBACK_PROJ_TEXTURE, GL_TRUE);
+
+ return GL_FALSE; /* don't apply ptex hack */
+}
+
+
+#define DO_EMIT_ATTR( ATTR, STYLE ) \
+do { \
+ imesa->vertex_attrs[imesa->vertex_attr_count].attrib = (ATTR); \
+ imesa->vertex_attrs[imesa->vertex_attr_count].format = (STYLE); \
+ imesa->vertex_attr_count++; \
+} while (0)
+
+#define NEED_ATTR( INDEX, SKIP ) \
+do { \
+ setupIndex |= (INDEX); \
+ skip &= ~(SKIP); \
+} while (0)
+
+#define EMIT_ATTR( ATTR, STYLE, INDEX, SKIP ) \
+do { \
+ NEED_ATTR( INDEX, SKIP ); \
+ DO_EMIT_ATTR( ATTR, STYLE ); \
+} while (0)
+
+#define EMIT_PAD( N ) \
+do { \
+ imesa->vertex_attrs[imesa->vertex_attr_count].attrib = 0; \
+ imesa->vertex_attrs[imesa->vertex_attr_count].format = EMIT_PAD; \
+ imesa->vertex_attrs[imesa->vertex_attr_count].offset = (N); \
+ imesa->vertex_attr_count++; \
+} while (0)
+
+#define SAVAGE_EMIT_XYZ 0x0001
+#define SAVAGE_EMIT_W 0x0002
+#define SAVAGE_EMIT_C0 0x0004
+#define SAVAGE_EMIT_C1 0x0008
+#define SAVAGE_EMIT_FOG 0x0010
+#define SAVAGE_EMIT_S0 0x0020
+#define SAVAGE_EMIT_T0 0x0040
+#define SAVAGE_EMIT_Q0 0x0080
+#define SAVAGE_EMIT_ST0 0x0060
+#define SAVAGE_EMIT_STQ0 0x00e0
+#define SAVAGE_EMIT_S1 0x0100
+#define SAVAGE_EMIT_T1 0x0200
+#define SAVAGE_EMIT_ST1 0x0300
+
+
+static __inline__ GLuint savageChooseVertexFormat_s3d( GLcontext *ctx )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ DECLARE_RENDERINPUTS(index_bitset);
+ GLuint setupIndex = SAVAGE_EMIT_XYZ;
+ GLubyte skip;
+
+ RENDERINPUTS_COPY( index_bitset, tnl->render_inputs_bitset );
+ imesa->vertex_attr_count = 0;
+
+ skip = SAVAGE_SKIP_ALL_S3D;
+ skip &= ~SAVAGE_SKIP_Z; /* all mesa vertices have a z coordinate */
+
+ /* EMIT_ATTR's must be in order as they tell t_vertex.c how to
+ * build up a hardware vertex.
+ */
+ if (RENDERINPUTS_TEST_RANGE( index_bitset, _TNL_FIRST_TEX, _TNL_LAST_TEX ) || !(ctx->_TriangleCaps & DD_FLATSHADE))
+ EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_4F_VIEWPORT, SAVAGE_EMIT_W, SAVAGE_SKIP_W );
+ else {
+ EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_3F_VIEWPORT, 0, 0 );
+ EMIT_PAD( 4 );
+ skip &= ~SAVAGE_SKIP_W;
+ }
+
+ /* t_context.c always includes a diffuse color */
+ EMIT_ATTR( _TNL_ATTRIB_COLOR0, EMIT_4UB_4F_BGRA, SAVAGE_EMIT_C0, SAVAGE_SKIP_C0 );
+
+ if (RENDERINPUTS_TEST( index_bitset, _TNL_ATTRIB_COLOR1 ))
+ EMIT_ATTR( _TNL_ATTRIB_COLOR1, EMIT_3UB_3F_BGR, SAVAGE_EMIT_C1, SAVAGE_SKIP_C1 );
+ else
+ EMIT_PAD( 3 );
+ if (RENDERINPUTS_TEST( index_bitset, _TNL_ATTRIB_FOG ))
+ EMIT_ATTR( _TNL_ATTRIB_FOG, EMIT_1UB_1F, SAVAGE_EMIT_FOG, SAVAGE_SKIP_C1 );
+ else
+ EMIT_PAD( 1 );
+ skip &= ~SAVAGE_SKIP_C1;
+
+ if (RENDERINPUTS_TEST( index_bitset, _TNL_ATTRIB_TEX0 )) {
+ if (imesa->ptexHack)
+ EMIT_ATTR( _TNL_ATTRIB_TEX0, EMIT_3F_XYW, SAVAGE_EMIT_STQ0, SAVAGE_SKIP_ST0);
+ else if (VB->TexCoordPtr[0]->size == 4)
+ assert (0); /* should be caught by savageCheckPTexHack */
+ else if (VB->TexCoordPtr[0]->size >= 2)
+ /* The chromium menu emits some 3D tex coords even though no
+ * 3D texture is enabled. Ignore the 3rd coordinate. */
+ EMIT_ATTR( _TNL_ATTRIB_TEX0, EMIT_2F, SAVAGE_EMIT_ST0, SAVAGE_SKIP_ST0 );
+ else if (VB->TexCoordPtr[0]->size == 1) {
+ EMIT_ATTR( _TNL_ATTRIB_TEX0, EMIT_1F, SAVAGE_EMIT_S0, SAVAGE_SKIP_S0 );
+ EMIT_PAD( 4 );
+ } else
+ EMIT_PAD( 8 );
+ } else
+ EMIT_PAD( 8 );
+ skip &= ~SAVAGE_SKIP_ST0;
+
+ assert (skip == 0);
+ imesa->skip = skip;
+ return setupIndex;
+}
+
+
+static __inline__ GLuint savageChooseVertexFormat_s4( GLcontext *ctx )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ DECLARE_RENDERINPUTS(index_bitset);
+ GLuint setupIndex = SAVAGE_EMIT_XYZ;
+ GLubyte skip;
+ GLuint size, mask;
+
+ RENDERINPUTS_COPY( index_bitset, tnl->render_inputs_bitset );
+ skip = SAVAGE_SKIP_ALL_S4;
+ skip &= ~SAVAGE_SKIP_Z; /* all mesa vertices have a z coordinate */
+
+ if (RENDERINPUTS_TEST_RANGE( index_bitset, _TNL_FIRST_TEX, _TNL_LAST_TEX ) || !(ctx->_TriangleCaps & DD_FLATSHADE))
+ NEED_ATTR( SAVAGE_EMIT_W, SAVAGE_SKIP_W );
+
+ /* t_context.c always includes a diffuse color */
+ NEED_ATTR( SAVAGE_EMIT_C0, SAVAGE_SKIP_C0 );
+
+ if (RENDERINPUTS_TEST( index_bitset, _TNL_ATTRIB_COLOR1 ))
+ NEED_ATTR( SAVAGE_EMIT_C1, SAVAGE_SKIP_C1 );
+ if (RENDERINPUTS_TEST( index_bitset, _TNL_ATTRIB_FOG ))
+ NEED_ATTR( SAVAGE_EMIT_FOG, SAVAGE_SKIP_C1 );
+
+ if (RENDERINPUTS_TEST( index_bitset, _TNL_ATTRIB_TEX0 )) {
+ if (imesa->ptexHack)
+ NEED_ATTR( SAVAGE_EMIT_STQ0, SAVAGE_SKIP_ST0);
+ else if (VB->TexCoordPtr[0]->size == 4)
+ assert (0); /* should be caught by savageCheckPTexHack */
+ else if (VB->TexCoordPtr[0]->size >= 2)
+ /* The chromium menu emits some 3D tex coords even though no
+ * 3D texture is enabled. Ignore the 3rd coordinate. */
+ NEED_ATTR( SAVAGE_EMIT_ST0, SAVAGE_SKIP_ST0 );
+ else
+ NEED_ATTR( SAVAGE_EMIT_S0, SAVAGE_SKIP_S0 );
+ }
+ if (RENDERINPUTS_TEST( index_bitset, _TNL_ATTRIB_TEX1 )) {
+ if (VB->TexCoordPtr[1]->size == 4)
+ /* projective textures are not supported by the hardware */
+ assert (0); /* should be caught by savageCheckPTexHack */
+ else if (VB->TexCoordPtr[1]->size >= 2)
+ NEED_ATTR( SAVAGE_EMIT_ST1, SAVAGE_SKIP_ST1 );
+ else
+ NEED_ATTR( SAVAGE_EMIT_S1, SAVAGE_SKIP_S1 );
+ }
+
+ /* if nothing changed we can skip the rest */
+ if (setupIndex == imesa->SetupIndex && imesa->vertex_size != 0)
+ return setupIndex;
+
+ if (imesa->enable_vdma) {
+ mask = SAVAGE_SKIP_W;
+ size = 10 - (skip & 1) - (skip >> 1 & 1) -
+ (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) -
+ (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
+
+ while (size < 8) {
+ if (skip & mask) {
+ skip &= ~mask;
+ size++;
+ }
+ mask <<= 1;
+ }
+ }
+
+ imesa->vertex_attr_count = 0;
+
+ if (skip & SAVAGE_SKIP_W)
+ DO_EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_3F_VIEWPORT );
+ else if (setupIndex & SAVAGE_EMIT_W)
+ DO_EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_4F_VIEWPORT );
+ else {
+ DO_EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_3F_VIEWPORT );
+ EMIT_PAD( 4 );
+ }
+
+ DO_EMIT_ATTR( _TNL_ATTRIB_COLOR0, EMIT_4UB_4F_BGRA );
+
+ if (!(skip & SAVAGE_SKIP_C1)) {
+ if (!(setupIndex & (SAVAGE_EMIT_C1|SAVAGE_EMIT_FOG)))
+ EMIT_PAD( 4 );
+ else {
+ if (setupIndex & SAVAGE_EMIT_C1)
+ DO_EMIT_ATTR( _TNL_ATTRIB_COLOR1, EMIT_3UB_3F_BGR );
+ else
+ EMIT_PAD( 3 );
+ if (setupIndex & SAVAGE_EMIT_FOG)
+ DO_EMIT_ATTR( _TNL_ATTRIB_FOG, EMIT_1UB_1F );
+ else
+ EMIT_PAD( 1 );
+ }
+ }
+
+ if ((skip & SAVAGE_SKIP_ST0) != SAVAGE_SKIP_ST0) {
+ if ((setupIndex & SAVAGE_EMIT_STQ0) == SAVAGE_EMIT_STQ0)
+ DO_EMIT_ATTR( _TNL_ATTRIB_TEX0, EMIT_3F_XYW );
+ else if ((setupIndex & SAVAGE_EMIT_ST0) == SAVAGE_EMIT_ST0)
+ DO_EMIT_ATTR( _TNL_ATTRIB_TEX0, EMIT_2F );
+ else if ((setupIndex & SAVAGE_EMIT_ST0) == SAVAGE_EMIT_S0) {
+ DO_EMIT_ATTR( _TNL_ATTRIB_TEX0, EMIT_1F );
+ if (!(skip & SAVAGE_SKIP_T0)) EMIT_PAD( 4 );
+ } else {
+ if (!(skip & SAVAGE_SKIP_S0)) EMIT_PAD( 4 );
+ if (!(skip & SAVAGE_SKIP_T0)) EMIT_PAD( 4 );
+ }
+ }
+
+ if ((skip & SAVAGE_SKIP_ST1) != SAVAGE_SKIP_ST1) {
+ if ((setupIndex & SAVAGE_EMIT_ST1) == SAVAGE_EMIT_ST1)
+ DO_EMIT_ATTR( _TNL_ATTRIB_TEX1, EMIT_2F );
+ else if ((setupIndex & SAVAGE_EMIT_ST1) == SAVAGE_EMIT_S1) {
+ DO_EMIT_ATTR( _TNL_ATTRIB_TEX1, EMIT_1F );
+ if (!(skip & SAVAGE_SKIP_T1)) EMIT_PAD( 4 );
+ } else {
+ if (!(skip & SAVAGE_SKIP_S1)) EMIT_PAD( 4 );
+ if (!(skip & SAVAGE_SKIP_T1)) EMIT_PAD( 4 );
+ }
+ }
+
+ imesa->skip = skip;
+ return setupIndex;
+}
+
+
+static void savageRenderStart( GLcontext *ctx )
+{
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLuint setupIndex = SAVAGE_EMIT_XYZ;
+ GLboolean ptexHack;
+
+ /* Check if we need to apply the ptex hack. Choose a new render
+ * state if necessary. (Note: this can't be done in
+ * savageRunPipeline, since the number of vertex coordinates can
+ * change in the pipeline. texmat or texgen or both?) */
+ ptexHack = savageCheckPTexHack( ctx );
+ if (ptexHack != imesa->ptexHack) {
+ imesa->ptexHack = ptexHack;
+ savageChooseRenderState (ctx);
+ }
+ /* Handle fallback cases identified in savageCheckPTexHack. */
+ if (SAVAGE_CONTEXT(ctx)->Fallback) {
+ tnl->Driver.Render.Start(ctx);
+ return;
+ }
+
+ /* Important:
+ */
+ VB->AttribPtr[VERT_ATTRIB_POS] = VB->NdcPtr;
+
+ if (imesa->savageScreen->chipset < S3_SAVAGE4) {
+ setupIndex = savageChooseVertexFormat_s3d(ctx);
+ } else {
+ setupIndex = savageChooseVertexFormat_s4(ctx);
+ }
+
+ /* Need to change the vertex emit code if the SetupIndex changed or
+ * is set for the first time (indicated by vertex_size == 0). */
+ if (setupIndex != imesa->SetupIndex || imesa->vertex_size == 0) {
+ GLuint hwVertexSize;
+ imesa->vertex_size =
+ _tnl_install_attrs( ctx,
+ imesa->vertex_attrs,
+ imesa->vertex_attr_count,
+ imesa->hw_viewport, 0 );
+ imesa->vertex_size >>= 2;
+ imesa->SetupIndex = setupIndex;
+
+ hwVertexSize = imesa->vertex_size;
+ if (setupIndex & SAVAGE_EMIT_Q0) {
+ /* The vertex setup code emits homogenous texture
+ * coordinates. They are converted to normal 2D coords by
+ * savage_ptex_tri/line/point. Now we have two different
+ * vertex sizes. Functions that emit vertices to the hardware
+ * need to use HwVertexSize, anything that manipulates the
+ * vertices generated by t_vertex uses vertex_size. */
+ hwVertexSize--;
+ assert (imesa->ptexHack);
+ } else
+ assert (!imesa->ptexHack);
+
+ if (hwVertexSize != imesa->HwVertexSize) {
+ /* Changing the vertex size: flush vertex and command buffer and
+ * discard the DMA buffer, if we were using one. */
+ savageFlushVertices(imesa);
+ savageFlushCmdBuf(imesa, GL_TRUE);
+ if (hwVertexSize == 8 && imesa->enable_vdma) {
+ if (SAVAGE_DEBUG & DEBUG_DMA)
+ fprintf (stderr, "Using DMA, skip=0x%02x\n", imesa->skip);
+ /* we can use vertex dma */
+ imesa->vtxBuf = &imesa->dmaVtxBuf;
+ } else {
+ if (SAVAGE_DEBUG & DEBUG_DMA)
+ fprintf (stderr, "Not using DMA, skip=0x%02x\n", imesa->skip);
+ imesa->vtxBuf = &imesa->clientVtxBuf;
+ }
+ imesa->HwVertexSize = hwVertexSize;
+ }
+ }
+}
+
+static void savageRenderFinish( GLcontext *ctx )
+{
+ /* Flush the last primitive now, before any state is changed. */
+ savageFlushVertices(SAVAGE_CONTEXT(ctx));
+
+ if (SAVAGE_CONTEXT(ctx)->RenderIndex & SAVAGE_FALLBACK_BIT)
+ _swrast_flush( ctx );
+}
+
+
+/**********************************************************************/
+/* Transition to/from hardware rasterization. */
+/**********************************************************************/
+
+static const char * const fallbackStrings[] = {
+ "Texture mode",
+ "Draw buffer",
+ "Read buffer",
+ "Color mask",
+ "Specular",
+ "LogicOp",
+ "glEnable(GL_STENCIL) without hw stencil buffer",
+ "glRenderMode(selection or feedback)",
+ "glBlendEquation",
+ "Hardware rasterization disabled",
+ "Projective texture",
+};
+
+void savageFallback( GLcontext *ctx, GLuint bit, GLboolean mode )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
+ GLuint oldfallback = imesa->Fallback;
+ GLuint index;
+ for (index = 0; (1 << index) < bit; ++index);
+
+ if (mode) {
+ imesa->Fallback |= bit;
+ if (oldfallback == 0) {
+ /* the first fallback */
+ _swsetup_Wakeup( ctx );
+ imesa->RenderIndex = ~0;
+ }
+ if (!(oldfallback & bit) && (SAVAGE_DEBUG & DEBUG_FALLBACKS))
+ fprintf (stderr, "Savage begin fallback: 0x%x %s\n",
+ bit, fallbackStrings[index]);
+ }
+ 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 = _tnl_build_vertices;
+ tnl->Driver.Render.CopyPV = _tnl_copy_pv;
+ tnl->Driver.Render.Interp = _tnl_interp;
+
+ _tnl_invalidate_vertex_state( ctx, ~0 );
+ _tnl_invalidate_vertices( ctx, ~0 );
+ _tnl_install_attrs( ctx,
+ imesa->vertex_attrs,
+ imesa->vertex_attr_count,
+ imesa->hw_viewport, 0 );
+
+ imesa->new_gl_state |= _SAVAGE_NEW_RENDER_STATE;
+ }
+ if ((oldfallback & bit) && (SAVAGE_DEBUG & DEBUG_FALLBACKS))
+ fprintf (stderr, "Savage end fallback: 0x%x %s\n",
+ bit, fallbackStrings[index]);
+ }
+}
+
+
+/**********************************************************************/
+/* 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 = _tnl_build_vertices;
+ tnl->Driver.Render.CopyPV = _tnl_copy_pv;
+ tnl->Driver.Render.Interp = _tnl_interp;
+
+ _tnl_init_vertices( ctx, ctx->Const.MaxArrayLockSize + 12,
+ (6 + 2*ctx->Const.MaxTextureUnits) * sizeof(GLfloat) );
+
+ SAVAGE_CONTEXT(ctx)->verts = (char *)tnl->clipspace.vertex_buf;
+}
diff --git a/src/savagetris.h b/src/savagetris.h
new file mode 100644
index 0000000..00803e7
--- /dev/null
+++ b/src/savagetris.h
@@ -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/server/savage_dri.h b/src/server/savage_dri.h
new file mode 100644
index 0000000..214d985
--- /dev/null
+++ b/src/server/savage_dri.h
@@ -0,0 +1,76 @@
+/*
+ * 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_DRI_H__
+#define __SAVAGE_DRI_H__
+
+#include "drm.h"
+
+typedef struct {
+ int chipset;
+ int width;
+ int height;
+ int mem;
+ int cpp;
+ int zpp;
+
+ int agpMode; /* 0 for PCI cards */
+
+ unsigned int sarea_priv_offset;
+
+ unsigned int bufferSize; /* size of DMA buffers */
+
+ unsigned int frontbufferSize;
+ unsigned int frontOffset;
+
+ unsigned int backbufferSize;
+ unsigned int backOffset;
+
+ unsigned int depthbufferSize;
+ unsigned int depthOffset;
+
+ unsigned int textureOffset;
+ unsigned int textureSize;
+ int logTextureGranularity;
+
+ /* Linear aperture */
+ drm_handle_t apertureHandle;
+ unsigned int apertureSize;
+ unsigned int aperturePitch; /* in byte */
+
+ /* Status page (probably not needed, but no harm, read-only) */
+ drm_handle_t statusHandle;
+ unsigned int statusSize;
+
+ /* AGP textures */
+ drm_handle_t agpTextureHandle;
+ unsigned int agpTextureSize;
+ int logAgpTextureGranularity;
+
+ /* Not sure about this one */
+ drm_handle_t xvmcSurfHandle; /* ? */
+} SAVAGEDRIRec, *SAVAGEDRIPtr;
+
+#endif