Leaked source code of windows server 2003
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.
 
 
 
 
 
 

488 lines
17 KiB

///////////////////////////////////////////////////////////////////////////////
// Copyright (C) Microsoft Corporation, 1998.
//
// pixproc.cpp
//
// Direct3D Reference Rasterizer - Pixel Processor
//
///////////////////////////////////////////////////////////////////////////////
#include "pch.cpp"
#pragma hdrstop
//-----------------------------------------------------------------------------
//
// DoPixel - Invoked for each pixel by the scan converter, applies texture,
// specular, fog, alpha blend, and writes result to surface. Also implements
// depth, alpha, and stencil tests.
//
//-----------------------------------------------------------------------------
void
ReferenceRasterizer::DoPixel( RRPixel& Pixel )
{
// apply texture (includes lookup&filter and blending)
if ( m_cActiveTextureStages > 0 )
{
RRColor TexturedColor = Pixel.Color;
DoTexture( Pixel, TexturedColor );
Pixel.Color = TexturedColor;
// check colorkey
for (INT32 i = 0; i < m_cActiveTextureStages; i++)
{
if ( NULL != m_pTexture[i] )
{
// kill pixel if colorkey killing and any samples matched
if ( m_pTexture[i]->m_bDoColorKeyKill &&
m_pTexture[i]->m_bColorKeyMatched )
{
return;
}
}
}
}
// do alpha test - bail out if failed
if ( m_dwRenderState[D3DRENDERSTATE_ALPHATESTENABLE] &&
!AlphaTest( Pixel.Color.A ) )
{
return;
}
// add specular and saturate
if ( m_dwRenderState[D3DRENDERSTATE_SPECULARENABLE] )
{
Pixel.Color.R += Pixel.Specular.R;
Pixel.Color.G += Pixel.Specular.G;
Pixel.Color.B += Pixel.Specular.B;
Pixel.Color.R = minimum( 1.f, Pixel.Color.R );
Pixel.Color.G = minimum( 1.f, Pixel.Color.G );
Pixel.Color.B = minimum( 1.f, Pixel.Color.B );
}
// apply fog
if ( m_dwRenderState[D3DRENDERSTATE_FOGENABLE] )
{
// get RRColor version of fog color
RRColor FogColor = m_dwRenderState[D3DRENDERSTATE_FOGCOLOR];
// do fog blend
// (TODO: account for pre-multiplied alpha here??)
RRColorComp ObjColorFrac = Pixel.FogIntensity; // f
RRColorComp FogColorFrac = ~Pixel.FogIntensity; // 1. - f
Pixel.Color.R = (ObjColorFrac * Pixel.Color.R) + (FogColorFrac * FogColor.R);
Pixel.Color.G = (ObjColorFrac * Pixel.Color.G) + (FogColorFrac * FogColor.G);
Pixel.Color.B = (ObjColorFrac * Pixel.Color.B) + (FogColorFrac * FogColor.B);
// NOTE: this can be done with a single (signed) multiply as
// (f)*Cp + (1-f)*Cf = f*(Cp-Cf) + Cf
}
//
// read current depth for this pixel and do depth test - cannot
// bail out if failed because stencil may need to be updated
//
RRDepth BufferDepth(Pixel.Depth.GetSType());
BOOL bDepthTestPassed = TRUE;
if ( m_dwRenderState[D3DRENDERSTATE_ZENABLE] )
{
m_pRenderTarget->ReadPixelDepth( Pixel.iX, Pixel.iY, BufferDepth );
bDepthTestPassed = DepthCloser( Pixel.Depth, BufferDepth );
}
//
// do stencil operation
//
BOOL bStencilTestPassed = TRUE;
if ( m_dwRenderState[D3DRENDERSTATE_STENCILENABLE] )
{
// read stencil buffer and do stencil operation
UINT8 uStncBuf = 0x0;
m_pRenderTarget->ReadPixelStencil( Pixel.iX, Pixel.iY, uStncBuf );
UINT8 uStncNew;
bStencilTestPassed = DoStencil( uStncBuf, bDepthTestPassed, Pixel.Depth.GetSType(), uStncNew );
// update stencil only if changed
if ( uStncNew != uStncBuf )
{
// compute new buffer value based on write mask
UINT8 uStncWMask = m_dwRenderState[D3DRENDERSTATE_STENCILWRITEMASK];
UINT8 uStncBufNew = (uStncBuf & ~uStncWMask) | (uStncNew & uStncWMask);
m_pRenderTarget->WritePixelStencil( Pixel.iX, Pixel.iY, uStncBufNew );
}
}
if ( !(bDepthTestPassed && bStencilTestPassed) )
{
return;
}
//
// do fragment generation processing - this is done prior to alpha blend
// somewhat arbitrarily because fragment generation and incremental alpha
// blending are mutually exclusive (blending of fragments requires multipass
// and fragment matching to get the correct result - fragment matching is
// not implemented here yet) (TODO: fragment matching)
//
// this may or may not complete the processing of this pixel
//
if ( m_bFragmentProcessingEnabled )
{
if ( DoFragmentGenerationProcessing( Pixel ) ) { return; }
}
//
// do alpha blend
//
if ( m_dwRenderState[D3DRENDERSTATE_ALPHABLENDENABLE] )
{
RRColor BufferColor;
m_pRenderTarget->ReadPixelColor( Pixel.iX, Pixel.iY, BufferColor );
DoAlphaBlend( Pixel.Color, BufferColor, Pixel.Color );
}
//
// update color and depth buffers
//
WritePixel( Pixel.iX, Pixel.iY, Pixel.Color, Pixel.Depth );
// additional fragment processing associated with buffer write
if ( m_bFragmentProcessingEnabled ) { DoFragmentBufferFixup( Pixel ); }
}
///////////////////////////////////////////////////////////////////////////////
// //
// Pixel Processing Utility Functions //
// //
///////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Depth compare method used for Z buffering and fragment processing.
//
// Returns TRUE if DepthVal is closer than DepthBuf. DepthA is the generated
// value and DepthB
//
//-----------------------------------------------------------------------------
BOOL
ReferenceRasterizer::DepthCloser(
const RRDepth& DepthVal,
const RRDepth& DepthBuf )
{
if ( !m_dwRenderState[D3DRENDERSTATE_ZENABLE] ) { return TRUE; }
switch ( m_dwRenderState[D3DRENDERSTATE_ZFUNC] )
{
case D3DCMP_NEVER: return FALSE;
case D3DCMP_LESS: return ( DOUBLE(DepthVal) < DOUBLE(DepthBuf) );
case D3DCMP_EQUAL: return ( DOUBLE(DepthVal) == DOUBLE(DepthBuf) );
case D3DCMP_LESSEQUAL: return ( DOUBLE(DepthVal) <= DOUBLE(DepthBuf) );
case D3DCMP_GREATER: return ( DOUBLE(DepthVal) > DOUBLE(DepthBuf) );
case D3DCMP_NOTEQUAL: return ( DOUBLE(DepthVal) != DOUBLE(DepthBuf) );
case D3DCMP_GREATEREQUAL: return ( DOUBLE(DepthVal) >= DOUBLE(DepthBuf) );
case D3DCMP_ALWAYS: return TRUE;
}
return TRUE;
}
//-----------------------------------------------------------------------------
//
// Alpha test method for pixel processing.
//
// Returns TRUE if alpha test passes.
//
//-----------------------------------------------------------------------------
BOOL
ReferenceRasterizer::AlphaTest( const RRColorComp& Alpha )
{
// grab 8 bit unsigned alpha value
UINT8 uAlpha = UINT8( Alpha );
// form 8 bit alpha reference value
UINT8 uAlphaRef8 = m_dwRenderState[D3DRENDERSTATE_ALPHAREF];
// do alpha test and either return directly or pass through
switch ( m_dwRenderState[D3DRENDERSTATE_ALPHAFUNC] )
{
case D3DCMP_NEVER: return FALSE;
case D3DCMP_LESS: return (uAlpha < uAlphaRef8);
case D3DCMP_EQUAL: return (uAlpha == uAlphaRef8);
case D3DCMP_LESSEQUAL: return (uAlpha <= uAlphaRef8);
case D3DCMP_GREATER: return (uAlpha > uAlphaRef8);
case D3DCMP_NOTEQUAL: return (uAlpha != uAlphaRef8);
case D3DCMP_GREATEREQUAL: return (uAlpha >= uAlphaRef8);
case D3DCMP_ALWAYS: return TRUE;
}
return TRUE;
}
//-----------------------------------------------------------------------------
//
// DoStencil - Performs stencil test. Returns TRUE if stencil test passed.
// Also computes stencil result value (to be written back to stencil planes
// if test passes, subject to stencil write mask).
//
//-----------------------------------------------------------------------------
BOOL
ReferenceRasterizer::DoStencil(
UINT8 uStncBuf, // in: stencil buffer value
BOOL bDepthTest, // in: boolean result of depth test
RRSurfaceType DepthSType, // in: surface type of Z buffer
UINT8& uStncRet) // out: stencil value result
{
// support 8 bit stencil only, so do everything as UINT8's
// get reference from renderstate
UINT8 uStncRef = (UINT8)(m_dwRenderState[D3DRENDERSTATE_STENCILREF]);
// form masked values for test
UINT8 uStncMask = (UINT8)(m_dwRenderState[D3DRENDERSTATE_STENCILMASK]);
UINT8 uStncBufM = uStncBuf & uStncMask;
UINT8 uStncRefM = uStncRef & uStncMask;
// max value for saturation ops
UINT8 uStncMax;
switch(DepthSType)
{
case RR_STYPE_Z24S8:
case RR_STYPE_S8Z24: uStncMax = 0xff; break;
case RR_STYPE_Z15S1:
case RR_STYPE_S1Z15: uStncMax = 0x1; break;
case RR_STYPE_Z24S4:
case RR_STYPE_S4Z24: uStncMax = 0xf; break;
default: uStncMax = 0; break; // don't let stencil become non 0
}
// do stencil compare function
BOOL bStncTest = FALSE;
switch ( m_dwRenderState[D3DRENDERSTATE_STENCILFUNC] )
{
case D3DCMP_NEVER: bStncTest = FALSE; break;
case D3DCMP_LESS: bStncTest = (uStncRefM < uStncBufM); break;
case D3DCMP_EQUAL: bStncTest = (uStncRefM == uStncBufM); break;
case D3DCMP_LESSEQUAL: bStncTest = (uStncRefM <= uStncBufM); break;
case D3DCMP_GREATER: bStncTest = (uStncRefM > uStncBufM); break;
case D3DCMP_NOTEQUAL: bStncTest = (uStncRefM != uStncBufM); break;
case D3DCMP_GREATEREQUAL: bStncTest = (uStncRefM >= uStncBufM); break;
case D3DCMP_ALWAYS: bStncTest = TRUE; break;
}
// determine which stencil operation to perform
DWORD dwStencilOp;
if ( !bStncTest )
{
// stencil test failed - depth test does not matter
dwStencilOp = m_dwRenderState[D3DRENDERSTATE_STENCILFAIL];
}
else
{
// stencil test passed - select based on depth pass/fail
dwStencilOp = ( !bDepthTest )
? ( m_dwRenderState[D3DRENDERSTATE_STENCILZFAIL] )
: ( m_dwRenderState[D3DRENDERSTATE_STENCILPASS] );
}
uStncRet = 0x0;
switch ( dwStencilOp )
{
case D3DSTENCILOP_KEEP: uStncRet = uStncBuf; break;
case D3DSTENCILOP_ZERO: uStncRet = 0x00; break;
case D3DSTENCILOP_REPLACE: uStncRet = uStncRef; break;
case D3DSTENCILOP_INCRSAT:
uStncRet = (uStncBuf==uStncMax)?(uStncMax):(uStncBuf+1); break;
case D3DSTENCILOP_DECRSAT:
uStncRet = (uStncBuf==0x00)?(0x00):(uStncBuf-1); break;
case D3DSTENCILOP_INVERT: uStncRet = ~uStncBuf; break;
case D3DSTENCILOP_INCR: uStncRet = uStncBuf+1; break;
case D3DSTENCILOP_DECR: uStncRet = uStncBuf-1; break;
}
return bStncTest;
}
//-----------------------------------------------------------------------------
//
// DoAlphaBlend - Performs color blending of source and destination colors
// producing a result color.
//
//-----------------------------------------------------------------------------
void
ReferenceRasterizer::DoAlphaBlend(
const RRColor& SrcColor, // in: source pixel color
const RRColor& DstColor, // in: destination (buffer) color
RRColor& ResColor) // out: result (blended) color
{
RRColor SrcColorFactor;
RRColor DstColorFactor;
BOOL bDestBlendOverride = FALSE;
// compute source blend factors
switch ( m_dwRenderState[D3DRENDERSTATE_SRCBLEND] )
{
default:
case D3DBLEND_ZERO:
SrcColorFactor.SetAllChannels( 0.F );
break;
case D3DBLEND_ONE:
SrcColorFactor.SetAllChannels( 1.F );
break;
case D3DBLEND_SRCCOLOR:
SrcColorFactor.R = SrcColor.R;
SrcColorFactor.G = SrcColor.G;
SrcColorFactor.B = SrcColor.B;
SrcColorFactor.A = SrcColor.A;
break;
case D3DBLEND_INVSRCCOLOR:
SrcColorFactor.R = ~SrcColor.R;
SrcColorFactor.G = ~SrcColor.G;
SrcColorFactor.B = ~SrcColor.B;
SrcColorFactor.A = ~SrcColor.A;
break;
case D3DBLEND_SRCALPHA:
SrcColorFactor.SetAllChannels( SrcColor.A );
break;
case D3DBLEND_INVSRCALPHA:
SrcColorFactor.SetAllChannels( ~SrcColor.A );
break;
case D3DBLEND_DESTALPHA:
SrcColorFactor.SetAllChannels( DstColor.A );
break;
case D3DBLEND_INVDESTALPHA:
SrcColorFactor.SetAllChannels( ~DstColor.A );
break;
case D3DBLEND_DESTCOLOR:
SrcColorFactor.R = DstColor.R;
SrcColorFactor.G = DstColor.G;
SrcColorFactor.B = DstColor.B;
SrcColorFactor.A = DstColor.A;
break;
case D3DBLEND_INVDESTCOLOR:
SrcColorFactor.R = ~DstColor.R;
SrcColorFactor.G = ~DstColor.G;
SrcColorFactor.B = ~DstColor.B;
SrcColorFactor.A = ~DstColor.A;
break;
case D3DBLEND_SRCALPHASAT:
{
RRColorComp F = minimum( SrcColor.A, ~DstColor.A );
SrcColorFactor.R = F;
SrcColorFactor.G = F;
SrcColorFactor.B = F;
}
SrcColorFactor.A = 1.F;
break;
// these are for SRCBLEND only and override DESTBLEND
case D3DBLEND_BOTHSRCALPHA:
bDestBlendOverride = TRUE;
SrcColorFactor.SetAllChannels( SrcColor.A );
DstColorFactor.SetAllChannels( ~SrcColor.A );
break;
case D3DBLEND_BOTHINVSRCALPHA:
bDestBlendOverride = TRUE;
SrcColorFactor.SetAllChannels( ~SrcColor.A );
DstColorFactor.SetAllChannels( SrcColor.A );
break;
}
// compute destination blend factors
if ( !bDestBlendOverride )
{
switch ( m_dwRenderState[D3DRENDERSTATE_DESTBLEND] )
{
default:
case D3DBLEND_ZERO:
DstColorFactor.SetAllChannels( 0.F );
break;
case D3DBLEND_ONE:
DstColorFactor.SetAllChannels( 1.F );
break;
case D3DBLEND_SRCCOLOR:
DstColorFactor.R = SrcColor.R;
DstColorFactor.G = SrcColor.G;
DstColorFactor.B = SrcColor.B;
DstColorFactor.A = SrcColor.A;
break;
case D3DBLEND_INVSRCCOLOR:
DstColorFactor.R = ~SrcColor.R;
DstColorFactor.G = ~SrcColor.G;
DstColorFactor.B = ~SrcColor.B;
DstColorFactor.A = ~SrcColor.A;
break;
case D3DBLEND_SRCALPHA:
DstColorFactor.SetAllChannels( SrcColor.A );
break;
case D3DBLEND_INVSRCALPHA:
DstColorFactor.SetAllChannels( ~SrcColor.A );
break;
case D3DBLEND_DESTALPHA:
DstColorFactor.SetAllChannels( DstColor.A );
break;
case D3DBLEND_INVDESTALPHA:
DstColorFactor.SetAllChannels( ~DstColor.A );
break;
case D3DBLEND_DESTCOLOR:
DstColorFactor.R = DstColor.R;
DstColorFactor.G = DstColor.G;
DstColorFactor.B = DstColor.B;
DstColorFactor.A = DstColor.A;
break;
case D3DBLEND_INVDESTCOLOR:
DstColorFactor.R = ~DstColor.R;
DstColorFactor.G = ~DstColor.G;
DstColorFactor.B = ~DstColor.B;
DstColorFactor.A = ~DstColor.A;
break;
case D3DBLEND_SRCALPHASAT:
{
RRColorComp F = minimum( SrcColor.A, ~DstColor.A );
DstColorFactor.R = F;
DstColorFactor.G = F;
DstColorFactor.B = F;
}
DstColorFactor.A = 1.F;
break;
}
}
// apply blend factors to update pixel color
ResColor.R = (SrcColorFactor.R * SrcColor.R) + (DstColorFactor.R * DstColor.R);
ResColor.G = (SrcColorFactor.G * SrcColor.G) + (DstColorFactor.G * DstColor.G);
ResColor.B = (SrcColorFactor.B * SrcColor.B) + (DstColorFactor.B * DstColor.B);
ResColor.A = (SrcColorFactor.A * SrcColor.A) + (DstColorFactor.A * DstColor.A);
// clamp result
ResColor.R = minimum( 1.f, maximum( 0.f, ResColor.R ) );
ResColor.G = minimum( 1.f, maximum( 0.f, ResColor.G ) );
ResColor.B = minimum( 1.f, maximum( 0.f, ResColor.B ) );
ResColor.A = minimum( 1.f, maximum( 0.f, ResColor.A ) );
}
///////////////////////////////////////////////////////////////////////////////
// end