/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_state.c,v 1.8 2002/12/16 16:18:58 dawes Exp $ */ /* * Copyright 2000, 2001 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 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Gareth Hughes * Keith Whitwell */ #include "radeon_context.h" #include "radeon_ioctl.h" #include "radeon_state.h" #include "radeon_tcl.h" #include "radeon_tex.h" #include "radeon_swtcl.h" #include "radeon_vtxfmt.h" #include "mem.h" #include "mmath.h" #include "enums.h" #include "colormac.h" #include "light.h" #include "api_arrayelt.h" #include "swrast/swrast.h" #include "array_cache/acache.h" #include "tnl/tnl.h" #include "tnl/t_pipeline.h" #include "swrast_setup/swrast_setup.h" #define MODEL_PROJ 0 #define MODEL 1 #define MODEL_IT 2 #define TEXMAT_0 3 #define TEXMAT_1 4 #define TEXMAT_2 5 /* ============================================================= * Alpha blending */ static void radeonAlphaFunc( GLcontext *ctx, GLenum func, GLchan ref ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); int pp_misc = rmesa->hw.ctx.cmd[CTX_PP_MISC]; RADEON_STATECHANGE( rmesa, ctx ); pp_misc &= ~(RADEON_ALPHA_TEST_OP_MASK | RADEON_REF_ALPHA_MASK); pp_misc |= (ref & RADEON_REF_ALPHA_MASK); switch ( func ) { case GL_NEVER: pp_misc |= RADEON_ALPHA_TEST_FAIL; break; case GL_LESS: pp_misc |= RADEON_ALPHA_TEST_LESS; break; case GL_EQUAL: pp_misc |= RADEON_ALPHA_TEST_EQUAL; break; case GL_LEQUAL: pp_misc |= RADEON_ALPHA_TEST_LEQUAL; break; case GL_GREATER: pp_misc |= RADEON_ALPHA_TEST_GREATER; break; case GL_NOTEQUAL: pp_misc |= RADEON_ALPHA_TEST_NEQUAL; break; case GL_GEQUAL: pp_misc |= RADEON_ALPHA_TEST_GEQUAL; break; case GL_ALWAYS: pp_misc |= RADEON_ALPHA_TEST_PASS; break; } rmesa->hw.ctx.cmd[CTX_PP_MISC] = pp_misc; } static void radeonBlendEquation( GLcontext *ctx, GLenum mode ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLuint b = rmesa->hw.ctx.cmd[CTX_RB3D_BLENDCNTL] & ~RADEON_COMB_FCN_MASK; GLboolean fallback = GL_FALSE; switch ( mode ) { case GL_FUNC_ADD: case GL_LOGIC_OP: b |= RADEON_COMB_FCN_ADD_CLAMP; break; case GL_FUNC_SUBTRACT: b |= RADEON_COMB_FCN_SUB_CLAMP; break; default: fallback = GL_TRUE; break; } FALLBACK( rmesa, RADEON_FALLBACK_BLEND_EQ, fallback ); if ( !fallback ) { RADEON_STATECHANGE( rmesa, ctx ); rmesa->hw.ctx.cmd[CTX_RB3D_BLENDCNTL] = b; if ( ctx->Color.ColorLogicOpEnabled ) { rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_ROP_ENABLE; } else { rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_ROP_ENABLE; } } } static void radeonBlendFunc( GLcontext *ctx, GLenum sfactor, GLenum dfactor ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLuint b = rmesa->hw.ctx.cmd[CTX_RB3D_BLENDCNTL] & ~(RADEON_SRC_BLEND_MASK | RADEON_DST_BLEND_MASK); GLboolean fallback = GL_FALSE; switch ( ctx->Color.BlendSrcRGB ) { case GL_ZERO: b |= RADEON_SRC_BLEND_GL_ZERO; break; case GL_ONE: b |= RADEON_SRC_BLEND_GL_ONE; break; case GL_DST_COLOR: b |= RADEON_SRC_BLEND_GL_DST_COLOR; break; case GL_ONE_MINUS_DST_COLOR: b |= RADEON_SRC_BLEND_GL_ONE_MINUS_DST_COLOR; break; case GL_SRC_COLOR: b |= RADEON_SRC_BLEND_GL_SRC_COLOR; break; case GL_ONE_MINUS_SRC_COLOR: b |= RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_COLOR; break; case GL_SRC_ALPHA: b |= RADEON_SRC_BLEND_GL_SRC_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: b |= RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_ALPHA; break; case GL_DST_ALPHA: b |= RADEON_SRC_BLEND_GL_DST_ALPHA; break; case GL_ONE_MINUS_DST_ALPHA: b |= RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA; break; case GL_SRC_ALPHA_SATURATE: b |= RADEON_SRC_BLEND_GL_SRC_ALPHA_SATURATE; break; case GL_CONSTANT_COLOR: case GL_ONE_MINUS_CONSTANT_COLOR: case GL_CONSTANT_ALPHA: case GL_ONE_MINUS_CONSTANT_ALPHA: fallback = GL_TRUE; break; } switch ( ctx->Color.BlendDstRGB ) { case GL_ZERO: b |= RADEON_DST_BLEND_GL_ZERO; break; case GL_ONE: b |= RADEON_DST_BLEND_GL_ONE; break; case GL_SRC_COLOR: b |= RADEON_DST_BLEND_GL_SRC_COLOR; break; case GL_ONE_MINUS_SRC_COLOR: b |= RADEON_DST_BLEND_GL_ONE_MINUS_SRC_COLOR; break; case GL_SRC_ALPHA: b |= RADEON_DST_BLEND_GL_SRC_ALPHA; break; case GL_ONE_MINUS_SRC_ALPHA: b |= RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA; break; case GL_DST_COLOR: b |= RADEON_DST_BLEND_GL_DST_COLOR; break; case GL_ONE_MINUS_DST_COLOR: b |= RADEON_DST_BLEND_GL_ONE_MINUS_DST_COLOR; break; case GL_DST_ALPHA: b |= RADEON_DST_BLEND_GL_DST_ALPHA; break; case GL_ONE_MINUS_DST_ALPHA: b |= RADEON_DST_BLEND_GL_ONE_MINUS_DST_ALPHA; break; case GL_CONSTANT_COLOR: case GL_ONE_MINUS_CONSTANT_COLOR: case GL_CONSTANT_ALPHA: case GL_ONE_MINUS_CONSTANT_ALPHA: fallback = GL_TRUE; break; } FALLBACK( rmesa, RADEON_FALLBACK_BLEND_FUNC, fallback ); if ( !fallback ) { RADEON_STATECHANGE( rmesa, ctx ); rmesa->hw.ctx.cmd[CTX_RB3D_BLENDCNTL] = b; } } static void radeonBlendFuncSeparate( GLcontext *ctx, GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorA, GLenum dfactorA ) { radeonBlendFunc( ctx, sfactorRGB, dfactorRGB ); } /* ============================================================= * Depth testing */ static void radeonDepthFunc( GLcontext *ctx, GLenum func ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); RADEON_STATECHANGE( rmesa, ctx ); rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] &= ~RADEON_Z_TEST_MASK; switch ( ctx->Depth.Func ) { case GL_NEVER: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_NEVER; break; case GL_LESS: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_LESS; break; case GL_EQUAL: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_EQUAL; break; case GL_LEQUAL: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_LEQUAL; break; case GL_GREATER: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_GREATER; break; case GL_NOTEQUAL: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_NEQUAL; break; case GL_GEQUAL: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_GEQUAL; break; case GL_ALWAYS: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_ALWAYS; break; } } static void radeonDepthMask( GLcontext *ctx, GLboolean flag ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); RADEON_STATECHANGE( rmesa, ctx ); if ( ctx->Depth.Mask ) { rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_WRITE_ENABLE; } else { rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] &= ~RADEON_Z_WRITE_ENABLE; } } static void radeonClearDepth( GLcontext *ctx, GLclampd d ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLuint format = (rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] & RADEON_DEPTH_FORMAT_MASK); switch ( format ) { case RADEON_DEPTH_FORMAT_16BIT_INT_Z: rmesa->state.depth.clear = d * 0x0000ffff; break; case RADEON_DEPTH_FORMAT_24BIT_INT_Z: rmesa->state.depth.clear = d * 0x00ffffff; break; } } /* ============================================================= * Fog */ static void radeonFogfv( GLcontext *ctx, GLenum pname, const GLfloat *param ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); union { int i; float f; } c, d; GLchan col[4]; c.i = rmesa->hw.fog.cmd[FOG_C]; d.i = rmesa->hw.fog.cmd[FOG_D]; switch (pname) { case GL_FOG_MODE: if (!ctx->Fog.Enabled) return; RADEON_STATECHANGE(rmesa, tcl); rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~RADEON_TCL_FOG_MASK; switch (ctx->Fog.Mode) { case GL_LINEAR: rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_TCL_FOG_LINEAR; if (ctx->Fog.Start == ctx->Fog.End) { c.f = 1.0F; d.f = 1.0F; } else { c.f = ctx->Fog.End/(ctx->Fog.End-ctx->Fog.Start); d.f = 1.0/(ctx->Fog.End-ctx->Fog.Start); } break; case GL_EXP: rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_TCL_FOG_EXP; c.f = 0.0; d.f = ctx->Fog.Density; break; case GL_EXP2: rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_TCL_FOG_EXP2; c.f = 0.0; d.f = -(ctx->Fog.Density * ctx->Fog.Density); break; default: return; } break; case GL_FOG_DENSITY: switch (ctx->Fog.Mode) { case GL_EXP: c.f = 0.0; d.f = ctx->Fog.Density; break; case GL_EXP2: c.f = 0.0; d.f = -(ctx->Fog.Density * ctx->Fog.Density); break; default: break; } break; case GL_FOG_START: case GL_FOG_END: if (ctx->Fog.Mode == GL_LINEAR) { if (ctx->Fog.Start == ctx->Fog.End) { c.f = 1.0F; d.f = 1.0F; } else { c.f = ctx->Fog.End/(ctx->Fog.End-ctx->Fog.Start); d.f = 1.0/(ctx->Fog.End-ctx->Fog.Start); } } break; case GL_FOG_COLOR: RADEON_STATECHANGE( rmesa, ctx ); UNCLAMPED_FLOAT_TO_RGB_CHAN( col, ctx->Fog.Color ); rmesa->hw.ctx.cmd[CTX_PP_FOG_COLOR] = radeonPackColor( 4, col[0], col[1], col[2], 0 ); break; case GL_FOG_COORDINATE_SOURCE_EXT: /* What to do? */ break; default: return; } if (c.i != rmesa->hw.fog.cmd[FOG_C] || d.i != rmesa->hw.fog.cmd[FOG_D]) { RADEON_STATECHANGE( rmesa, fog ); rmesa->hw.fog.cmd[FOG_C] = c.i; rmesa->hw.fog.cmd[FOG_D] = d.i; } } /* ============================================================= * Scissoring */ static GLboolean intersect_rect( XF86DRIClipRectPtr out, XF86DRIClipRectPtr a, XF86DRIClipRectPtr 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; if ( out->x1 >= out->x2 ) return GL_FALSE; if ( out->y1 >= out->y2 ) return GL_FALSE; return GL_TRUE; } void radeonRecalcScissorRects( radeonContextPtr rmesa ) { XF86DRIClipRectPtr out; int i; /* Grow cliprect store? */ if (rmesa->state.scissor.numAllocedClipRects < rmesa->numClipRects) { while (rmesa->state.scissor.numAllocedClipRects < rmesa->numClipRects) { rmesa->state.scissor.numAllocedClipRects += 1; /* zero case */ rmesa->state.scissor.numAllocedClipRects *= 2; } if (rmesa->state.scissor.pClipRects) FREE(rmesa->state.scissor.pClipRects); rmesa->state.scissor.pClipRects = MALLOC( rmesa->state.scissor.numAllocedClipRects * sizeof(XF86DRIClipRectRec) ); if (!rmesa->state.scissor.numAllocedClipRects) { /* FALLBACK( rmesa, RADEON_FALLBACK_MEMORY, GL_TRUE ); */ rmesa->state.scissor.numAllocedClipRects = 0; return; } } out = rmesa->state.scissor.pClipRects; rmesa->state.scissor.numClipRects = 0; for ( i = 0 ; i < rmesa->numClipRects ; i++ ) { if ( intersect_rect( out, &rmesa->pClipRects[i], &rmesa->state.scissor.rect ) ) { rmesa->state.scissor.numClipRects++; out++; } } } static void radeonUpdateScissor( GLcontext *ctx ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); if ( rmesa->dri.drawable ) { __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; int x = ctx->Scissor.X; int y = dPriv->h - ctx->Scissor.Y - ctx->Scissor.Height; int w = ctx->Scissor.X + ctx->Scissor.Width - 1; int h = dPriv->h - ctx->Scissor.Y - 1; rmesa->state.scissor.rect.x1 = x + dPriv->x; rmesa->state.scissor.rect.y1 = y + dPriv->y; rmesa->state.scissor.rect.x2 = w + dPriv->x + 1; rmesa->state.scissor.rect.y2 = h + dPriv->y + 1; radeonRecalcScissorRects( rmesa ); } } static void radeonScissor( GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); if ( ctx->Scissor.Enabled ) { RADEON_FIREVERTICES( rmesa ); /* don't pipeline cliprect changes */ radeonUpdateScissor( ctx ); } } /* ============================================================= * Culling */ static void radeonCullFace( GLcontext *ctx, GLenum unused ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLuint s = rmesa->hw.set.cmd[SET_SE_CNTL]; GLuint t = rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL]; s |= RADEON_FFACE_SOLID | RADEON_BFACE_SOLID; t &= ~(RADEON_CULL_FRONT | RADEON_CULL_BACK); if ( ctx->Polygon.CullFlag ) { switch ( ctx->Polygon.CullFaceMode ) { case GL_FRONT: s &= ~RADEON_FFACE_SOLID; t |= RADEON_CULL_FRONT; break; case GL_BACK: s &= ~RADEON_BFACE_SOLID; t |= RADEON_CULL_BACK; break; case GL_FRONT_AND_BACK: s &= ~(RADEON_FFACE_SOLID | RADEON_BFACE_SOLID); t |= (RADEON_CULL_FRONT | RADEON_CULL_BACK); break; } } if ( rmesa->hw.set.cmd[SET_SE_CNTL] != s ) { RADEON_STATECHANGE(rmesa, set ); rmesa->hw.set.cmd[SET_SE_CNTL] = s; } if ( rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] != t ) { RADEON_STATECHANGE(rmesa, tcl ); rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] = t; } } static void radeonFrontFace( GLcontext *ctx, GLenum mode ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); RADEON_STATECHANGE( rmesa, set ); rmesa->hw.set.cmd[SET_SE_CNTL] &= ~RADEON_FFACE_CULL_DIR_MASK; RADEON_STATECHANGE( rmesa, tcl ); rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~RADEON_CULL_FRONT_IS_CCW; switch ( mode ) { case GL_CW: rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_FFACE_CULL_CW; break; case GL_CCW: rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_FFACE_CULL_CCW; rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_CULL_FRONT_IS_CCW; break; } } /* ============================================================= * Line state */ static void radeonLineWidth( GLcontext *ctx, GLfloat widthf ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); RADEON_STATECHANGE( rmesa, lin ); RADEON_STATECHANGE( rmesa, set ); /* Line width is stored in U6.4 format. */ rmesa->hw.lin.cmd[LIN_SE_LINE_WIDTH] = (GLuint)(widthf * 16.0); if ( widthf > 1.0 ) { rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_WIDELINE_ENABLE; } else { rmesa->hw.set.cmd[SET_SE_CNTL] &= ~RADEON_WIDELINE_ENABLE; } } static void radeonLineStipple( GLcontext *ctx, GLint factor, GLushort pattern ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); RADEON_STATECHANGE( rmesa, lin ); rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] = ((((GLuint)factor & 0xff) << 16) | ((GLuint)pattern)); } /* ============================================================= * Masks */ static void radeonColorMask( GLcontext *ctx, GLboolean r, GLboolean g, GLboolean b, GLboolean a ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLuint mask = radeonPackColor( rmesa->radeonScreen->cpp, ctx->Color.ColorMask[RCOMP], ctx->Color.ColorMask[GCOMP], ctx->Color.ColorMask[BCOMP], ctx->Color.ColorMask[ACOMP] ); if ( rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK] != mask ) { RADEON_STATECHANGE( rmesa, msk ); rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK] = mask; } } /* ============================================================= * Polygon state */ static void radeonPolygonOffset( GLcontext *ctx, GLfloat factor, GLfloat units ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLfloat constant = units * rmesa->state.depth.scale; RADEON_STATECHANGE( rmesa, zbs ); rmesa->hw.zbs.cmd[ZBS_SE_ZBIAS_FACTOR] = *(GLuint *)&factor; rmesa->hw.zbs.cmd[ZBS_SE_ZBIAS_CONSTANT] = *(GLuint *)&constant; } static void radeonPolygonStipple( GLcontext *ctx, const GLubyte *mask ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLuint i; drmRadeonStipple stipple; /* Must flip pattern upside down. */ for ( i = 0 ; i < 32 ; i++ ) { rmesa->state.stipple.mask[31 - i] = ((GLuint *) mask)[i]; } /* TODO: push this into cmd mechanism */ RADEON_FIREVERTICES( rmesa ); LOCK_HARDWARE( rmesa ); /* FIXME: Use window x,y offsets into stipple RAM. */ stipple.mask = rmesa->state.stipple.mask; drmCommandWrite( rmesa->dri.fd, DRM_RADEON_STIPPLE, &stipple, sizeof(drmRadeonStipple) ); UNLOCK_HARDWARE( rmesa ); } static void radeonPolygonMode( GLcontext *ctx, GLenum face, GLenum mode ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLboolean flag = (ctx->_TriangleCaps & DD_TRI_UNFILLED) != 0; /* Can't generally do unfilled via tcl, but some good special * cases work. */ TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_UNFILLED, flag); if (rmesa->TclFallback) { radeonChooseRenderState( ctx ); radeonChooseVertexState( ctx ); } } /* ============================================================= * Rendering attributes * * We really don't want to recalculate all this every time we bind a * texture. These things shouldn't change all that often, so it makes * sense to break them out of the core texture state update routines. */ /* Examine lighting and texture state to determine if separate specular * should be enabled. */ static void radeonUpdateSpecular( GLcontext *ctx ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); CARD32 p = rmesa->hw.ctx.cmd[CTX_PP_CNTL]; if ( ctx->_TriangleCaps & DD_SEPARATE_SPECULAR ) { p |= RADEON_SPECULAR_ENABLE; } else { p &= ~RADEON_SPECULAR_ENABLE; } if ( rmesa->hw.ctx.cmd[CTX_PP_CNTL] != p ) { RADEON_STATECHANGE( rmesa, ctx ); rmesa->hw.ctx.cmd[CTX_PP_CNTL] = p; } /* Bizzare: have to leave lighting enabled to get fog. */ RADEON_STATECHANGE( rmesa, tcl ); if ((ctx->Light.Enabled && ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) { rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_SPECULAR; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_DIFFUSE; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE; rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE; } else if (ctx->Fog.Enabled) { if (ctx->Light.Enabled) { rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_SPECULAR; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_DIFFUSE; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE; rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE; } else { rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_SPECULAR; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_DIFFUSE; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE; rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE; } } else if (ctx->Light.Enabled) { rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_SPECULAR; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_DIFFUSE; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~RADEON_TCL_VTX_PK_SPEC; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE; rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE; } else if (ctx->Fog.ColorSumEnabled ) { rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_SPECULAR; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_DIFFUSE; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE; rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_LIGHTING_ENABLE; } else { rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_SPECULAR; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_DIFFUSE; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~RADEON_TCL_VTX_PK_SPEC; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE; rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_LIGHTING_ENABLE; } /* Update vertex/render formats */ if (rmesa->TclFallback) { radeonChooseRenderState( ctx ); radeonChooseVertexState( ctx ); } } /* ============================================================= * Materials */ /* Update on colormaterial, material emmissive/ambient, * lightmodel.globalambient */ static void update_global_ambient( GLcontext *ctx ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); float *fcmd = (float *)RADEON_DB_STATE( glt ); /* Need to do more if both emmissive & ambient are PREMULT: */ if ((rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] & ((3 << RADEON_EMISSIVE_SOURCE_SHIFT) | (3 << RADEON_AMBIENT_SOURCE_SHIFT))) == 0) { COPY_3V( &fcmd[GLT_RED], ctx->Light.Material[0].Emission); ACC_SCALE_3V( &fcmd[GLT_RED], ctx->Light.Model.Ambient, ctx->Light.Material[0].Ambient); } else { COPY_3V( &fcmd[GLT_RED], ctx->Light.Model.Ambient ); } RADEON_DB_STATECHANGE(rmesa, &rmesa->hw.glt); } /* Update on change to * - light[p].colors * - light[p].enabled * - material, * - colormaterial enabled * - colormaterial bitmask */ static void update_light_colors( GLcontext *ctx, GLuint p ) { struct gl_light *l = &ctx->Light.Light[p]; /* fprintf(stderr, "%s\n", __FUNCTION__); */ if (l->Enabled) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); float *fcmd = (float *)RADEON_DB_STATE( lit[p] ); GLuint bitmask = ctx->Light.ColorMaterialBitmask; struct gl_material *mat = &ctx->Light.Material[0]; COPY_4V( &fcmd[LIT_AMBIENT_RED], l->Ambient ); COPY_4V( &fcmd[LIT_DIFFUSE_RED], l->Diffuse ); COPY_4V( &fcmd[LIT_SPECULAR_RED], l->Specular ); if (!ctx->Light.ColorMaterialEnabled) bitmask = 0; if ((bitmask & FRONT_AMBIENT_BIT) == 0) SELF_SCALE_3V( &fcmd[LIT_AMBIENT_RED], mat->Ambient ); if ((bitmask & FRONT_DIFFUSE_BIT) == 0) SELF_SCALE_3V( &fcmd[LIT_DIFFUSE_RED], mat->Diffuse ); if ((bitmask & FRONT_SPECULAR_BIT) == 0) SELF_SCALE_3V( &fcmd[LIT_SPECULAR_RED], mat->Specular ); RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.lit[p] ); } } /* Also fallback for asym colormaterial mode in twoside lighting... */ static void check_twoside_fallback( GLcontext *ctx ) { GLboolean fallback = GL_FALSE; if (ctx->Light.Enabled && ctx->Light.Model.TwoSide) { if (memcmp( &ctx->Light.Material[0], &ctx->Light.Material[1], sizeof(struct gl_material)) != 0) fallback = GL_TRUE; else if (ctx->Light.ColorMaterialEnabled && (ctx->Light.ColorMaterialBitmask & BACK_MATERIAL_BITS) != ((ctx->Light.ColorMaterialBitmask & FRONT_MATERIAL_BITS)<<1)) fallback = GL_TRUE; } TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_LIGHT_TWOSIDE, fallback ); } static void radeonColorMaterial( GLcontext *ctx, GLenum face, GLenum mode ) { if (ctx->Light.ColorMaterialEnabled) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLuint light_model_ctl = rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]; GLuint mask = ctx->Light.ColorMaterialBitmask; /* Default to PREMULT: */ light_model_ctl &= ~((3 << RADEON_EMISSIVE_SOURCE_SHIFT) | (3 << RADEON_AMBIENT_SOURCE_SHIFT) | (3 << RADEON_DIFFUSE_SOURCE_SHIFT) | (3 << RADEON_SPECULAR_SOURCE_SHIFT)); if (mask & FRONT_EMISSION_BIT) { light_model_ctl |= (RADEON_LM_SOURCE_VERTEX_DIFFUSE << RADEON_EMISSIVE_SOURCE_SHIFT); } if (mask & FRONT_AMBIENT_BIT) { light_model_ctl |= (RADEON_LM_SOURCE_VERTEX_DIFFUSE << RADEON_AMBIENT_SOURCE_SHIFT); } if (mask & FRONT_DIFFUSE_BIT) { light_model_ctl |= (RADEON_LM_SOURCE_VERTEX_DIFFUSE << RADEON_DIFFUSE_SOURCE_SHIFT); } if (mask & FRONT_SPECULAR_BIT) { light_model_ctl |= (RADEON_LM_SOURCE_VERTEX_DIFFUSE << RADEON_SPECULAR_SOURCE_SHIFT); } if (light_model_ctl != rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]) { GLuint p; RADEON_STATECHANGE( rmesa, tcl ); rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] = light_model_ctl; for (p = 0 ; p < MAX_LIGHTS; p++) update_light_colors( ctx, p ); update_global_ambient( ctx ); } } check_twoside_fallback( ctx ); } void radeonUpdateMaterial( GLcontext *ctx ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLfloat *fcmd = (GLfloat *)RADEON_DB_STATE( mtl ); GLuint p; GLuint mask = ~0; if (ctx->Light.ColorMaterialEnabled) mask &= ~ctx->Light.ColorMaterialBitmask; if (RADEON_DEBUG & DEBUG_STATE) fprintf(stderr, "%s\n", __FUNCTION__); if (mask & FRONT_EMISSION_BIT) { fcmd[MTL_EMMISSIVE_RED] = ctx->Light.Material[0].Emission[0]; fcmd[MTL_EMMISSIVE_GREEN] = ctx->Light.Material[0].Emission[1]; fcmd[MTL_EMMISSIVE_BLUE] = ctx->Light.Material[0].Emission[2]; fcmd[MTL_EMMISSIVE_ALPHA] = ctx->Light.Material[0].Emission[3]; } if (mask & FRONT_AMBIENT_BIT) { fcmd[MTL_AMBIENT_RED] = ctx->Light.Material[0].Ambient[0]; fcmd[MTL_AMBIENT_GREEN] = ctx->Light.Material[0].Ambient[1]; fcmd[MTL_AMBIENT_BLUE] = ctx->Light.Material[0].Ambient[2]; fcmd[MTL_AMBIENT_ALPHA] = ctx->Light.Material[0].Ambient[3]; } if (mask & FRONT_DIFFUSE_BIT) { fcmd[MTL_DIFFUSE_RED] = ctx->Light.Material[0].Diffuse[0]; fcmd[MTL_DIFFUSE_GREEN] = ctx->Light.Material[0].Diffuse[1]; fcmd[MTL_DIFFUSE_BLUE] = ctx->Light.Material[0].Diffuse[2]; fcmd[MTL_DIFFUSE_ALPHA] = ctx->Light.Material[0].Diffuse[3]; } if (mask & FRONT_SPECULAR_BIT) { fcmd[MTL_SPECULAR_RED] = ctx->Light.Material[0].Specular[0]; fcmd[MTL_SPECULAR_GREEN] = ctx->Light.Material[0].Specular[1]; fcmd[MTL_SPECULAR_BLUE] = ctx->Light.Material[0].Specular[2]; fcmd[MTL_SPECULAR_ALPHA] = ctx->Light.Material[0].Specular[3]; } if (mask & FRONT_SHININESS_BIT) { fcmd[MTL_SHININESS] = ctx->Light.Material[0].Shininess; } if (RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.mtl )) { for (p = 0 ; p < MAX_LIGHTS; p++) update_light_colors( ctx, p ); check_twoside_fallback( ctx ); update_global_ambient( ctx ); } else if (RADEON_DEBUG & (DEBUG_PRIMS|DEBUG_STATE)) fprintf(stderr, "%s: Elided noop material call\n", __FUNCTION__); } /* _NEW_LIGHT * _NEW_MODELVIEW * _MESA_NEW_NEED_EYE_COORDS * * Uses derived state from mesa: * _VP_inf_norm * _h_inf_norm * _Position * _NormDirection * _ModelViewInvScale * _NeedEyeCoords * _EyeZDir * * which are calculated in light.c and are correct for the current * lighting space (model or eye), hence dependencies on _NEW_MODELVIEW * and _MESA_NEW_NEED_EYE_COORDS. */ static void update_light( GLcontext *ctx ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); /* Have to check these, or have an automatic shortcircuit mechanism * to remove noop statechanges. (Or just do a better job on the * front end). */ { GLuint tmp = rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]; if (ctx->_NeedEyeCoords) tmp &= ~RADEON_LIGHT_IN_MODELSPACE; else tmp |= RADEON_LIGHT_IN_MODELSPACE; /* Leave this test disabled: (unexplained q3 lockup) (even with new packets) */ if (tmp != rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]) { RADEON_STATECHANGE( rmesa, tcl ); rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] = tmp; } } { GLfloat *fcmd = (GLfloat *)RADEON_DB_STATE( eye ); fcmd[EYE_X] = ctx->_EyeZDir[0]; fcmd[EYE_Y] = ctx->_EyeZDir[1]; fcmd[EYE_Z] = - ctx->_EyeZDir[2]; fcmd[EYE_RESCALE_FACTOR] = ctx->_ModelViewInvScale; RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.eye ); } /* RADEON_STATECHANGE( rmesa, glt ); */ if (ctx->Light.Enabled) { GLint p; for (p = 0 ; p < MAX_LIGHTS; p++) { if (ctx->Light.Light[p].Enabled) { struct gl_light *l = &ctx->Light.Light[p]; GLfloat *fcmd = (GLfloat *)RADEON_DB_STATE( lit[p] ); if (l->EyePosition[3] == 0.0) { COPY_3FV( &fcmd[LIT_POSITION_X], l->_VP_inf_norm ); COPY_3FV( &fcmd[LIT_DIRECTION_X], l->_h_inf_norm ); fcmd[LIT_POSITION_W] = 0; fcmd[LIT_DIRECTION_W] = 0; } else { COPY_4V( &fcmd[LIT_POSITION_X], l->_Position ); fcmd[LIT_DIRECTION_X] = -l->_NormDirection[0]; fcmd[LIT_DIRECTION_Y] = -l->_NormDirection[1]; fcmd[LIT_DIRECTION_Z] = -l->_NormDirection[2]; fcmd[LIT_DIRECTION_W] = 0; } RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.lit[p] ); } } } } static void radeonLightfv( GLcontext *ctx, GLenum light, GLenum pname, const GLfloat *params ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLint p = light - GL_LIGHT0; struct gl_light *l = &ctx->Light.Light[p]; GLfloat *fcmd = (GLfloat *)rmesa->hw.lit[p].cmd; switch (pname) { case GL_AMBIENT: case GL_DIFFUSE: case GL_SPECULAR: update_light_colors( ctx, p ); break; case GL_SPOT_DIRECTION: /* picked up in update_light */ break; case GL_POSITION: { /* positions picked up in update_light, but can do flag here */ GLuint flag = (p&1)? RADEON_LIGHT_1_IS_LOCAL : RADEON_LIGHT_0_IS_LOCAL; GLuint idx = TCL_PER_LIGHT_CTL_0 + p/2; RADEON_STATECHANGE(rmesa, tcl); if (l->EyePosition[3] != 0.0F) rmesa->hw.tcl.cmd[idx] |= flag; else rmesa->hw.tcl.cmd[idx] &= ~flag; break; } case GL_SPOT_EXPONENT: RADEON_STATECHANGE(rmesa, lit[p]); fcmd[LIT_SPOT_EXPONENT] = params[0]; break; case GL_SPOT_CUTOFF: { GLuint flag = (p&1) ? RADEON_LIGHT_1_IS_SPOT : RADEON_LIGHT_0_IS_SPOT; GLuint idx = TCL_PER_LIGHT_CTL_0 + p/2; RADEON_STATECHANGE(rmesa, lit[p]); fcmd[LIT_SPOT_CUTOFF] = l->_CosCutoff; RADEON_STATECHANGE(rmesa, tcl); if (l->SpotCutoff != 180.0F) rmesa->hw.tcl.cmd[idx] |= flag; else rmesa->hw.tcl.cmd[idx] &= ~flag; break; } case GL_CONSTANT_ATTENUATION: RADEON_STATECHANGE(rmesa, lit[p]); fcmd[LIT_ATTEN_CONST] = params[0]; break; case GL_LINEAR_ATTENUATION: RADEON_STATECHANGE(rmesa, lit[p]); fcmd[LIT_ATTEN_LINEAR] = params[0]; break; case GL_QUADRATIC_ATTENUATION: RADEON_STATECHANGE(rmesa, lit[p]); fcmd[LIT_ATTEN_QUADRATIC] = params[0]; break; default: return; } } static void radeonLightModelfv( GLcontext *ctx, GLenum pname, const GLfloat *param ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); switch (pname) { case GL_LIGHT_MODEL_AMBIENT: update_global_ambient( ctx ); break; case GL_LIGHT_MODEL_LOCAL_VIEWER: RADEON_STATECHANGE( rmesa, tcl ); if (ctx->Light.Model.LocalViewer) rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LOCAL_VIEWER; else rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_LOCAL_VIEWER; break; case GL_LIGHT_MODEL_TWO_SIDE: RADEON_STATECHANGE( rmesa, tcl ); if (ctx->Light.Model.TwoSide) rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_LIGHT_TWOSIDE; else rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~RADEON_LIGHT_TWOSIDE; check_twoside_fallback( ctx ); if (rmesa->TclFallback) { radeonChooseRenderState( ctx ); radeonChooseVertexState( ctx ); } break; case GL_LIGHT_MODEL_COLOR_CONTROL: radeonUpdateSpecular(ctx); RADEON_STATECHANGE( rmesa, tcl ); if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_DIFFUSE_SPECULAR_COMBINE; else rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_DIFFUSE_SPECULAR_COMBINE; break; default: break; } } static void radeonShadeModel( GLcontext *ctx, GLenum mode ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLuint s = rmesa->hw.set.cmd[SET_SE_CNTL]; s &= ~(RADEON_DIFFUSE_SHADE_MASK | RADEON_ALPHA_SHADE_MASK | RADEON_SPECULAR_SHADE_MASK | RADEON_FOG_SHADE_MASK); switch ( mode ) { case GL_FLAT: s |= (RADEON_DIFFUSE_SHADE_FLAT | RADEON_ALPHA_SHADE_FLAT | RADEON_SPECULAR_SHADE_FLAT | RADEON_FOG_SHADE_FLAT); break; case GL_SMOOTH: s |= (RADEON_DIFFUSE_SHADE_GOURAUD | RADEON_ALPHA_SHADE_GOURAUD | RADEON_SPECULAR_SHADE_GOURAUD | RADEON_FOG_SHADE_GOURAUD); break; default: return; } if ( rmesa->hw.set.cmd[SET_SE_CNTL] != s ) { RADEON_STATECHANGE( rmesa, set ); rmesa->hw.set.cmd[SET_SE_CNTL] = s; } } /* ============================================================= * User clip planes */ static void radeonClipPlane( GLcontext *ctx, GLenum plane, const GLfloat *eq ) { GLint p = (GLint) plane - (GLint) GL_CLIP_PLANE0; radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLint *ip = (GLint *)ctx->Transform._ClipUserPlane[p]; RADEON_STATECHANGE( rmesa, ucp[p] ); rmesa->hw.ucp[p].cmd[UCP_X] = ip[0]; rmesa->hw.ucp[p].cmd[UCP_Y] = ip[1]; rmesa->hw.ucp[p].cmd[UCP_Z] = ip[2]; rmesa->hw.ucp[p].cmd[UCP_W] = ip[3]; } static void radeonUpdateClipPlanes( GLcontext *ctx ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLuint p; for (p = 0; p < ctx->Const.MaxClipPlanes; p++) { if (ctx->Transform.ClipEnabled[p]) { GLint *ip = (GLint *)ctx->Transform._ClipUserPlane[p]; RADEON_STATECHANGE( rmesa, ucp[p] ); rmesa->hw.ucp[p].cmd[UCP_X] = ip[0]; rmesa->hw.ucp[p].cmd[UCP_Y] = ip[1]; rmesa->hw.ucp[p].cmd[UCP_Z] = ip[2]; rmesa->hw.ucp[p].cmd[UCP_W] = ip[3]; } } } /* ============================================================= * Stencil */ static void radeonStencilFunc( GLcontext *ctx, GLenum func, GLint ref, GLuint mask ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLuint refmask = ((ctx->Stencil.Ref << RADEON_STENCIL_REF_SHIFT) | (ctx->Stencil.ValueMask << RADEON_STENCIL_MASK_SHIFT)); RADEON_STATECHANGE( rmesa, ctx ); RADEON_STATECHANGE( rmesa, msk ); rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] &= ~RADEON_STENCIL_TEST_MASK; rmesa->hw.msk.cmd[MSK_RB3D_STENCILREFMASK] &= ~(RADEON_STENCIL_REF_MASK| RADEON_STENCIL_VALUE_MASK); switch ( ctx->Stencil.Function ) { case GL_NEVER: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_NEVER; break; case GL_LESS: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_LESS; break; case GL_EQUAL: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_EQUAL; break; case GL_LEQUAL: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_LEQUAL; break; case GL_GREATER: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_GREATER; break; case GL_NOTEQUAL: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_NEQUAL; break; case GL_GEQUAL: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_GEQUAL; break; case GL_ALWAYS: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_ALWAYS; break; } rmesa->hw.msk.cmd[MSK_RB3D_STENCILREFMASK] |= refmask; } static void radeonStencilMask( GLcontext *ctx, GLuint mask ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); RADEON_STATECHANGE( rmesa, msk ); rmesa->hw.msk.cmd[MSK_RB3D_STENCILREFMASK] &= ~RADEON_STENCIL_WRITE_MASK; rmesa->hw.msk.cmd[MSK_RB3D_STENCILREFMASK] |= (ctx->Stencil.WriteMask << RADEON_STENCIL_WRITEMASK_SHIFT); } static void radeonStencilOp( GLcontext *ctx, GLenum fail, GLenum zfail, GLenum zpass ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); RADEON_STATECHANGE( rmesa, ctx ); rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] &= ~(RADEON_STENCIL_FAIL_MASK | RADEON_STENCIL_ZFAIL_MASK | RADEON_STENCIL_ZPASS_MASK); switch ( ctx->Stencil.FailFunc ) { case GL_KEEP: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_KEEP; break; case GL_ZERO: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_ZERO; break; case GL_REPLACE: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_REPLACE; break; case GL_INCR: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_INC; break; case GL_DECR: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_DEC; break; case GL_INVERT: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_INVERT; break; } switch ( ctx->Stencil.ZFailFunc ) { case GL_KEEP: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_KEEP; break; case GL_ZERO: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_ZERO; break; case GL_REPLACE: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_REPLACE; break; case GL_INCR: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_INC; break; case GL_DECR: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_DEC; break; case GL_INVERT: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_INVERT; break; } switch ( ctx->Stencil.ZPassFunc ) { case GL_KEEP: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_KEEP; break; case GL_ZERO: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_ZERO; break; case GL_REPLACE: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_REPLACE; break; case GL_INCR: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_INC; break; case GL_DECR: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_DEC; break; case GL_INVERT: rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_INVERT; break; } } static void radeonClearStencil( GLcontext *ctx, GLint s ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); rmesa->state.stencil.clear = ((GLuint) ctx->Stencil.Clear | (0xff << RADEON_STENCIL_MASK_SHIFT) | (ctx->Stencil.WriteMask << RADEON_STENCIL_WRITEMASK_SHIFT)); } /* ============================================================= * Window position and viewport transformation */ /* * To correctly position primitives: */ #define SUBPIXEL_X 0.125 #define SUBPIXEL_Y 0.125 void radeonUpdateWindow( GLcontext *ctx ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; GLfloat xoffset = (GLfloat)dPriv->x; GLfloat yoffset = (GLfloat)dPriv->y + dPriv->h; const GLfloat *v = ctx->Viewport._WindowMap.m; GLfloat sx = v[MAT_SX]; GLfloat tx = v[MAT_TX] + xoffset + SUBPIXEL_X; GLfloat sy = - v[MAT_SY]; GLfloat ty = (- v[MAT_TY]) + yoffset + SUBPIXEL_Y; GLfloat sz = v[MAT_SZ] * rmesa->state.depth.scale; GLfloat tz = v[MAT_TZ] * rmesa->state.depth.scale; RADEON_FIREVERTICES( rmesa ); RADEON_STATECHANGE( rmesa, vpt ); rmesa->hw.vpt.cmd[VPT_SE_VPORT_XSCALE] = *(GLuint *)&sx; rmesa->hw.vpt.cmd[VPT_SE_VPORT_XOFFSET] = *(GLuint *)&tx; rmesa->hw.vpt.cmd[VPT_SE_VPORT_YSCALE] = *(GLuint *)&sy; rmesa->hw.vpt.cmd[VPT_SE_VPORT_YOFFSET] = *(GLuint *)&ty; rmesa->hw.vpt.cmd[VPT_SE_VPORT_ZSCALE] = *(GLuint *)&sz; rmesa->hw.vpt.cmd[VPT_SE_VPORT_ZOFFSET] = *(GLuint *)&tz; } static void radeonViewport( GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height ) { /* Don't pipeline viewport changes, conflict with window offset * setting below. Could apply deltas to rescue pipelined viewport * values, or keep the originals hanging around. */ RADEON_FIREVERTICES( RADEON_CONTEXT(ctx) ); radeonUpdateWindow( ctx ); } static void radeonDepthRange( GLcontext *ctx, GLclampd nearval, GLclampd farval ) { radeonUpdateWindow( ctx ); } void radeonUpdateViewportOffset( GLcontext *ctx ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; GLfloat xoffset = (GLfloat)dPriv->x; GLfloat yoffset = (GLfloat)dPriv->y + dPriv->h; const GLfloat *v = ctx->Viewport._WindowMap.m; GLfloat tx = v[MAT_TX] + xoffset; GLfloat ty = (- v[MAT_TY]) + yoffset; if ( rmesa->hw.vpt.cmd[VPT_SE_VPORT_XOFFSET] != *(GLuint *)&tx || rmesa->hw.vpt.cmd[VPT_SE_VPORT_YOFFSET] != *(GLuint *)&ty ) { /* Note: this should also modify whatever data the context reset * code uses... */ rmesa->hw.vpt.cmd[VPT_SE_VPORT_XOFFSET] = *(GLuint *)&tx; rmesa->hw.vpt.cmd[VPT_SE_VPORT_YOFFSET] = *(GLuint *)&ty; /* update polygon stipple x/y screen offset */ { GLuint stx, sty; GLuint m = rmesa->hw.msc.cmd[MSC_RE_MISC]; m &= ~(RADEON_STIPPLE_X_OFFSET_MASK | RADEON_STIPPLE_Y_OFFSET_MASK); /* add magic offsets, then invert */ stx = 31 - ((rmesa->dri.drawable->x - 1) & RADEON_STIPPLE_COORD_MASK); sty = 31 - ((rmesa->dri.drawable->y + rmesa->dri.drawable->h - 1) & RADEON_STIPPLE_COORD_MASK); m |= ((stx << RADEON_STIPPLE_X_OFFSET_SHIFT) | (sty << RADEON_STIPPLE_Y_OFFSET_SHIFT)); if ( rmesa->hw.msc.cmd[MSC_RE_MISC] != m ) { RADEON_STATECHANGE( rmesa, msc ); rmesa->hw.msc.cmd[MSC_RE_MISC] = m; } } } radeonUpdateScissor( ctx ); } /* ============================================================= * Miscellaneous */ static void radeonClearColor( GLcontext *ctx, const GLchan c[4] ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); rmesa->state.color.clear = radeonPackColor( rmesa->radeonScreen->cpp, c[0], c[1], c[2], c[3] ); } static void radeonRenderMode( GLcontext *ctx, GLenum mode ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); FALLBACK( rmesa, RADEON_FALLBACK_RENDER_MODE, (mode != GL_RENDER) ); } static GLuint radeon_rop_tab[] = { RADEON_ROP_CLEAR, RADEON_ROP_AND, RADEON_ROP_AND_REVERSE, RADEON_ROP_COPY, RADEON_ROP_AND_INVERTED, RADEON_ROP_NOOP, RADEON_ROP_XOR, RADEON_ROP_OR, RADEON_ROP_NOR, RADEON_ROP_EQUIV, RADEON_ROP_INVERT, RADEON_ROP_OR_REVERSE, RADEON_ROP_COPY_INVERTED, RADEON_ROP_OR_INVERTED, RADEON_ROP_NAND, RADEON_ROP_SET, }; static void radeonLogicOpCode( GLcontext *ctx, GLenum opcode ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLuint rop = (GLuint)opcode - GL_CLEAR; ASSERT( rop < 16 ); RADEON_STATECHANGE( rmesa, msk ); rmesa->hw.msk.cmd[MSK_RB3D_ROPCNTL] = radeon_rop_tab[rop]; } void radeonSetCliprects( radeonContextPtr rmesa, GLenum mode ) { __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; switch ( mode ) { case GL_FRONT_LEFT: rmesa->numClipRects = dPriv->numClipRects; rmesa->pClipRects = (XF86DRIClipRectPtr)dPriv->pClipRects; break; case GL_BACK_LEFT: /* Can't ignore 2d windows if we are page flipping. */ if ( dPriv->numBackClipRects == 0 || rmesa->doPageFlip ) { rmesa->numClipRects = dPriv->numClipRects; rmesa->pClipRects = (XF86DRIClipRectPtr)dPriv->pClipRects; } else { rmesa->numClipRects = dPriv->numBackClipRects; rmesa->pClipRects = (XF86DRIClipRectPtr)dPriv->pBackClipRects; } break; default: fprintf(stderr, "bad mode in radeonSetCliprects\n"); return; } if (rmesa->state.scissor.enabled) radeonRecalcScissorRects( rmesa ); } static void radeonSetDrawBuffer( GLcontext *ctx, GLenum mode ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); if (RADEON_DEBUG & DEBUG_DRI) fprintf(stderr, "%s %s\n", __FUNCTION__, _mesa_lookup_enum_by_nr( mode )); RADEON_FIREVERTICES(rmesa); /* don't pipeline cliprect changes */ switch ( mode ) { case GL_FRONT_LEFT: FALLBACK( rmesa, RADEON_FALLBACK_DRAW_BUFFER, GL_FALSE ); if ( rmesa->sarea->pfCurrentPage == 1 ) { rmesa->state.color.drawOffset = rmesa->radeonScreen->backOffset; rmesa->state.color.drawPitch = rmesa->radeonScreen->backPitch; } else { rmesa->state.color.drawOffset = rmesa->radeonScreen->frontOffset; rmesa->state.color.drawPitch = rmesa->radeonScreen->frontPitch; } rmesa->state.pixel.readOffset = rmesa->state.color.drawOffset; rmesa->state.pixel.readPitch = rmesa->state.color.drawPitch; radeonSetCliprects( rmesa, GL_FRONT_LEFT ); break; case GL_BACK_LEFT: FALLBACK( rmesa, RADEON_FALLBACK_DRAW_BUFFER, GL_FALSE ); if ( rmesa->sarea->pfCurrentPage == 1 ) { rmesa->state.color.drawOffset = rmesa->radeonScreen->frontOffset; rmesa->state.color.drawPitch = rmesa->radeonScreen->frontPitch; } else { rmesa->state.color.drawOffset = rmesa->radeonScreen->backOffset; rmesa->state.color.drawPitch = rmesa->radeonScreen->backPitch; } rmesa->state.pixel.readOffset = rmesa->state.color.drawOffset; rmesa->state.pixel.readPitch = rmesa->state.color.drawPitch; radeonSetCliprects( rmesa, GL_BACK_LEFT ); break; default: FALLBACK( rmesa, RADEON_FALLBACK_DRAW_BUFFER, GL_TRUE ); return; } RADEON_STATECHANGE( rmesa, ctx ); rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = (rmesa->state.color.drawOffset & RADEON_COLOROFFSET_MASK); rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = rmesa->state.color.drawPitch; } /* ============================================================= * State enable/disable */ static void radeonEnable( GLcontext *ctx, GLenum cap, GLboolean state ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLuint p, flag; if ( RADEON_DEBUG & DEBUG_STATE ) fprintf( stderr, "%s( %s = %s )\n", __FUNCTION__, _mesa_lookup_enum_by_nr( cap ), state ? "GL_TRUE" : "GL_FALSE" ); switch ( cap ) { /* Fast track this one... */ case GL_TEXTURE_1D: case GL_TEXTURE_2D: case GL_TEXTURE_3D: break; case GL_ALPHA_TEST: RADEON_STATECHANGE( rmesa, ctx ); if (state) { rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_ALPHA_TEST_ENABLE; } else { rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_ALPHA_TEST_ENABLE; } break; case GL_BLEND: RADEON_STATECHANGE( rmesa, ctx ); if (state) { rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_ALPHA_BLEND_ENABLE; } else { rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_ALPHA_BLEND_ENABLE; } if ( ctx->Color.ColorLogicOpEnabled ) { rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_ROP_ENABLE; } else { rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_ROP_ENABLE; } break; case GL_CLIP_PLANE0: case GL_CLIP_PLANE1: case GL_CLIP_PLANE2: case GL_CLIP_PLANE3: case GL_CLIP_PLANE4: case GL_CLIP_PLANE5: p = cap-GL_CLIP_PLANE0; RADEON_STATECHANGE( rmesa, tcl ); if (state) { rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= (RADEON_UCP_ENABLE_0<hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~(RADEON_UCP_ENABLE_0<hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_Z_ENABLE; } else { rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_Z_ENABLE; } break; case GL_DITHER: RADEON_STATECHANGE(rmesa, ctx ); if ( state ) { rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_DITHER_ENABLE; } else { rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_DITHER_ENABLE; } break; case GL_FOG: RADEON_STATECHANGE(rmesa, ctx ); if ( state ) { rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_FOG_ENABLE; radeonFogfv( ctx, GL_FOG_MODE, 0 ); } else { rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_FOG_ENABLE; RADEON_STATECHANGE(rmesa, tcl); rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~RADEON_TCL_FOG_MASK; } radeonUpdateSpecular( ctx ); /* for PK_SPEC */ if (rmesa->TclFallback) radeonChooseVertexState( ctx ); break; case GL_LIGHT0: case GL_LIGHT1: case GL_LIGHT2: case GL_LIGHT3: case GL_LIGHT4: case GL_LIGHT5: case GL_LIGHT6: case GL_LIGHT7: RADEON_STATECHANGE(rmesa, tcl); p = cap - GL_LIGHT0; if (p&1) flag = (RADEON_LIGHT_1_ENABLE | RADEON_LIGHT_1_ENABLE_AMBIENT | RADEON_LIGHT_1_ENABLE_SPECULAR); else flag = (RADEON_LIGHT_0_ENABLE | RADEON_LIGHT_0_ENABLE_AMBIENT | RADEON_LIGHT_0_ENABLE_SPECULAR); if (state) rmesa->hw.tcl.cmd[p/2 + TCL_PER_LIGHT_CTL_0] |= flag; else rmesa->hw.tcl.cmd[p/2 + TCL_PER_LIGHT_CTL_0] &= ~flag; /* */ update_light_colors( ctx, p ); break; case GL_LIGHTING: RADEON_STATECHANGE(rmesa, tcl); if (state) { /* rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE; */ /* rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_DIFFUSE; */ } else { /* rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_LIGHTING_ENABLE; */ /* rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_DIFFUSE; */ } radeonUpdateSpecular(ctx); check_twoside_fallback( ctx ); break; case GL_LINE_SMOOTH: RADEON_STATECHANGE( rmesa, ctx ); if ( state ) { rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_ANTI_ALIAS_LINE; } else { rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_ANTI_ALIAS_LINE; } break; case GL_LINE_STIPPLE: RADEON_STATECHANGE( rmesa, ctx ); if ( state ) { rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_PATTERN_ENABLE; } else { rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_PATTERN_ENABLE; } break; case GL_COLOR_LOGIC_OP: RADEON_STATECHANGE( rmesa, ctx ); if ( state ) { rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_ROP_ENABLE; } else { rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_ROP_ENABLE; } break; case GL_NORMALIZE: RADEON_STATECHANGE( rmesa, tcl ); if ( state ) { rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_NORMALIZE_NORMALS; } else { rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_NORMALIZE_NORMALS; } break; case GL_POLYGON_OFFSET_POINT: if (rmesa->dri.drmMinor == 1) { radeonChooseRenderState( ctx ); } else { RADEON_STATECHANGE( rmesa, set ); if ( state ) { rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_ZBIAS_ENABLE_POINT; } else { rmesa->hw.set.cmd[SET_SE_CNTL] &= ~RADEON_ZBIAS_ENABLE_POINT; } } break; case GL_POLYGON_OFFSET_LINE: if (rmesa->dri.drmMinor == 1) { radeonChooseRenderState( ctx ); } else { RADEON_STATECHANGE( rmesa, set ); if ( state ) { rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_ZBIAS_ENABLE_LINE; } else { rmesa->hw.set.cmd[SET_SE_CNTL] &= ~RADEON_ZBIAS_ENABLE_LINE; } } break; case GL_POLYGON_OFFSET_FILL: if (rmesa->dri.drmMinor == 1) { radeonChooseRenderState( ctx ); } else { RADEON_STATECHANGE( rmesa, set ); if ( state ) { rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_ZBIAS_ENABLE_TRI; } else { rmesa->hw.set.cmd[SET_SE_CNTL] &= ~RADEON_ZBIAS_ENABLE_TRI; } } break; case GL_POLYGON_SMOOTH: RADEON_STATECHANGE( rmesa, ctx ); if ( state ) { rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_ANTI_ALIAS_POLY; } else { rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_ANTI_ALIAS_POLY; } break; case GL_POLYGON_STIPPLE: RADEON_STATECHANGE(rmesa, ctx ); if ( state ) { rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_STIPPLE_ENABLE; } else { rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_STIPPLE_ENABLE; } break; case GL_RESCALE_NORMAL_EXT: { GLboolean tmp = ctx->_NeedEyeCoords ? state : !state; RADEON_STATECHANGE( rmesa, tcl ); if ( tmp ) { rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_RESCALE_NORMALS; } else { rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_RESCALE_NORMALS; } break; } case GL_SCISSOR_TEST: RADEON_FIREVERTICES( rmesa ); rmesa->state.scissor.enabled = state; radeonUpdateScissor( ctx ); break; case GL_STENCIL_TEST: if ( rmesa->state.stencil.hwBuffer ) { RADEON_STATECHANGE( rmesa, ctx ); if ( state ) { rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_STENCIL_ENABLE; } else { rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_STENCIL_ENABLE; } } else { FALLBACK( rmesa, RADEON_FALLBACK_STENCIL, state ); } break; case GL_TEXTURE_GEN_Q: case GL_TEXTURE_GEN_R: case GL_TEXTURE_GEN_S: case GL_TEXTURE_GEN_T: /* Picked up in radeonUpdateTextureState. */ rmesa->recheck_texgen[ctx->Texture.CurrentUnit] = GL_TRUE; break; case GL_COLOR_SUM_EXT: radeonUpdateSpecular ( ctx ); break; default: return; } } static void radeonLightingSpaceChange( GLcontext *ctx ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLboolean tmp; RADEON_STATECHANGE( rmesa, tcl ); if (RADEON_DEBUG & DEBUG_STATE) fprintf(stderr, "%s %d\n", __FUNCTION__, ctx->_NeedEyeCoords); if (ctx->_NeedEyeCoords) tmp = ctx->Transform.RescaleNormals; else tmp = !ctx->Transform.RescaleNormals; if ( tmp ) { rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_RESCALE_NORMALS; } else { rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_RESCALE_NORMALS; } } /* ============================================================= * Deferred state management - matrices, textures, other? */ static void upload_matrix( radeonContextPtr rmesa, GLfloat *src, int idx ) { float *dest = ((float *)RADEON_DB_STATE( mat[idx] ))+MAT_ELT_0; int i; for (i = 0 ; i < 4 ; i++) { *dest++ = src[i]; *dest++ = src[i+4]; *dest++ = src[i+8]; *dest++ = src[i+12]; } RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.mat[idx] ); } static void upload_matrix_t( radeonContextPtr rmesa, GLfloat *src, int idx ) { float *dest = ((float *)RADEON_DB_STATE( mat[idx] ))+MAT_ELT_0; memcpy(dest, src, 16*sizeof(float)); RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.mat[idx] ); } static void update_texturematrix( GLcontext *ctx ) { radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); GLuint tpc = rmesa->hw.tcl.cmd[TCL_TEXTURE_PROC_CTL]; GLuint vs = rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL]; int unit; rmesa->TexMatEnabled = 0; for (unit = 0 ; unit < 2; unit++) { if (!ctx->Texture.Unit[unit]._ReallyEnabled) { } else if (ctx->TextureMatrix[unit].type != MATRIX_IDENTITY) { GLuint inputshift = RADEON_TEXGEN_0_INPUT_SHIFT + unit*4; rmesa->TexMatEnabled |= (RADEON_TEXGEN_TEXMAT_0_ENABLE| RADEON_TEXMAT_0_ENABLE) << unit; if (rmesa->TexGenEnabled & (RADEON_TEXMAT_0_ENABLE << unit)) { /* Need to preconcatenate any active texgen * obj/eyeplane matrices: */ _math_matrix_mul_matrix( &rmesa->tmpmat, &rmesa->TexGenMatrix[unit], &ctx->TextureMatrix[unit] ); upload_matrix( rmesa, rmesa->tmpmat.m, TEXMAT_0+unit ); } else { rmesa->TexMatEnabled |= (RADEON_TEXGEN_INPUT_TEXCOORD_0+unit) << inputshift; upload_matrix( rmesa, ctx->TextureMatrix[unit].m, TEXMAT_0+unit ); } } else if (rmesa->TexGenEnabled & (RADEON_TEXMAT_0_ENABLE << unit)) { upload_matrix( rmesa, rmesa->TexGenMatrix[unit].m, TEXMAT_0+unit ); } } tpc = (rmesa->TexMatEnabled | rmesa->TexGenEnabled); vs &= ~((0xf << RADEON_TCL_TEX_0_OUTPUT_SHIFT) | (0xf << RADEON_TCL_TEX_1_OUTPUT_SHIFT)); if (tpc & RADEON_TEXGEN_TEXMAT_0_ENABLE) vs |= RADEON_TCL_TEX_COMPUTED_TEX_0 << RADEON_TCL_TEX_0_OUTPUT_SHIFT; else vs |= RADEON_TCL_TEX_INPUT_TEX_0 << RADEON_TCL_TEX_0_OUTPUT_SHIFT; if (tpc & RADEON_TEXGEN_TEXMAT_1_ENABLE) vs |= RADEON_TCL_TEX_COMPUTED_TEX_1 << RADEON_TCL_TEX_1_OUTPUT_SHIFT; else vs |= RADEON_TCL_TEX_INPUT_TEX_1 << RADEON_TCL_TEX_1_OUTPUT_SHIFT; if (tpc != rmesa->hw.tcl.cmd[TCL_TEXTURE_PROC_CTL] || vs != rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL]) { RADEON_STATECHANGE(rmesa, tcl); rmesa->hw.tcl.cmd[TCL_TEXTURE_PROC_CTL] = tpc; rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] = vs; } } void radeonValidateState( GLcontext *ctx ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); GLuint new_state = rmesa->NewGLState; if (new_state & _NEW_TEXTURE) { radeonUpdateTextureState( ctx ); new_state |= rmesa->NewGLState; /* may add TEXTURE_MATRIX */ } /* Need an event driven matrix update? */ if (new_state & (_NEW_MODELVIEW|_NEW_PROJECTION)) upload_matrix( rmesa, ctx->_ModelProjectMatrix.m, MODEL_PROJ ); /* Need these for lighting (shouldn't upload otherwise) */ if (new_state & (_NEW_MODELVIEW)) { upload_matrix( rmesa, ctx->ModelView.m, MODEL ); upload_matrix_t( rmesa, ctx->ModelView.inv, MODEL_IT ); } /* Does this need to be triggered on eg. modelview for * texgen-derived objplane/eyeplane matrices? */ if (new_state & _NEW_TEXTURE_MATRIX) { update_texturematrix( ctx ); } if (new_state & (_NEW_LIGHT|_NEW_MODELVIEW|_MESA_NEW_NEED_EYE_COORDS)) { update_light( ctx ); } /* emit all active clip planes if projection matrix changes. */ if (new_state & (_NEW_PROJECTION)) { if (ctx->Transform._AnyClip) radeonUpdateClipPlanes( ctx ); } rmesa->NewGLState = 0; } static void radeonInvalidateState( 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 ); _ae_invalidate_state( ctx, new_state ); RADEON_CONTEXT(ctx)->NewGLState |= new_state; radeonVtxfmtInvalidate( ctx ); } static void radeonWrapRunPipeline( GLcontext *ctx ) { radeonContextPtr rmesa = RADEON_CONTEXT(ctx); TNLcontext *tnl = TNL_CONTEXT(ctx); if (0) fprintf(stderr, "%s, newstate: %x\n", __FUNCTION__, rmesa->NewGLState); /* Validate state: */ if (rmesa->NewGLState) radeonValidateState( ctx ); if (tnl->vb.Material) { TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_MATERIAL, GL_TRUE ); } /* Run the pipeline. */ _tnl_run_pipeline( ctx ); if (tnl->vb.Material) { TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_MATERIAL, GL_FALSE ); radeonUpdateMaterial( ctx ); /* not needed any more? */ } } /* Initialize the driver's state functions. */ void radeonInitStateFuncs( GLcontext *ctx ) { ctx->Driver.UpdateState = radeonInvalidateState; ctx->Driver.LightingSpaceChange = radeonLightingSpaceChange; ctx->Driver.SetDrawBuffer = radeonSetDrawBuffer; ctx->Driver.AlphaFunc = radeonAlphaFunc; ctx->Driver.BlendEquation = radeonBlendEquation; ctx->Driver.BlendFunc = radeonBlendFunc; ctx->Driver.BlendFuncSeparate = radeonBlendFuncSeparate; ctx->Driver.ClearColor = radeonClearColor; ctx->Driver.ClearDepth = radeonClearDepth; ctx->Driver.ClearIndex = NULL; ctx->Driver.ClearStencil = radeonClearStencil; ctx->Driver.ClipPlane = radeonClipPlane; ctx->Driver.ColorMask = radeonColorMask; ctx->Driver.CullFace = radeonCullFace; ctx->Driver.DepthFunc = radeonDepthFunc; ctx->Driver.DepthMask = radeonDepthMask; ctx->Driver.DepthRange = radeonDepthRange; ctx->Driver.Enable = radeonEnable; ctx->Driver.Fogfv = radeonFogfv; ctx->Driver.FrontFace = radeonFrontFace; ctx->Driver.Hint = NULL; ctx->Driver.IndexMask = NULL; ctx->Driver.LightModelfv = radeonLightModelfv; ctx->Driver.Lightfv = radeonLightfv; ctx->Driver.LineStipple = radeonLineStipple; ctx->Driver.LineWidth = radeonLineWidth; ctx->Driver.LogicOpcode = radeonLogicOpCode; ctx->Driver.PolygonMode = radeonPolygonMode; if (RADEON_CONTEXT(ctx)->dri.drmMinor > 1) ctx->Driver.PolygonOffset = radeonPolygonOffset; ctx->Driver.PolygonStipple = radeonPolygonStipple; ctx->Driver.RenderMode = radeonRenderMode; ctx->Driver.Scissor = radeonScissor; ctx->Driver.ShadeModel = radeonShadeModel; ctx->Driver.StencilFunc = radeonStencilFunc; ctx->Driver.StencilMask = radeonStencilMask; ctx->Driver.StencilOp = radeonStencilOp; ctx->Driver.Viewport = radeonViewport; /* Pixel path fallbacks */ ctx->Driver.Accum = _swrast_Accum; ctx->Driver.Bitmap = _swrast_Bitmap; ctx->Driver.CopyPixels = _swrast_CopyPixels; ctx->Driver.DrawPixels = _swrast_DrawPixels; ctx->Driver.ReadPixels = _swrast_ReadPixels; /* 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; TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange = radeonUpdateMaterial; TNL_CONTEXT(ctx)->Driver.RunPipeline = radeonWrapRunPipeline; }