diff options
-rw-r--r-- | configure.ac | 5 | ||||
-rw-r--r-- | src/Makefile.am | 19 | ||||
-rw-r--r-- | src/savage_3d_reg.h | 711 | ||||
-rw-r--r-- | src/savage_bci.h | 612 | ||||
-rw-r--r-- | src/savage_init.h | 157 | ||||
-rw-r--r-- | src/savage_xmesa.c | 1079 | ||||
-rw-r--r-- | src/savagecontext.h | 322 | ||||
-rw-r--r-- | src/savagedd.c | 101 | ||||
-rw-r--r-- | src/savagedd.h | 32 | ||||
-rw-r--r-- | src/savageioctl.c | 662 | ||||
-rw-r--r-- | src/savageioctl.h | 203 | ||||
-rw-r--r-- | src/savagerender.c | 370 | ||||
-rw-r--r-- | src/savagespan.c | 277 | ||||
-rw-r--r-- | src/savagespan.h | 137 | ||||
-rw-r--r-- | src/savagestate.c | 1728 | ||||
-rw-r--r-- | src/savagestate.h | 41 | ||||
-rw-r--r-- | src/savagetex.c | 2100 | ||||
-rw-r--r-- | src/savagetex.h | 83 | ||||
-rw-r--r-- | src/savagetris.c | 1299 | ||||
-rw-r--r-- | src/savagetris.h | 49 | ||||
-rw-r--r-- | src/server/savage_dri.h | 76 |
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 |