diff options
Diffstat (limited to 'src/mesa/drivers/dri/savage/savagestate.c')
-rw-r--r-- | src/mesa/drivers/dri/savage/savagestate.c | 1746 |
1 files changed, 1746 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/savage/savagestate.c b/src/mesa/drivers/dri/savage/savagestate.c new file mode 100644 index 00000000000..44cf2f20d37 --- /dev/null +++ b/src/mesa/drivers/dri/savage/savagestate.c @@ -0,0 +1,1746 @@ +/* + * 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 "array_cache/acache.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; + + imesa->NotFirstFrame = GL_FALSE; + savageXMesaSetFrontClipRects( imesa ); + FALLBACK( ctx, SAVAGE_FALLBACK_DRAW_BUFFER, GL_FALSE ); + break; + case BUFFER_BIT_BACK_LEFT: + imesa->IsDouble = GL_TRUE; + imesa->regs.s4.destCtrl.ni.offset = imesa->savageScreen->backOffset>>11; + imesa->NotFirstFrame = GL_FALSE; + savageXMesaSetBackClipRects( imesa ); + FALLBACK( ctx, SAVAGE_FALLBACK_DRAW_BUFFER, GL_FALSE ); + break; + default: + FALLBACK( ctx, SAVAGE_FALLBACK_DRAW_BUFFER, GL_TRUE ); + return; + } + + 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]; + imesa->regs.s4.stencilCtrl.ni.readMask = ctx->Stencil.ValueMask[0]; + + 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]) { + imesa->regs.s4.stencilCtrl.ni.writeMask = ctx->Stencil.WriteMask[0]; + 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 ); + _ac_InvalidateState( ctx, new_state ); + _tnl_InvalidateState( ctx, new_state ); + SAVAGE_CONTEXT(ctx)->new_gl_state |= new_state; +} + + +void savageDDInitStateFuncs(GLcontext *ctx) +{ + ctx->Driver.UpdateState = savageDDInvalidateState; + ctx->Driver.BlendEquationSeparate = savageDDBlendEquationSeparate; + ctx->Driver.Fogfv = savageDDFogfv; + ctx->Driver.Scissor = savageDDScissor; +#if HW_CULL + ctx->Driver.CullFace = savageDDCullFaceFrontFace; + ctx->Driver.FrontFace = savageDDCullFaceFrontFace; +#else + ctx->Driver.CullFace = 0; + ctx->Driver.FrontFace = 0; +#endif /* end #if HW_CULL */ + ctx->Driver.PolygonMode=NULL; + ctx->Driver.PolygonStipple = 0; + ctx->Driver.LineStipple = 0; + ctx->Driver.LineWidth = 0; + ctx->Driver.LogicOpcode = 0; + ctx->Driver.DrawBuffer = savageDDDrawBuffer; + ctx->Driver.ReadBuffer = savageDDReadBuffer; + ctx->Driver.ClearColor = savageDDClearColor; + + ctx->Driver.DepthRange = savageDepthRange; + ctx->Driver.Viewport = savageViewport; + ctx->Driver.RenderMode = savageRenderMode; + + ctx->Driver.ClearIndex = 0; + ctx->Driver.IndexMask = 0; + + if (SAVAGE_CONTEXT( ctx )->savageScreen->chipset >= S3_SAVAGE4) { + ctx->Driver.Enable = savageDDEnable_s4; + ctx->Driver.AlphaFunc = savageDDAlphaFunc_s4; + ctx->Driver.DepthFunc = savageDDDepthFunc_s4; + ctx->Driver.DepthMask = savageDDDepthMask_s4; + ctx->Driver.BlendFuncSeparate = savageDDBlendFuncSeparate_s4; + ctx->Driver.ColorMask = savageDDColorMask_s4; + ctx->Driver.ShadeModel = savageDDShadeModel_s4; + ctx->Driver.LightModelfv = savageDDLightModelfv_s4; + 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; + } + + /* Swrast hooks for imaging extensions: + */ + ctx->Driver.CopyColorTable = _swrast_CopyColorTable; + ctx->Driver.CopyColorSubTable = _swrast_CopyColorSubTable; + ctx->Driver.CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D; + ctx->Driver.CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D; +} |