You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1446 lines
52 KiB
1446 lines
52 KiB
//-----------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|
|
|