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.
1036 lines
34 KiB
1036 lines
34 KiB
///////////////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) Microsoft Corporation, 2000.
|
|
//
|
|
// refdev.cpp
|
|
//
|
|
// Direct3D Reference Device - public interfaces
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
// This is a global static array of the block sizes in bytes for the
|
|
// various DXTn compression formats
|
|
int g_DXTBlkSize[NUM_DXT_FORMATS] =
|
|
{
|
|
sizeof(DXTBlockRGB),
|
|
sizeof(DXTBlockAlpha4),
|
|
sizeof(DXTBlockAlpha4),
|
|
sizeof(DXTBlockAlpha3),
|
|
sizeof(DXTBlockAlpha3),
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Memory management function installation
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// global pointers to memory allocation functions (used through MEM* macros)
|
|
LPVOID (__cdecl *g_pfnMemAlloc)( size_t size ) = NULL;
|
|
void (__cdecl *g_pfnMemFree)( LPVOID lptr ) = NULL;
|
|
LPVOID (__cdecl *g_pfnMemReAlloc)( LPVOID ptr, size_t size ) = NULL;
|
|
|
|
// install memory management functions - must be called before instancing
|
|
// rasterizer object
|
|
void RefRastSetMemif(
|
|
LPVOID(__cdecl *pfnMemAlloc)(size_t),
|
|
void(__cdecl *pfnMemFree)(LPVOID),
|
|
LPVOID(__cdecl *pfnMemReAlloc)(LPVOID,size_t))
|
|
{
|
|
DPFRR(1, "RefRastSetMemif %08x %08x %08x\n",
|
|
pfnMemAlloc,pfnMemFree,pfnMemReAlloc);
|
|
g_pfnMemAlloc = pfnMemAlloc;
|
|
g_pfnMemFree = pfnMemFree;
|
|
g_pfnMemReAlloc = pfnMemReAlloc;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Public Interface Methods //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// SetRenderTarget -
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
RefDev::SetRenderTarget( RDRenderTarget* pRenderTarget )
|
|
{
|
|
m_pRenderTarget = pRenderTarget;
|
|
|
|
// update the W scaling values for mapping interpolated W's into buffer range
|
|
m_fWBufferNorm[0] = pRenderTarget->m_fWRange[0];
|
|
FLOAT fWRange = pRenderTarget->m_fWRange[1] - pRenderTarget->m_fWRange[0];
|
|
m_fWBufferNorm[1] = ( 0. != fWRange ) ? ( 1./fWRange ) : ( 1. );
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// SetTextureStageState -
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// map DX6(&7) texture filtering enums to DX8 enums
|
|
static DWORD
|
|
MapDX6toDX8TexFilter( DWORD dwStageState, DWORD dwValue )
|
|
{
|
|
switch (dwStageState)
|
|
{
|
|
case D3DTSS_MAGFILTER:
|
|
switch (dwValue)
|
|
{
|
|
case D3DTFG_POINT : return D3DTEXF_POINT;
|
|
case D3DTFG_LINEAR : return D3DTEXF_LINEAR;
|
|
case D3DTFG_FLATCUBIC : return D3DTEXF_FLATCUBIC;
|
|
case D3DTFG_GAUSSIANCUBIC : return D3DTEXF_GAUSSIANCUBIC;
|
|
case D3DTFG_ANISOTROPIC : return D3DTEXF_ANISOTROPIC;
|
|
}
|
|
break;
|
|
case D3DTSS_MINFILTER:
|
|
switch (dwValue)
|
|
{
|
|
case D3DTFN_POINT : return D3DTEXF_POINT;
|
|
case D3DTFN_LINEAR : return D3DTEXF_LINEAR;
|
|
case D3DTFN_ANISOTROPIC : return D3DTEXF_ANISOTROPIC;
|
|
}
|
|
break;
|
|
case D3DTSS_MIPFILTER:
|
|
switch (dwValue)
|
|
{
|
|
case D3DTFP_NONE : return D3DTEXF_NONE;
|
|
case D3DTFP_POINT : return D3DTEXF_POINT;
|
|
case D3DTFP_LINEAR : return D3DTEXF_LINEAR;
|
|
}
|
|
break;
|
|
}
|
|
return 0x0;
|
|
}
|
|
|
|
void
|
|
RefDev::SetTextureStageState(
|
|
DWORD dwStage, DWORD dwStageState, DWORD dwValue )
|
|
{
|
|
// check for range before continuing
|
|
if ( dwStage >= D3DHAL_TSS_MAXSTAGES)
|
|
{
|
|
return;
|
|
}
|
|
if (dwStageState > D3DTSS_MAX)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// set in internal per-stage state
|
|
m_TextureStageState[dwStage].m_dwVal[dwStageState] = dwValue;
|
|
|
|
m_dwRastFlags |= RDRF_TEXTURESTAGESTATE_CHANGED;
|
|
|
|
switch ( dwStageState )
|
|
{
|
|
|
|
case D3DTSS_TEXTUREMAP:
|
|
|
|
// bind texture indicated by handle to m_pTexture array
|
|
if (IsDriverDX6AndBefore() || IsInterfaceDX6AndBefore())
|
|
{
|
|
// This is the legacy behavior (prev. to DX7)
|
|
MapTextureHandleToDevice( dwStage );
|
|
}
|
|
else
|
|
{
|
|
// This is the new behavior (DX7 and beyond)
|
|
SetTextureHandle( dwStage, dwValue );
|
|
}
|
|
m_dwRastFlags |= RDRF_LEGACYPIXELSHADER_CHANGED;
|
|
break;
|
|
|
|
case D3DTSS_COLOROP:
|
|
m_dwRastFlags |= RDRF_LEGACYPIXELSHADER_CHANGED;
|
|
break;
|
|
|
|
// not including legacy headers, so don't have D3DTSS_ADDRESS
|
|
// case D3DTSS_ADDRESS:
|
|
// // map single set ADDRESS to U, V controls (pre-DX8 interfaces only)
|
|
// m_TextureStageState[dwStage].m_dwVal[D3DTSS_ADDRESSU] = dwValue;
|
|
// m_TextureStageState[dwStage].m_dwVal[D3DTSS_ADDRESSV] = dwValue;
|
|
// break;
|
|
|
|
case D3DTSS_MAGFILTER:
|
|
case D3DTSS_MINFILTER:
|
|
case D3DTSS_MIPFILTER:
|
|
if ( IsDriverDX7AndBefore() )
|
|
{
|
|
m_TextureStageState[dwStage].m_dwVal[dwStageState]
|
|
= MapDX6toDX8TexFilter( dwStageState, dwValue );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// TextureCreate - Instantiates new RDSurface2D object, computes texture handle
|
|
// to associate with it, and returns both to caller. Note that texture handle
|
|
// is a pointer and can be used to get at the corresponding texture object.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
RefDev::TextureCreate(
|
|
LPD3DTEXTUREHANDLE phTex, RDSurface2D** ppTex )
|
|
{
|
|
// allocate internal texture structure
|
|
*ppTex = new RDSurface2D();
|
|
_ASSERTa( NULL != *ppTex, "new failure on texture create", return FALSE; );
|
|
|
|
// use separately allocated pointer for handle
|
|
RDSurface2D** ppTexForHandle = (RDSurface2D**)MEMALLOC( sizeof(RDSurface2D*) );
|
|
_ASSERTa( NULL != ppTexForHandle, "malloc failure on texture create", return FALSE; );
|
|
*ppTexForHandle = *ppTex;
|
|
|
|
// return texture handle
|
|
(*ppTex)->m_hTex = (ULONG_PTR)ppTexForHandle;
|
|
*phTex = (*ppTex)->m_hTex;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// TextureDestroy -
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
RefDev::TextureDestroy( D3DTEXTUREHANDLE hTex )
|
|
{
|
|
// first check if texture about to be destroyed is mapped - if so then
|
|
// unmap it
|
|
for ( int iStage=0; iStage<D3DHAL_TSS_MAXSTAGES; iStage++ )
|
|
{
|
|
if ( hTex == m_TextureStageState[iStage].m_dwVal[D3DTSS_TEXTUREMAP] )
|
|
{
|
|
SetTextureStageState( iStage, D3DTSS_TEXTUREMAP, 0x0 );
|
|
}
|
|
}
|
|
|
|
// resolve handle to RDSurface2D pointer
|
|
RDSurface2D* pTex = MapHandleToTexture( hTex );
|
|
if ( NULL == pTex ) { return FALSE; }
|
|
|
|
// free the handle pointer
|
|
#ifdef _IA64_
|
|
_ASSERTa(FALSE, "This will not work on IA64", return FALSE;);
|
|
#endif
|
|
RDSurface2D** ppTex = (RDSurface2D**)ULongToPtr(hTex);
|
|
if ( NULL != ppTex) { MEMFREE( ppTex ); }
|
|
|
|
// free the RDSurface2D
|
|
delete pTex;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// TextureGetSurf -
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
DWORD
|
|
RefDev::TextureGetSurf( D3DTEXTUREHANDLE hTex )
|
|
{
|
|
RDSurface2D* pTex = MapHandleToTexture(hTex);
|
|
if ( NULL == pTex ) { return 0x0; }
|
|
return PtrToUlong( pTex->m_pDDSLcl[0] );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// GetCurrentTextureMaps - This function fills in a passed array texture handles
|
|
// and pointers. The array should be sized by D3DHAL_TSS_MAXSTAGES.
|
|
//
|
|
// This is used to facilitate external locking/unlocking of surfaces used for
|
|
// textures.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
int
|
|
RefDev::GetCurrentTextureMaps(
|
|
D3DTEXTUREHANDLE *phTex, RDSurface2D** pTex)
|
|
{
|
|
UpdateActiveTexStageCount();
|
|
|
|
for ( int i=0; i<m_cActiveTextureStages; i++ )
|
|
{
|
|
if ( NULL == m_pTexture[i] )
|
|
{
|
|
phTex[i] = 0x0;
|
|
pTex[i] = NULL;
|
|
}
|
|
else
|
|
{
|
|
phTex[i] = m_pTexture[i]->m_hTex;
|
|
pTex[i] = m_pTexture[i];
|
|
}
|
|
}
|
|
return m_cActiveTextureStages;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// SceneCapture - Used to trigger fragment buffer resolve.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
//#define DO_SCENE_RENDER_TIME
|
|
|
|
#ifdef DO_SCENE_RENDER_TIME
|
|
#include <mmsystem.h>
|
|
#endif
|
|
void
|
|
RefDev::SceneCapture( DWORD dwFlags )
|
|
{
|
|
static INT32 iScene = 0;
|
|
static INT32 iLastSceneEnd = 0;
|
|
#ifdef DO_SCENE_RENDER_TIME
|
|
static DWORD timeBS = 0;
|
|
#endif
|
|
|
|
switch (dwFlags)
|
|
{
|
|
case D3DHAL_SCENE_CAPTURE_START:
|
|
iScene++;
|
|
#ifdef DO_SCENE_RENDER_TIME
|
|
timeBS = timeGetTime();
|
|
#endif
|
|
break;
|
|
case D3DHAL_SCENE_CAPTURE_END:
|
|
if (iScene == iLastSceneEnd) break; // getting multiple END per BEGIN
|
|
iLastSceneEnd = iScene;
|
|
#ifdef DO_SCENE_RENDER_TIME
|
|
{
|
|
|
|
DWORD timeES = timeGetTime();
|
|
FLOAT dt = (FLOAT)(timeES - timeBS)/1000.f;
|
|
timeBS = 0;
|
|
RDDebugPrintf("SceneRenderTime: %f", dt );
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Query functions to get pointer to current render target and render state.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
RDRenderTarget*
|
|
RefDev::GetRenderTarget(void)
|
|
{
|
|
return m_pRenderTarget;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
RefDev::UpdateRastState( void )
|
|
{
|
|
// check 'dirty' flags
|
|
if (m_dwRastFlags & RDRF_MULTISAMPLE_CHANGED)
|
|
{
|
|
// update multi-sample RS related state
|
|
m_Rast.SetSampleMode(
|
|
m_pRenderTarget->m_pColor->m_iSamples,
|
|
m_dwRenderState[D3DRS_MULTISAMPLEANTIALIAS] );
|
|
m_Rast.SetSampleMask(
|
|
m_dwRenderState[D3DRS_MULTISAMPLEMASK] );
|
|
m_dwRastFlags &= ~(RDRF_MULTISAMPLE_CHANGED);
|
|
}
|
|
if (m_dwRastFlags & RDRF_PIXELSHADER_CHANGED)
|
|
{
|
|
if (m_CurrentPShaderHandle)
|
|
{
|
|
m_Rast.m_pCurrentPixelShader =
|
|
GetPShader(m_CurrentPShaderHandle);
|
|
m_Rast.m_bLegacyPixelShade = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// legacy pixel shader
|
|
m_Rast.UpdateLegacyPixelShader();
|
|
m_Rast.m_pCurrentPixelShader = m_Rast.m_pLegacyPixelShader;
|
|
m_Rast.m_bLegacyPixelShade = TRUE;
|
|
}
|
|
UpdateActiveTexStageCount();
|
|
|
|
m_dwRastFlags &= ~(RDRF_PIXELSHADER_CHANGED);
|
|
}
|
|
if (m_dwRastFlags & RDRF_LEGACYPIXELSHADER_CHANGED)
|
|
{
|
|
if (m_Rast.m_bLegacyPixelShade)
|
|
{
|
|
m_Rast.UpdateLegacyPixelShader();
|
|
m_Rast.m_pCurrentPixelShader = m_Rast.m_pLegacyPixelShader;
|
|
UpdateActiveTexStageCount();
|
|
}
|
|
m_dwRastFlags &= ~(RDRF_LEGACYPIXELSHADER_CHANGED);
|
|
|
|
}
|
|
if (m_dwRastFlags & RDRF_TEXTURESTAGESTATE_CHANGED)
|
|
{
|
|
m_Rast.UpdateTextureControls();
|
|
m_dwRastFlags &= ~(RDRF_TEXTURESTAGESTATE_CHANGED);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Begin/End bracket functions - Called before/after a list of primitives are
|
|
// rendered.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
RefDev::BeginRendering( void )
|
|
{
|
|
// If already in Begin, do nothing
|
|
if( m_bInBegin ) return S_OK;
|
|
|
|
#ifdef _X86_
|
|
// save floating point mode and set to extended precision mode
|
|
{
|
|
WORD wTemp, wSave;
|
|
__asm
|
|
{
|
|
fstcw wSave
|
|
mov ax, wSave
|
|
or ax, 300h ;; extended precision mode
|
|
// and ax, 00FFh ;; single precision mode + round nearest or even
|
|
mov wTemp, ax
|
|
fldcw wTemp
|
|
}
|
|
m_wSaveFP = wSave;
|
|
}
|
|
#endif
|
|
m_bInBegin = TRUE;
|
|
return S_OK;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT
|
|
RefDev::EndRendering( void )
|
|
{
|
|
if ( m_bInBegin )
|
|
{
|
|
#ifdef _X86_
|
|
// restore floating point mode
|
|
{
|
|
WORD wSave = m_wSaveFP;
|
|
__asm {fldcw wSave}
|
|
}
|
|
#endif
|
|
m_bInBegin = FALSE;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Clear specified rectangles in the render target
|
|
// Directly handles the command from the DP2 stream
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT RefDev::Clear(LPD3DHAL_DP2COMMAND pCmd)
|
|
{
|
|
D3DHAL_DP2CLEAR *pData = (D3DHAL_DP2CLEAR*)(pCmd + 1);
|
|
WORD i;
|
|
INT32 x,y;
|
|
RDColor fillColor(pData->dwFillColor);
|
|
RDDepth fillDepth;
|
|
if (m_pRenderTarget->m_pDepth)
|
|
{
|
|
fillDepth.SetSType(m_pRenderTarget->m_pDepth->GetSurfaceFormat());
|
|
}
|
|
|
|
fillDepth = pData->dvFillDepth;
|
|
|
|
struct
|
|
{
|
|
D3DHAL_DP2COMMAND cmd;
|
|
D3DHAL_DP2CLEAR data;
|
|
} WholeViewport;
|
|
|
|
if (!(pData->dwFlags & D3DCLEAR_COMPUTERECTS))
|
|
{
|
|
// Do nothing for non-pure device
|
|
}
|
|
else
|
|
if (pCmd->wStateCount == 0)
|
|
{
|
|
// When wStateCount is zero we need to clear whole viewport
|
|
WholeViewport.cmd = *pCmd;
|
|
WholeViewport.cmd.wStateCount = 1;
|
|
WholeViewport.data.dwFlags = pData->dwFlags;
|
|
WholeViewport.data.dwFillColor = pData->dwFillColor;
|
|
WholeViewport.data.dvFillDepth = pData->dvFillDepth;
|
|
WholeViewport.data.dwFillStencil = pData->dwFillStencil;
|
|
WholeViewport.data.Rects[0].left = m_Clipper.m_Viewport.dwX;
|
|
WholeViewport.data.Rects[0].top = m_Clipper.m_Viewport.dwY;
|
|
WholeViewport.data.Rects[0].right = m_Clipper.m_Viewport.dwX +
|
|
m_Clipper.m_Viewport.dwWidth;
|
|
WholeViewport.data.Rects[0].bottom = m_Clipper.m_Viewport.dwY +
|
|
m_Clipper.m_Viewport.dwHeight;
|
|
// Replace pointers and continue as usual
|
|
pCmd = (LPD3DHAL_DP2COMMAND)&WholeViewport;
|
|
pData = &WholeViewport.data;
|
|
}
|
|
else
|
|
{
|
|
// We need to cull all rects against the current viewport
|
|
UINT nRects = pCmd->wStateCount;
|
|
// Compute how much memory we need to process rects
|
|
UINT NeededSize = sizeof(D3DHAL_DP2COMMAND) +
|
|
sizeof(D3DHAL_DP2CLEAR) +
|
|
(nRects-1) * sizeof(RECT); // One rect is in DP2CLEAR
|
|
HRESULT hr = S_OK;
|
|
HR_RET(m_ClearRectBuffer.Grow(NeededSize));
|
|
|
|
RECT vwport; // Viewport rectangle to cull against
|
|
vwport.left = m_Clipper.m_Viewport.dwX;
|
|
vwport.top = m_Clipper.m_Viewport.dwY;
|
|
vwport.right = m_Clipper.m_Viewport.dwX + m_Clipper.m_Viewport.dwWidth;
|
|
vwport.bottom = m_Clipper.m_Viewport.dwY + m_Clipper.m_Viewport.dwHeight;
|
|
|
|
// Go through input rects and build output rect array
|
|
LPRECT pInputRects = pData->Rects;
|
|
LPRECT pOutputRects = (LPRECT)(&m_ClearRectBuffer[0] +
|
|
sizeof(D3DHAL_DP2COMMAND) +
|
|
sizeof(D3DHAL_DP2CLEAR) -
|
|
sizeof(RECT));
|
|
UINT nOutputRects = 0;
|
|
for (UINT i = 0; i < nRects; i++)
|
|
{
|
|
if (IntersectRect(&pOutputRects[nOutputRects], &vwport,
|
|
&pInputRects[i]))
|
|
{
|
|
nOutputRects++;
|
|
}
|
|
}
|
|
|
|
if (nOutputRects == 0)
|
|
return S_OK;
|
|
|
|
// Now replace pCmd and pData pointers and continue as usual
|
|
LPD3DHAL_DP2CLEAR pOldData = pData;
|
|
LPD3DHAL_DP2COMMAND pOldCmd = pCmd;
|
|
|
|
pCmd = (LPD3DHAL_DP2COMMAND)&m_ClearRectBuffer[0];
|
|
pData = (D3DHAL_DP2CLEAR*)(pCmd + 1);
|
|
*pCmd = *pOldCmd;
|
|
pCmd->wStateCount = (WORD)nOutputRects;
|
|
pData->dwFlags = pOldData->dwFlags;
|
|
pData->dwFillColor = pOldData->dwFillColor;
|
|
pData->dvFillDepth = pOldData->dvFillDepth;
|
|
pData->dwFillStencil = pOldData->dwFillStencil;
|
|
}
|
|
|
|
#ifdef _X86_
|
|
// Float to integer conversion routines for 24+ bit buffers work
|
|
// only with extended FPU mode.
|
|
//
|
|
WORD wSaveFP;
|
|
// save floating point mode and set to extended precision mode
|
|
{
|
|
WORD wTemp, wSave;
|
|
__asm
|
|
{
|
|
fstcw wSaveFP
|
|
mov ax, wSaveFP
|
|
or ax, 300h ;; extended precision mode
|
|
mov wTemp, ax
|
|
fldcw wTemp
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if(pData->dwFlags & D3DCLEAR_TARGET)
|
|
{
|
|
if (m_dwRenderState[D3DRENDERSTATE_DITHERENABLE] == FALSE)
|
|
{
|
|
m_pRenderTarget->Clear(fillColor, pCmd);
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < pCmd->wStateCount; i++)
|
|
{
|
|
for (y = pData->Rects[i].top; y < pData->Rects[i].bottom; ++y)
|
|
{
|
|
for (x = pData->Rects[i].left; x < pData->Rects[i].right; ++x)
|
|
{
|
|
m_pRenderTarget->WritePixelColor(x, y, fillColor, TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
switch (pData->dwFlags & (D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL))
|
|
{
|
|
case (D3DCLEAR_ZBUFFER):
|
|
m_pRenderTarget->ClearDepth(fillDepth, pCmd);
|
|
break;
|
|
case (D3DCLEAR_STENCIL):
|
|
m_pRenderTarget->ClearStencil(pData->dwFillStencil, pCmd);
|
|
break;
|
|
case (D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL):
|
|
m_pRenderTarget->ClearDepthStencil(fillDepth, pData->dwFillStencil, pCmd);
|
|
break;
|
|
}
|
|
|
|
#ifdef _X86_
|
|
// restore floating point mode
|
|
{
|
|
__asm {fldcw wSaveFP}
|
|
}
|
|
#endif
|
|
return D3D_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Clear specified rectangles in the render target
|
|
// Directly handles the command from the DP2 stream
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void RDRenderTarget::Clear(RDColor fillColor, LPD3DHAL_DP2COMMAND pCmd)
|
|
{
|
|
LPD3DHAL_DP2CLEAR pData = (LPD3DHAL_DP2CLEAR)(pCmd + 1);
|
|
UINT32 dwColor = 0;
|
|
fillColor.ConvertTo( m_pColor->GetSurfaceFormat(), 0.5f, (char*)&dwColor);
|
|
|
|
for (DWORD i = 0; i < pCmd->wStateCount; i++)
|
|
{
|
|
DWORD x0 = pData->Rects[i].left;
|
|
DWORD y0 = pData->Rects[i].top;
|
|
DWORD dwWidth = ( pData->Rects[i].right - x0 ) * m_pColor->GetSamples();
|
|
DWORD dwHeight = pData->Rects[i].bottom - y0;
|
|
char* pSurface = PixelAddress( x0, y0, 0, 0, m_pColor );
|
|
switch ( m_pColor->GetSurfaceFormat() )
|
|
{
|
|
case RD_SF_B8G8R8A8:
|
|
case RD_SF_B8G8R8X8:
|
|
{
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT32 *p = (UINT32*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
*p++ = dwColor;
|
|
}
|
|
pSurface += m_pColor->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case RD_SF_B8G8R8:
|
|
{
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT8 *p = (UINT8*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
*p++ = ((UINT8*)&dwColor)[0];
|
|
*p++ = ((UINT8*)&dwColor)[1];
|
|
*p++ = ((UINT8*)&dwColor)[2];
|
|
}
|
|
pSurface += m_pColor->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case RD_SF_B4G4R4A4:
|
|
case RD_SF_B5G6R5:
|
|
case RD_SF_B5G5R5A1:
|
|
case RD_SF_B5G5R5X1:
|
|
{
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT16 *p = (UINT16*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
*p++ = (UINT16)dwColor;
|
|
}
|
|
pSurface += m_pColor->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case RD_SF_B2G3R3:
|
|
{
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT8 *p = (UINT8*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
*p++ = (UINT8)dwColor;
|
|
}
|
|
pSurface += m_pColor->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
for (int y = y0; y < pData->Rects[i].bottom; ++y)
|
|
{
|
|
for (int x = x0; x < pData->Rects[i].right; ++x)
|
|
{
|
|
this->WritePixelColor(x, y, fillColor, TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Clear specified rectangles in the depth buffer
|
|
// Directly handles the command from the DP2 stream
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void RDRenderTarget::ClearDepth(RDDepth fillDepth, LPD3DHAL_DP2COMMAND pCmd)
|
|
{
|
|
LPD3DHAL_DP2CLEAR pData = (LPD3DHAL_DP2CLEAR)(pCmd + 1);
|
|
|
|
if (!m_pDepth) return;
|
|
for (DWORD i = 0; i < pCmd->wStateCount; i++)
|
|
{
|
|
DWORD x0 = pData->Rects[i].left;
|
|
DWORD y0 = pData->Rects[i].top;
|
|
DWORD dwWidth = ( pData->Rects[i].right - x0 ) * m_pDepth->GetSamples();
|
|
DWORD dwHeight = pData->Rects[i].bottom - y0;
|
|
char* pSurface = PixelAddress( x0, y0, 0, 0, m_pDepth );
|
|
switch ( m_pDepth->GetSurfaceFormat() )
|
|
{
|
|
case RD_SF_Z16S0:
|
|
{
|
|
UINT16 Depth = UINT16(fillDepth);
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT16 *p = (UINT16*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
*p++ = Depth;
|
|
}
|
|
pSurface += m_pDepth->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
case RD_SF_Z24S8:
|
|
case RD_SF_Z24X8:
|
|
case RD_SF_Z24X4S4:
|
|
{
|
|
UINT32 Depth = UINT32(fillDepth) << 8;
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT32 *p = (UINT32*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
// need to do read-modify-write to not step on stencil
|
|
*p++ = (*p & ~(0xffffff00)) | Depth;
|
|
}
|
|
pSurface += m_pDepth->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
case RD_SF_S8Z24:
|
|
case RD_SF_X8Z24:
|
|
case RD_SF_X4S4Z24:
|
|
{
|
|
UINT32 Depth = UINT32(fillDepth) & 0x00ffffff;
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT32 *p = (UINT32*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
// need to do read-modify-write to not step on stencil
|
|
*p++ = (*p & ~(0x00ffffff)) | Depth;
|
|
}
|
|
pSurface += m_pDepth->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
case RD_SF_Z15S1:
|
|
{
|
|
UINT16 Depth = UINT16(fillDepth) << 1;
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT16 *p = (UINT16*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
// need to do read-modify-write to not step on stencil
|
|
*p++ = (*p & ~(0xfffe)) | Depth;
|
|
}
|
|
pSurface += m_pDepth->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
case RD_SF_S1Z15:
|
|
{
|
|
UINT16 Depth = UINT16(fillDepth) & 0x7fff;
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT16 *p = (UINT16*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
// need to do read-modify-write to not step on stencil
|
|
*p++ = (*p & ~(0x7fff)) | Depth;
|
|
}
|
|
pSurface += m_pDepth->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
case RD_SF_Z32S0:
|
|
{
|
|
UINT32 Depth = UINT32(fillDepth);
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT32 *p = (UINT32*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
*p++ = Depth;
|
|
}
|
|
pSurface += m_pDepth->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
for (int y = y0; y < pData->Rects[i].bottom; ++y)
|
|
{
|
|
for (int x = x0; x < pData->Rects[i].right; ++x)
|
|
{
|
|
this->WritePixelDepth(x, y, fillDepth);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Clear specified rectangles in the stencil buffer
|
|
// Directly handles the command from the DP2 stream
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void RDRenderTarget::ClearStencil(UINT8 uStencil, LPD3DHAL_DP2COMMAND pCmd)
|
|
{
|
|
LPD3DHAL_DP2CLEAR pData = (LPD3DHAL_DP2CLEAR)(pCmd + 1);
|
|
|
|
for (DWORD i = 0; i < pCmd->wStateCount; i++)
|
|
{
|
|
DWORD x0 = pData->Rects[i].left;
|
|
DWORD y0 = pData->Rects[i].top;
|
|
DWORD dwWidth = (pData->Rects[i].right - x0 ) * m_pDepth->GetSamples();
|
|
DWORD dwHeight = pData->Rects[i].bottom - y0;
|
|
char* pSurface = PixelAddress( x0, y0, 0, 0, m_pDepth );
|
|
switch ( m_pDepth->GetSurfaceFormat() )
|
|
{
|
|
case RD_SF_Z24S8:
|
|
{
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT8 *p = (UINT8*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
*p = uStencil;
|
|
p += 4;
|
|
}
|
|
pSurface += m_pDepth->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
case RD_SF_S8Z24:
|
|
{
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT8 *p = (UINT8*)&pSurface[3];
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
*p = uStencil;
|
|
p += 4;
|
|
}
|
|
pSurface += m_pDepth->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
case RD_SF_Z24X4S4:
|
|
{
|
|
UINT32 stencil = uStencil & 0xf;
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT32 *p = (UINT32*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
// need to do read-modify-write to not step on depth
|
|
*p++ = (*p & ~(0x000000ff)) | stencil;
|
|
}
|
|
pSurface += m_pDepth->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
case RD_SF_X4S4Z24:
|
|
{
|
|
UINT32 stencil = (uStencil & 0xf) << 24;
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT32 *p = (UINT32*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
// need to do read-modify-write to not step on depth
|
|
*p++ = (*p & ~(0xff000000)) | stencil;
|
|
}
|
|
pSurface += m_pDepth->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
case RD_SF_Z15S1:
|
|
{
|
|
UINT16 stencil = uStencil & 0x1;
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT16 *p = (UINT16*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
// need to do read-modify-write to not step on depth
|
|
*p++ = (*p & ~(0x0001)) | stencil;
|
|
}
|
|
pSurface += m_pDepth->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
case RD_SF_S1Z15:
|
|
{
|
|
UINT16 stencil = uStencil << 15;
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT16 *p = (UINT16*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
// need to do read-modify-write to not step on depth
|
|
*p++ = (*p & ~(0x8000)) | stencil;
|
|
}
|
|
pSurface += m_pDepth->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
case RD_SF_Z16S0:
|
|
case RD_SF_Z32S0:
|
|
break;
|
|
default:
|
|
{
|
|
for (int y = y0; y < pData->Rects[i].bottom; ++y)
|
|
{
|
|
for (int x = x0; x < pData->Rects[i].right; ++x)
|
|
{
|
|
this->WritePixelStencil(x, y, uStencil);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Clear specified rectangles in the depth and stencil buffers
|
|
// Directly handles the command from the DP2 stream
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
void RDRenderTarget::ClearDepthStencil(RDDepth fillDepth, UINT8 uStencil, LPD3DHAL_DP2COMMAND pCmd)
|
|
{
|
|
LPD3DHAL_DP2CLEAR pData = (LPD3DHAL_DP2CLEAR)(pCmd + 1);
|
|
|
|
for (DWORD i = 0; i < pCmd->wStateCount; i++)
|
|
{
|
|
DWORD x0 = pData->Rects[i].left;
|
|
DWORD y0 = pData->Rects[i].top;
|
|
DWORD dwWidth = ( pData->Rects[i].right - x0 ) * m_pDepth->GetSamples();
|
|
DWORD dwHeight = pData->Rects[i].bottom - y0;
|
|
char* pSurface = PixelAddress( x0, y0, 0, 0, m_pDepth );
|
|
switch (m_pDepth->GetSurfaceFormat())
|
|
{
|
|
case RD_SF_Z16S0:
|
|
case RD_SF_Z32S0:
|
|
break;
|
|
case RD_SF_Z24S8:
|
|
case RD_SF_Z24X8:
|
|
case RD_SF_S8Z24:
|
|
case RD_SF_X8Z24:
|
|
case RD_SF_Z24X4S4:
|
|
case RD_SF_X4S4Z24:
|
|
{
|
|
UINT32 v;
|
|
switch (m_pDepth->GetSurfaceFormat())
|
|
{
|
|
case RD_SF_Z24S8: v = (UINT32(fillDepth) << 8) + uStencil; break;
|
|
case RD_SF_Z24X8: v = (UINT32(fillDepth) << 8); break;
|
|
case RD_SF_S8Z24: v = (UINT32(fillDepth) & 0x00ffffff) + (uStencil << 24); break;
|
|
case RD_SF_X8Z24: v = (UINT32(fillDepth) & 0x00ffffff); break;
|
|
case RD_SF_Z24X4S4: v = (UINT32(fillDepth) << 8) + (uStencil & 0xf); break;
|
|
case RD_SF_X4S4Z24: v = (UINT32(fillDepth) & 0x00ffffff) + ((uStencil & 0xf) << 24); break;
|
|
}
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT32 *p = (UINT32*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
*p++ = v;
|
|
}
|
|
pSurface += m_pDepth->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
case RD_SF_Z15S1:
|
|
case RD_SF_S1Z15:
|
|
{
|
|
UINT16 v;
|
|
switch (m_pDepth->GetSurfaceFormat())
|
|
{
|
|
case RD_SF_Z15S1: v = (UINT16(fillDepth) << 1) + (uStencil & 0x1); break;
|
|
case RD_SF_S1Z15: v = (UINT16(fillDepth) & 0x7fff) + (uStencil << 15); break;
|
|
}
|
|
for (DWORD y = dwHeight; y > 0; y--)
|
|
{
|
|
UINT16 *p = (UINT16*)pSurface;
|
|
for (DWORD x = dwWidth; x > 0; x--)
|
|
{
|
|
*p++ = v;
|
|
}
|
|
pSurface += m_pDepth->GetPitch();
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
for (int y = y0; y < pData->Rects[i].bottom; ++y)
|
|
{
|
|
for (int x = x0; x < pData->Rects[i].right; ++x)
|
|
{
|
|
this->WritePixelDepth(x, y, fillDepth);
|
|
this->WritePixelStencil(x, y, uStencil);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// end
|
|
|