| /* $XFree86: xc/lib/GL/mesa/src/drv/ffb/ffb_state.c,v 1.5 2002/10/30 12:51:27 alanh Exp $ |
| * |
| * GLX Hardware Device Driver for Sun Creator/Creator3D |
| * Copyright (C) 2000, 2001 David S. Miller |
| * |
| * 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, sublicense, |
| * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL |
| * DAVID MILLER, OR ANY OTHER CONTRIBUTORS 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. |
| * |
| * |
| * David S. Miller <davem@redhat.com> |
| */ |
| |
| #include "mtypes.h" |
| #include "colormac.h" |
| #include "mm.h" |
| #include "ffb_dd.h" |
| #include "ffb_span.h" |
| #include "ffb_depth.h" |
| #include "ffb_context.h" |
| #include "ffb_vb.h" |
| #include "ffb_tris.h" |
| #include "ffb_state.h" |
| #include "ffb_lock.h" |
| #include "extensions.h" |
| #include "enums.h" |
| |
| #include "swrast/swrast.h" |
| #include "vbo/vbo.h" |
| #include "tnl/tnl.h" |
| #include "swrast_setup/swrast_setup.h" |
| |
| #include "tnl/t_pipeline.h" |
| |
| #undef STATE_TRACE |
| |
| static unsigned int ffbComputeAlphaFunc(GLcontext *ctx) |
| { |
| unsigned int xclip; |
| GLubyte alphaRef; |
| |
| #ifdef STATE_TRACE |
| fprintf(stderr, "ffbDDAlphaFunc: func(%s) ref(%02x)\n", |
| _mesa_lookup_enum_by_nr(ctx->Color.AlphaFunc), |
| ctx->Color.AlphaRef & 0xff); |
| #endif |
| |
| switch (ctx->Color.AlphaFunc) { |
| case GL_NEVER: xclip = FFB_XCLIP_TEST_NEVER; break; |
| case GL_LESS: xclip = FFB_XCLIP_TEST_LT; break; |
| case GL_EQUAL: xclip = FFB_XCLIP_TEST_EQ; break; |
| case GL_LEQUAL: xclip = FFB_XCLIP_TEST_LE; break; |
| case GL_GREATER: xclip = FFB_XCLIP_TEST_GT; break; |
| case GL_NOTEQUAL: xclip = FFB_XCLIP_TEST_NE; break; |
| case GL_GEQUAL: xclip = FFB_XCLIP_TEST_GE; break; |
| case GL_ALWAYS: xclip = FFB_XCLIP_TEST_ALWAYS; break; |
| |
| default: |
| return FFB_XCLIP_TEST_ALWAYS | 0x00; |
| } |
| |
| CLAMPED_FLOAT_TO_UBYTE(alphaRef, ctx->Color.AlphaRef); |
| xclip |= (alphaRef & 0xff); |
| |
| return xclip; |
| } |
| |
| static void ffbDDAlphaFunc(GLcontext *ctx, GLenum func, GLfloat ref) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| |
| if (ctx->Color.AlphaEnabled) { |
| unsigned int xclip = ffbComputeAlphaFunc(ctx); |
| |
| if (fmesa->xclip != xclip) { |
| fmesa->xclip = xclip; |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_XCLIP, 1); |
| } |
| } |
| } |
| |
| static void ffbDDBlendEquationSeparate(GLcontext *ctx, |
| GLenum modeRGB, GLenum modeA) |
| { |
| |
| #ifdef STATE_TRACE |
| fprintf(stderr, "ffbDDBlendEquation: mode(%s)\n", |
| _mesa_lookup_enum_by_nr(modeRGB)); |
| #endif |
| assert( modeRGB == modeA ); |
| FALLBACK( ctx, (modeRGB != GL_FUNC_ADD), FFB_BADATTR_BLENDEQN); |
| } |
| |
| static void ffbDDBlendFuncSeparate(GLcontext *ctx, GLenum sfactorRGB, |
| GLenum dfactorRGB, GLenum sfactorA, |
| GLenum dfactorA) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| unsigned int blendc = 1 << 4; |
| |
| #ifdef STATE_TRACE |
| fprintf(stderr, "ffbDDBlendFuncSeparate: sRGB(%s) dRGB(%s) sA(%s) dA(%s)\n", |
| _mesa_lookup_enum_by_nr(sfactorRGB), |
| _mesa_lookup_enum_by_nr(dfactorRGB), |
| _mesa_lookup_enum_by_nr(sfactorA), |
| _mesa_lookup_enum_by_nr(dfactorA)); |
| #endif |
| switch (ctx->Color.BlendSrcRGB) { |
| case GL_ZERO: |
| blendc |= (0 << 0); |
| break; |
| |
| case GL_ONE: |
| blendc |= (1 << 0); |
| break; |
| |
| case GL_ONE_MINUS_SRC_ALPHA: |
| blendc |= (2 << 0); |
| break; |
| |
| case GL_SRC_ALPHA: |
| blendc |= (3 << 0); |
| break; |
| |
| default: |
| if (ctx->Color.BlendEnabled) |
| FALLBACK( ctx, FFB_BADATTR_BLENDFUNC, GL_TRUE ); |
| return; |
| }; |
| |
| switch (ctx->Color.BlendDstRGB) { |
| case GL_ZERO: |
| blendc |= (0 << 2); |
| break; |
| |
| case GL_ONE: |
| blendc |= (1 << 2); |
| break; |
| |
| case GL_ONE_MINUS_SRC_ALPHA: |
| blendc |= (2 << 2); |
| break; |
| |
| case GL_SRC_ALPHA: |
| blendc |= (3 << 2); |
| break; |
| |
| default: |
| if (ctx->Color.BlendEnabled) |
| FALLBACK( ctx, FFB_BADATTR_BLENDFUNC, GL_TRUE ); |
| return; |
| }; |
| |
| if (ctx->Color.BlendEnabled && |
| ctx->Color.ColorLogicOpEnabled && |
| ctx->Color.LogicOp != GL_COPY) { |
| /* We could avoid this if sfactor is GL_ONE and |
| * dfactor is GL_ZERO. I do not think that is even |
| * worthwhile to check because if someone is using |
| * blending they use more interesting settings and |
| * also it would add more state tracking to a lot |
| * of the code in this file. |
| */ |
| FALLBACK(ctx, FFB_BADATTR_BLENDROP, GL_TRUE); |
| return; |
| } |
| |
| FALLBACK( ctx, (FFB_BADATTR_BLENDFUNC|FFB_BADATTR_BLENDROP), GL_FALSE ); |
| |
| if (blendc != fmesa->blendc) { |
| fmesa->blendc = blendc; |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_BLEND, 1); |
| } |
| } |
| |
| static void ffbDDDepthFunc(GLcontext *ctx, GLenum func) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| GLuint cmp; |
| |
| #ifdef STATE_TRACE |
| fprintf(stderr, "ffbDDDepthFunc: func(%s)\n", |
| _mesa_lookup_enum_by_nr(func)); |
| #endif |
| |
| switch (func) { |
| case GL_NEVER: |
| cmp = FFB_CMP_MAGN_NEVER; |
| break; |
| case GL_ALWAYS: |
| cmp = FFB_CMP_MAGN_ALWAYS; |
| break; |
| case GL_LESS: |
| cmp = FFB_CMP_MAGN_LT; |
| break; |
| case GL_LEQUAL: |
| cmp = FFB_CMP_MAGN_LE; |
| break; |
| case GL_EQUAL: |
| cmp = FFB_CMP_MAGN_EQ; |
| break; |
| case GL_GREATER: |
| cmp = FFB_CMP_MAGN_GT; |
| break; |
| case GL_GEQUAL: |
| cmp = FFB_CMP_MAGN_GE; |
| break; |
| case GL_NOTEQUAL: |
| cmp = FFB_CMP_MAGN_NE; |
| break; |
| default: |
| return; |
| }; |
| |
| if (! ctx->Depth.Test) |
| cmp = FFB_CMP_MAGN_ALWAYS; |
| |
| cmp <<= 16; |
| cmp = (fmesa->cmp & ~(0xff<<16)) | cmp; |
| if (cmp != fmesa->cmp) { |
| fmesa->cmp = cmp; |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_CMP, 1); |
| } |
| } |
| |
| static void ffbDDDepthMask(GLcontext *ctx, GLboolean flag) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| GLuint fbc = fmesa->fbc; |
| GLboolean enabled_now; |
| |
| #ifdef STATE_TRACE |
| fprintf(stderr, "ffbDDDepthMask: flag(%d)\n", flag); |
| #endif |
| |
| if ((fbc & FFB_FBC_ZE_MASK) == FFB_FBC_ZE_OFF) |
| enabled_now = GL_FALSE; |
| else |
| enabled_now = GL_TRUE; |
| |
| if (flag != enabled_now) { |
| fbc &= ~FFB_FBC_ZE_MASK; |
| if (flag) { |
| fbc |= FFB_FBC_WB_C | FFB_FBC_ZE_ON; |
| } else { |
| fbc |= FFB_FBC_ZE_OFF; |
| fbc &= ~FFB_FBC_WB_C; |
| } |
| fmesa->fbc = fbc; |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_FBC, 1); |
| } |
| } |
| |
| static void |
| ffbDDStencilFuncSeparate(GLcontext *ctx, GLenum face, GLenum func, |
| GLint ref, GLuint mask) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| unsigned int stencil, stencilctl, consty; |
| |
| /* We will properly update sw/hw state when stenciling is |
| * enabled. |
| */ |
| if (! ctx->Stencil.Enabled) |
| return; |
| |
| stencilctl = fmesa->stencilctl; |
| stencilctl &= ~(7 << 16); |
| |
| switch (func) { |
| case GL_ALWAYS: stencilctl |= (0 << 16); break; |
| case GL_GREATER: stencilctl |= (1 << 16); break; |
| case GL_EQUAL: stencilctl |= (2 << 16); break; |
| case GL_GEQUAL: stencilctl |= (3 << 16); break; |
| case GL_NEVER: stencilctl |= (4 << 16); break; |
| case GL_LEQUAL: stencilctl |= (5 << 16); break; |
| case GL_NOTEQUAL: stencilctl |= (6 << 16); break; |
| case GL_LESS: stencilctl |= (7 << 16); break; |
| |
| default: |
| return; |
| }; |
| |
| consty = ref & 0xf; |
| |
| stencil = fmesa->stencil; |
| stencil &= ~(0xf << 20); |
| stencil |= (mask & 0xf) << 20; |
| |
| if (fmesa->stencil != stencil || |
| fmesa->stencilctl != stencilctl || |
| fmesa->consty != consty) { |
| fmesa->stencil = stencil; |
| fmesa->stencilctl = stencilctl; |
| fmesa->consty = consty; |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_STENCIL, 6); |
| } |
| } |
| |
| static void |
| ffbDDStencilMaskSeparate(GLcontext *ctx, GLenum face, GLuint mask) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| |
| mask &= 0xf; |
| if (fmesa->ypmask != mask) { |
| fmesa->ypmask = mask; |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_YPMASK, 1); |
| } |
| } |
| |
| static void |
| ffbDDStencilOpSeparate(GLcontext *ctx, GLenum face, GLenum fail, |
| GLenum zfail, GLenum zpass) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| unsigned int stencilctl; |
| |
| /* We will properly update sw/hw state when stenciling is |
| * enabled. |
| */ |
| if (! ctx->Stencil.Enabled) |
| return; |
| |
| stencilctl = fmesa->stencilctl; |
| stencilctl &= ~(0xfff00000); |
| |
| switch (fail) { |
| case GL_ZERO: stencilctl |= (0 << 28); break; |
| case GL_KEEP: stencilctl |= (1 << 28); break; |
| case GL_INVERT: stencilctl |= (2 << 28); break; |
| case GL_REPLACE: stencilctl |= (3 << 28); break; |
| case GL_INCR: stencilctl |= (4 << 28); break; |
| case GL_DECR: stencilctl |= (5 << 28); break; |
| |
| default: |
| return; |
| }; |
| |
| switch (zfail) { |
| case GL_ZERO: stencilctl |= (0 << 24); break; |
| case GL_KEEP: stencilctl |= (1 << 24); break; |
| case GL_INVERT: stencilctl |= (2 << 24); break; |
| case GL_REPLACE: stencilctl |= (3 << 24); break; |
| case GL_INCR: stencilctl |= (4 << 24); break; |
| case GL_DECR: stencilctl |= (5 << 24); break; |
| |
| default: |
| return; |
| }; |
| |
| switch (zpass) { |
| case GL_ZERO: stencilctl |= (0 << 20); break; |
| case GL_KEEP: stencilctl |= (1 << 20); break; |
| case GL_INVERT: stencilctl |= (2 << 20); break; |
| case GL_REPLACE: stencilctl |= (3 << 20); break; |
| case GL_INCR: stencilctl |= (4 << 20); break; |
| case GL_DECR: stencilctl |= (5 << 20); break; |
| |
| default: |
| return; |
| }; |
| |
| if (fmesa->stencilctl != stencilctl) { |
| fmesa->stencilctl = stencilctl; |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_STENCIL, 6); |
| } |
| } |
| |
| static void ffbCalcViewportRegs(GLcontext *ctx) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| __DRIdrawablePrivate *dPriv = fmesa->driDrawable; |
| GLuint xmin, xmax, ymin, ymax, zmin, zmax; |
| unsigned int vcmin, vcmax; |
| |
| xmin = ctx->Viewport.X + dPriv->x; |
| xmax = xmin + ctx->Viewport.Width; |
| ymax = dPriv->y + dPriv->h - ctx->Viewport.Y; |
| ymin = ymax - ctx->Viewport.Height; |
| if (ctx->Scissor.Enabled) { |
| GLuint sc_xmin, sc_xmax, sc_ymin, sc_ymax; |
| |
| sc_xmin = ctx->Viewport.X + dPriv->x; |
| sc_xmax = sc_xmin + ctx->Viewport.Width; |
| sc_ymax = dPriv->y + dPriv->h - ctx->Viewport.Y; |
| sc_ymin = sc_ymax - ctx->Viewport.Height; |
| if (sc_xmin > xmin) |
| xmin = sc_xmin; |
| if (sc_xmax < xmax) |
| xmax = sc_xmax; |
| if (sc_ymin > ymin) |
| ymin = sc_ymin; |
| if (sc_ymax < ymax) |
| ymax = sc_ymax; |
| } |
| zmin = ((GLdouble)ctx->Viewport.Near * 0x0fffffff); |
| zmax = ((GLdouble)ctx->Viewport.Far * 0x0fffffff); |
| |
| vcmin = ((ymin & 0xffff) << 16) | (xmin & 0xffff); |
| vcmax = ((ymax & 0xffff) << 16) | (xmax & 0xffff); |
| if (fmesa->vclipmin != vcmin || |
| fmesa->vclipmax != vcmax || |
| fmesa->vclipzmin != zmin || |
| fmesa->vclipzmax != zmax) { |
| fmesa->vclipmin = vcmin; |
| fmesa->vclipmax = vcmax; |
| fmesa->vclipzmin = zmin; |
| fmesa->vclipzmax = zmax; |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_CLIP, (4 + (4 * 2))); |
| } |
| } |
| |
| void ffbCalcViewport(GLcontext *ctx) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| const GLfloat *v = ctx->Viewport._WindowMap.m; |
| GLfloat *m = fmesa->hw_viewport; |
| __DRIdrawablePrivate *dPriv = fmesa->driDrawable; |
| |
| m[MAT_SX] = v[MAT_SX]; |
| m[MAT_TX] = v[MAT_TX] + dPriv->x + SUBPIXEL_X; |
| m[MAT_SY] = - v[MAT_SY]; |
| m[MAT_TY] = - v[MAT_TY] + dPriv->h + dPriv->y + SUBPIXEL_Y; |
| m[MAT_SZ] = v[MAT_SZ] * ((GLdouble)1.0 / (GLdouble)0x0fffffff); |
| m[MAT_TZ] = v[MAT_TZ] * ((GLdouble)1.0 / (GLdouble)0x0fffffff); |
| |
| fmesa->depth_scale = ((GLdouble)1.0 / (GLdouble)0x0fffffff); |
| |
| ffbCalcViewportRegs(ctx); |
| |
| fmesa->setupnewinputs |= VERT_BIT_POS; |
| } |
| |
| static void ffbDDViewport(GLcontext *ctx, GLint x, GLint y, |
| GLsizei width, GLsizei height) |
| { |
| ffbCalcViewport(ctx); |
| } |
| |
| static void ffbDDDepthRange(GLcontext *ctx, GLclampd nearval, GLclampd farval) |
| { |
| ffbCalcViewport(ctx); |
| } |
| |
| static void ffbDDScissor(GLcontext *ctx, GLint cx, GLint cy, |
| GLsizei cw, GLsizei ch) |
| { |
| ffbCalcViewport(ctx); |
| } |
| |
| static void ffbDDDrawBuffer(GLcontext *ctx, GLenum buffer) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| unsigned int fbc = fmesa->fbc; |
| |
| #ifdef STATE_TRACE |
| fprintf(stderr, "ffbDDDrawBuffer: mode(%s)\n", |
| _mesa_lookup_enum_by_nr(buffer)); |
| #endif |
| fbc &= ~(FFB_FBC_WB_AB | FFB_FBC_RB_MASK); |
| switch (buffer) { |
| case GL_FRONT: |
| if (fmesa->back_buffer == 0) |
| fbc |= FFB_FBC_WB_B | FFB_FBC_RB_B; |
| else |
| fbc |= FFB_FBC_WB_A | FFB_FBC_RB_A; |
| break; |
| |
| case GL_BACK: |
| if (fmesa->back_buffer == 0) |
| fbc |= FFB_FBC_WB_A | FFB_FBC_RB_A; |
| else |
| fbc |= FFB_FBC_WB_B | FFB_FBC_RB_B; |
| break; |
| |
| case GL_FRONT_AND_BACK: |
| fbc |= FFB_FBC_WB_AB; |
| break; |
| |
| default: |
| return; |
| }; |
| |
| if (fbc != fmesa->fbc) { |
| fmesa->fbc = fbc; |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_FBC, 1); |
| } |
| } |
| |
| |
| static void ffbDDReadBuffer(GLcontext *ctx, GLenum buffer) |
| { |
| /* no-op, unless you implement h/w glRead/CopyPixels */ |
| } |
| |
| |
| /* |
| * Specifies buffer for sw fallbacks (spans) |
| */ |
| #if 000 |
| /* XXX |
| * This function is obsolete. It's not clear how this really effected |
| * span reading/writing above. The span functions should use the |
| * incoming driRenderbuffer (gl_renderbuffer) pointer to determine how |
| * to read from the specified bufer. |
| */ |
| static void ffbDDSetBuffer(GLcontext *ctx, GLframebuffer *colorBuffer, |
| GLuint bufferBit) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| unsigned int fbc = fmesa->fbc; |
| |
| #ifdef STATE_TRACE |
| fprintf(stderr, "ffbDDSetReadBuffer: mode(%s)\n", |
| _mesa_lookup_enum_by_nr(buffer)); |
| #endif |
| fbc &= ~(FFB_FBC_RB_MASK); |
| switch (bufferBit) { |
| case BUFFER_BIT_FRONT_LEFT: |
| if (fmesa->back_buffer == 0) |
| fbc |= FFB_FBC_RB_B; |
| else |
| fbc |= FFB_FBC_RB_A; |
| break; |
| |
| case BUFFER_BIT_BACK_LEFT: |
| if (fmesa->back_buffer == 0) |
| fbc |= FFB_FBC_RB_A; |
| else |
| fbc |= FFB_FBC_RB_B; |
| break; |
| |
| default: |
| _mesa_problem(ctx, "Unexpected buffer in ffbDDSetBuffer()"); |
| return; |
| }; |
| |
| if (fbc != fmesa->fbc) { |
| fmesa->fbc = fbc; |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_FBC, 1); |
| } |
| } |
| #endif |
| |
| |
| static void ffbDDClearColor(GLcontext *ctx, const GLfloat color[4]) |
| { |
| ffbContextPtr fmesa = FFB_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]); |
| |
| fmesa->clear_pixel = ((c[0] << 0) | |
| (c[1] << 8) | |
| (c[2] << 16)); |
| } |
| |
| static void ffbDDClearDepth(GLcontext *ctx, GLclampd depth) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| |
| fmesa->clear_depth = Z_FROM_MESA(depth * 4294967295.0f); |
| } |
| |
| static void ffbDDClearStencil(GLcontext *ctx, GLint stencil) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| |
| fmesa->clear_stencil = stencil & 0xf; |
| } |
| |
| /* XXX Actually, should I be using FBC controls for this? -DaveM */ |
| static void ffbDDColorMask(GLcontext *ctx, |
| GLboolean r, GLboolean g, |
| GLboolean b, GLboolean a) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| unsigned int new_pmask = 0x0; |
| |
| #ifdef STATE_TRACE |
| fprintf(stderr, "ffbDDColorMask: r(%d) g(%d) b(%d) a(%d)\n", |
| r, g, b, a); |
| #endif |
| if (r) |
| new_pmask |= 0x000000ff; |
| if (g) |
| new_pmask |= 0x0000ff00; |
| if (b) |
| new_pmask |= 0x00ff0000; |
| if (a) |
| new_pmask |= 0xff000000; |
| |
| if (fmesa->pmask != new_pmask) { |
| fmesa->pmask = new_pmask; |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_PMASK, 1); |
| } |
| } |
| |
| static void ffbDDLogicOp(GLcontext *ctx, GLenum op) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| unsigned int rop; |
| |
| #ifdef STATE_TRACE |
| fprintf(stderr, "ffbDDLogicOp: op(%s)\n", |
| _mesa_lookup_enum_by_nr(op)); |
| #endif |
| switch (op) { |
| case GL_CLEAR: rop = FFB_ROP_ZERO; break; |
| case GL_SET: rop = FFB_ROP_ONES; break; |
| case GL_COPY: rop = FFB_ROP_NEW; break; |
| case GL_AND: rop = FFB_ROP_NEW_AND_OLD; break; |
| case GL_NAND: rop = FFB_ROP_NEW_AND_NOLD; break; |
| case GL_OR: rop = FFB_ROP_NEW_OR_OLD; break; |
| case GL_NOR: rop = FFB_ROP_NEW_OR_NOLD; break; |
| case GL_XOR: rop = FFB_ROP_NEW_XOR_OLD; break; |
| case GL_NOOP: rop = FFB_ROP_OLD; break; |
| case GL_COPY_INVERTED: rop = FFB_ROP_NNEW; break; |
| case GL_INVERT: rop = FFB_ROP_NOLD; break; |
| case GL_EQUIV: rop = FFB_ROP_NNEW_XOR_NOLD; break; |
| case GL_AND_REVERSE: rop = FFB_ROP_NEW_AND_NOLD; break; |
| case GL_AND_INVERTED: rop = FFB_ROP_NNEW_AND_OLD; break; |
| case GL_OR_REVERSE: rop = FFB_ROP_NEW_OR_NOLD; break; |
| case GL_OR_INVERTED: rop = FFB_ROP_NNEW_OR_OLD; break; |
| |
| default: |
| return; |
| }; |
| |
| rop |= fmesa->rop & ~0xff; |
| if (rop != fmesa->rop) { |
| fmesa->rop = rop; |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_ROP, 1); |
| |
| if (op == GL_COPY) |
| FALLBACK( ctx, FFB_BADATTR_BLENDROP, GL_FALSE ); |
| } |
| } |
| |
| #if 0 |
| /* XXX Also need to track near/far just like 3dfx driver. |
| * XXX |
| * XXX Actually, that won't work, because the 3dfx chip works by |
| * XXX having 1/w coordinates fed to it for each primitive, and |
| * XXX it uses this to index it's 64 entry fog table. |
| */ |
| static void ffb_fog_linear(GLcontext *ctx, ffbContextPtr fmesa) |
| { |
| GLfloat c = ctx->ProjectionMatrix.m[10]; |
| GLfloat d = ctx->ProjectionMatrix.m[14]; |
| GLfloat tz = ctx->Viewport.WindowMap.m[MAT_TZ]; |
| GLfloat szInv = 1.0F / ctx->Viewport.WindowMap.m[MAT_SZ]; |
| GLfloat fogEnd = ctx->Fog.End; |
| GLfloat fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start); |
| GLfloat ndcz; |
| GLfloat eyez; |
| GLfloat Zzero, Zone; |
| unsigned int zb, zf; |
| |
| /* Compute the Z at which f reaches 0.0, this is the full |
| * saturation point. |
| * |
| * Thus compute Z (as seen by the chip during rendering), |
| * such that: |
| * |
| * 0.0 = (fogEnd - eyez) * fogScale |
| * |
| * fogScale is usually not zero, thus we are looking for: |
| * |
| * fogEnd = eyez |
| * |
| * fogEnd = -d / (c + ((Z - tz) * szInv)) |
| * fogEnd * (c + ((Z - tz) * szInv)) = -d |
| * (c + ((Z - tz) * szInv)) = -d / fogEnd |
| * (Z - tz) * szInv = (-d / fogEnd) - c |
| * (Z - tz) = ((-d / fogEnd) - c) / szInv |
| * Z = (((-d / fogEnd) - c) / szInv) + tz |
| */ |
| Zzero = (((-d / fogEnd) - c) / szInv) + tz; |
| |
| /* Compute the Z at which f reaches 1.0, this is where |
| * the incoming frag's full intensity is shown. This |
| * equation is: |
| * |
| * 1.0 = (fogEnd - eyez) |
| * |
| * We are looking for: |
| * |
| * 1.0 + eyez = fogEnd |
| * |
| * 1.0 + (-d / (c + ((Z - tz) * szInv))) = fogEnd |
| * -d / (c + ((Z - tz) * szInv)) = fogEnd - 1.0 |
| * -d / (FogEnd - 1.0) = (c + ((Z - tz) * szInv)) |
| * (-d / (fogEnd - 1.0)) - c = ((Z - tz) * szInv) |
| * ((-d / (fogEnd - 1.0)) - c) / szInv = (Z - tz) |
| * (((-d / (fogEnd - 1.0)) - c) / szInv) + tz = Z |
| */ |
| Zone = (((-d / (fogEnd - 1.0)) - c) / szInv) + tz; |
| |
| /* FFB's Zfront must be less than Zback, thus we may have |
| * to invert Sf/Sb to satisfy this constraint. |
| */ |
| if (Zzero < Zone) { |
| sf = 0.0; |
| sb = 1.0; |
| zf = Z_FROM_MESA(Zzero); |
| zb = Z_FROM_MESA(Zone); |
| } else { |
| sf = 1.0; |
| sb = 0.0; |
| zf = Z_FROM_MESA(Zone); |
| zb = Z_FROM_MESA(Zzero); |
| } |
| } |
| #endif |
| |
| static void ffbDDFogfv(GLcontext *ctx, GLenum pname, const GLfloat *param) |
| { |
| #ifdef STATE_TRACE |
| fprintf(stderr, "ffbDDFogfv: pname(%s)\n", _mesa_lookup_enum_by_nr(pname)); |
| #endif |
| } |
| |
| static void ffbDDLineStipple(GLcontext *ctx, GLint factor, GLushort pattern) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| |
| #ifdef STATE_TRACE |
| fprintf(stderr, "ffbDDLineStipple: factor(%d) pattern(%04x)\n", |
| factor, pattern); |
| #endif |
| if (ctx->Line.StippleFlag) { |
| factor = ctx->Line.StippleFactor; |
| pattern = ctx->Line.StipplePattern; |
| if ((GLuint) factor > 15) { |
| fmesa->lpat = FFB_LPAT_BAD; |
| } else { |
| fmesa->lpat = ((factor << FFB_LPAT_SCALEVAL_SHIFT) | |
| (0 << FFB_LPAT_PATLEN_SHIFT) | |
| ((pattern & 0xffff) << FFB_LPAT_PATTERN_SHIFT)); |
| } |
| } else { |
| fmesa->lpat = 0; |
| } |
| } |
| |
| void ffbXformAreaPattern(ffbContextPtr fmesa, const GLubyte *mask) |
| { |
| __DRIdrawablePrivate *dPriv = fmesa->driDrawable; |
| int i, lines, xoff; |
| |
| lines = 0; |
| i = (dPriv->y + dPriv->h) & (32 - 1); |
| xoff = dPriv->x & (32 - 1); |
| while (lines++ < 32) { |
| GLuint raw = |
| (((GLuint)mask[0] << 24) | |
| ((GLuint)mask[1] << 16) | |
| ((GLuint)mask[2] << 8) | |
| ((GLuint)mask[3] << 0)); |
| |
| fmesa->pattern[i] = |
| (raw << xoff) | (raw >> (32 - xoff)); |
| i = (i - 1) & (32 - 1); |
| mask += 4; |
| } |
| |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_APAT, 32); |
| } |
| |
| static void ffbDDPolygonStipple(GLcontext *ctx, const GLubyte *mask) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| |
| #ifdef STATE_TRACE |
| fprintf(stderr, "ffbDDPolygonStipple: state(%d)\n", |
| ctx->Polygon.StippleFlag); |
| #endif |
| ffbXformAreaPattern(fmesa, mask); |
| } |
| |
| static void ffbDDEnable(GLcontext *ctx, GLenum cap, GLboolean state) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| unsigned int tmp; |
| |
| #ifdef STATE_TRACE |
| fprintf(stderr, "ffbDDEnable: %s state(%d)\n", |
| _mesa_lookup_enum_by_nr(cap), state); |
| #endif |
| switch (cap) { |
| case GL_ALPHA_TEST: |
| if (state) |
| tmp = ffbComputeAlphaFunc(ctx); |
| else |
| tmp = FFB_XCLIP_TEST_ALWAYS; |
| |
| if (tmp != fmesa->xclip) { |
| fmesa->xclip = tmp; |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_XCLIP, 1); |
| } |
| break; |
| |
| case GL_BLEND: |
| tmp = (fmesa->ppc & ~FFB_PPC_ABE_MASK); |
| if (state) { |
| tmp |= FFB_PPC_ABE_ENABLE; |
| } else { |
| tmp |= FFB_PPC_ABE_DISABLE; |
| } |
| if (fmesa->ppc != tmp) { |
| fmesa->ppc = tmp; |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_PPC, 1); |
| ffbDDBlendFuncSeparate(ctx, 0, 0, 0, 0 ); |
| } |
| break; |
| |
| case GL_DEPTH_TEST: |
| if (state) |
| tmp = 0x0fffffff; |
| else |
| tmp = 0x00000000; |
| if (tmp != fmesa->magnc) { |
| unsigned int fbc = fmesa->fbc; |
| fbc &= ~FFB_FBC_ZE_MASK; |
| if (state) |
| fbc |= FFB_FBC_ZE_ON; |
| else |
| fbc |= FFB_FBC_ZE_OFF; |
| fmesa->fbc = fbc; |
| ffbDDDepthFunc(ctx, ctx->Depth.Func); |
| fmesa->magnc = tmp; |
| FFB_MAKE_DIRTY(fmesa, (FFB_STATE_MAGNC | FFB_STATE_FBC), 2); |
| } |
| break; |
| |
| case GL_SCISSOR_TEST: |
| ffbDDScissor(ctx, ctx->Scissor.X, ctx->Scissor.Y, |
| ctx->Scissor.Width, ctx->Scissor.Height); |
| break; |
| |
| case GL_STENCIL_TEST: |
| if (!(fmesa->ffb_sarea->flags & FFB_DRI_FFB2PLUS)) { |
| FALLBACK( ctx, FFB_BADATTR_STENCIL, state ); |
| } |
| |
| tmp = fmesa->fbc & ~FFB_FBC_YE_MASK; |
| if (state) { |
| ffbDDStencilFuncSeparate(ctx, GL_FRONT, |
| ctx->Stencil.Function[0], |
| ctx->Stencil.Ref[0], |
| ctx->Stencil.ValueMask[0]); |
| ffbDDStencilMaskSeparate(ctx, GL_FRONT, |
| ctx->Stencil.WriteMask[0]); |
| ffbDDStencilOpSeparate(ctx, GL_FRONT, |
| ctx->Stencil.FailFunc[0], |
| ctx->Stencil.ZFailFunc[0], |
| ctx->Stencil.ZPassFunc[0]); |
| tmp |= FFB_FBC_YE_MASK; |
| } else { |
| fmesa->stencil = 0xf0000000; |
| fmesa->stencilctl = 0x33300000; |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_STENCIL, 6); |
| tmp |= FFB_FBC_YE_OFF; |
| } |
| if (tmp != fmesa->fbc) { |
| fmesa->fbc = tmp; |
| FFB_MAKE_DIRTY(fmesa, FFB_STATE_FBC, 1); |
| } |
| break; |
| |
| case GL_FOG: |
| /* Until I implement the fog support... */ |
| FALLBACK( ctx, FFB_BADATTR_FOG, state ); |
| break; |
| |
| case GL_LINE_STIPPLE: |
| if (! state) |
| fmesa->lpat = 0; |
| else |
| ffbDDLineStipple(ctx, |
| ctx->Line.StippleFactor, |
| ctx->Line.StipplePattern); |
| break; |
| |
| case GL_POLYGON_STIPPLE: |
| /* Do nothing, we interrogate the state during |
| * reduced primitive changes. Since our caller |
| * will set NEW_POLYGON in the ctx NewState this |
| * will cause the driver rasterization functions |
| * to be reevaluated, which will cause us to force |
| * a reduced primitive change next rendering pass |
| * and it all works out. |
| */ |
| break; |
| |
| default: |
| break; |
| }; |
| } |
| |
| void ffbSyncHardware(ffbContextPtr fmesa) |
| { |
| ffb_fbcPtr ffb = fmesa->regs; |
| unsigned int dirty; |
| int i; |
| |
| FFBFifo(fmesa, fmesa->state_fifo_ents); |
| |
| dirty = fmesa->state_dirty; |
| if (dirty & (FFB_STATE_FBC | FFB_STATE_PPC | FFB_STATE_DRAWOP | |
| FFB_STATE_ROP | FFB_STATE_LPAT | FFB_STATE_WID)) { |
| if (dirty & FFB_STATE_FBC) |
| ffb->fbc = fmesa->fbc; |
| if (dirty & FFB_STATE_PPC) |
| ffb->ppc = fmesa->ppc; |
| if (dirty & FFB_STATE_DRAWOP) |
| ffb->drawop = fmesa->drawop; |
| if (dirty & FFB_STATE_ROP) |
| ffb->rop = fmesa->rop; |
| if (dirty & FFB_STATE_LPAT) |
| ffb->rop = fmesa->lpat; |
| if (dirty & FFB_STATE_WID) |
| ffb->wid = fmesa->wid; |
| } |
| if (dirty & (FFB_STATE_PMASK | FFB_STATE_XPMASK | FFB_STATE_YPMASK | |
| FFB_STATE_ZPMASK | FFB_STATE_XCLIP | FFB_STATE_CMP | |
| FFB_STATE_MATCHAB | FFB_STATE_MAGNAB | FFB_STATE_MATCHC | |
| FFB_STATE_MAGNC)) { |
| if (dirty & FFB_STATE_PMASK) |
| ffb->pmask = fmesa->pmask; |
| if (dirty & FFB_STATE_XPMASK) |
| ffb->xpmask = fmesa->xpmask; |
| if (dirty & FFB_STATE_YPMASK) |
| ffb->ypmask = fmesa->ypmask; |
| if (dirty & FFB_STATE_ZPMASK) |
| ffb->zpmask = fmesa->zpmask; |
| if (dirty & FFB_STATE_XCLIP) |
| ffb->xclip = fmesa->xclip; |
| if (dirty & FFB_STATE_CMP) |
| ffb->cmp = fmesa->cmp; |
| if (dirty & FFB_STATE_MATCHAB) |
| ffb->matchab = fmesa->matchab; |
| if (dirty & FFB_STATE_MAGNAB) |
| ffb->magnab = fmesa->magnab; |
| if (dirty & FFB_STATE_MATCHC) |
| ffb->matchc = fmesa->matchc; |
| if (dirty & FFB_STATE_MAGNC) |
| ffb->magnc = fmesa->magnc; |
| } |
| |
| if (dirty & FFB_STATE_DCUE) { |
| ffb->dcss = fmesa->dcss; |
| ffb->dcsf = fmesa->dcsf; |
| ffb->dcsb = fmesa->dcsb; |
| ffb->dczf = fmesa->dczf; |
| ffb->dczb = fmesa->dczb; |
| if (fmesa->ffb_sarea->flags & (FFB_DRI_FFB2 | FFB_DRI_FFB2PLUS)) { |
| ffb->dcss1 = fmesa->dcss1; |
| ffb->dcss2 = fmesa->dcss2; |
| ffb->dcss3 = fmesa->dcss3; |
| ffb->dcs2 = fmesa->dcs2; |
| ffb->dcs3 = fmesa->dcs3; |
| ffb->dcs4 = fmesa->dcs4; |
| ffb->dcd2 = fmesa->dcd2; |
| ffb->dcd3 = fmesa->dcd3; |
| ffb->dcd4 = fmesa->dcd4; |
| } |
| } |
| |
| if (dirty & FFB_STATE_BLEND) { |
| ffb->blendc = fmesa->blendc; |
| ffb->blendc1 = fmesa->blendc1; |
| ffb->blendc2 = fmesa->blendc2; |
| } |
| |
| if (dirty & FFB_STATE_CLIP) { |
| ffb->vclipmin = fmesa->vclipmin; |
| ffb->vclipmax = fmesa->vclipmax; |
| ffb->vclipzmin = fmesa->vclipzmin; |
| ffb->vclipzmax = fmesa->vclipzmax; |
| for (i = 0; i < 4; i++) { |
| ffb->auxclip[i].min = fmesa->aux_clips[i].min; |
| ffb->auxclip[i].max = fmesa->aux_clips[i].max; |
| } |
| } |
| |
| if ((dirty & FFB_STATE_STENCIL) && |
| (fmesa->ffb_sarea->flags & FFB_DRI_FFB2PLUS)) { |
| ffb->stencil = fmesa->stencil; |
| ffb->stencilctl = fmesa->stencilctl; |
| ffb->fbc = FFB_FBC_WB_C; |
| ffb->rawstencilctl = (fmesa->stencilctl | (1 << 19)); |
| ffb->fbc = fmesa->fbc; |
| ffb->consty = fmesa->consty; |
| } |
| |
| if (dirty & FFB_STATE_APAT) { |
| for (i = 0; i < 32; i++) |
| ffb->pattern[i] = fmesa->pattern[i]; |
| } |
| |
| fmesa->state_dirty = 0; |
| fmesa->state_fifo_ents = 0; |
| fmesa->ffbScreen->rp_active = 1; |
| } |
| |
| static void ffbDDUpdateState(GLcontext *ctx, GLuint newstate) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| |
| /* When we are hw rendering, changing certain kinds of |
| * state does not require flushing all of our context. |
| */ |
| if (fmesa->bad_fragment_attrs == 0 && |
| (newstate & ~_NEW_COLOR) == 0) |
| return; |
| |
| _swrast_InvalidateState( ctx, newstate ); |
| _swsetup_InvalidateState( ctx, newstate ); |
| _vbo_InvalidateState( ctx, newstate ); |
| _tnl_InvalidateState( ctx, newstate ); |
| |
| if (newstate & _NEW_TEXTURE) |
| FALLBACK( ctx, FFB_BADATTR_TEXTURE, |
| (ctx->Texture._EnabledUnits != 0)); |
| |
| #ifdef STATE_TRACE |
| fprintf(stderr, "ffbDDUpdateState: newstate(%08x)\n", newstate); |
| #endif |
| |
| fmesa->new_gl_state |= newstate; |
| |
| /* Force a reduced primitive change next rendering |
| * pass. |
| */ |
| fmesa->raster_primitive = GL_POLYGON + 1; |
| |
| #if 0 |
| /* When the modelview matrix changes, this changes what |
| * the eye coordinates will be so we have to recompute |
| * the depth cueing parameters. |
| * |
| * XXX DD_HAVE_HARDWARE_FOG. |
| */ |
| if (ctx->Fog.Enabled && (newstate & _NEW_MODELVIEW)) |
| ffb_update_fog(); |
| #endif |
| } |
| |
| |
| void ffbDDInitStateFuncs(GLcontext *ctx) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| |
| ctx->Driver.UpdateState = ffbDDUpdateState; |
| |
| ctx->Driver.Enable = ffbDDEnable; |
| ctx->Driver.AlphaFunc = ffbDDAlphaFunc; |
| ctx->Driver.BlendEquationSeparate = ffbDDBlendEquationSeparate; |
| ctx->Driver.BlendFuncSeparate = ffbDDBlendFuncSeparate; |
| ctx->Driver.DepthFunc = ffbDDDepthFunc; |
| ctx->Driver.DepthMask = ffbDDDepthMask; |
| ctx->Driver.Fogfv = ffbDDFogfv; |
| ctx->Driver.LineStipple = ffbDDLineStipple; |
| ctx->Driver.PolygonStipple = ffbDDPolygonStipple; |
| ctx->Driver.Scissor = ffbDDScissor; |
| ctx->Driver.ColorMask = ffbDDColorMask; |
| ctx->Driver.LogicOpcode = ffbDDLogicOp; |
| ctx->Driver.Viewport = ffbDDViewport; |
| ctx->Driver.DepthRange = ffbDDDepthRange; |
| |
| if (fmesa->ffb_sarea->flags & FFB_DRI_FFB2PLUS) { |
| ctx->Driver.StencilFuncSeparate = ffbDDStencilFuncSeparate; |
| ctx->Driver.StencilMaskSeparate = ffbDDStencilMaskSeparate; |
| ctx->Driver.StencilOpSeparate = ffbDDStencilOpSeparate; |
| } |
| |
| ctx->Driver.DrawBuffer = ffbDDDrawBuffer; |
| ctx->Driver.ReadBuffer = ffbDDReadBuffer; |
| ctx->Driver.ClearColor = ffbDDClearColor; |
| ctx->Driver.ClearDepth = ffbDDClearDepth; |
| ctx->Driver.ClearStencil = ffbDDClearStencil; |
| |
| /* We will support color index modes later... -DaveM */ |
| /* |
| ctx->Driver.ClearIndex = 0; |
| ctx->Driver.IndexMask = 0; |
| */ |
| } |
| |
| void ffbDDInitContextHwState(GLcontext *ctx) |
| { |
| ffbContextPtr fmesa = FFB_CONTEXT(ctx); |
| int fifo_count = 0; |
| int i; |
| |
| fmesa->hw_locked = 0; |
| |
| fmesa->bad_fragment_attrs = 0; |
| fmesa->state_dirty = FFB_STATE_ALL; |
| fmesa->new_gl_state = ~0; |
| |
| fifo_count = 1; |
| fmesa->fbc = (FFB_FBC_WE_FORCEON | FFB_FBC_WM_COMBINED | |
| FFB_FBC_SB_BOTH | FFB_FBC_ZE_MASK | |
| FFB_FBC_YE_OFF | FFB_FBC_XE_OFF | |
| FFB_FBC_RGBE_MASK); |
| if (ctx->Visual.doubleBufferMode) { |
| /* Buffer B is the initial back buffer. */ |
| fmesa->back_buffer = 1; |
| fmesa->fbc |= FFB_FBC_WB_BC | FFB_FBC_RB_B; |
| } else { |
| fmesa->back_buffer = 0; |
| fmesa->fbc |= FFB_FBC_WB_A | FFB_FBC_RB_A; |
| } |
| |
| fifo_count += 1; |
| fmesa->ppc = (FFB_PPC_ACE_DISABLE | FFB_PPC_DCE_DISABLE | |
| FFB_PPC_ABE_DISABLE | FFB_PPC_VCE_3D | |
| FFB_PPC_APE_DISABLE | FFB_PPC_TBE_OPAQUE | |
| FFB_PPC_ZS_CONST | FFB_PPC_YS_CONST | |
| FFB_PPC_XS_WID | FFB_PPC_CS_VAR); |
| |
| fifo_count += 3; |
| fmesa->drawop = FFB_DRAWOP_RECTANGLE; |
| |
| /* GL_COPY is the default LogicOp. */ |
| fmesa->rop = (FFB_ROP_NEW << 16) | (FFB_ROP_NEW << 8) | FFB_ROP_NEW; |
| |
| /* No line patterning enabled. */ |
| fmesa->lpat = 0x00000000; |
| |
| /* We do not know the WID value until the first context switch. */ |
| fifo_count += 1; |
| fmesa->wid = ~0; |
| |
| fifo_count += 5; |
| |
| /* ColorMask, all enabled. */ |
| fmesa->pmask = 0xffffffff; |
| |
| fmesa->xpmask = 0x000000ff; |
| fmesa->ypmask = 0x0000000f; |
| fmesa->zpmask = 0x0fffffff; |
| |
| /* AlphaFunc GL_ALWAYS, AlphaRef 0 */ |
| fmesa->xclip = FFB_XCLIP_TEST_ALWAYS | 0x00; |
| |
| /* This sets us up to use WID clipping (so the DRI clipping |
| * rectangle is unneeded by us). All other match and magnitude |
| * tests are set to pass. |
| */ |
| fifo_count += 5; |
| fmesa->cmp = ((FFB_CMP_MATCH_ALWAYS << 24) | /* MATCH C */ |
| (FFB_CMP_MAGN_ALWAYS << 16) | /* MAGN C */ |
| (FFB_CMP_MATCH_EQ << 8) | /* MATCH AB */ |
| (FFB_CMP_MAGN_ALWAYS << 0)); /* MAGN AB */ |
| fmesa->matchab = 0xff000000; |
| fmesa->magnab = 0x00000000; |
| fmesa->matchc = 0x00000000; |
| fmesa->magnc = 0x00000000; |
| |
| /* Depth cue parameters, all zeros to start. */ |
| fifo_count += 14; |
| fmesa->dcss = 0x00000000; |
| fmesa->dcsf = 0x00000000; |
| fmesa->dcsb = 0x00000000; |
| fmesa->dczf = 0x00000000; |
| fmesa->dczb = 0x00000000; |
| fmesa->dcss1 = 0x00000000; |
| fmesa->dcss2 = 0x00000000; |
| fmesa->dcss3 = 0x00000000; |
| fmesa->dcs2 = 0x00000000; |
| fmesa->dcs3 = 0x00000000; |
| fmesa->dcs4 = 0x00000000; |
| fmesa->dcd2 = 0x00000000; |
| fmesa->dcd3 = 0x00000000; |
| fmesa->dcd4 = 0x00000000; |
| |
| /* Alpha blending unit state. */ |
| fifo_count += 3; |
| fmesa->blendc = (1 << 0) | (0 << 2); /* src(GL_ONE) | dst(GL_ZERO) */ |
| fmesa->blendc1 = 0x00000000; |
| fmesa->blendc2 = 0x00000000; |
| |
| /* ViewPort clip state. */ |
| fifo_count += 4 + (4 * 2); |
| fmesa->vclipmin = 0x00000000; |
| fmesa->vclipmax = 0xffffffff; |
| fmesa->vclipzmin = 0x00000000; |
| fmesa->vclipzmax = 0x0fffffff; |
| for (i = 0; i < 4; i++) { |
| fmesa->aux_clips[0].min = 0x00000000; |
| fmesa->aux_clips[0].max = 0x00000000; |
| } |
| |
| /* Stenciling state. */ |
| fifo_count += 6; |
| fmesa->stencil = 0xf0000000; /* Stencil MASK, Y plane */ |
| fmesa->stencilctl = 0x33300000; /* All stencil tests disabled */ |
| fmesa->consty = 0x0; |
| |
| /* Area pattern, used for polygon stipples. */ |
| fifo_count += 32; |
| for (i = 0; i < 32; i++) |
| fmesa->pattern[i] = 0x00000000; |
| |
| fmesa->state_fifo_ents = fifo_count; |
| fmesa->state_all_fifo_ents = fifo_count; |
| } |