/* * Copyright 2000-2001 VA Linux Systems, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * on the rights to use, copy, modify, merge, publish, distribute, sub * license, and/or sell copies of the Software, and to permit persons to whom * the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Keith Whitwell */ #include "main/mtypes.h" #include "main/colormac.h" #include "main/dd.h" #include "main/mm.h" #include "main/state.h" #include "mgacontext.h" #include "mgadd.h" #include "mgastate.h" #include "mgatex.h" #include "mgavb.h" #include "mgatris.h" #include "mgaioctl.h" #include "mgaregs.h" #include "swrast/swrast.h" #include "vbo/vbo.h" #include "tnl/tnl.h" #include "tnl/t_context.h" #include "tnl/t_pipeline.h" #include "swrast_setup/swrast_setup.h" #include "xmlpool.h" #include "drirenderbuffer.h" static void updateSpecularLighting( struct gl_context *ctx ); static const GLuint mgarop_NoBLK[16] = { DC_atype_rpl | 0x00000000, DC_atype_rstr | 0x00080000, DC_atype_rstr | 0x00040000, DC_atype_rpl | 0x000c0000, DC_atype_rstr | 0x00020000, DC_atype_rstr | 0x000a0000, DC_atype_rstr | 0x00060000, DC_atype_rstr | 0x000e0000, DC_atype_rstr | 0x00010000, DC_atype_rstr | 0x00090000, DC_atype_rstr | 0x00050000, DC_atype_rstr | 0x000d0000, DC_atype_rpl | 0x00030000, DC_atype_rstr | 0x000b0000, DC_atype_rstr | 0x00070000, DC_atype_rpl | 0x000f0000 }; /* ============================================================= * Alpha blending */ static void mgaDDAlphaFunc(struct gl_context *ctx, GLenum func, GLfloat ref) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); GLubyte refByte; GLuint a; CLAMPED_FLOAT_TO_UBYTE(refByte, ref); switch ( func ) { case GL_NEVER: a = AC_atmode_alt; refByte = 0; break; case GL_LESS: a = AC_atmode_alt; break; case GL_GEQUAL: a = AC_atmode_agte; break; case GL_LEQUAL: a = AC_atmode_alte; break; case GL_GREATER: a = AC_atmode_agt; break; case GL_NOTEQUAL: a = AC_atmode_ane; break; case GL_EQUAL: a = AC_atmode_ae; break; case GL_ALWAYS: a = AC_atmode_noacmp; break; default: a = 0; break; } MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); mmesa->hw.alpha_func = a | MGA_FIELD( AC_atref, refByte ); } static void updateBlendLogicOp(struct gl_context *ctx) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); GLboolean logicOp = _mesa_rgba_logicop_enabled(ctx); MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); mmesa->hw.blend_func_enable = (ctx->Color.BlendEnabled && !logicOp) ? ~0 : 0; FALLBACK( ctx, MGA_FALLBACK_BLEND, ctx->Color.BlendEnabled && !logicOp && mmesa->hw.blend_func == (AC_src_src_alpha_sat | AC_dst_zero) ); } static void mgaDDBlendEquationSeparate(struct gl_context *ctx, GLenum modeRGB, GLenum modeA) { assert( modeRGB == modeA ); updateBlendLogicOp( ctx ); } static void mgaDDBlendFuncSeparate( struct gl_context *ctx, GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorA, GLenum dfactorA ) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); GLuint src; GLuint dst; switch (ctx->Color.Blend[0].SrcRGB) { case GL_ZERO: src = AC_src_zero; break; case GL_SRC_ALPHA: src = AC_src_src_alpha; break; case GL_ONE: default: /* never happens */ src = AC_src_one; break; case GL_DST_COLOR: src = AC_src_dst_color; break; case GL_ONE_MINUS_DST_COLOR: src = AC_src_om_dst_color; break; case GL_ONE_MINUS_SRC_ALPHA: src = AC_src_om_src_alpha; break; case GL_DST_ALPHA: src = (ctx->Visual.alphaBits > 0) ? AC_src_dst_alpha : AC_src_one; break; case GL_ONE_MINUS_DST_ALPHA: src = (ctx->Visual.alphaBits > 0) ? AC_src_om_dst_alpha : AC_src_zero; break; case GL_SRC_ALPHA_SATURATE: src = (ctx->Visual.alphaBits > 0) ? AC_src_src_alpha_sat : AC_src_zero; break; } switch (ctx->Color.Blend[0].DstRGB) { case GL_SRC_ALPHA: dst = AC_dst_src_alpha; break; case GL_ONE_MINUS_SRC_ALPHA: dst = AC_dst_om_src_alpha; break; default: /* never happens */ case GL_ZERO: dst = AC_dst_zero; break; case GL_ONE: dst = AC_dst_one; break; case GL_SRC_COLOR: dst = AC_dst_src_color; break; case GL_ONE_MINUS_SRC_COLOR: dst = AC_dst_om_src_color; break; case GL_DST_ALPHA: dst = (ctx->Visual.alphaBits > 0) ? AC_dst_dst_alpha : AC_dst_one; break; case GL_ONE_MINUS_DST_ALPHA: dst = (ctx->Visual.alphaBits > 0) ? AC_dst_om_dst_alpha : AC_dst_zero; break; } MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); mmesa->hw.blend_func = (src | dst); FALLBACK( ctx, MGA_FALLBACK_BLEND, ctx->Color.BlendEnabled && !_mesa_rgba_logicop_enabled(ctx) && mmesa->hw.blend_func == (AC_src_src_alpha_sat | AC_dst_zero) ); } /* ============================================================= * Depth testing */ static void mgaDDDepthFunc(struct gl_context *ctx, GLenum func) { mgaContextPtr mmesa = MGA_CONTEXT( ctx ); int zmode; switch (func) { case GL_NEVER: /* can't do this in h/w, we'll use a s/w fallback */ FALLBACK (ctx, MGA_FALLBACK_DEPTH, ctx->Depth.Test); /* FALLTHROUGH */ case GL_ALWAYS: zmode = DC_zmode_nozcmp; break; case GL_LESS: zmode = DC_zmode_zlt; break; case GL_LEQUAL: zmode = DC_zmode_zlte; break; case GL_EQUAL: zmode = DC_zmode_ze; break; case GL_GREATER: zmode = DC_zmode_zgt; break; case GL_GEQUAL: zmode = DC_zmode_zgte; break; case GL_NOTEQUAL: zmode = DC_zmode_zne; break; default: zmode = 0; break; } MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); mmesa->hw.zmode &= DC_zmode_MASK; mmesa->hw.zmode |= zmode; } static void mgaDDDepthMask(struct gl_context *ctx, GLboolean flag) { mgaContextPtr mmesa = MGA_CONTEXT( ctx ); MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); mmesa->hw.zmode &= DC_atype_MASK; mmesa->hw.zmode |= (flag) ? DC_atype_zi : DC_atype_i; } static void mgaDDClearDepth(struct gl_context *ctx, GLclampd d) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); /* Select the Z depth. The ~ is used because the _MASK values in the * MGA driver are used to mask OFF the selected bits. In this case, * we want to mask off everything except the MA_zwidth bits. */ switch (mmesa->setup.maccess & ~MA_zwidth_MASK) { case MA_zwidth_16: mmesa->ClearDepth = d * 0x0000ffff; break; case MA_zwidth_24: mmesa->ClearDepth = d * 0xffffff00; break; case MA_zwidth_32: mmesa->ClearDepth = d * 0xffffffff; break; default: return; } } /* ============================================================= * Fog */ static void mgaDDFogfv(struct gl_context *ctx, GLenum pname, const GLfloat *param) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); if (pname == GL_FOG_COLOR) { GLuint color = PACK_COLOR_888((GLubyte)(ctx->Fog.Color[0]*255.0F), (GLubyte)(ctx->Fog.Color[1]*255.0F), (GLubyte)(ctx->Fog.Color[2]*255.0F)); MGA_STATECHANGE(mmesa, MGA_UPLOAD_CONTEXT); mmesa->setup.fogcolor = color; } } /* ============================================================= * Scissoring */ void mgaUpdateClipping(const struct gl_context *ctx) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); if (mmesa->driDrawable) { int x1 = mmesa->driDrawable->x + ctx->Scissor.X; int y1 = mmesa->driDrawable->y + mmesa->driDrawable->h - (ctx->Scissor.Y + ctx->Scissor.Height); int x2 = x1 + ctx->Scissor.Width; int y2 = y1 + ctx->Scissor.Height; if (x1 < 0) x1 = 0; if (y1 < 0) y1 = 0; if (x2 < 0) x2 = 0; if (y2 < 0) y2 = 0; mmesa->scissor_rect.x1 = x1; mmesa->scissor_rect.y1 = y1; mmesa->scissor_rect.x2 = x2; mmesa->scissor_rect.y2 = y2; mmesa->dirty |= MGA_UPLOAD_CLIPRECTS; } } static void mgaDDScissor( struct gl_context *ctx, GLint x, GLint y, GLsizei w, GLsizei h ) { if ( ctx->Scissor.Enabled ) { FLUSH_BATCH( MGA_CONTEXT(ctx) ); /* don't pipeline cliprect changes */ mgaUpdateClipping( ctx ); } } /* ============================================================= * Culling */ #define _CULL_DISABLE 0 #define _CULL_NEGATIVE ((1<<11)|(1<<5)|(1<<16)) #define _CULL_POSITIVE (1<<11) static void mgaDDCullFaceFrontFace(struct gl_context *ctx, GLenum unused) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); if (ctx->Polygon.CullFlag && ctx->Polygon.CullFaceMode != GL_FRONT_AND_BACK) { mmesa->hw.cull = _CULL_NEGATIVE; if (ctx->Polygon.CullFaceMode == GL_FRONT) mmesa->hw.cull ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE); if (ctx->Polygon.FrontFace != GL_CCW) mmesa->hw.cull ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE); mmesa->hw.cull_dualtex = mmesa->hw.cull ^ (_CULL_POSITIVE ^ _CULL_NEGATIVE); /* warp bug? */ } else { mmesa->hw.cull = _CULL_DISABLE; mmesa->hw.cull_dualtex = _CULL_DISABLE; } } /* ============================================================= * Masks */ static void mgaDDColorMask(struct gl_context *ctx, GLboolean r, GLboolean g, GLboolean b, GLboolean a ) { mgaContextPtr mmesa = MGA_CONTEXT( ctx ); mgaScreenPrivate *mgaScreen = mmesa->mgaScreen; GLuint mask = mgaPackColor(mgaScreen->cpp, ctx->Color.ColorMask[0][RCOMP], ctx->Color.ColorMask[0][GCOMP], ctx->Color.ColorMask[0][BCOMP], ctx->Color.ColorMask[0][ACOMP]); if (mgaScreen->cpp == 2) mask = mask | (mask << 16); if (mmesa->setup.plnwt != mask) { MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); mmesa->setup.plnwt = mask; } } /* ============================================================= * Polygon state */ static int mgaStipples[16] = { 0xffff, 0xa5a5, 0x5a5a, 0xa0a0, 0x5050, 0x0a0a, 0x0505, 0x8020, 0x0401, 0x1040, 0x0208, 0x0802, 0x4010, 0x0104, 0x2080, 0x0000 }; /** * The MGA supports a subset of possible 4x4 stipples natively, GL * wants 32x32. Fortunately stipple is usually a repeating pattern. * * \param ctx GL rendering context to be affected * \param mask Pointer to the 32x32 stipple mask */ static void mgaDDPolygonStipple( struct gl_context *ctx, const GLubyte *mask ) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); const GLubyte *m = mask; GLubyte p[4]; int i,j,k; int active = (ctx->Polygon.StippleFlag && mmesa->raster_primitive == GL_TRIANGLES); GLuint stipple; FLUSH_BATCH(mmesa); mmesa->haveHwStipple = 0; if (active) { mmesa->dirty |= MGA_UPLOAD_CONTEXT; mmesa->setup.dwgctl &= ~(0xf<<20); } p[0] = mask[0] & 0xf; p[0] |= p[0] << 4; p[1] = mask[4] & 0xf; p[1] |= p[1] << 4; p[2] = mask[8] & 0xf; p[2] |= p[2] << 4; p[3] = mask[12] & 0xf; p[3] |= p[3] << 4; for (k = 0 ; k < 8 ; k++) for (j = 0 ; j < 4; j++) for (i = 0 ; i < 4 ; i++) if (*m++ != p[j]) { return; } stipple = ( ((p[0] & 0xf) << 0) | ((p[1] & 0xf) << 4) | ((p[2] & 0xf) << 8) | ((p[3] & 0xf) << 12) ); for (i = 0 ; i < 16 ; i++) if (mgaStipples[i] == stipple) { mmesa->poly_stipple = i<<20; mmesa->haveHwStipple = 1; break; } if (active) { mmesa->setup.dwgctl &= ~(0xf<<20); mmesa->setup.dwgctl |= mmesa->poly_stipple; } } /* ============================================================= * 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. */ static void updateSpecularLighting( struct gl_context *ctx ) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); unsigned int specen; specen = _mesa_need_secondary_color(ctx) ? TMC_specen_enable : 0; if ( specen != mmesa->hw.specen ) { mmesa->hw.specen = specen; mmesa->dirty |= MGA_UPLOAD_TEX0 | MGA_UPLOAD_TEX1; } } /* ============================================================= * Materials */ static void mgaDDLightModelfv(struct gl_context *ctx, GLenum pname, const GLfloat *param) { if (pname == GL_LIGHT_MODEL_COLOR_CONTROL) { FLUSH_BATCH( MGA_CONTEXT(ctx) ); updateSpecularLighting( ctx ); } } /* ============================================================= * Stencil */ static void mgaDDStencilFuncSeparate(struct gl_context *ctx, GLenum face, GLenum func, GLint ref, GLuint mask) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); GLuint stencil; GLuint stencilctl; stencil = MGA_FIELD( S_sref, ref ) | MGA_FIELD( S_smsk, mask ); switch (func) { case GL_NEVER: stencilctl = SC_smode_snever; break; case GL_LESS: stencilctl = SC_smode_slt; break; case GL_LEQUAL: stencilctl = SC_smode_slte; break; case GL_GREATER: stencilctl = SC_smode_sgt; break; case GL_GEQUAL: stencilctl = SC_smode_sgte; break; case GL_NOTEQUAL: stencilctl = SC_smode_sne; break; case GL_EQUAL: stencilctl = SC_smode_se; break; case GL_ALWAYS: default: stencilctl = SC_smode_salways; break; } MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); mmesa->hw.stencil &= (S_sref_MASK & S_smsk_MASK); mmesa->hw.stencil |= stencil; mmesa->hw.stencilctl &= SC_smode_MASK; mmesa->hw.stencilctl |= stencilctl; } static void mgaDDStencilMaskSeparate(struct gl_context *ctx, GLenum face, GLuint mask) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); mmesa->hw.stencil &= S_swtmsk_MASK; mmesa->hw.stencil |= MGA_FIELD( S_swtmsk, mask ); } static void mgaDDStencilOpSeparate(struct gl_context *ctx, GLenum face, GLenum fail, GLenum zfail, GLenum zpass) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); GLuint stencilctl; stencilctl = 0; switch (ctx->Stencil.FailFunc[0]) { case GL_KEEP: stencilctl |= SC_sfailop_keep; break; case GL_ZERO: stencilctl |= SC_sfailop_zero; break; case GL_REPLACE: stencilctl |= SC_sfailop_replace; break; case GL_INCR: stencilctl |= SC_sfailop_incrsat; break; case GL_DECR: stencilctl |= SC_sfailop_decrsat; break; case GL_INCR_WRAP: stencilctl |= SC_sfailop_incr; break; case GL_DECR_WRAP: stencilctl |= SC_sfailop_decr; break; case GL_INVERT: stencilctl |= SC_sfailop_invert; break; default: break; } switch (ctx->Stencil.ZFailFunc[0]) { case GL_KEEP: stencilctl |= SC_szfailop_keep; break; case GL_ZERO: stencilctl |= SC_szfailop_zero; break; case GL_REPLACE: stencilctl |= SC_szfailop_replace; break; case GL_INCR: stencilctl |= SC_szfailop_incrsat; break; case GL_DECR: stencilctl |= SC_szfailop_decrsat; break; case GL_INCR_WRAP: stencilctl |= SC_szfailop_incr; break; case GL_DECR_WRAP: stencilctl |= SC_szfailop_decr; break; case GL_INVERT: stencilctl |= SC_szfailop_invert; break; default: break; } switch (ctx->Stencil.ZPassFunc[0]) { case GL_KEEP: stencilctl |= SC_szpassop_keep; break; case GL_ZERO: stencilctl |= SC_szpassop_zero; break; case GL_REPLACE: stencilctl |= SC_szpassop_replace; break; case GL_INCR: stencilctl |= SC_szpassop_incrsat; break; case GL_DECR: stencilctl |= SC_szpassop_decrsat; break; case GL_INCR_WRAP: stencilctl |= SC_szpassop_incr; break; case GL_DECR_WRAP: stencilctl |= SC_szpassop_decr; break; case GL_INVERT: stencilctl |= SC_szpassop_invert; break; default: break; } MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); mmesa->hw.stencilctl &= (SC_sfailop_MASK & SC_szfailop_MASK & SC_szpassop_MASK); mmesa->hw.stencilctl |= stencilctl; } /* ============================================================= * Window position and viewport transformation */ void mgaCalcViewport( struct gl_context *ctx ) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); const GLfloat *v = ctx->Viewport._WindowMap.m; GLfloat *m = mmesa->hw_viewport; /* See also mga_translate_vertex. */ m[MAT_SX] = v[MAT_SX]; m[MAT_TX] = v[MAT_TX] + mmesa->drawX + SUBPIXEL_X; m[MAT_SY] = - v[MAT_SY]; m[MAT_TY] = - v[MAT_TY] + mmesa->driDrawable->h + mmesa->drawY + SUBPIXEL_Y; m[MAT_SZ] = v[MAT_SZ] * mmesa->depth_scale; m[MAT_TZ] = v[MAT_TZ] * mmesa->depth_scale; mmesa->SetupNewInputs = ~0; } static void mgaViewport( struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height ) { mgaCalcViewport( ctx ); } static void mgaDepthRange( struct gl_context *ctx, GLclampd nearval, GLclampd farval ) { mgaCalcViewport( ctx ); } /* ============================================================= * Miscellaneous */ static void mgaDDClearColor(struct gl_context *ctx, const GLfloat color[4] ) { mgaContextPtr mmesa = MGA_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]); mmesa->ClearColor = mgaPackColor( mmesa->mgaScreen->cpp, c[0], c[1], c[2], c[3]); } /* Fallback to swrast for select and feedback. */ static void mgaRenderMode( struct gl_context *ctx, GLenum mode ) { FALLBACK( ctx, MGA_FALLBACK_RENDERMODE, (mode != GL_RENDER) ); } static void mgaDDLogicOp( struct gl_context *ctx, GLenum opcode ) { mgaContextPtr mmesa = MGA_CONTEXT( ctx ); MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); mmesa->hw.rop = mgarop_NoBLK[ opcode & 0x0f ]; } static void mga_set_cliprects(mgaContextPtr mmesa) { __DRIdrawable *driDrawable = mmesa->driDrawable; if ((mmesa->draw_buffer != MGA_FRONT) || (driDrawable->numBackClipRects == 0)) { if (driDrawable->numClipRects == 0) { static drm_clip_rect_t zeroareacliprect = {0,0,0,0}; mmesa->numClipRects = 1; mmesa->pClipRects = &zeroareacliprect; } else { mmesa->numClipRects = driDrawable->numClipRects; mmesa->pClipRects = driDrawable->pClipRects; } mmesa->drawX = driDrawable->x; mmesa->drawY = driDrawable->y; } else { mmesa->numClipRects = driDrawable->numBackClipRects; mmesa->pClipRects = driDrawable->pBackClipRects; mmesa->drawX = driDrawable->backX; mmesa->drawY = driDrawable->backY; } mmesa->setup.dstorg = mmesa->drawOffset; mmesa->dirty |= MGA_UPLOAD_CONTEXT | MGA_UPLOAD_CLIPRECTS; } void mgaUpdateRects( mgaContextPtr mmesa, GLuint buffers ) { __DRIdrawable *const driDrawable = mmesa->driDrawable; __DRIdrawable *const driReadable = mmesa->driReadable; mmesa->dirty_cliprects = 0; driUpdateFramebufferSize(mmesa->glCtx, driDrawable); if (driDrawable != driReadable) { driUpdateFramebufferSize(mmesa->glCtx, driReadable); } mga_set_cliprects(mmesa); mgaUpdateClipping( mmesa->glCtx ); mgaCalcViewport( mmesa->glCtx ); } static void mgaDDDrawBuffer(struct gl_context *ctx, GLenum mode ) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); FLUSH_BATCH( mmesa ); if (ctx->DrawBuffer->_NumColorDrawBuffers != 1) { /* GL_NONE or GL_FRONT_AND_BACK or stereo left&right, etc */ FALLBACK( ctx, MGA_FALLBACK_DRAW_BUFFER, GL_TRUE ); return; } switch ( ctx->DrawBuffer->_ColorDrawBufferIndexes[0] ) { case BUFFER_FRONT_LEFT: mmesa->setup.dstorg = mmesa->mgaScreen->frontOffset; mmesa->draw_buffer = MGA_FRONT; break; case BUFFER_BACK_LEFT: mmesa->setup.dstorg = mmesa->mgaScreen->backOffset; mmesa->draw_buffer = MGA_BACK; break; default: FALLBACK( ctx, MGA_FALLBACK_DRAW_BUFFER, GL_TRUE ); return; } mmesa->dirty |= MGA_UPLOAD_CONTEXT; mga_set_cliprects(mmesa); FALLBACK(ctx, MGA_FALLBACK_DRAW_BUFFER, GL_FALSE); } static void mgaDDReadBuffer(struct gl_context *ctx, GLenum mode ) { /* nothing, until we implement h/w glRead/CopyPixels or CopyTexImage */ } /* ============================================================= * State enable/disable */ static void mgaDDEnable(struct gl_context *ctx, GLenum cap, GLboolean state) { mgaContextPtr mmesa = MGA_CONTEXT( ctx ); switch(cap) { case GL_DITHER: MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); if (!ctx->Color.DitherFlag) mmesa->setup.maccess |= MA_nodither_enable; else mmesa->setup.maccess &= ~MA_nodither_enable; break; case GL_LIGHTING: case GL_COLOR_SUM_EXT: FLUSH_BATCH( mmesa ); updateSpecularLighting( ctx ); break; case GL_ALPHA_TEST: MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); mmesa->hw.alpha_func_enable = (state) ? ~0 : 0; break; case GL_DEPTH_TEST: MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); FALLBACK (ctx, MGA_FALLBACK_DEPTH, ctx->Depth.Func == GL_NEVER && ctx->Depth.Test); break; case GL_SCISSOR_TEST: FLUSH_BATCH( mmesa ); mmesa->scissor = state; mgaUpdateClipping( ctx ); break; case GL_FOG: MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); if (ctx->Fog.Enabled) mmesa->setup.maccess |= MA_fogen_enable; else mmesa->setup.maccess &= ~MA_fogen_enable; break; case GL_CULL_FACE: mgaDDCullFaceFrontFace( ctx, 0 ); break; case GL_TEXTURE_1D: case GL_TEXTURE_2D: case GL_TEXTURE_3D: break; case GL_POLYGON_STIPPLE: if (mmesa->haveHwStipple && mmesa->raster_primitive == GL_TRIANGLES) { MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); mmesa->setup.dwgctl &= ~(0xf<<20); if (state) mmesa->setup.dwgctl |= mmesa->poly_stipple; } break; case GL_BLEND: case GL_COLOR_LOGIC_OP: updateBlendLogicOp( ctx ); break; case GL_STENCIL_TEST: MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); if (mmesa->hw_stencil) { mmesa->hw.stencil_enable = ( state ) ? ~0 : 0; } else { FALLBACK( ctx, MGA_FALLBACK_STENCIL, state ); } default: break; } } /* ============================================================= */ static void mgaDDPrintDirty( const char *msg, GLuint state ) { fprintf(stderr, "%s (0x%03x): %s%s%s%s%s%s%s\n", msg, (unsigned int) state, (state & MGA_WAIT_AGE) ? "wait-age " : "", (state & MGA_UPLOAD_TEX0IMAGE) ? "upload-tex0-img " : "", (state & MGA_UPLOAD_TEX1IMAGE) ? "upload-tex1-img " : "", (state & MGA_UPLOAD_CONTEXT) ? "upload-ctx " : "", (state & MGA_UPLOAD_TEX0) ? "upload-tex0 " : "", (state & MGA_UPLOAD_TEX1) ? "upload-tex1 " : "", (state & MGA_UPLOAD_PIPE) ? "upload-pipe " : "" ); } /* Push the state into the sarea and/or texture memory. */ void mgaEmitHwStateLocked( mgaContextPtr mmesa ) { drm_mga_sarea_t *sarea = mmesa->sarea; struct gl_context * ctx = mmesa->glCtx; if (MGA_DEBUG & DEBUG_VERBOSE_MSG) mgaDDPrintDirty( __FUNCTION__, mmesa->dirty ); if (mmesa->dirty & MGA_UPLOAD_CONTEXT) { mmesa->setup.wflag = _CULL_DISABLE; if (mmesa->raster_primitive == GL_TRIANGLES) { if ((ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT && ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT)) { mmesa->setup.wflag = mmesa->hw.cull_dualtex; } else { mmesa->setup.wflag = mmesa->hw.cull; } } mmesa->setup.stencil = mmesa->hw.stencil & mmesa->hw.stencil_enable; mmesa->setup.stencilctl = mmesa->hw.stencilctl & mmesa->hw.stencil_enable; /* If depth testing is not enabled, then use the no Z-compare / no * Z-write mode. Otherwise, use whatever is set in hw.zmode. */ mmesa->setup.dwgctl &= (DC_zmode_MASK & DC_atype_MASK); mmesa->setup.dwgctl |= (ctx->Depth.Test) ? mmesa->hw.zmode : (DC_zmode_nozcmp | DC_atype_i); mmesa->setup.dwgctl &= DC_bop_MASK; mmesa->setup.dwgctl |= _mesa_rgba_logicop_enabled(ctx) ? mmesa->hw.rop : mgarop_NoBLK[ GL_COPY & 0x0f ]; mmesa->setup.alphactrl &= AC_src_MASK & AC_dst_MASK & AC_atmode_MASK & AC_atref_MASK & AC_alphasel_MASK; mmesa->setup.alphactrl |= (mmesa->hw.alpha_func & mmesa->hw.alpha_func_enable) | (mmesa->hw.blend_func & mmesa->hw.blend_func_enable) | ((AC_src_one | AC_dst_zero) & ~mmesa->hw.blend_func_enable) | mmesa->hw.alpha_sel; memcpy( &sarea->context_state, &mmesa->setup, sizeof(mmesa->setup)); } if ((mmesa->dirty & MGA_UPLOAD_TEX0) && mmesa->CurrentTexObj[0]) { memcpy(&sarea->tex_state[0], &mmesa->CurrentTexObj[0]->setup, sizeof(sarea->tex_state[0])); } if ((mmesa->dirty & MGA_UPLOAD_TEX1) && mmesa->CurrentTexObj[1]) { memcpy(&sarea->tex_state[1], &mmesa->CurrentTexObj[1]->setup, sizeof(sarea->tex_state[1])); } if (mmesa->dirty & (MGA_UPLOAD_TEX0 | MGA_UPLOAD_TEX1)) { sarea->tex_state[0].texctl2 &= ~TMC_specen_enable; sarea->tex_state[1].texctl2 &= ~TMC_specen_enable; sarea->tex_state[0].texctl2 |= mmesa->hw.specen; sarea->tex_state[1].texctl2 |= mmesa->hw.specen; } if (mmesa->dirty & MGA_UPLOAD_PIPE) { /* mmesa->sarea->wacceptseq = mmesa->hw_primitive; */ mmesa->sarea->warp_pipe = mmesa->vertex_format; mmesa->sarea->vertsize = mmesa->vertex_size; } mmesa->sarea->dirty |= mmesa->dirty; mmesa->dirty &= MGA_UPLOAD_CLIPRECTS; } /* ============================================================= */ static void mgaDDValidateState( struct gl_context *ctx ) { mgaContextPtr mmesa = MGA_CONTEXT( ctx ); FLUSH_BATCH( mmesa ); if (mmesa->NewGLState & _NEW_TEXTURE) { mgaUpdateTextureState(ctx); } if (!mmesa->Fallback) { if (mmesa->NewGLState & _MGA_NEW_RASTERSETUP) { mgaChooseVertexState( ctx ); } if (mmesa->NewGLState & _MGA_NEW_RENDERSTATE) { mgaChooseRenderState( ctx ); } } mmesa->NewGLState = 0; } static void mgaDDInvalidateState( struct gl_context *ctx, GLuint new_state ) { _swrast_InvalidateState( ctx, new_state ); _swsetup_InvalidateState( ctx, new_state ); _vbo_InvalidateState( ctx, new_state ); _tnl_InvalidateState( ctx, new_state ); MGA_CONTEXT(ctx)->NewGLState |= new_state; } static void mgaRunPipeline( struct gl_context *ctx ) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); if (mmesa->NewGLState) { mgaDDValidateState( ctx ); } if (mmesa->dirty) { mgaEmitHwStateLocked( mmesa ); } _tnl_run_pipeline( ctx ); } void mgaInitState( mgaContextPtr mmesa ) { mgaScreenPrivate *mgaScreen = mmesa->mgaScreen; struct gl_context *ctx = mmesa->glCtx; if (ctx->Visual.doubleBufferMode) { /* use back buffer by default */ mmesa->draw_buffer = MGA_BACK; mmesa->drawOffset = mmesa->mgaScreen->backOffset; mmesa->readOffset = mmesa->mgaScreen->backOffset; mmesa->setup.dstorg = mgaScreen->backOffset; } else { /* use front buffer by default */ mmesa->draw_buffer = MGA_FRONT; mmesa->drawOffset = mmesa->mgaScreen->frontOffset; mmesa->readOffset = mmesa->mgaScreen->frontOffset; mmesa->setup.dstorg = mgaScreen->frontOffset; } mmesa->setup.maccess = (MA_memreset_disable | MA_fogen_disable | MA_tlutload_disable | MA_nodither_disable | MA_dit555_disable); if (driQueryOptioni (&mmesa->optionCache, "color_reduction") != DRI_CONF_COLOR_REDUCTION_DITHER) mmesa->setup.maccess |= MA_nodither_enable; switch (mmesa->mgaScreen->cpp) { case 2: mmesa->setup.maccess |= MA_pwidth_16; break; case 4: mmesa->setup.maccess |= MA_pwidth_32; break; default: fprintf( stderr, "Error: unknown cpp %d, exiting...\n", mmesa->mgaScreen->cpp ); exit( 1 ); } switch (mmesa->glCtx->Visual.depthBits) { case 16: mmesa->setup.maccess |= MA_zwidth_16; break; case 24: mmesa->setup.maccess |= MA_zwidth_24; break; case 32: mmesa->setup.maccess |= MA_zwidth_32; break; } mmesa->hw.blend_func = AC_src_one | AC_dst_zero; mmesa->hw.blend_func_enable = 0; mmesa->hw.alpha_func = AC_atmode_noacmp | MGA_FIELD( AC_atref, 0x00 ); mmesa->hw.alpha_func_enable = 0; mmesa->hw.rop = mgarop_NoBLK[ GL_COPY & 0x0f ]; mmesa->hw.zmode = DC_zmode_zlt | DC_atype_zi; mmesa->hw.stencil = MGA_FIELD( S_sref, 0x00) | MGA_FIELD( S_smsk, 0xff ) | MGA_FIELD( S_swtmsk, 0xff ); mmesa->hw.stencilctl = SC_smode_salways | SC_sfailop_keep | SC_szfailop_keep | SC_szpassop_keep; mmesa->hw.stencil_enable = 0; mmesa->hw.cull = _CULL_DISABLE; mmesa->hw.cull_dualtex = _CULL_DISABLE; mmesa->hw.specen = 0; mmesa->hw.alpha_sel = AC_alphasel_diffused; mmesa->setup.dwgctl = (DC_opcod_trap | DC_linear_xy | DC_solid_disable | DC_arzero_disable | DC_sgnzero_disable | DC_shftzero_enable | MGA_FIELD( DC_bop, 0xC ) | MGA_FIELD( DC_trans, 0x0 ) | DC_bltmod_bmonolef | DC_pattern_disable | DC_transc_disable | DC_clipdis_disable); mmesa->setup.plnwt = ~0; mmesa->setup.alphactrl = (AC_amode_alpha_channel | AC_astipple_disable | AC_aten_disable); mmesa->setup.fogcolor = PACK_COLOR_888((GLubyte)(ctx->Fog.Color[0]*255.0F), (GLubyte)(ctx->Fog.Color[1]*255.0F), (GLubyte)(ctx->Fog.Color[2]*255.0F)); mmesa->setup.wflag = 0; mmesa->setup.tdualstage0 = 0; mmesa->setup.tdualstage1 = 0; mmesa->setup.fcol = 0; mmesa->dirty |= MGA_UPLOAD_CONTEXT; mmesa->envcolor[0] = 0; mmesa->envcolor[1] = 0; } void mgaDDInitStateFuncs( struct gl_context *ctx ) { ctx->Driver.UpdateState = mgaDDInvalidateState; ctx->Driver.Enable = mgaDDEnable; ctx->Driver.LightModelfv = mgaDDLightModelfv; ctx->Driver.AlphaFunc = mgaDDAlphaFunc; ctx->Driver.BlendEquationSeparate = mgaDDBlendEquationSeparate; ctx->Driver.BlendFuncSeparate = mgaDDBlendFuncSeparate; ctx->Driver.DepthFunc = mgaDDDepthFunc; ctx->Driver.DepthMask = mgaDDDepthMask; ctx->Driver.Fogfv = mgaDDFogfv; ctx->Driver.Scissor = mgaDDScissor; ctx->Driver.CullFace = mgaDDCullFaceFrontFace; ctx->Driver.FrontFace = mgaDDCullFaceFrontFace; ctx->Driver.ColorMask = mgaDDColorMask; ctx->Driver.DrawBuffer = mgaDDDrawBuffer; ctx->Driver.ReadBuffer = mgaDDReadBuffer; ctx->Driver.ClearColor = mgaDDClearColor; ctx->Driver.ClearDepth = mgaDDClearDepth; ctx->Driver.LogicOpcode = mgaDDLogicOp; ctx->Driver.PolygonStipple = mgaDDPolygonStipple; ctx->Driver.StencilFuncSeparate = mgaDDStencilFuncSeparate; ctx->Driver.StencilMaskSeparate = mgaDDStencilMaskSeparate; ctx->Driver.StencilOpSeparate = mgaDDStencilOpSeparate; ctx->Driver.DepthRange = mgaDepthRange; ctx->Driver.Viewport = mgaViewport; ctx->Driver.RenderMode = mgaRenderMode; TNL_CONTEXT(ctx)->Driver.RunPipeline = mgaRunPipeline; }