|
|
//----------------------------------------------------------------------------
//
// rastctx.cpp
//
// Context functions + state functions.
//
// Copyright (C) Microsoft Corporation, 1997.
//
//----------------------------------------------------------------------------
#include "pch.cpp"
#pragma hdrstop
// Unlock previous texture if necessary. It's called before the texture handle
// is going to be changed.
#define CHECK_AND_UNLOCK_TEXTURE \
{ \ if (m_uFlags & D3DCONTEXT_TEXTURE_LOCKED) \ { \ RastUnlockSpanTexture(); \ } \ }
//----------------------------------------------------------------------------
//
// FillContext
//
// Fill the context with the info. from the surfaces.
//
//----------------------------------------------------------------------------
HRESULT D3DContext::FillContext(LPDIRECTDRAWSURFACE pDDS, LPDIRECTDRAWSURFACE pDDSZ) { HRESULT hr;
LPDDRAWI_DDRAWSURFACE_LCL pLcl = ((LPDDRAWI_DDRAWSURFACE_INT)(pDDS))->lpLcl; m_RastCtx.iSurfaceStride = DDSurf_Pitch(pLcl); m_RastCtx.iSurfaceBitCount = DDSurf_BitDepth(pLcl); m_RastCtx.iSurfaceStep = m_RastCtx.iSurfaceBitCount/8; HR_RET(FindOutSurfFormat(&(DDSurf_PixFmt(pLcl)), (D3DI_SPANTEX_FORMAT *)&(m_RastCtx.iSurfaceType))); m_RastCtx.Clip.left = m_RastCtx.Clip.top = 0; m_RastCtx.Clip.bottom = DDSurf_Height(pLcl); m_RastCtx.Clip.right = DDSurf_Width(pLcl);
if (pDDSZ != NULL) { pLcl = ((LPDDRAWI_DDRAWSURFACE_INT)(pDDSZ))->lpLcl; m_RastCtx.pZBits = (PUINT8)SURFACE_MEMORY(pDDSZ); m_RastCtx.iZStride = DDSurf_Pitch(pLcl); m_RastCtx.iZBitCount = DDSurf_BitDepth(pLcl); m_RastCtx.iZStep = m_RastCtx.iZBitCount/8; } else { m_RastCtx.pZBits = NULL; m_RastCtx.iZStride = 0; m_RastCtx.iZBitCount = 0; m_RastCtx.iZStep = 0; }
m_RastCtx.pDDS = pDDS; m_RastCtx.pDDSZ = pDDSZ;
m_RastCtx.dwSize = sizeof(D3DI_RASTCTX);
// Make sure SpanInit is called at least once
SetAllStatesDirtyBits();
// Check for MsGolf AppHack
if (pLcl->lpSurfMore->lpDD_lcl->dwAppHackFlags & DDRAW_APPCOMPAT_FORCEMODULATED) { m_uFlags |= D3DCONTEXT_APPHACK_MSGOLF; }
return D3D_OK; }
HRESULT D3DContext::Initialize(LPDIRECTDRAWSURFACE pDDS, LPDIRECTDRAWSURFACE pDDSZ, DWORD BeadSet, DWORD devVer) { HRESULT hr;
// Initialize the primitive processor.
HR_RET(m_PrimProc.Initialize());
memset(&m_RastCtx, 0, sizeof(m_RastCtx));
m_uFlags = 0; HR_RET(FillContext(pDDS, pDDSZ));
m_PrimProc.SetCtx(&m_RastCtx);
dwSize = sizeof(D3DContext);
// Initialize bead table enum
m_RastCtx.BeadSet = (D3DI_BEADSET)BeadSet;
// Init FVF data as legacy TL vertex
m_fvfData.preFVF = -1; CheckFVF(D3DFVF_TLVERTEX);
m_RastCtx.uDevVer = devVer;
// All render and texture stage state is initialized by
// DIRECT3DDEVICEI::stateInitialize
// Init prim function table. It will be updated for, or when FVF
// control word changes or when fill mode changes.
m_fnPrims.pfnTri = RGB_TriNoPackSolid; m_fnPrims.pfnPoint = RGB_PointNoPack; m_fnPrims.pfnLine = RGB_LineNoPack; // This one should be always the same.
m_fnPrims.pfnStoreLastPixelState = RGB_StoreLastPixelState; m_fnPrims.pfnDp2SetRenderStates = RGB_Dp2SetRenderStates; m_fnPrims.pfnDp2TextureStageState = RGB_Dp2TextureStageState; m_fnPrims.pfnDp2SetViewport = RGB_Dp2SetViewport; m_fnPrims.pfnDp2SetWRange = RGB_Dp2SetWRange;
// Enable MMX Fast Paths (Monolithics) if a registry key for it is not 0
m_RastCtx.dwMMXFPDisableMask[0] = 0x0; // enable MMX FP's by default
HKEY hKey = (HKEY) NULL; if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, RESPATH_D3D, &hKey) ) { DWORD dwType; DWORD dwValue; DWORD dwDisableMask[MMX_FP_DISABLE_MASK_NUM] = {0x0}; DWORD dwSize = 4;
// only code up looking at one mask, for now
DDASSERT(MMX_FP_DISABLE_MASK_NUM == 1);
if ( ERROR_SUCCESS == RegQueryValueEx( hKey, "MMXFPDisableMask0", NULL, &dwType, (LPBYTE) &dwValue, &dwSize) && dwType == REG_DWORD ) { dwDisableMask[0] = dwValue; } if ( ERROR_SUCCESS == RegQueryValueEx( hKey, "MMX Fast Path", NULL, &dwType, (LPBYTE) &dwValue, &dwSize) && dwType == REG_DWORD) { if (dwValue == 0) { // Override MMXFPDisableMask0 and disable all MMX Fast Paths
m_RastCtx.dwMMXFPDisableMask[0] = 0xffffffff; } else { // Take all MMX paths not disabled by MMXFPDisableMask0
m_RastCtx.dwMMXFPDisableMask[0] = dwDisableMask[0]; } }
RegCloseKey( hKey ); }
return D3D_OK; }
HRESULT D3DContext::SetViewport(LPD3DHAL_DP2VIEWPORTINFO pVpt) { m_RastCtx.Clip.left = pVpt->dwX; m_RastCtx.Clip.top = pVpt->dwY; m_RastCtx.Clip.bottom = pVpt->dwY + pVpt->dwHeight; m_RastCtx.Clip.right = pVpt->dwX + pVpt->dwWidth; return D3D_OK; }
//----------------------------------------------------------------------------
//
// RastContextCreateC
//
// Calls RastContextCreate with the C bead set.
//
//----------------------------------------------------------------------------
DWORD __stdcall RastContextCreateC(LPD3DHAL_CONTEXTCREATEDATA pCtxData) { return RastContextCreate(pCtxData, (DWORD)D3DIBS_C); }
//----------------------------------------------------------------------------
//
// RastContextCreateMMX
//
// Calls RastContextCreate with the MMX bead set.
//
//----------------------------------------------------------------------------
DWORD __stdcall RastContextCreateMMX(LPD3DHAL_CONTEXTCREATEDATA pCtxData) { return RastContextCreate(pCtxData, (DWORD)D3DIBS_MMX); }
//----------------------------------------------------------------------------
//
// RastContextCreateMMXAsRGB
//
// Calls RastContextCreate with the MMX bead set, but remember that we
// came from RGB.
//
//----------------------------------------------------------------------------
DWORD __stdcall RastContextCreateMMXAsRGB(LPD3DHAL_CONTEXTCREATEDATA pCtxData) { return RastContextCreate(pCtxData, (DWORD)D3DIBS_MMXASRGB); }
//----------------------------------------------------------------------------
//
// RastContextCreate
//
// Creates a RASTCTX and initializes it with the info passed in.
//
//----------------------------------------------------------------------------
DWORD __stdcall RastContextCreate(LPD3DHAL_CONTEXTCREATEDATA pCtxData, DWORD BeadSet) { DDASSERT(pCtxData != NULL);
D3DContext *pDCtx = new D3DContext;
if (pDCtx == NULL) { pCtxData->ddrval = DDERR_OUTOFMEMORY; return DDHAL_DRIVER_HANDLED; }
pCtxData->ddrval = pDCtx->Initialize(pCtxData->lpDDS, pCtxData->lpDDSZ, BeadSet, (DWORD)pCtxData->dwhContext);
pCtxData->dwhContext = (ULONG_PTR)pDCtx;
PD3DI_RASTCTX pCtx = pDCtx->GetRastCtx(); if (D3DI_SPTFMT_PALETTE8 == pCtx->iSurfaceType) { // 8 bit surfaces no longer supported by DX7
// AnanKan: Need to return a proer error message.
pCtxData->ddrval = DDERR_OUTOFMEMORY; return DDHAL_DRIVER_HANDLED; }
return DDHAL_DRIVER_HANDLED; }
//----------------------------------------------------------------------------
//
// RastContextDestroy
//
// Destroy a rast context.
//
//----------------------------------------------------------------------------
DWORD __stdcall RastContextDestroy(LPD3DHAL_CONTEXTDESTROYDATA pCtxDestroyData) { D3DContext *pDCtx;
VALIDATE_D3DCONTEXT("RastContextDestroy", pCtxDestroyData);
PD3DI_RASTCTX pCtx = pDCtx->GetRastCtx(); delete pDCtx;
pCtxDestroyData->ddrval = D3D_OK; return DDHAL_DRIVER_HANDLED; }
//----------------------------------------------------------------------------
//
// ValidateTextureStageState
//
// Utility function that returns an appropriate D3DERR_ if the current
// multi-texture setup can not be rendered, D3D_OK otherwise.
//
//----------------------------------------------------------------------------
HRESULT D3DContext::ValidateTextureStageState(void) { #if DBG
if ((m_RastCtx.pTexture[0] == m_RastCtx.pTexture[1]) && (m_RastCtx.pTexture[0] != NULL) ) { // except under very special circumstances, this will not work in RGB/MMX
// since we keep a lot of stage state in the D3DI_SPANTEX structure
D3D_ERR("(Rast) ValidateTextureStageState Warning, pTexture[0] == pTexture[1]"); } #endif
for (INT i = 0; i < D3DHAL_TSS_MAXSTAGES; i++) { switch(m_RastCtx.pdwTextureStageState[i][D3DTSS_COLOROP]) { default: return D3DERR_UNSUPPORTEDCOLOROPERATION; case D3DTOP_DISABLE: return D3D_OK; // don't have to validate further if the stage is disabled
case D3DTOP_SELECTARG1: case D3DTOP_SELECTARG2: case D3DTOP_MODULATE: case D3DTOP_MODULATE2X: case D3DTOP_MODULATE4X: case D3DTOP_ADD: case D3DTOP_ADDSIGNED: case D3DTOP_BLENDDIFFUSEALPHA: case D3DTOP_BLENDTEXTUREALPHA: case D3DTOP_BLENDFACTORALPHA: case D3DTOP_BLENDTEXTUREALPHAPM: case D3DTOP_ADDSIGNED2X: case D3DTOP_SUBTRACT: case D3DTOP_ADDSMOOTH: case D3DTOP_MODULATEALPHA_ADDCOLOR: case D3DTOP_MODULATECOLOR_ADDALPHA: break; }
switch(m_RastCtx.pdwTextureStageState[i][D3DTSS_COLORARG1] & ~(D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT)) { default: return D3DERR_UNSUPPORTEDCOLORARG; case (D3DTA_TEXTURE): break; }
switch(m_RastCtx.pdwTextureStageState[i][D3DTSS_COLORARG2] & ~(D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT)) { default: return D3DERR_UNSUPPORTEDCOLORARG; case (D3DTA_TFACTOR): case (D3DTA_CURRENT): case (D3DTA_DIFFUSE): case (D3DTA_SPECULAR): break; }
switch(m_RastCtx.pdwTextureStageState[i][D3DTSS_ALPHAOP]) { default: return D3DERR_UNSUPPORTEDALPHAOPERATION; case D3DTOP_DISABLE: break; case D3DTOP_SELECTARG1: case D3DTOP_SELECTARG2: case D3DTOP_MODULATE: case D3DTOP_MODULATE2X: case D3DTOP_MODULATE4X: case D3DTOP_ADD: case D3DTOP_ADDSIGNED: case D3DTOP_BLENDDIFFUSEALPHA: case D3DTOP_BLENDTEXTUREALPHA: case D3DTOP_BLENDFACTORALPHA: case D3DTOP_BLENDTEXTUREALPHAPM: case D3DTOP_ADDSIGNED2X: case D3DTOP_SUBTRACT: case D3DTOP_ADDSMOOTH: // only validate alpha args if alpha op is not disable
switch(m_RastCtx.pdwTextureStageState[i][D3DTSS_ALPHAARG1] & ~(D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT)) { default: return D3DERR_UNSUPPORTEDALPHAARG; case (D3DTA_TEXTURE): break; }
switch(m_RastCtx.pdwTextureStageState[i][D3DTSS_ALPHAARG2] & ~(D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT)) { default: return D3DERR_UNSUPPORTEDALPHAARG; case (D3DTA_TFACTOR): case (D3DTA_CURRENT): case (D3DTA_DIFFUSE): case (D3DTA_SPECULAR): break; } break; }
} return D3D_OK; }
//----------------------------------------------------------------------------
//
// RastValidateTextureStageState
//
// Returns whether the current multitexture setup can be rendered and, if
// so, the number of passes required to render it.
//
//----------------------------------------------------------------------------
DWORD __stdcall RastValidateTextureStageState(LPD3DHAL_VALIDATETEXTURESTAGESTATEDATA pData) { D3DContext *pDCtx;
VALIDATE_D3DCONTEXT("RastValidateTextureStageState", pData);
pData->dwNumPasses = 1;
pData->ddrval = pDCtx->ValidateTextureStageState();
return DDHAL_DRIVER_HANDLED; }
//----------------------------------------------------------------------------
//
// RastSetRenderTarget
//
// Update a rast context with the info from a new render target.
//
//----------------------------------------------------------------------------
DWORD __stdcall RastSetRenderTarget(LPD3DHAL_SETRENDERTARGETDATA pTgtData) { D3DContext *pDCtx;
VALIDATE_D3DCONTEXT("RastSetRenderTarget", pTgtData);
pTgtData->ddrval = pDCtx->FillContext(pTgtData->lpDDS, pTgtData->lpDDSZ);
return DDHAL_DRIVER_HANDLED; }
//----------------------------------------------------------------------------
//
// SetRenderState
//
// Check to see if a state change requires an update to the D3DCTX.
//
//----------------------------------------------------------------------------
HRESULT D3DContext::SetRenderState(UINT32 uState, UINT32 uStateVal) { // Assume d3dim has filtered out unchanged states
StateChanged(uState);
m_RastCtx.pdwRenderState[uState] = uStateVal;
switch(uState) { case D3DRENDERSTATE_FOGENABLE : case D3DRENDERSTATE_FOGCOLOR : case D3DRENDERSTATE_FOGTABLEMODE : case D3DRENDERSTATE_FOGTABLESTART : case D3DRENDERSTATE_FOGTABLEEND : case D3DRENDERSTATE_FOGTABLEDENSITY: break; case D3DRENDERSTATE_CULLMODE: // Set face culling sign from state.
switch(uStateVal) { case D3DCULL_CCW: m_RastCtx.uCullFaceSign = 1; break; case D3DCULL_CW: m_RastCtx.uCullFaceSign = 0; break; case D3DCULL_NONE: m_RastCtx.uCullFaceSign = 2; break; } break; case D3DRENDERSTATE_ZENABLE: if ( (D3DZB_FALSE != uStateVal) && (NULL == m_RastCtx.pDDSZ) ) { DPF(0, "(ERROR) (Rast) SetRenderState: Can't set D3DRENDERSTATE_ZENABLE to %d if there is no Z Buffer", uStateVal); m_RastCtx.pdwRenderState[uState] = D3DZB_FALSE; } break; case D3DRENDERSTATE_LASTPIXEL: // Set last-pixel flag from state.
if (uStateVal) { m_PrimProc.SetFlags(PPF_DRAW_LAST_LINE_PIXEL); } else { m_PrimProc.ClrFlags(PPF_DRAW_LAST_LINE_PIXEL); } break;
// map legacy modes with one-to-one mappings to texture stage 0
case D3DRENDERSTATE_TEXTUREADDRESS: m_RastCtx.pdwTextureStageState[0][D3DTSS_ADDRESS] = m_RastCtx.pdwTextureStageState[0][D3DTSS_ADDRESSU] = m_RastCtx.pdwTextureStageState[0][D3DTSS_ADDRESSV] = uStateVal; MapTextureStageState(0); break; case D3DRENDERSTATE_TEXTUREADDRESSU: m_RastCtx.pdwTextureStageState[0][D3DTSS_ADDRESSU] = uStateVal; MapTextureStageState(0); break; case D3DRENDERSTATE_TEXTUREADDRESSV: m_RastCtx.pdwTextureStageState[0][D3DTSS_ADDRESSV] = uStateVal; MapTextureStageState(0); break; case D3DRENDERSTATE_MIPMAPLODBIAS: m_RastCtx.pdwTextureStageState[0][D3DTSS_MIPMAPLODBIAS] = uStateVal; MapTextureStageState(0); break; case D3DRENDERSTATE_BORDERCOLOR: m_RastCtx.pdwTextureStageState[0][D3DTSS_BORDERCOLOR] = uStateVal; MapTextureStageState(0); break;
case D3DRENDERSTATE_TEXTUREMAG: case D3DRENDERSTATE_TEXTUREMIN: // map legacy filtering/sampling state to texture stage 0
MapLegacyTextureFilter(); // assign to current texture
MapTextureStageState(0); break;
case D3DRENDERSTATE_TEXTUREMAPBLEND: // map legacy blending state to texture stage 0
MapLegacyTextureBlend(); break;
// map legacy WRAPU/V to per-index controls
case D3DRENDERSTATE_WRAPU: m_RastCtx.pdwRenderState[D3DRENDERSTATE_WRAP0] &= ~D3DWRAP_U; m_RastCtx.pdwRenderState[D3DRENDERSTATE_WRAP0] |= ((uStateVal) ? D3DWRAP_U : 0); StateChanged(D3DRENDERSTATE_WRAP0); break; case D3DRENDERSTATE_WRAPV: m_RastCtx.pdwRenderState[D3DRENDERSTATE_WRAP0] &= ~D3DWRAP_V; m_RastCtx.pdwRenderState[D3DRENDERSTATE_WRAP0] |= ((uStateVal) ? D3DWRAP_V : 0); StateChanged(D3DRENDERSTATE_WRAP0); break;
//
// NOTE - this compututation of cActTex does not account for blend-only stages
//
case D3DRENDERSTATE_TEXTUREHANDLE:
CHECK_AND_UNLOCK_TEXTURE;
// map handle thru to stage 0
m_RastCtx.pdwTextureStageState[0][D3DTSS_TEXTUREMAP] = uStateVal; m_RastCtx.pTexture[1] = NULL; // set up for single stage
if (uStateVal == 0) { m_RastCtx.pTexture[0] = NULL; } else { m_RastCtx.pTexture[0] = HANDLE_TO_SPANTEX(uStateVal); } // map stage 0 state to first texture
MapTextureStageState(0); UpdateActiveTexStageCount(); break;
}
return D3D_OK; }
HRESULT D3DContext::SetTextureStageState(DWORD dwStage, DWORD dwState, DWORD uStateVal) { // Assume d3dim has filtered out unchanged states
StateChanged(RAST_TSS_DIRTYBIT(dwStage, dwState));
m_RastCtx.pdwTextureStageState[dwStage][dwState] = uStateVal; switch (dwState) { case D3DTSS_TEXTUREMAP: // Silently zero out legacy handle. They didn't mean it.
if (m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREHANDLE] != 0 && uStateVal != 0) { m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREHANDLE] = 0; }
CHECK_AND_UNLOCK_TEXTURE;
if (uStateVal == 0) { if (dwStage == 0) { if (m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREHANDLE] == 0 ) { m_RastCtx.pTexture[0] = NULL; } } else { m_RastCtx.pTexture[dwStage] = NULL; } // disables higher stages also, but don't clear pTexture[i]'s
// since they may be used later when this stage is set to non-NULL
} else { // if lower stages are null, this will be noted by UpdateActiveTexStageCount
m_RastCtx.pTexture[dwStage] = HANDLE_TO_SPANTEX(uStateVal); }
#if DBG
if (m_RastCtx.pTexture[dwStage]) { int iTexCount = 0; for (int i = 0; i < D3DHAL_TSS_MAXSTAGES; i++) { if (m_RastCtx.pTexture[dwStage] == m_RastCtx.pTexture[i]) { iTexCount ++; } } if (iTexCount > 1) { D3D_ERR( "Same texture handle was used more than once." ); return DDERR_INVALIDPARAMS; } } #endif
// map stage state to texture
MapTextureStageState(dwStage); UpdateActiveTexStageCount(); break;
// map single set ADDRESS to both U and V controls for stages 0 & 1
case D3DTSS_ADDRESS: m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_ADDRESSU] = uStateVal; m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_ADDRESSV] = uStateVal; MapTextureStageState(dwStage); break; case D3DTSS_ADDRESSU: case D3DTSS_ADDRESSV: case D3DTSS_MIPMAPLODBIAS: case D3DTSS_MAXMIPLEVEL: case D3DTSS_BORDERCOLOR: case D3DTSS_MAGFILTER: case D3DTSS_MINFILTER: case D3DTSS_MIPFILTER: MapTextureStageState(dwStage); break; case D3DTSS_COLOROP: case D3DTSS_COLORARG1: case D3DTSS_COLORARG2: case D3DTSS_ALPHAOP: case D3DTSS_ALPHAARG1: case D3DTSS_ALPHAARG2: // anything that effects the validity of the texture blending
// could change the number of active texture stages
UpdateActiveTexStageCount(); break; }
return D3D_OK; }
//-----------------------------------------------------------------------------
//
// UpdateActiveTexStageCount - Steps through per-stage renderstate and computes
// a count of currently active texture stages. For legacy texture, the count
// is at most one.
//
//-----------------------------------------------------------------------------
HRESULT D3DContext::UpdateActiveTexStageCount( void ) { HRESULT hr; UINT cNewActTex = 0;
// conservative but correct
if ((hr = ValidateTextureStageState()) == D3D_OK) { // always one active texture stage for legacy texture mode
if ( NULL != m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREHANDLE] ) { cNewActTex = 1; } else { // count number of contiguous-from-zero active texture blend stages
for ( INT iStage=0; iStage<D3DHAL_TSS_MAXSTAGES; iStage++ ) { // check for disabled stage (subsequent are thus inactive)
// also conservatively checks for incorrectly enabled stage (might be legacy)
if ( ( m_RastCtx.pdwTextureStageState[iStage][D3DTSS_COLOROP] == D3DTOP_DISABLE ) || ( m_RastCtx.pTexture[iStage] == NULL ) ) { break; }
// stage is active
cNewActTex ++; } } } if (m_RastCtx.cActTex != cNewActTex) { CHECK_AND_UNLOCK_TEXTURE; StateChanged(D3DRENDERSTATE_TEXTUREHANDLE); m_RastCtx.cActTex = cNewActTex; }
return hr; }
//----------------------------------------------------------------------------
//
// UpdateRenderStates
//
// Update a list of render states and notify components of state change.
//
//----------------------------------------------------------------------------
HRESULT D3DContext:: UpdateRenderStates(LPDWORD puStateChange, UINT cStateChanges) { HRESULT hr; INT i; UINT32 State, StateVal;
if (cStateChanges == 0) { return D3D_OK; }
// Update the D3DCTX
for (i = 0; i < (INT)cStateChanges; i++) { State = *puStateChange ++; StateVal = * puStateChange++; HR_RET(SetRenderState(State, StateVal)); } return D3D_OK; }
//----------------------------------------------------------------------------
//
// UpdateAllRenderStates
//
// Update all render states.
// It is still kept here because we probably need it in the case of fail-over.
//
//----------------------------------------------------------------------------
HRESULT D3DContext::UpdateAllRenderStates(LPDWORD puStates) { HRESULT hr, hrSet; INT i;
DDASSERT(puStates != NULL);
// Update D3DCTX.
// Attempt to set as many states as possible, even if there are
// errors on some. This allows context initialization to work
// even though some of the states fail due to dependencies on
// other state, such as active texture handles.
// SetRenderState failures are noted and returned eventually,
// even if everything else succeeds.
hrSet = D3D_OK; for (i = 0; i < D3DHAL_MAX_RSTATES_AND_STAGES; i++) { if ((hr = SetRenderState(i, puStates[i])) != D3D_OK) { hrSet = hr; } }
return hrSet; }
//----------------------------------------------------------------------------
//
// Dp2SetRenderStates
//
// Called by Drawprim2 to set render states..
//
//----------------------------------------------------------------------------
HRESULT D3DContext::Dp2SetRenderStates(LPD3DHAL_DP2COMMAND pCmd, LPDWORD lpdwRuntimeRStates) { WORD wStateCount = pCmd->wStateCount; INT i; HRESULT hr; D3DHAL_DP2RENDERSTATE *pRenderState = (D3DHAL_DP2RENDERSTATE *)(pCmd + 1); // Flush the prim proc before any state changs
HR_RET(End(FALSE));
for (i = 0; i < (INT)wStateCount; i++, pRenderState++) { UINT32 type = (UINT32) pRenderState->RenderState;
// Set the runtime copy (if necessary)
if (NULL != lpdwRuntimeRStates) { lpdwRuntimeRStates[pRenderState->RenderState] = pRenderState->dwState; }
// Set the state
HR_RET(SetRenderState(pRenderState->RenderState, pRenderState->dwState)); }
hr = Begin(); return hr; } //----------------------------------------------------------------------------
//
// Begin - Before rendering preparation
//
//
//----------------------------------------------------------------------------
HRESULT D3DContext::Begin(void) { HRESULT hr;
DDASSERT((m_uFlags & D3DCONTEXT_IN_BEGIN) == 0);
// ATTENTION call this less often?
UpdateColorKeyAndPalette();
// Check for state changes
if (IsAnyStatesChanged()) { // Check for fillmode change
if (IsStateChanged(D3DRENDERSTATE_FILLMODE)) { UpdatePrimFunctionTbl(); }
BOOL bMaxMipLevelsDirty = FALSE; for (INT j = 0; j < (INT)m_RastCtx.cActTex; j++) { PD3DI_SPANTEX pSpanTex = m_RastCtx.pTexture[j]; if (pSpanTex) { bMaxMipLevelsDirty = bMaxMipLevelsDirty || (pSpanTex->uFlags & D3DI_SPANTEX_MAXMIPLEVELS_DIRTY); } }
if (IsStateChanged(D3DRENDERSTATE_TEXTUREHANDLE) || IsStateChanged(RAST_TSS_DIRTYBIT(0, D3DTSS_TEXTUREMAP)) || IsStateChanged(RAST_TSS_DIRTYBIT(1, D3DTSS_TEXTUREMAP)) || bMaxMipLevelsDirty) { // Relock texture if texture handles have changed.
// SetRenderState should have already unlocked the texture.
if (m_uFlags & D3DCONTEXT_TEXTURE_LOCKED) { RastUnlockSpanTexture(); } HR_RET(RastLockSpanTexture()); }
// Check for WRAP state change
for (int iWrap=0; iWrap<8; iWrap++) { D3DRENDERSTATETYPE iWrapState = (D3DRENDERSTATETYPE)(D3DRENDERSTATE_WRAP0+iWrap); if (IsStateChanged(iWrapState)) { int i; for (i=0; i < D3DHAL_TSS_MAXSTAGES; i++) { if (m_fvfData.TexIdx[i] == iWrap) { m_RastCtx.pdwWrap[i] = m_RastCtx.pdwRenderState[iWrapState]; } } } }
// Notify primitive Processor of state change.
m_PrimProc.StateChanged();
// Clear state dirtybits
ClearAllStatesDirtyBits();
// Must call SpanInit AFTER texture is locked, since this
// sets various flags and fields that are needed for bead choosing
// Call SpanInit to setup the beads
HR_RET(SpanInit(&m_RastCtx)); }
// If texture is not locked yet, lock it
if (!(m_uFlags & D3DCONTEXT_TEXTURE_LOCKED)) { HR_RET(RastLockSpanTexture()); }
// Lock rendering target.
if ((hr=LockSurface(m_RastCtx.pDDS, (LPVOID *)&(m_RastCtx.pSurfaceBits))) != D3D_OK) { RastUnlockSpanTexture(); return hr; } if (m_RastCtx.pDDSZ != NULL) { if ((hr=LockSurface(m_RastCtx.pDDSZ, (LPVOID *)&(m_RastCtx.pZBits))) != D3D_OK) { RastUnlockSpanTexture(); UnlockSurface(m_RastCtx.pDDS); return hr; } } else { m_RastCtx.pZBits = NULL; }
// Prepare the primitive processor
m_PrimProc.Begin(); m_uFlags |= D3DCONTEXT_IN_BEGIN;
return D3D_OK;
}
//-----------------------------------------------------------------------------
//
// MapTextureStageState - Maps statestage texture state to spantex object
//
//-----------------------------------------------------------------------------
void D3DContext::MapTextureStageState( DWORD dwStage ) { if (m_RastCtx.pTexture[dwStage] == NULL) return; //
// assign texture state from stage 0
//
m_RastCtx.pTexture[dwStage]->TexAddrU = (D3DTEXTUREADDRESS)(m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_ADDRESSU]); m_RastCtx.pTexture[dwStage]->TexAddrV = (D3DTEXTUREADDRESS)(m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_ADDRESSV]); m_RastCtx.pTexture[dwStage]->BorderColor = (D3DCOLOR)(m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_BORDERCOLOR]); m_RastCtx.pTexture[dwStage]->uMagFilter = (D3DTEXTUREMAGFILTER)(m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_MAGFILTER]); m_RastCtx.pTexture[dwStage]->uMinFilter = (D3DTEXTUREMINFILTER)(m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_MINFILTER]); m_RastCtx.pTexture[dwStage]->uMipFilter = (D3DTEXTUREMIPFILTER)(m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_MIPFILTER]); m_RastCtx.pTexture[dwStage]->fLODBias = m_RastCtx.pfTextureStageState[dwStage][D3DTSS_MIPMAPLODBIAS];
if (m_RastCtx.pTexture[dwStage]->iMaxMipLevel != (INT32)m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_MAXMIPLEVEL]) { m_RastCtx.pTexture[dwStage]->iMaxMipLevel = (INT32)m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_MAXMIPLEVEL]; m_RastCtx.pTexture[dwStage]->uFlags |= D3DI_SPANTEX_MAXMIPLEVELS_DIRTY; } }
//-----------------------------------------------------------------------------
//
// MapLegacyTextureFilter -
//
//-----------------------------------------------------------------------------
void D3DContext::MapLegacyTextureFilter( void ) { // D3D legacy filter specifications are (XXXMIP)YYY where XXX is the
// mip filter and YYY is the filter used within an LOD
// map MAG filter - legacy support is point or linear (and maybe aniso)
switch ( m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREMAG] ) { default: case D3DFILTER_NEAREST: m_RastCtx.pdwTextureStageState[0][D3DTSS_MAGFILTER] = D3DTFG_POINT; break; case D3DFILTER_LINEAR: // select based on aniso enable
m_RastCtx.pdwTextureStageState[0][D3DTSS_MAGFILTER] = D3DTFG_LINEAR; break; } // map MIN and MIP filter at the same time - legacy support
// has them intermingled...
switch ( m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREMIN] ) { case D3DFILTER_NEAREST: m_RastCtx.pdwTextureStageState[0][D3DTSS_MINFILTER] = D3DTFN_POINT; m_RastCtx.pdwTextureStageState[0][D3DTSS_MIPFILTER] = D3DTFP_NONE; break; case D3DFILTER_MIPNEAREST: m_RastCtx.pdwTextureStageState[0][D3DTSS_MINFILTER] = D3DTFN_POINT; m_RastCtx.pdwTextureStageState[0][D3DTSS_MIPFILTER] = D3DTFP_POINT; break; case D3DFILTER_LINEARMIPNEAREST: m_RastCtx.pdwTextureStageState[0][D3DTSS_MINFILTER] = D3DTFN_POINT; m_RastCtx.pdwTextureStageState[0][D3DTSS_MIPFILTER] = D3DTFP_LINEAR; break; case D3DFILTER_LINEAR: m_RastCtx.pdwTextureStageState[0][D3DTSS_MINFILTER] = D3DTFN_LINEAR; m_RastCtx.pdwTextureStageState[0][D3DTSS_MIPFILTER] = D3DTFP_NONE; break; case D3DFILTER_MIPLINEAR: m_RastCtx.pdwTextureStageState[0][D3DTSS_MINFILTER] = D3DTFN_LINEAR; m_RastCtx.pdwTextureStageState[0][D3DTSS_MIPFILTER] = D3DTFP_POINT; break; case D3DFILTER_LINEARMIPLINEAR: m_RastCtx.pdwTextureStageState[0][D3DTSS_MINFILTER] = D3DTFN_LINEAR; m_RastCtx.pdwTextureStageState[0][D3DTSS_MIPFILTER] = D3DTFP_LINEAR; break; } }
//-----------------------------------------------------------------------------
//
// MapLegacyTextureBlend - Maps legacy (pre-DX6) texture blend modes to DX6
// texture blending controls. Uses per-stage program mode (first stage only).
// This mapping is done whenever the legacy TBLEND renderstate is set, and
// does overwrite any previously set DX6 texture blending controls.
//
//-----------------------------------------------------------------------------
void D3DContext::MapLegacyTextureBlend( void ) { // disable texture blend processing stage 1 (this also disables subsequent stages)
m_RastCtx.pdwTextureStageState[1][D3DTSS_COLOROP] = D3DTOP_DISABLE;
// set texture blend processing stage 0 to match legacy mode
switch ( m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREMAPBLEND] ) { default: case D3DTBLEND_DECALMASK: // unsupported - do decal
case D3DTBLEND_DECAL: case D3DTBLEND_COPY: m_RastCtx.pdwTextureStageState[0][D3DTSS_COLOROP] = D3DTOP_SELECTARG1; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAOP] = D3DTOP_SELECTARG1; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG1] = D3DTA_TEXTURE; break;
case D3DTBLEND_MODULATEMASK: // unsupported - do modulate
case D3DTBLEND_MODULATE: m_RastCtx.pdwTextureStageState[0][D3DTSS_COLOROP] = D3DTOP_MODULATE; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG2] = D3DTA_DIFFUSE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAOP] = D3DTOP_SELECTARG1; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG2] = D3DTA_DIFFUSE; break;
case D3DTBLEND_MODULATEALPHA: m_RastCtx.pdwTextureStageState[0][D3DTSS_COLOROP] = D3DTOP_MODULATE; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG2] = D3DTA_DIFFUSE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAOP] = D3DTOP_MODULATE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG2] = D3DTA_DIFFUSE; break;
case D3DTBLEND_DECALALPHA: m_RastCtx.pdwTextureStageState[0][D3DTSS_COLOROP] = D3DTOP_BLENDTEXTUREALPHA; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG2] = D3DTA_DIFFUSE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAOP] = D3DTOP_SELECTARG2; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG2] = D3DTA_DIFFUSE; break;
case D3DTBLEND_ADD: m_RastCtx.pdwTextureStageState[0][D3DTSS_COLOROP] = D3DTOP_ADD; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG2] = D3DTA_DIFFUSE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAOP] = D3DTOP_SELECTARG2; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG2] = D3DTA_DIFFUSE; break; }
// since we change [D3DHAL_TSS_OFFSET(0,D3DTSS_COLOROP), we can go from DISABLE to
// something else, and we can need to update the TexStageCount
UpdateActiveTexStageCount(); }
|