//----------------------------------------------------------------------------- // // This file contains the span state validation function. // // Copyright (C) Microsoft Corporation, 1997. // //----------------------------------------------------------------------------- #include "rgb_pch.h" #pragma hdrstop include(`bead.mh') #include "BdStr_mh.h" #include "RastCap.h" #include "RastColl.h" #include "spindbg.hpp" static CRastCollection g_RastCollection; UINT16 g_uDitherTable[16] = { 0x00, 0x80, 0x20, 0xa0, 0xc0, 0x40, 0xe0, 0x60, 0x30, 0xb0, 0x10, 0x90, 0xf0, 0x70, 0xd0, 0x50 }; //----------------------------------------------------------------------------- // // DoZCompareSetup // // Initializes arithmetic Z compare state based on the Z test function. // //----------------------------------------------------------------------------- void DoZCompareSetup(PD3DI_RASTCTX pCtx, BOOL bIsMMX) { INT32 iXorMask; if (bIsMMX) { iXorMask = -1; } else { iXorMask = 1; } D3DCMPFUNC ZFunc = (D3DCMPFUNC)pCtx->pdwRenderState[D3DRS_ZFUNC]; if (!pCtx->pdwRenderState[D3DRS_ZENABLE]) { // setup ALWAYS if Z is not enabled, since we may be going into // the test beads for other reasons (like stencil) ZFunc = D3DCMP_ALWAYS; } switch (ZFunc) { case D3DCMP_NEVER: pCtx->iZAndMask = 0; pCtx->iZNeg = 0; pCtx->iZXorMask = iXorMask; break; case D3DCMP_ALWAYS: pCtx->iZAndMask = 0; pCtx->iZNeg = 0; pCtx->iZXorMask = 0; break; case D3DCMP_LESS: pCtx->iZAndMask = ~0; pCtx->iZNeg = 0; pCtx->iZXorMask = iXorMask; break; case D3DCMP_GREATEREQUAL: pCtx->iZAndMask = ~0; pCtx->iZNeg = 0; pCtx->iZXorMask = 0; break; case D3DCMP_EQUAL: pCtx->iZAndMask = 0x7fffffff; pCtx->iZNeg = 1; pCtx->iZXorMask = iXorMask; break; case D3DCMP_NOTEQUAL: pCtx->iZAndMask = 0x7fffffff; pCtx->iZNeg = 1; pCtx->iZXorMask = 0; break; default: case D3DCMP_LESSEQUAL: pCtx->iZAndMask = ~0; pCtx->iZNeg = 1; pCtx->iZXorMask = iXorMask; break; case D3DCMP_GREATER: pCtx->iZAndMask = ~0; pCtx->iZNeg = 1; pCtx->iZXorMask = 0; break; } if (bIsMMX) { pCtx->iZXorMask = ~pCtx->iZXorMask; } } //----------------------------------------------------------------------------- // // DoACompareSetup // // Initializes arithmetic alpha compare state based on the alpha test function. // //----------------------------------------------------------------------------- void DoACompareSetup(PD3DI_RASTCTX pCtx, BOOL bIsMMX) { INT32 iXorMask; if (bIsMMX) { iXorMask = -1; } else { iXorMask = 1; } switch ((D3DCMPFUNC)pCtx->pdwRenderState[D3DRS_ALPHAFUNC]) { case D3DCMP_NEVER: pCtx->iAAndMask = 0; pCtx->iANeg = 0; pCtx->iAXorMask = iXorMask; break; default: case D3DCMP_ALWAYS: pCtx->iAAndMask = 0; pCtx->iANeg = 0; pCtx->iAXorMask = 0; break; case D3DCMP_LESS: pCtx->iAAndMask = ~0; pCtx->iANeg = 0; pCtx->iAXorMask = iXorMask; break; case D3DCMP_GREATEREQUAL: pCtx->iAAndMask = ~0; pCtx->iANeg = 0; pCtx->iAXorMask = 0; break; case D3DCMP_EQUAL: pCtx->iAAndMask = 0x7fffffff; pCtx->iANeg = 1; pCtx->iAXorMask = iXorMask; break; case D3DCMP_NOTEQUAL: pCtx->iAAndMask = 0x7fffffff; pCtx->iANeg = 1; pCtx->iAXorMask = 0; break; case D3DCMP_LESSEQUAL: pCtx->iAAndMask = ~0; pCtx->iANeg = 1; pCtx->iAXorMask = iXorMask; break; case D3DCMP_GREATER: pCtx->iAAndMask = ~0; pCtx->iANeg = 1; pCtx->iAXorMask = 0; break; } if (bIsMMX) { pCtx->iAXorMask = ~pCtx->iAXorMask; } // iARef is an 8.8 ALPHAREF value for use by RGB and MMX. // D3DRS_ALPHAREF is now an 8 bit (0xff max) value. pCtx->iARef = pCtx->pdwRenderState[D3DRS_ALPHAREF] << 8; } //----------------------------------------------------------------------------- // // DoSCompareSetup // // Initializes arithmetic stencil compare state based on the stencil function. // //----------------------------------------------------------------------------- void DoSCompareSetup(PD3DI_RASTCTX pCtx, BOOL bIsMMX) { INT32 iXorMask; if (bIsMMX) { iXorMask = -1; } else { iXorMask = 1; } switch ((D3DCMPFUNC)pCtx->pdwRenderState[D3DRS_STENCILFUNC]) { case D3DCMP_NEVER: pCtx->iSAndMask = 0; pCtx->iSNeg = 0; pCtx->iSXorMask = iXorMask; break; default: case D3DCMP_ALWAYS: pCtx->iSAndMask = 0; pCtx->iSNeg = 0; pCtx->iSXorMask = 0; break; case D3DCMP_LESS: pCtx->iSAndMask = ~0; pCtx->iSNeg = 0; pCtx->iSXorMask = iXorMask; break; case D3DCMP_GREATEREQUAL: pCtx->iSAndMask = ~0; pCtx->iSNeg = 0; pCtx->iSXorMask = 0; break; case D3DCMP_EQUAL: pCtx->iSAndMask = 0x7fffffff; pCtx->iSNeg = 1; pCtx->iSXorMask = iXorMask; break; case D3DCMP_NOTEQUAL: pCtx->iSAndMask = 0x7fffffff; pCtx->iSNeg = 1; pCtx->iSXorMask = 0; break; case D3DCMP_LESSEQUAL: pCtx->iSAndMask = ~0; pCtx->iSNeg = 1; pCtx->iSXorMask = iXorMask; break; case D3DCMP_GREATER: pCtx->iSAndMask = ~0; pCtx->iSNeg = 1; pCtx->iSXorMask = 0; break; } if (bIsMMX) { pCtx->iSXorMask = ~pCtx->iSXorMask; } } //----------------------------------------------------------------------------- // // DoTexAddrSetup // // Initializes arithmetic texture address state state based on the texture // address function. iTex is the texure to setup. // //----------------------------------------------------------------------------- void DoTexAddrSetup(PD3DI_RASTCTX pCtx, INT32 iTex) { PD3DI_SPANTEX pTex = pCtx->pTexture[iTex]; // Note that it is essential to turn on mirroring when in CLAMP/BORDER mode // to avoid filtering artifacts at the edge of the texture switch (pTex->TexAddrU) { default: case D3DTADDRESS_WRAP: pTex->iFlipMaskU = 0; pTex->iClampMinU = 0; pTex->iClampMaxU = 0; pTex->iClampEnU = 0; break; case D3DTADDRESS_MIRROR: pTex->iFlipMaskU = pTex->uMaskU+1; pTex->iClampMinU = 0; pTex->iClampMaxU = 0; pTex->iClampEnU = 0; break; case D3DTADDRESS_CLAMP: pTex->iFlipMaskU = pTex->uMaskU+1; pTex->iClampMinU = 0; pTex->iClampMaxU = pTex->uMaskU; pTex->iClampEnU = -1; break; case D3DTADDRESS_BORDER: pTex->iFlipMaskU = pTex->uMaskU+1; pTex->iClampMinU = -1; pTex->iClampMaxU = -1; pTex->iClampEnU = -1; break; } switch (pTex->TexAddrV) { default: case D3DTADDRESS_WRAP: pTex->iFlipMaskV = 0; pTex->iClampMinV = 0; pTex->iClampMaxV = 0; pTex->iClampEnV = 0; break; case D3DTADDRESS_MIRROR: pTex->iFlipMaskV = pTex->uMaskV+1; pTex->iClampMinV = 0; pTex->iClampMaxV = 0; pTex->iClampEnV = 0; break; case D3DTADDRESS_CLAMP: pTex->iFlipMaskV = pTex->uMaskV+1; pTex->iClampMinV = 0; pTex->iClampMaxV = pTex->uMaskV; pTex->iClampEnV = -1; break; case D3DTADDRESS_BORDER: pTex->iFlipMaskV = pTex->uMaskV+1; pTex->iClampMinV = -1; pTex->iClampMaxV = -1; pTex->iClampEnV = -1; break; } } // CMMX is no longer linked in // extern BEADTABLE g_CMMX_BeadTbl; extern BEADTABLE g_C_BeadTbl; #ifdef _X86_ extern BEADTABLE g_MMX_BeadTbl; #else BEADTABLE g_MMX_BeadTbl = g_C_BeadTbl; #endif #if 0 && DBG #define RANGE_CHECK(val,max) DDASSERT(((val) >= 0) && ((val) < (max))) #else #define RANGE_CHECK(val,max) #endif // #undef DPF_MODNAME // #define DPF_MODNAME "SpanInit" //----------------------------------------------------------------------------- // // SpanInit // // Initializes derived state (function pointers and arithmetic compare values) // based on the render state, surface type, etc. // //----------------------------------------------------------------------------- HRESULT SpanInit(PD3DI_RASTCTX pCtx) { int iZTest, iZFormat, iZWrite, iZFunc, iZDeferred, iStencil, iAlphaTest, iShadeMode, iSpecular, iVertexFog, iTexture, iTextureAddr[D3DHAL_TSS_MAXSTAGES], iTextureBorder[D3DHAL_TSS_MAXSTAGES], iTexturePerspective, iTextureFilter[D3DHAL_TSS_MAXSTAGES], iTextureMip[D3DHAL_TSS_MAXSTAGES], iTextureLOD[D3DHAL_TSS_MAXSTAGES], iTextureFormat[D3DHAL_TSS_MAXSTAGES], iTextureColorKey[D3DHAL_TSS_MAXSTAGES], iTextureBlend, iTextureAlphaOverride[D3DHAL_TSS_MAXSTAGES], iMono, iAlphaBlend, iAlphaDither, iBlend, iROP, iSrcBlend, iDestBlend, iTargetPixelFormat, iDither; PFNRENDERSPANS pfnRenderSpans; PFNSPANLAYER pfnTexAddr[D3DHAL_TSS_MAXSTAGES], pfnColorBlend, pfnColorGen; PBEADTABLE pBeadTable; CRastCapRecord RastCapRec; #if DBG if (SPIGETFLAGS(DBG_USER_FLAGS) & SPIU_BREAK_ON_SPANINIT) { DebugBreak(); } #endif switch (pCtx->BeadSet) { #ifdef _X86_ // Uncomment these (and comment out cases below) to test MMX on legacy code // case D3DIBS_CMMX: // case D3DIBS_C: case D3DIBS_MMXASRGB: // this is only different in pCtx->BeadSet for identification case D3DIBS_MMX: pBeadTable = &g_MMX_BeadTbl; break; #endif default: SPIDPFM((SPIM_INVALID,"Invalid BeadSet %d\n", pCtx->BeadSet)); // fall through case D3DIBS_CMMX: // CMMX code is no longer used, make this behave the same as C case D3DIBS_C: pBeadTable = &g_C_BeadTbl; break; } DoZCompareSetup(pCtx, (pBeadTable == &g_MMX_BeadTbl)); DoACompareSetup(pCtx, (pBeadTable == &g_MMX_BeadTbl)); DoSCompareSetup(pCtx, (pBeadTable == &g_MMX_BeadTbl)); // The function pointers that point to various beads are stored in // multi-dimensional arrays. In order to access the correct bead, we // use numerical indices into these arrays. The indices are either // the exact value of the renderstate used to choose the bead, or are // values chosen by looking at the value of the renderstate. // values needed to choose Test and AlphaTest beads iZTest = (pCtx->pdwRenderState[D3DRS_ZENABLE] || pCtx->pdwRenderState[D3DRS_STENCILENABLE]) ? 1 : 0; RastCapRec.Set_ZTest(iZTest); switch (pCtx->iZBitCount) { default : SPIDPFM((SPIM_INVALID,"Invalid Z surface bit count, iZBitCount == 0x%x\n", pCtx->iZBitCount)); case 0 : case 16 : iZFormat = 0; break; case 32 : iZFormat = 1; break; } RastCapRec.Set_ZFormat(iZFormat); iZWrite = pCtx->pdwRenderState[D3DRS_ZWRITEENABLE] ? 1 : 0; RastCapRec.Set_ZWrite(iZWrite); switch (pCtx->pdwRenderState[D3DRS_ZFUNC]) { case D3DCMP_NEVER : case D3DCMP_ALWAYS : iZFunc = 0; break; case D3DCMP_LESS : case D3DCMP_GREATEREQUAL : iZFunc = 1; break; case D3DCMP_EQUAL : case D3DCMP_NOTEQUAL : iZFunc = 2; break; default : SPIDPFM((SPIM_INVALID,"Invalid renderstate value, D3DRS_ZFUNC == 0x%x\n", pCtx->pdwRenderState[D3DRS_ZFUNC])); case D3DCMP_LESSEQUAL : case D3DCMP_GREATER : iZFunc = 3; break; } if (!pCtx->pdwRenderState[D3DRS_ZENABLE]) { // setup ALWAYS if Z is not enabled, since we may be going into // the test beads for other reasons (like stencil) iZFunc = 0; iZWrite = 0; // do not write iterated Z, but stencil will be written if needed } RastCapRec.Set_ZFunc(iZFunc); // Ignore stipple (D3DRENDERSTATE_STIPPLEENABLE), since no software rasterizers do it. RastCapRec.Set_Stipple(0); iAlphaTest = pCtx->pdwRenderState[D3DRS_ALPHATESTENABLE] ? 1 : 0; RastCapRec.Set_AlphaTest(iAlphaTest); iStencil = pCtx->pdwRenderState[D3DRS_STENCILENABLE] ? 1 : 0; RastCapRec.Set_Stencil(iStencil); // values needed for TestFail, TexAddr1 and ColorGen beads switch (pCtx->pdwRenderState[D3DRS_SHADEMODE]) { case D3DSHADE_FLAT : iShadeMode = 0; break; default : SPIDPFM((SPIM_INVALID,"Invalid renderstate value, D3DRS_SHADEMODE == 0x%x\n", pCtx->pdwRenderState[D3DRS_SHADEMODE])); case D3DSHADE_GOURAUD : case D3DSHADE_PHONG : iShadeMode = 1; break; } RastCapRec.Set_ShadeMode(iShadeMode); iSpecular = pCtx->pdwRenderState[D3DRS_SPECULARENABLE] ? 1 : 0; RastCapRec.Set_Specular(iSpecular); iVertexFog = pCtx->pdwRenderState[D3DRS_FOGENABLE] ? 1 : 0; RastCapRec.Set_VertexFog(iVertexFog); // turn on alpha dither for color key so the pixels go away for // the software rasterizers iAlphaDither = (false&& pCtx->pdwRenderState[D3DRENDERSTATE_COLORKEYENABLE] ? 1 : 0); // are we texturing at all? if (pCtx->cActTex == 0) { iTexture = 0; RastCapRec.Set_Texture(iTexture); iTextureBlend = 0; RastCapRec.Set_TextureBlend(iTextureBlend); iTexturePerspective = 0; RastCapRec.Set_TexturePersp(iTexturePerspective); iTextureAlphaOverride[0] = 0; RastCapRec.Set_TextureAlphaOverride(0, iTextureAlphaOverride[0]); iTextureColorKey[0] = 0; RastCapRec.Set_TextureColorKey(0, iTextureColorKey[0]); } else { iTexturePerspective = (true|| pCtx->pdwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] ? 1 : 0); RastCapRec.Set_TexturePersp(iTexturePerspective); if (iTexturePerspective) { iTexture = 2; } else { iTexture = 1; } // If Multi-texture then iTexture must be incremented by two. This only effects fail cases. if (!(pCtx->pdwTextureStageState[1][D3DTSS_COLOROP] == D3DTOP_DISABLE)) { iTexture += 2; } RastCapRec.Set_Texture(iTexture); for (INT32 i = 0; i < (INT32)pCtx->cActTex; i++) { DoTexAddrSetup(pCtx, i); // values needed to choose TexAddr bead, TexRead routine // easiest to deal with border separately if ((pCtx->pTexture[i]->TexAddrU == D3DTADDRESS_BORDER) || (pCtx->pTexture[i]->TexAddrV == D3DTADDRESS_BORDER)) { iTextureBorder[i] = 1; } else { iTextureBorder[i] = 0; } RastCapRec.Set_TextureBorder(i, iTextureBorder[i]); switch (pCtx->pTexture[i]->TexAddrU) { default : SPIDPFM((SPIM_INVALID,"Invalid texture address mode, TexAddrU == 0x%x\n", pCtx->pTexture[i]->TexAddrU)); case D3DTADDRESS_WRAP : if ((pCtx->pTexture[i]->TexAddrV == D3DTADDRESS_WRAP) || (pCtx->pTexture[i]->TexAddrV == D3DTADDRESS_MIRROR)) { iTextureAddr[i] = 0; } else { iTextureAddr[i] = 1; } break; case D3DTADDRESS_MIRROR : if ((pCtx->pTexture[i]->TexAddrV == D3DTADDRESS_WRAP) || (pCtx->pTexture[i]->TexAddrV == D3DTADDRESS_MIRROR)) { iTextureAddr[i] = 0; } else { iTextureAddr[i] = 1; } break; case D3DTADDRESS_CLAMP : iTextureAddr[i] = 1; break; case D3DTADDRESS_BORDER : iTextureAddr[i] = 1; break; } RastCapRec.Set_TextureAddr(i, iTextureAddr[i]); if (i >= 1) { // no LOD info for second texture or later, just use uMagFilter switch (pCtx->pTexture[i]->uMagFilter) { default : SPIDPFM((SPIM_INVALID,"Invalid texture filter mode, uMagFilter == 0x%x\n", pCtx->pTexture[i]->uMagFilter)); case D3DTFG_POINT : iTextureFilter[i] = 0; break; case D3DTFG_LINEAR : case D3DTFG_FLATCUBIC: case D3DTFG_GAUSSIANCUBIC: case D3DTFG_ANISOTROPIC: iTextureFilter[i] = 1; break; } iTextureMip[i] = 0; iTextureLOD[i] = 0; } else { switch (pCtx->pTexture[i]->uMagFilter) { default : SPIDPFM((SPIM_INVALID,"Invalid texture filter mode, uMagFilter == 0x%x\n", pCtx->pTexture[i]->uMagFilter)); case D3DTFG_POINT : if (pCtx->pTexture[i]->uMinFilter == D3DTFN_POINT) { iTextureFilter[i] = 0; } else { iTextureFilter[i] = 2; } break; case D3DTFG_LINEAR : case D3DTFG_FLATCUBIC: case D3DTFG_GAUSSIANCUBIC: case D3DTFG_ANISOTROPIC: if (pCtx->pTexture[i]->uMinFilter == D3DTFN_LINEAR) { iTextureFilter[i] = 1; } else { iTextureFilter[i] = 2; } break; } iTextureLOD[i] = 1; if ( (i == 0) && (pCtx->pTexture[i]->uMipFilter == D3DTFP_LINEAR) ) { iTextureMip[i] = 1; } else { iTextureMip[i] = 0; // only set LOD to 0 if not mip filtering AND it is NOT the maybe // bilinear filter case if ( (pCtx->pTexture[i]->uMipFilter == D3DTFP_NONE) && (iTextureFilter[i] != 2) ) { iTextureLOD[i] = 0; } } } RastCapRec.Set_TextureFilter(i, iTextureFilter[i]); RastCapRec.Set_TextureMip(i, iTextureMip[i]); RastCapRec.Set_TextureLOD(i, iTextureLOD[i]); // set iTextureAlphaOverride if texture doesn't have an alpha and should use // iterated alpha iTextureAlphaOverride[i] = 0; RastCapRec.Set_TextureAlphaOverride(i, iTextureAlphaOverride[i]); // values needed to chose TexRead routine switch(pCtx->pTexture[i]->Format) { default : SPIDPFM((SPIM_INVALID,"Invalid texture surface bit count, " "Format == 0x%x\n",(DWORD) pCtx->pTexture[i]->Format)); return DDERR_INVALIDPARAMS; case D3DI_SPTFMT_B8G8R8 : iTextureFormat[i] = 0; iTextureAlphaOverride[i] = 1; break; case D3DI_SPTFMT_B8G8R8A8 : iTextureFormat[i] = 1; break; case D3DI_SPTFMT_B8G8R8X8 : // still necessary to select texture read that sets alpha to 0xff // for alpha dither iTextureFormat[i] = 0; iTextureAlphaOverride[i] = 1; break; case D3DI_SPTFMT_B5G6R5 : iTextureFormat[i] = 2; iTextureAlphaOverride[i] = 1; break; case D3DI_SPTFMT_B5G5R5 : iTextureFormat[i] = 3; iTextureAlphaOverride[i] = 1; break; case D3DI_SPTFMT_PALETTE4 : if (pCtx->pTexture[i]->pPalette == NULL) { // D3D_ERR("(Rast) NULL palette in paletted texture"); return DDERR_INVALIDPARAMS; } if (pCtx->pTexture[i]->uFlags & D3DI_SPANTEX_ALPHAPALETTE) { iTextureFormat[i] = 10; } else { iTextureFormat[i] = 4; iTextureAlphaOverride[i] = 1; } break; case D3DI_SPTFMT_PALETTE8 : if (pCtx->pTexture[i]->pPalette == NULL) { // D3D_ERR("(Rast) NULL palette in paletted texture"); return DDERR_INVALIDPARAMS; } if (pCtx->pTexture[i]->uFlags & D3DI_SPANTEX_ALPHAPALETTE) { iTextureFormat[i] = 11; } else { iTextureFormat[i] = 5; iTextureAlphaOverride[i] = 1; } break; case D3DI_SPTFMT_B5G5R5A1 : iTextureFormat[i] = 6; break; case D3DI_SPTFMT_B4G4R4A4 : iTextureFormat[i] = 7; break; case D3DI_SPTFMT_L8 : iTextureFormat[i] = 8; iTextureAlphaOverride[i] = 1; break; case D3DI_SPTFMT_L8A8 : iTextureFormat[i] = 9; break; } RastCapRec.Set_TextureFormat(i, iTextureFormat[i]); iTextureColorKey[i] = (false&& pCtx->pdwRenderState[D3DRENDERSTATE_COLORKEYENABLE] ? ((pCtx->pTexture[i]->uFlags & D3DI_SPANTEX_HAS_TRANSPARENT) != 0) : 0); RastCapRec.Set_TextureColorKey(i, iTextureColorKey[i]); } // choose TexBlend bead iTextureBlend = -1; if ((pCtx->pdwTextureStageState[1][D3DTSS_COLOROP] == D3DTOP_DISABLE) && (pCtx->pdwTextureStageState[0][D3DTSS_COLORARG1] == pCtx->pdwTextureStageState[0][D3DTSS_ALPHAARG1]) && (pCtx->pdwTextureStageState[0][D3DTSS_COLORARG2] == pCtx->pdwTextureStageState[0][D3DTSS_ALPHAARG2])) { // might be legacy texture blend mode if ((pCtx->pdwTextureStageState[0][D3DTSS_COLOROP] == D3DTOP_SELECTARG1) && (pCtx->pdwTextureStageState[0][D3DTSS_ALPHAOP] == D3DTOP_SELECTARG1) && (pCtx->pdwTextureStageState[0][D3DTSS_COLORARG1] == D3DTA_TEXTURE)) { // copy, decal, decalmask iTextureBlend = 1; } if ((pCtx->pdwTextureStageState[0][D3DTSS_COLOROP] == D3DTOP_MODULATE) && (pCtx->pdwTextureStageState[0][D3DTSS_ALPHAOP] == D3DTOP_SELECTARG1) && (pCtx->pdwTextureStageState[0][D3DTSS_COLORARG1] == D3DTA_TEXTURE) && (pCtx->pdwTextureStageState[0][D3DTSS_COLORARG2] == D3DTA_DIFFUSE)) { // modulate, modulatemask if (iTextureAlphaOverride[0]) { iTextureBlend = 3; } else { iTextureBlend = 2; } } } if (iTextureBlend == -1) { INT iCOp = 0; INT iCArg1 = 0; INT iCArg2 = 0; INT iAOp = 0; INT iAArg1 = 0; INT iAArg2 = 0; pCtx->cActBldStage = 0; for (INT32 i = 0; i < (INT32)pCtx->cActTex; i++) { switch(pCtx->pdwTextureStageState[i][D3DTSS_COLOROP]) { default: SPIDPFM((SPIM_INVALID,"Invalid COLOROP0[%d] == 0x%x\n", i, (DWORD) pCtx->pdwTextureStageState[i][D3DTSS_COLOROP])); case D3DTOP_DISABLE: iCOp = 0; break; case D3DTOP_SELECTARG1: iCOp = 1; break; case D3DTOP_SELECTARG2: iCOp = 2; break; case D3DTOP_MODULATE: iCOp = 3; break; case D3DTOP_MODULATE2X: iCOp = 4; break; case D3DTOP_MODULATE4X: iCOp = 5; break; case D3DTOP_ADD: iCOp = 6; break; case D3DTOP_ADDSIGNED: iCOp = 7; break; case D3DTOP_BLENDDIFFUSEALPHA: iCOp = 8; break; case D3DTOP_BLENDTEXTUREALPHA: iCOp = 9; break; case D3DTOP_BLENDFACTORALPHA: iCOp = 10; break; case D3DTOP_BLENDTEXTUREALPHAPM: iCOp = 11; break; case D3DTOP_ADDSIGNED2X: iCOp = 12; break; case D3DTOP_SUBTRACT: iCOp = 13; break; case D3DTOP_ADDSMOOTH: iCOp = 14; break; case D3DTOP_MODULATEALPHA_ADDCOLOR: iCOp = 15; break; case D3DTOP_MODULATECOLOR_ADDALPHA: iCOp = 16; break; } if (iCOp == 0 && i > 0) { break; } switch(pCtx->pdwTextureStageState[i][D3DTSS_COLORARG1]) { default: SPIDPFM((SPIM_INVALID,"Invalid COLORARG1[%d] == 0x%x\n", i, (DWORD) pCtx->pdwTextureStageState[i][D3DTSS_COLORARG1])); case (D3DTA_TEXTURE): iCArg1 = 0; break; case (D3DTA_TEXTURE|D3DTA_COMPLEMENT): iCArg1 = 1; break; case (D3DTA_ALPHAREPLICATE|D3DTA_TEXTURE): iCArg1 = 2; break; case (D3DTA_ALPHAREPLICATE|D3DTA_TEXTURE|D3DTA_COMPLEMENT): iCArg1 = 3; break; } switch(pCtx->pdwTextureStageState[i][D3DTSS_COLORARG2]) { default: SPIDPFM((SPIM_INVALID,"Invalid COLORARG2[%d] == 0x%x\n", i, (DWORD) pCtx->pdwTextureStageState[i][D3DTSS_COLORARG2])); case (D3DTA_DIFFUSE): iCArg2 = 0; break; case (D3DTA_CURRENT): iCArg2 = 1; break; case (D3DTA_TFACTOR): iCArg2 = 2; break; case (D3DTA_COMPLEMENT|D3DTA_DIFFUSE): iCArg2 = 3; break; case (D3DTA_COMPLEMENT|D3DTA_CURRENT): iCArg2 = 4; break; case (D3DTA_COMPLEMENT|D3DTA_TFACTOR): iCArg2 = 5; break; case (D3DTA_ALPHAREPLICATE|D3DTA_DIFFUSE): iCArg2 = 6; break; case (D3DTA_ALPHAREPLICATE|D3DTA_CURRENT): iCArg2 = 7; break; case (D3DTA_ALPHAREPLICATE|D3DTA_TFACTOR): iCArg2 = 8; break; case (D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT|D3DTA_DIFFUSE): iCArg2 = 9; break; case (D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT|D3DTA_CURRENT): iCArg2 = 10; break; case (D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT|D3DTA_TFACTOR): iCArg2 = 11; break; case (D3DTA_SPECULAR): iCArg2 = 12; break; case (D3DTA_COMPLEMENT|D3DTA_SPECULAR): iCArg2 = 13; break; case (D3DTA_ALPHAREPLICATE|D3DTA_SPECULAR): iCArg2 = 14; break; case (D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT|D3DTA_SPECULAR): iCArg2 = 15; break; } switch(pCtx->pdwTextureStageState[i][D3DTSS_ALPHAOP]) { default: SPIDPFM((SPIM_INVALID,"Invalid ALPHAOP[%d] == 0x%x\n", i, (DWORD) pCtx->pdwTextureStageState[i][D3DTSS_ALPHAOP])); case D3DTOP_DISABLE: iAOp = 0; break; case D3DTOP_SELECTARG1: iAOp = 1; break; case D3DTOP_SELECTARG2: iAOp = 2; break; case D3DTOP_MODULATE: iAOp = 3; break; case D3DTOP_MODULATE2X: iAOp = 4; break; case D3DTOP_MODULATE4X: iAOp = 5; break; case D3DTOP_ADD: iAOp = 6; break; case D3DTOP_ADDSIGNED: iAOp = 7; break; case D3DTOP_BLENDDIFFUSEALPHA: iAOp = 8; break; case D3DTOP_BLENDTEXTUREALPHA: iAOp = 9; break; case D3DTOP_BLENDFACTORALPHA: iAOp = 10; break; case D3DTOP_BLENDTEXTUREALPHAPM: iAOp = 11; break; case D3DTOP_ADDSIGNED2X: iAOp = 12; break; case D3DTOP_SUBTRACT: iAOp = 13; break; case D3DTOP_ADDSMOOTH: iAOp = 14; break; } switch(pCtx->pdwTextureStageState[i][D3DTSS_ALPHAARG1]) { default: SPIDPFM((SPIM_INVALID,"Invalid ALPHAARG1[%d] == 0x%x\n", i, (DWORD) pCtx->pdwTextureStageState[i][D3DTSS_ALPHAARG1])); case (D3DTA_TEXTURE): case (D3DTA_ALPHAREPLICATE|D3DTA_TEXTURE): iAArg1 = 0; break; case (D3DTA_TEXTURE|D3DTA_COMPLEMENT): case (D3DTA_ALPHAREPLICATE|D3DTA_TEXTURE|D3DTA_COMPLEMENT): iAArg1 = 1; break; } switch(pCtx->pdwTextureStageState[i][D3DTSS_ALPHAARG2]) { default: SPIDPFM((SPIM_INVALID,"Invalid ALPHAARG2[%d] == 0x%x\n", i, (DWORD) pCtx->pdwTextureStageState[i][D3DTSS_ALPHAARG2])); case (D3DTA_DIFFUSE): case (D3DTA_ALPHAREPLICATE|D3DTA_DIFFUSE): iAArg2 = 0; break; case (D3DTA_CURRENT): case (D3DTA_ALPHAREPLICATE|D3DTA_CURRENT): iAArg2 = 1; break; case (D3DTA_TFACTOR): case (D3DTA_ALPHAREPLICATE|D3DTA_TFACTOR): iAArg2 = 2; break; case (D3DTA_COMPLEMENT|D3DTA_DIFFUSE): case (D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT|D3DTA_DIFFUSE): iAArg2 = 3; break; case (D3DTA_COMPLEMENT|D3DTA_CURRENT): case (D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT|D3DTA_CURRENT): iAArg2 = 4; break; case (D3DTA_COMPLEMENT|D3DTA_TFACTOR): case (D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT|D3DTA_TFACTOR): iAArg2 = 5; break; case (D3DTA_SPECULAR): case (D3DTA_ALPHAREPLICATE|D3DTA_SPECULAR): iAArg2 = 6; break; case (D3DTA_COMPLEMENT|D3DTA_SPECULAR): case (D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT|D3DTA_SPECULAR): iAArg2 = 7; break; } pCtx->pfnTexBlendOpColor[i] = pBeadTable->pTexBlendOpColorBeads->pfnTexBlendOpColor[iCOp]; pCtx->pfnTexBlendGetColor[i] = pBeadTable->pTexBlendGetColorBeads->pfnTexBlendGetColor[iCArg2][iCArg1]; pCtx->pfnTexBlendOpAlpha[i] = pBeadTable->pTexBlendOpAlphaBeads->pfnTexBlendOpAlpha[iAOp]; pCtx->pfnTexBlendGetAlpha[i] = pBeadTable->pTexBlendGetAlphaBeads->pfnTexBlendGetAlpha[iAArg2][iAArg1]; pCtx->cActBldStage += 1; } if ( pCtx->cActBldStage <= 1 ) { // Tex1_Gen iTextureBlend = 4; } else { // TexM_Gen iTextureBlend = 5; } } RastCapRec.Set_TextureBlend(iTextureBlend); } // Ignore mono (D3DRENDERSTATE_MONOENABLE), since no software rasterizers do anything with it. iMono = 0; RastCapRec.Set_Mono(iMono); // values needed to choose ColorBlend bead iAlphaBlend = pCtx->pdwRenderState[D3DRS_ALPHABLENDENABLE] ? 1 : 0; RastCapRec.Set_AlphaBlend(iAlphaBlend); if (!iAlphaBlend || ((pCtx->pdwRenderState[D3DRS_SRCBLEND] == D3DBLEND_ONE) && (pCtx->pdwRenderState[D3DRS_DESTBLEND] == D3DBLEND_ZERO))) { iBlend = 0; } else { iBlend = 1; } RastCapRec.Set_Blend(iBlend); if (true|| pCtx->pdwRenderState[D3DRENDERSTATE_ROP2] == R2_COPYPEN) { iROP = 0; } else { iROP = 1; } RastCapRec.Set_ROP(iROP); // value needed to choose DestBlend routine switch (pCtx->pdwRenderState[D3DRS_DESTBLEND]) { default : SPIDPFM((SPIM_INVALID,"Invalid renderstate value, D3DRS_DESTBLEND == 0x%x\n", pCtx->pdwRenderState[D3DRS_DESTBLEND])); case D3DBLEND_ZERO : iDestBlend = 0; break; case D3DBLEND_ONE : iDestBlend = 1; break; case D3DBLEND_SRCCOLOR : iDestBlend = 2; break; case D3DBLEND_INVSRCCOLOR : iDestBlend = 3; break; case D3DBLEND_SRCALPHA : iDestBlend = 4; break; case D3DBLEND_INVSRCALPHA : iDestBlend = 5; break; case D3DBLEND_DESTALPHA : iDestBlend = 6; break; case D3DBLEND_INVDESTALPHA : iDestBlend = 7; break; case D3DBLEND_DESTCOLOR : iDestBlend = 8; break; case D3DBLEND_INVDESTCOLOR : iDestBlend = 9; break; case D3DBLEND_SRCALPHASAT : iDestBlend = 10; break; } // set iSrcBlend after iDestBlend so BOTHSRCALPHA can override iDestBlend // value needed to choose SrcBlend routine switch (pCtx->pdwRenderState[D3DRS_SRCBLEND]) { case D3DBLEND_ZERO : iSrcBlend = 0; break; default : SPIDPFM((SPIM_INVALID,"Invalid renderstate value, D3DRS_SRCBLEND == 0x%x\n", pCtx->pdwRenderState[D3DRS_SRCBLEND])); case D3DBLEND_ONE : iSrcBlend = 1; break; case D3DBLEND_SRCCOLOR : iSrcBlend = 2; break; case D3DBLEND_INVSRCCOLOR : iSrcBlend = 3; break; case D3DBLEND_SRCALPHA : iSrcBlend = 4; break; case D3DBLEND_INVSRCALPHA : iSrcBlend = 5; break; case D3DBLEND_DESTALPHA : iSrcBlend = 6; break; case D3DBLEND_INVDESTALPHA : iSrcBlend = 7; break; case D3DBLEND_DESTCOLOR : iSrcBlend = 8; break; case D3DBLEND_INVDESTCOLOR : iSrcBlend = 9; break; case D3DBLEND_SRCALPHASAT : iSrcBlend = 10; break; // these are special and set both source and dest case D3DBLEND_BOTHSRCALPHA : iSrcBlend = 4; iDestBlend = 5; break; case D3DBLEND_BOTHINVSRCALPHA : iSrcBlend = 5; iDestBlend = 4; break; } RastCapRec.Set_SrcBlend(iSrcBlend); RastCapRec.Set_DestBlend(iDestBlend); // values needed to choose BufWrite bead and BufRead routine switch (pCtx->iSurfaceType) { default : SPIDPFM((SPIM_INVALID,"Invalid target surface type, iSurfaceType == 0x%x\n", pCtx->iSurfaceType)); case RAST_STYPE_B8G8R8X8: iTargetPixelFormat = 0; break; case RAST_STYPE_B8G8R8A8: iTargetPixelFormat = 1; break; case RAST_STYPE_B5G6R5: iTargetPixelFormat = 2; break; case RAST_STYPE_B5G5R5: iTargetPixelFormat = 3; break; case RAST_STYPE_B5G5R5A1: iTargetPixelFormat = 4; break; case RAST_STYPE_B8G8R8: iTargetPixelFormat = 5; break; case RAST_STYPE_PALETTE8: iTargetPixelFormat = 6; break; } RastCapRec.Set_TargetPixelFormat(iTargetPixelFormat); iDither = pCtx->pdwRenderState[D3DRS_DITHERENABLE] ? 1 : 0; RastCapRec.Set_Dither(iDither); iZDeferred = iAlphaTest || iAlphaDither; // Set optional postprocessing beads first so that their addresses // can be referenced later. pCtx->pfnPixelEnd = pBeadTable->pPixelEndBeads->pfnPixelEnd[0]; pCtx->pfnSpanEnd = pBeadTable->pSpanEndBeads->pfnSpanEnd[0]; // start stringing beads together, back to front order avoids a lot of // conditional logic #if DBG // null out all bead ptrs pCtx->pfnBegin = NULL; pCtx->pfnLoopEnd = NULL; pCtx->pfnTestPassEnd = NULL; pCtx->pfnTestFailEnd = NULL; pCtx->pfnTexAddrEnd = NULL; pCtx->pfnTexRead[0] = NULL; pCtx->pfnTexRead[1] = NULL; pCtx->pfnTexAddr[0] = NULL; pCtx->pfnTexBlendEnd = NULL; pCtx->pfnColorGenEnd = NULL; pCtx->pfnAlphaTestPassEnd = NULL; pCtx->pfnAlphaTestFailEnd = NULL; pCtx->pfnSrcBlend = NULL; pCtx->pfnDestBlend = NULL; pCtx->pfnBufRead = NULL; pCtx->pfnColorBlendEnd = NULL; pCtx->pfnPixelEnd = NULL; pCtx->pfnSpanEnd = NULL; #endif // range check indices used to select BufWrite bead RANGE_CHECK(iDither,DITHERING_NUM); RANGE_CHECK(iTargetPixelFormat,TARGETPIXELFORMAT_NUM); // select BufWrite bead, which can be called through pfnColorBlendEnd, // pfnAlphaTestPassEnd, pfnColorGenEnd, pfnTexBlendEnd pCtx->pfnTexBlendEnd = pCtx->pfnColorGenEnd = pCtx->pfnAlphaTestPassEnd = pCtx->pfnColorBlendEnd = pBeadTable->pBufWriteBeads->pfnBufWrite[iDither][iTargetPixelFormat]; #if DBG strcpy(pCtx->szBufWrite,rgszBufWrite[iDither][iTargetPixelFormat]); #endif // range check indices used to select ColorBlend bead RANGE_CHECK(iROP,ROP_NUM); RANGE_CHECK(iBlend,BLEND_NUM); // select ColorBlend bead, which can be called through // pfnATextEnd, pfnColorGenEnd, or pfnTexBlendEnd if ((pfnColorBlend = pBeadTable->pColorBlendBeads->pfnColorBlend[iROP][iBlend]) == NULL) { pCtx->pfnColorBlendEnd = NULL; } else { pCtx->pfnTexBlendEnd = pCtx->pfnColorGenEnd = pCtx->pfnAlphaTestPassEnd = pfnColorBlend; } #if DBG strcpy(pCtx->szColorBlend,rgszColorBlend[iROP][iBlend]); #endif // range check index used to select BufRead bead RANGE_CHECK(iTargetPixelFormat,TARGETPIXELFORMAT_NUM); // select Buf Read routine pCtx->pfnBufRead = pBeadTable->pBufReadBeads->pfnBufRead[iTargetPixelFormat]; #if DBG strcpy(pCtx->szBufRead,rgszBufRead[iTargetPixelFormat]); #endif if (iBlend) { // range check index used to select DestBlend bead RANGE_CHECK(iDestBlend,DESTBLEND_NUM); // select DestBlend routine pCtx->pfnDestBlend = pBeadTable->pDestBlendBeads->pfnDestBlend[iDestBlend]; #if DBG strcpy(pCtx->szDestBlend,rgszDestBlend[iDestBlend]); #endif // range check index used to select SrcBlend bead RANGE_CHECK(iSrcBlend,SRCBLEND_NUM); // select SrcBlend routine pCtx->pfnSrcBlend = pBeadTable->pSrcBlendBeads->pfnSrcBlend[iSrcBlend]; #if DBG strcpy(pCtx->szSrcBlend,rgszSrcBlend[iSrcBlend]); #endif } else { pCtx->pfnDestBlend = NULL; pCtx->pfnSrcBlend = NULL; #if DBG strcpy(pCtx->szDestBlend,"NULL"); strcpy(pCtx->szSrcBlend,"NULL"); #endif } // select AlphaTest/AlphaDitheringTest bead, which can be called through // pfnColorBlendEnd, pfnColorGenEnd, or pfnTexBlendEnd // range check indices used to select AlphaTest bead RANGE_CHECK(iStencil,STENCIL_NUM); RANGE_CHECK(iZFormat,ZFORMAT_NUM); RANGE_CHECK(iZWrite,ZWRITE_NUM); RANGE_CHECK(iAlphaDither,COLORKEY_NUM); RANGE_CHECK(iAlphaTest,ALPHATEST_NUM); if (iAlphaTest || iAlphaDither) { pCtx->pfnTexBlendEnd = pCtx->pfnColorGenEnd = pBeadTable->pAlphaTestBeads->pfnAlphaTest[iStencil] [iZFormat] [iZWrite || iStencil] [iAlphaDither] [iAlphaTest]; // If AlphaTest fails, it goes to where the BufWrite bead ends pCtx->pfnAlphaTestFailEnd = pCtx->pfnPixelEnd; #if DBG strcpy(pCtx->szAlphaTest,rgszAlphaTest[iStencil][iZFormat][iZWrite] [iAlphaDither][iAlphaTest]); #endif } else { pCtx->pfnAlphaTestPassEnd = NULL; pCtx->pfnAlphaTestFailEnd = NULL; #if DBG strcpy(pCtx->szAlphaTest, "NULL"); #endif } // range check indices used to select ColorGen bead RANGE_CHECK(iMono,MONO_NUM); RANGE_CHECK(iVertexFog,VERTEXFOG_NUM); RANGE_CHECK(iSpecular,SPECULAR_NUM); RANGE_CHECK(iShadeMode,SHADEMODE_NUM); // select ColorGen bead, which can be called through pfnTexBlendEnd if ((pfnColorGen = pBeadTable->pColorGenBeads->pfnColorGen[iMono][iVertexFog][iSpecular][iShadeMode]) == NULL) { pCtx->pfnColorGenEnd = NULL; } else { pCtx->pfnTexBlendEnd = pfnColorGen; } #if DBG strcpy(pCtx->szColorGen, rgszColorGen[iMono][iVertexFog][iSpecular][iShadeMode]); #endif // range check indices used to select TexBlend bead RANGE_CHECK(iTextureBlend,TEXTUREBLEND_NUM); // select TexBlend bead, which can be called through pfnTexAddr2End, // pfnTexAddr1End, pfnTestPassEnd, or pfnLoopEnd pCtx->pfnLoopEnd = pCtx->pfnTestPassEnd = pCtx->pfnTexAddrEnd = pBeadTable->pTexBlendBeads->pfnTexBlend[iTextureBlend]; #if DBG strcpy(pCtx->szTexBlend,rgszTexBlend[iTextureBlend]); #endif if (iTexture) { if (pCtx->cActTex >= 2) { for (INT32 i = 1; i < (INT32)pCtx->cActTex; i ++) { // range check indices used to select TexRead bead RANGE_CHECK(iTextureColorKey[i],COLORKEY_NUM); RANGE_CHECK(iTextureBorder[i],TEXTUREBORDER_NUM); RANGE_CHECK(iTextureFormat[i],TEXTUREFORMAT_NUM); // select TexAddr2 bead, which can be called through pfnTexAddr1 // select TexRead routine pCtx->pfnTexRead[i] = pBeadTable->pTexReadBeads->pfnTexRead[iTextureColorKey[i]][iTextureBorder[i]][iTextureFormat[i]]; #if DBG strcpy(pCtx->szTexRead[i], rgszTexRead[iTextureColorKey[i]][iTextureBorder[i]][iTextureFormat[i]]); #endif // range check indices used to select Tex1Addr bead RANGE_CHECK(iTextureLOD[i],TEXTURELOD_NUM); RANGE_CHECK(iTextureFilter[i],TEXTUREFILTER_NUM); RANGE_CHECK(iTexturePerspective,TEXTUREPERSPECTIVE_NUM); RANGE_CHECK(iTextureAddr[i],TEXTUREADDRESS_NUM); // select TexAddr1 bead, which can be called through pfnTestPassEnd or // pfnLoopEnd pCtx->pfnTexAddr[i] = (pBeadTable->pTex2AddrBeads->pfnTex2Addr[iTextureFilter[i]] [iTexturePerspective][iTextureAddr[i]]); #if DBG strcpy(pCtx->szTexAddr[i],rgszTex2Addr[iTextureFilter[i]] [iTexturePerspective][iTextureAddr[i]]); #endif } } else { pCtx->pfnTexRead[1] = NULL; pCtx->pfnTexAddr[1] = NULL; #if DBG strcpy(pCtx->szTexAddr[1],"NULL"); strcpy(pCtx->szTexRead[1],"NULL"); #endif } // range check indices used to select TexRead bead RANGE_CHECK(iTextureColorKey[0],COLORKEY_NUM); RANGE_CHECK(iTextureBorder[0],TEXTUREBORDER_NUM); RANGE_CHECK(iTextureFormat[0],TEXTUREFORMAT_NUM); // select TexRead routine pCtx->pfnTexRead[0] = pBeadTable->pTexReadBeads->pfnTexRead[iTextureColorKey[0]][iTextureBorder[0]][iTextureFormat[0]]; #if DBG strcpy(pCtx->szTexRead[0], rgszTexRead[iTextureColorKey[0]][iTextureBorder[0]][iTextureFormat[0]]); #endif // range check indices used to select Tex1Addr bead RANGE_CHECK(iTextureLOD[0],TEXTURELOD_NUM); RANGE_CHECK(iTextureFilter[0],TEXTUREFILTER_NUM); RANGE_CHECK(iTexturePerspective,TEXTUREPERSPECTIVE_NUM); RANGE_CHECK(iTextureAddr[0],TEXTUREADDRESS_NUM); // select TexAddr1 bead, which can be called through pfnTestPassEnd or // pfnLoopEnd pCtx->pfnTexAddr[0] = (iTextureMip[0]) ? (pBeadTable->pTex1AddrMipBeads->pfnTex1AddrMip[0]) : (pBeadTable->pTex1AddrBeads->pfnTex1Addr[iTextureLOD[0]][iTextureFilter[0]] [iTexturePerspective][iTextureAddr[0]]); pCtx->pfnLoopEnd = pCtx->pfnTestPassEnd = pBeadTable->pTexAddrWrapperBeads->pfnTexAddrWrapper[0]; #if DBG if (iTextureMip[0]) { strcpy(pCtx->szTexAddr[0],rgszTex1AddrMip[0]); } else { strcpy(pCtx->szTexAddr[0],rgszTex1Addr[iTextureLOD[0]][iTextureFilter[0]] [iTexturePerspective][iTextureAddr[0]]); } #endif } else { pCtx->pfnTexAddrEnd = NULL; pCtx->pfnTexRead[0] = NULL; #if DBG strcpy(pCtx->szTexRead[0],"NULL"); strcpy(pCtx->szTexAddr[0],"NULL"); strcpy(pCtx->szTexAddr[1],"NULL"); #endif } // select Test bead, which can be called through pfnLoopEnd if (iZTest) { // range check indices used to select Test bead RANGE_CHECK(iStencil,STENCIL_NUM); RANGE_CHECK(iZFunc,ZFUNC_NUM); RANGE_CHECK(iZWrite,ZWRITE_NUM); // ATTENTION range check this // RANGE_CHECK(iAlphaTest,ALPHATEST_NUM); RANGE_CHECK(iZFormat,ZFORMAT_NUM); RANGE_CHECK(iSpecular,SPECULAR_NUM); RANGE_CHECK(iVertexFog,VERTEXFOG_NUM); RANGE_CHECK(iTexture,TEXTURE_NUM); RANGE_CHECK(iShadeMode,SHADEMODE_NUM); // if alpha testing, defer Z write pCtx->pfnLoopEnd = pBeadTable->pTestBeads->pfnTest[iStencil][iZFunc] [iZDeferred][iZWrite][iZFormat]; // select where this bead is going to go if the test fails pCtx->pfnTestFailEnd = pBeadTable->pTestFailBeads->pfnTestFail[iSpecular | iVertexFog][iTexture][iShadeMode]; if (iZDeferred && iStencil) { // If alpha testing and stenciling, need to // defer stencil update until after the alpha test. // // This is not an issue for Z, since we never want to write Z // if the Z test fails (hence we do not care about the outcome of // the alpha test. pCtx->pfnTestFailEnd = pCtx->pfnTestPassEnd; } #if DBG strcpy(pCtx->szTest,rgszTest[iStencil][iZFunc][iZDeferred][iZWrite][iZFormat]); strcpy(pCtx->szTestFail, rgszTestFail[iSpecular | iVertexFog][iTexture][iShadeMode]); #endif } else { pCtx->pfnTestPassEnd = NULL; pCtx->pfnTestFailEnd = NULL; #if DBG strcpy(pCtx->szTest,"NULL"); strcpy(pCtx->szTestFail,"NULL"); #endif } // select Loop bead pCtx->pfnBegin = pBeadTable->pBeginBeads->pfnBegin[0]; pCtx->pfnRenderSpans = pBeadTable->pRenderSpansBeads->pfnRenderSpans[0]; #if DBG SPIDPFM((SPIM_REPORT,"Test = %s\n",pCtx->szTest)); SPIDPFM((SPIM_REPORT,"TestFail = %s\n",pCtx->szTestFail)); SPIDPFM((SPIM_REPORT,"TexAddr[0] = %s\n",pCtx->szTexAddr[0])); SPIDPFM((SPIM_REPORT,"TexRead1 = %s\n",pCtx->szTexRead[0])); SPIDPFM((SPIM_REPORT,"TexRead2 = %s\n",pCtx->szTexRead[1])); SPIDPFM((SPIM_REPORT,"TexAddr[1] = %s\n",pCtx->szTexAddr[1])); SPIDPFM((SPIM_REPORT,"TexBlend = %s\n",pCtx->szTexBlend)); SPIDPFM((SPIM_REPORT,"ColorGen = %s\n",pCtx->szColorGen)); SPIDPFM((SPIM_REPORT,"ColorBlend = %s\n",pCtx->szColorBlend)); SPIDPFM((SPIM_REPORT,"SrcBlend = %s\n",pCtx->szSrcBlend)); SPIDPFM((SPIM_REPORT,"DestBlend = %s\n",pCtx->szDestBlend)); SPIDPFM((SPIM_REPORT,"BufRead = %s\n",pCtx->szBufRead)); SPIDPFM((SPIM_REPORT,"AlphaTest = %s\n",pCtx->szAlphaTest)); SPIDPFM((SPIM_REPORT,"BufWrite = %s\n",pCtx->szBufWrite)); SPIDPFM((SPIM_REPORT,"RastCap = 0x%x 0x%x 0x%x\n", RastCapRec.GetCapDWord(0), RastCapRec.GetCapDWord(1), RastCapRec.GetCapDWord(2))); #if 0 DWORD dwCheckSum = RastCapRec.GetCapDWord(0) ^ RastCapRec.GetCapDWord(1) ^ RastCapRec.GetCapDWord(2); static DWORD dwCheckSumLast; if (dwCheckSum != dwCheckSumLast) { dwCheckSumLast = dwCheckSum; DPF(0, "Spaninit"); DPF(0, "Test = %s",pCtx->szTest); DPF(0, "TestFail = %s",pCtx->szTestFail); DPF(0, "TexAddr[0] = %s",pCtx->szTexAddr[0]); DPF(0, "TexRead1 = %s",pCtx->szTexRead[0]); DPF(0, "TexRead2 = %s",pCtx->szTexRead[1]); DPF(0, "TexAddr[1] = %s",pCtx->szTexAddr[1]); DPF(0, "TexBlend = %s",pCtx->szTexBlend); DPF(0, "ColorGen = %s",pCtx->szColorGen); DPF(0, "ColorBlend = %s",pCtx->szColorBlend); DPF(0, "SrcBlend = %s",pCtx->szSrcBlend); DPF(0, "DestBlend = %s",pCtx->szDestBlend); DPF(0, "BufRead = %s",pCtx->szBufRead); DPF(0, "AlphaTest = %s",pCtx->szAlphaTest); DPF(0, "BufWrite = %s",pCtx->szBufWrite); DPF(0, "RastCap = 0x%x 0x%x 0x%x", RastCapRec.GetCapDWord(0), RastCapRec.GetCapDWord(1), RastCapRec.GetCapDWord(2)); } #endif #endif // is there a monolithic rasterizer that can do exactly // what is needed? RASTFNREC* pfnRastFnRec; if ((pfnRastFnRec = g_RastCollection.Search(pCtx, &RastCapRec)) != NULL) { // yes, then replace beaded rasterizer with monolithic // DDASSERT(pfnRastFnRec->pfnRastFunc != 0); pCtx->pfnRenderSpans = pfnRastFnRec->pfnRastFunc; #if DBG // null out all the others pCtx->pfnBegin = pCtx->pfnLoopEnd = pCtx->pfnTestPassEnd = pCtx->pfnTestFailEnd = pCtx->pfnTexAddrEnd = pCtx->pfnTexBlendEnd = pCtx->pfnColorGenEnd = pCtx->pfnAlphaTestPassEnd = pCtx->pfnAlphaTestFailEnd = pCtx->pfnColorBlendEnd = pCtx->pfnPixelEnd = NULL; pCtx->pfnTexAddr[0] = NULL; #endif } #if 0 && DBG static RASTFNREC* pfnLastRastFnRec = (RASTFNREC*)-1; if (pfnLastRastFnRec != pfnRastFnRec) { if (pfnRastFnRec) { D3D_INFO(0, "SpanInit: Fast path rasterizer %s chosen", pfnRastFnRec->pszRastDesc); } else { D3D_WARN(0, "SpanInit: No fast path rasterizer chosen"); } pfnLastRastFnRec = pfnRastFnRec; } #endif return S_OK; }