windows-nt/Source/XPSP1/NT/multimedia/directx/dxg/ref8/tnl/vstream.cpp
2020-09-26 16:20:57 +08:00

1421 lines
43 KiB
C++

/*============================================================================
*
* Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
*
* File: vshader.cpp
* Content: SetStreamSource and VertexShader
* software implementation.
*
****************************************************************************/
#include "pch.cpp"
#pragma hdrstop
/////////////////////////////////////////////////////////////////////////
//
// Helper functions
//
/////////////////////////////////////////////////////////////////////////
void
Copy_FLOAT1( LPVOID pInputStream, RDVECTOR4* pVertexRegister )
{
pVertexRegister->x = *(float*)pInputStream;
pVertexRegister->y = 0;
pVertexRegister->z = 0;
pVertexRegister->w = 1;
}
void
Copy_FLOAT2( LPVOID pInputStream, RDVECTOR4* pVertexRegister )
{
pVertexRegister->x = ((float*)pInputStream)[0];
pVertexRegister->y = ((float*)pInputStream)[1];
pVertexRegister->z = 0;
pVertexRegister->w = 1;
}
void
Copy_FLOAT3( LPVOID pInputStream, RDVECTOR4* pVertexRegister )
{
pVertexRegister->x = ((float*)pInputStream)[0];
pVertexRegister->y = ((float*)pInputStream)[1];
pVertexRegister->z = ((float*)pInputStream)[2];
pVertexRegister->w = 1;
}
void
Copy_FLOAT4( LPVOID pInputStream, RDVECTOR4* pVertexRegister )
{
pVertexRegister->x = ((float*)pInputStream)[0];
pVertexRegister->y = ((float*)pInputStream)[1];
pVertexRegister->z = ((float*)pInputStream)[2];
pVertexRegister->w = ((float*)pInputStream)[3];
}
void
Copy_D3DCOLOR( LPVOID pInputStream, RDVECTOR4* pVertexRegister )
{
const float scale = 1.0f/255.f;
const DWORD v = ((DWORD*)pInputStream)[0];
pVertexRegister->a = scale * RGBA_GETALPHA(v);
pVertexRegister->r = scale * RGBA_GETRED(v);
pVertexRegister->g = scale * RGBA_GETGREEN(v);
pVertexRegister->b = scale * RGBA_GETBLUE(v);
}
void
Copy_UBYTE4( LPVOID pInputStream, RDVECTOR4* pVertexRegister )
{
const BYTE* v = (BYTE *)pInputStream;
pVertexRegister->x = v[0];
pVertexRegister->y = v[1];
pVertexRegister->z = v[2];
pVertexRegister->w = v[3];
}
void
Copy_SHORT2( LPVOID pInputStream, RDVECTOR4* pVertexRegister )
{
const SHORT* v = ((SHORT*)pInputStream);
pVertexRegister->x = v[0];
pVertexRegister->y = v[1];
pVertexRegister->z = 0;
pVertexRegister->w = 1;
}
void
Copy_SHORT4( LPVOID pInputStream, RDVECTOR4* pVertexRegister )
{
const SHORT* v = ((SHORT*)pInputStream);
pVertexRegister->x = v[0];
pVertexRegister->y = v[1];
pVertexRegister->z = v[2];
pVertexRegister->w = v[3];
}
inline HRESULT
SetVElement( RDVElement& ve, DWORD dwReg, DWORD dwDataType, DWORD dwOffset )
{
ve.m_dwOffset = dwOffset;
ve.m_dwRegister = dwReg;
ve.m_dwDataType = dwDataType;
switch( dwDataType )
{
case D3DVSDT_FLOAT1:
ve.m_pfnCopy = Copy_FLOAT1;
break;
case D3DVSDT_FLOAT2:
ve.m_pfnCopy = Copy_FLOAT2;
break;
case D3DVSDT_FLOAT3:
ve.m_pfnCopy = Copy_FLOAT3;
break;
case D3DVSDT_FLOAT4:
ve.m_pfnCopy = Copy_FLOAT4;
break;
case D3DVSDT_D3DCOLOR:
ve.m_pfnCopy = Copy_D3DCOLOR;
break;
case D3DVSDT_UBYTE4:
ve.m_pfnCopy = Copy_UBYTE4;
break;
case D3DVSDT_SHORT2:
ve.m_pfnCopy = Copy_SHORT2;
break;
case D3DVSDT_SHORT4:
ve.m_pfnCopy = Copy_SHORT4;
break;
default:
return E_FAIL;
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Based on register and data type the function computes FVF dword and texture
// presence bits:
// - bits 0 - 7 in the qwFVF2 are used as texture presence bits
// - bits 12 - 14 in the qwFVF are used as count of blend weights
//-----------------------------------------------------------------------------
HRESULT
UpdateFVF( DWORD dwRegister, DWORD dwDataType, UINT64* pqwFVF,
UINT64* pqwFVF2, DWORD* pdwNumBetas )
{
DWORD dwNumFloats = 0;
switch( dwRegister )
{
case D3DVSDE_POSITION:
if( dwDataType != D3DVSDT_FLOAT3 )
{
DPFERR( "Position register must be FLOAT3 for"
"fixed-function pipeline" );
return DDERR_GENERIC;
}
*pqwFVF |= D3DFVF_XYZ;
break;
case D3DVSDE_POSITION2:
if( dwDataType != D3DVSDT_FLOAT3 )
{
DPFERR( "Position register must be FLOAT3 for"
"fixed-function pipeline" );
return DDERR_GENERIC;
}
*pqwFVF |= D3DFVFP_POSITION2;
break;
case D3DVSDE_BLENDWEIGHT:
{
int n = 0;
switch (dwDataType)
{
case D3DVSDT_FLOAT1:
n = 1;
break;
case D3DVSDT_FLOAT2:
n = 2;
break;
case D3DVSDT_FLOAT3:
n = 3;
break;
case D3DVSDT_FLOAT4:
n = 4;
break;
default:
DPFERR( "Invalid data type set for vertex blends" );
return DDERR_GENERIC;
}
// Update number of floats after position
*pdwNumBetas = *pdwNumBetas + n;
break;
}
case D3DVSDE_NORMAL:
if( dwDataType != D3DVSDT_FLOAT3 )
{
DPFERR( "Normal register must be FLOAT3 for fixed-function"
"pipeline" );
return DDERR_GENERIC;
}
*pqwFVF |= D3DFVF_NORMAL;
break;
case D3DVSDE_NORMAL2:
if( dwDataType != D3DVSDT_FLOAT3 )
{
DPFERR( "Normal register must be FLOAT3 for fixed-function"
"pipeline" );
return DDERR_GENERIC;
}
*pqwFVF |= D3DFVFP_NORMAL2;
break;
case D3DVSDE_PSIZE:
if( dwDataType != D3DVSDT_FLOAT1 )
{
DPFERR( "Point size register must be FLOAT1 for fixed-function"
"pipeline" );
return DDERR_GENERIC;
}
*pqwFVF |= D3DFVF_PSIZE;
break;
case D3DVSDE_DIFFUSE:
if( dwDataType != D3DVSDT_D3DCOLOR )
{
DPFERR( "Diffuse register must be D3DCOLOR for"
"fixed-function pipeline" );
return DDERR_GENERIC;
}
*pqwFVF |= D3DFVF_DIFFUSE;
break;
case D3DVSDE_SPECULAR:
if( dwDataType != D3DVSDT_D3DCOLOR )
{
DPFERR( "Specular register must be PACKEDBYTE for"
"fixed-function pipeline" );
return DDERR_GENERIC;
}
*pqwFVF |= D3DFVF_SPECULAR;
break;
case D3DVSDE_BLENDINDICES:
if ( dwDataType != D3DVSDT_UBYTE4 )
{
DPFERR( "Blend Indicex register must be UBYTE4 for"
"fixed-function pipeline" );
return DDERR_GENERIC;
}
*pqwFVF |= D3DFVFP_BLENDINDICES;
break;
case D3DVSDE_TEXCOORD0:
case D3DVSDE_TEXCOORD1:
case D3DVSDE_TEXCOORD2:
case D3DVSDE_TEXCOORD3:
case D3DVSDE_TEXCOORD4:
case D3DVSDE_TEXCOORD5:
case D3DVSDE_TEXCOORD6:
case D3DVSDE_TEXCOORD7:
{
DWORD dwTextureIndex = dwRegister - D3DVSDE_TEXCOORD0;
DWORD dwBit = 1 << dwTextureIndex;
if( *pqwFVF2 & dwBit )
{
DPFERR( "Texture register is set second time" );
return DDERR_GENERIC;
}
*pqwFVF2 |= dwBit;
switch( dwDataType )
{
case D3DVSDT_FLOAT1:
*pqwFVF |= D3DFVF_TEXCOORDSIZE1(dwTextureIndex);
break;
case D3DVSDT_FLOAT2:
*pqwFVF |= D3DFVF_TEXCOORDSIZE2(dwTextureIndex);
break;
case D3DVSDT_FLOAT3:
*pqwFVF |= D3DFVF_TEXCOORDSIZE3(dwTextureIndex);
break;
case D3DVSDT_FLOAT4:
*pqwFVF |= D3DFVF_TEXCOORDSIZE4(dwTextureIndex);
break;
default:
DPFERR( "Invalid data type set for texture register" );
return DDERR_GENERIC;
break;
}
break;
}
default:
DPFERR( "Invalid register set for fixed-function pipeline" );
return DDERR_GENERIC;
break;
}
return S_OK;
}
/////////////////////////////////////////////////////////////////////////
//
// class RDVStreamDecl
//
/////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// RDVStreamDecl::Constructor
//-----------------------------------------------------------------------------
RDVStreamDecl::RDVStreamDecl()
{
m_dwNumElements = 0;
m_dwStride = 0;
m_dwStreamIndex = 0;
m_bIsStreamTess = FALSE;
}
//-----------------------------------------------------------------------------
// RDVStreamDecl::MakeVElementArray
//-----------------------------------------------------------------------------
HRESULT
RDVStreamDecl::MakeVElementArray( UINT64 qwFVF )
{
HRESULT hr = S_OK;
DWORD dwOffset = 0; // In Bytes
m_dwStride = GetFVFVertexSize( qwFVF );
m_dwStreamIndex = 0;
m_dwNumElements = 0;
dwOffset = 0 + ( qwFVF & D3DFVF_RESERVED0 ? 4 : 0 );
//
// Position and Blend Weights
//
switch( qwFVF & D3DFVF_POSITION_MASK )
{
case D3DFVF_XYZ:
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_POSITION,
D3DVSDT_FLOAT3, dwOffset );
m_dwNumElements++;
dwOffset += 4*3;
break;
case D3DFVF_XYZRHW:
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_POSITION,
D3DVSDT_FLOAT4, dwOffset );
m_dwNumElements++;
dwOffset += 4*4;
break;
case D3DFVF_XYZB1:
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_POSITION,
D3DVSDT_FLOAT3, dwOffset );
m_dwNumElements++;
dwOffset += 4*3;
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_BLENDWEIGHT,
D3DVSDT_FLOAT1, dwOffset );
dwOffset += 4*1;
m_dwNumElements++;
break;
case D3DFVF_XYZB2:
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_POSITION,
D3DVSDT_FLOAT3, dwOffset );
m_dwNumElements++;
dwOffset += 4*3;
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_BLENDWEIGHT,
D3DVSDT_FLOAT2, dwOffset );
dwOffset += 4*2;
m_dwNumElements++;
break;
case D3DFVF_XYZB3:
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_POSITION,
D3DVSDT_FLOAT3, dwOffset );
m_dwNumElements++;
dwOffset += 4*3;
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_BLENDWEIGHT,
D3DVSDT_FLOAT3, dwOffset );
dwOffset += 4*3;
m_dwNumElements++;
break;
case D3DFVF_XYZB4:
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_POSITION,
D3DVSDT_FLOAT3, dwOffset );
m_dwNumElements++;
dwOffset += 4*3;
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_BLENDWEIGHT,
D3DVSDT_FLOAT4, dwOffset );
dwOffset += 4*4;
m_dwNumElements++;
break;
case D3DFVF_XYZB5:
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_POSITION,
D3DVSDT_FLOAT3, dwOffset );
m_dwNumElements++;
dwOffset += 4*3;
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_BLENDWEIGHT,
D3DVSDT_FLOAT4, dwOffset );
dwOffset += 4*5; // Even though the velement is float4, skip 5 floats.
m_dwNumElements++;
break;
default:
DPFERR( "Unable to compute offsets, strange FVF bits set" );
return E_FAIL;
}
//
// Normal
//
if( qwFVF & D3DFVF_NORMAL )
{
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_NORMAL,
D3DVSDT_FLOAT3, dwOffset );
m_dwNumElements++;
dwOffset += 4*3;
}
//
// Point Size
//
if( qwFVF & D3DFVF_PSIZE )
{
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_PSIZE,
D3DVSDT_FLOAT1, dwOffset );
m_dwNumElements++;
dwOffset += 4;
}
//
// Diffuse Color
//
if( qwFVF & D3DFVF_DIFFUSE )
{
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_DIFFUSE,
D3DVSDT_D3DCOLOR, dwOffset );
m_dwNumElements++;
dwOffset += 4;
}
//
// Specular Color
//
if( qwFVF & D3DFVF_SPECULAR )
{
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_SPECULAR,
D3DVSDT_D3DCOLOR, dwOffset );
m_dwNumElements++;
dwOffset += 4;
}
//
// Texture coordinates
//
DWORD dwNumTexCoord = (DWORD)(FVF_TEXCOORD_NUMBER(qwFVF));
DWORD dwTextureFormats = (DWORD)((qwFVF >> 16) & 0xffff);
// Texture formats size 00 01 10 11
static DWORD dwTextureSize[4] = {2*4, 3*4, 4*4, 4};
static DWORD dwTextureType[4] = {D3DVSDT_FLOAT2, D3DVSDT_FLOAT3,
D3DVSDT_FLOAT4, D3DVSDT_FLOAT1};
for (DWORD i=0; i < dwNumTexCoord; i++)
{
SetVElement( m_Elements[m_dwNumElements], D3DVSDE_TEXCOORD0 + i,
dwTextureType[dwTextureFormats & 3], dwOffset );
dwOffset += dwTextureSize[dwTextureFormats & 3];
dwTextureFormats >>= 2;
m_dwNumElements++;
}
return hr;
}
//-----------------------------------------------------------------------------
// RDVStreamDecl::Parse
//-----------------------------------------------------------------------------
HRESULT
RDVStreamDecl::Parse( DWORD ** ppToken,
BOOL bFixedFunction,
BOOL bStreamTess,
UINT64* pqwFVF,
UINT64* pqwFVF2,
DWORD* pdwNumBetas)
{
HRESULT hr = S_OK;
m_bIsStreamTess = bStreamTess;
DWORD* pToken = *ppToken;
DWORD dwCurrentOffset = 0;
while( TRUE )
{
DWORD dwToken = *pToken++;
const DWORD dwTokenType = RDVSD_GETTOKENTYPE( dwToken );
switch( dwTokenType )
{
case D3DVSD_TOKEN_NOP: break;
case D3DVSD_TOKEN_TESSELLATOR:
{
if( bStreamTess == FALSE )
{
DPFERR( "Unexpected Tesselator Token for this stream" );
return E_FAIL;
}
if( m_dwNumElements >= RD_MAX_NUMELEMENTS )
{
DPFERR( "Tesselator Stream Token:" );
DPFERR( " Number of vertex elements generated"
" is greater than max supported" );
return DDERR_GENERIC;
}
RDVElement& Element = m_Elements[m_dwNumElements++];
const DWORD dwDataType = RDVSD_GETDATATYPE(dwToken);
const DWORD dwRegister = RDVSD_GETVERTEXREG(dwToken);
const DWORD dwRegisterIn = RDVSD_GETVERTEXREGIN(dwToken);
Element.m_dwToken = dwToken;
Element.m_dwOffset = dwCurrentOffset;
Element.m_dwRegister = dwRegister;
Element.m_dwDataType = dwDataType;
Element.m_dwStreamIndex = m_dwStreamIndex;
Element.m_dwRegisterIn = dwRegisterIn;
Element.m_bIsTessGen = TRUE;
switch (dwDataType)
{
case D3DVSDT_FLOAT2:
dwCurrentOffset += sizeof(float) * 2;
Element.m_pfnCopy = Copy_FLOAT2;
break;
case D3DVSDT_FLOAT3:
dwCurrentOffset += sizeof(float) * 3;
Element.m_pfnCopy = Copy_FLOAT3;
break;
default:
DPFERR( "Invalid element data type in a Tesselator token" );
return DDERR_GENERIC;
}
// Compute input FVF for fixed-function pipeline
if( bFixedFunction )
{
hr = UpdateFVF( dwRegister, dwDataType, pqwFVF, pqwFVF2,
pdwNumBetas );
if( FAILED( hr ) )
{
DPFERR( "UpdateFVF failed" );
return DDERR_INVALIDPARAMS;
}
}
else
{
if( dwRegister >= RD_MAX_NUMINPUTREG )
{
DPFERR( "D3DVSD_TOKEN_STREAMDATA:"
"Invalid register number" );
return DDERR_GENERIC;
}
}
break;
}
case D3DVSD_TOKEN_STREAMDATA:
{
switch( RDVSD_GETDATALOADTYPE( dwToken ) )
{
case RDVSD_LOADREGISTER:
{
if( m_dwNumElements >= RD_MAX_NUMELEMENTS )
{
DPFERR( "D3DVSD_TOKEN_STREAMDATA:" );
DPFERR( " Number of vertex elements in a stream"
"is greater than max supported" );
return DDERR_GENERIC;
}
RDVElement& Element = m_Elements[m_dwNumElements++];
const DWORD dwDataType = RDVSD_GETDATATYPE(dwToken);
const DWORD dwRegister = RDVSD_GETVERTEXREG(dwToken);
Element.m_dwToken = dwToken;
Element.m_dwOffset = dwCurrentOffset;
Element.m_dwRegister = dwRegister;
Element.m_dwDataType = dwDataType;
Element.m_dwStreamIndex = m_dwStreamIndex;
switch( dwDataType )
{
case D3DVSDT_FLOAT1:
dwCurrentOffset += sizeof(float);
Element.m_pfnCopy = Copy_FLOAT1;
break;
case D3DVSDT_FLOAT2:
dwCurrentOffset += sizeof(float) * 2;
Element.m_pfnCopy = Copy_FLOAT2;
break;
case D3DVSDT_FLOAT3:
dwCurrentOffset += sizeof(float) * 3;
Element.m_pfnCopy = Copy_FLOAT3;
break;
case D3DVSDT_FLOAT4:
dwCurrentOffset += sizeof(float) * 4;
Element.m_pfnCopy = Copy_FLOAT4;
break;
case D3DVSDT_D3DCOLOR:
dwCurrentOffset += sizeof(DWORD);
Element.m_pfnCopy = Copy_D3DCOLOR;
break;
case D3DVSDT_UBYTE4:
dwCurrentOffset += sizeof(DWORD);
Element.m_pfnCopy = Copy_UBYTE4;
break;
case D3DVSDT_SHORT2:
dwCurrentOffset += sizeof(SHORT) * 2;
Element.m_pfnCopy = Copy_SHORT2;
break;
case D3DVSDT_SHORT4:
dwCurrentOffset += sizeof(SHORT) * 4;
Element.m_pfnCopy = Copy_SHORT4;
break;
default:
DPFERR( "D3DVSD_TOKEN_STREAMDATA:"
"Invalid element data type" );
return DDERR_GENERIC;
}
// Compute input FVF for fixed-function pipeline
if( bFixedFunction )
{
hr = UpdateFVF( dwRegister, dwDataType, pqwFVF, pqwFVF2,
pdwNumBetas );
if( FAILED( hr ) )
{
DPFERR( "UpdateFVF failed" );
return DDERR_INVALIDPARAMS;
}
}
else
{
if( dwRegister >= RD_MAX_NUMINPUTREG )
{
DPFERR( "D3DVSD_TOKEN_STREAMDATA:"
"Invalid register number" );
return DDERR_GENERIC;
}
}
break;
}
case RDVSD_SKIP:
{
const DWORD dwCount = RDVSD_GETSKIPCOUNT( dwToken );
dwCurrentOffset += dwCount * sizeof(DWORD);
break;
}
default:
DPFERR( "Invalid data load type" );
return DDERR_GENERIC;
}
break;
}
default:
{
*ppToken = pToken - 1;
m_dwStride = dwCurrentOffset;
return S_OK;
}
} // switch
} // while
return S_OK;
}
/////////////////////////////////////////////////////////////////////////
//
// class RDVDeclaration
//
/////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// RDVDeclaration::Destructor
//-----------------------------------------------------------------------------
RDVDeclaration::~RDVDeclaration()
{
RDVConstantData* pConst = m_pConstants;
while( pConst )
{
RDVConstantData* pNext =
static_cast<RDVConstantData *>(pConst->m_pNext);
delete pConst;
pConst = pNext;
}
}
//-----------------------------------------------------------------------------
// RDVDeclaration::MakeVElementArray
//-----------------------------------------------------------------------------
HRESULT
RDVDeclaration::MakeVElementArray( UINT64 qwFVF )
{
HRESULT hr = S_OK;
m_qwInputFVF = qwFVF;
m_dwNumActiveStreams = 1;
// Go through the FVF and make the elements
RDVStreamDecl& Stream = m_StreamArray[0];
hr = Stream.MakeVElementArray( qwFVF );
if( FAILED( hr ) )
{
return hr;
}
m_dwNumElements = Stream.m_dwNumElements;
memcpy( &m_VertexElements, &Stream.m_Elements,
sizeof( RDVElement ) * m_dwNumElements );
return hr;
}
//-----------------------------------------------------------------------------
// RDVDeclaration::Parse
//-----------------------------------------------------------------------------
HRESULT
RDVDeclaration::Parse( DWORD* pDecl, BOOL bFixedFunction )
{
HRESULT hr = S_OK;
UINT64 qwFVF = 0; // FVF for fixed-function pipeline
UINT64 qwFVF2 = 0; // Texture presence bits (8 bits)
DWORD dwNumBetas = 0; // The number of betas.
DWORD dwStreamPresent = 0; // Bit is set if a stream is used
DWORD* pToken = pDecl;
BOOL bStreamTess = FALSE;
while( TRUE )
{
DWORD dwToken = *pToken++;
const DWORD dwTokenType = RDVSD_GETTOKENTYPE(dwToken);
switch( dwTokenType )
{
case D3DVSD_TOKEN_NOP:
break;
case D3DVSD_TOKEN_STREAM:
{
DWORD dwStream;
if( RDVSD_ISSTREAMTESS(dwToken) )
{
if( RDVSD_GETSTREAMNUMBER(dwToken) )
{
DPFERR( "No stream number should be specified for a"
" Tesselator stream" );
return E_FAIL;
}
dwStream = RDVSD_STREAMTESS;
bStreamTess = TRUE;
}
else
{
dwStream = RDVSD_GETSTREAMNUMBER(dwToken);
bStreamTess = FALSE;
}
if( dwStream > RDVSD_STREAMTESS )
{
DPFERR( "Stream number is too big" );
return DDERR_INVALIDPARAMS;
}
// Has this stream already been declared ?
if( dwStreamPresent & (1 << dwStream) )
{
DPFERR( "Stream already defined in this declaration" );
return DDERR_INVALIDPARAMS;
}
// Mark the stream as seen
dwStreamPresent |= 1 << dwStream;
RDVStreamDecl& Stream = m_StreamArray[m_dwNumActiveStreams];
Stream.m_dwStreamIndex = dwStream;
hr = Stream.Parse(&pToken, bFixedFunction, bStreamTess,
&qwFVF, &qwFVF2, &dwNumBetas);
if( FAILED( hr ) )
{
return hr;
}
//
// Save the stride computed for the tesselator stream
//
if( bStreamTess )
{
m_dwStreamTessStride = Stream.m_dwStride;
}
m_dwNumActiveStreams++;
break;
}
case D3DVSD_TOKEN_STREAMDATA:
{
DPFERR( "D3DVSD_TOKEN_STREAMDATA could only be used"
"after D3DVSD_TOKEN_STREAM" );
return DDERR_GENERIC;
}
case D3DVSD_TOKEN_CONSTMEM:
{
RDVConstantData * cd = new RDVConstantData;
if( cd == NULL )
{
return E_OUTOFMEMORY;
}
cd->m_dwCount = RDVSD_GETCONSTCOUNT(dwToken);
cd->m_dwAddress = RDVSD_GETCONSTADDRESS(dwToken);
if( cd->m_dwCount + cd->m_dwAddress > RD_MAX_NUMCONSTREG )
{
delete cd;
DPFERR( "D3DVSD_TOKEN_CONSTMEM writes outside"
"constant memory" );
return DDERR_GENERIC;
}
const DWORD dwSize = cd->m_dwCount << 2; // number of DWORDs
cd->m_pData = new DWORD[dwSize];
if( cd->m_pData == NULL )
{
return E_OUTOFMEMORY;
}
memcpy( cd->m_pData, pToken, dwSize << 2 );
if( m_pConstants == NULL )
m_pConstants = cd;
else
m_pConstants->Append(cd);
pToken += dwSize;
break;
}
case D3DVSD_TOKEN_EXT:
{
// Skip extension info
DWORD dwCount = RDVSD_GETEXTCOUNT(dwToken);
pToken += dwCount;
break;
}
case D3DVSD_TOKEN_END:
{
goto l_End;
}
default:
{
DPFERR( "Invalid declaration token: %10x", dwToken );
return DDERR_INVALIDPARAMS;
}
}
}
l_End:
// Now accumulate all the vertex elements into the declaration
DWORD dwCurrElement = 0;
m_dwNumElements = 0;
// Build a VElement List in the Declaration.
for( DWORD i=0; i<m_dwNumActiveStreams; i++ )
{
RDVStreamDecl& Stream = m_StreamArray[i];
for( DWORD j=0; j<Stream.m_dwNumElements; j++ )
{
m_VertexElements[dwCurrElement] = Stream.m_Elements[j];
dwCurrElement++;
}
m_dwNumElements += Stream.m_dwNumElements;
}
// If any tesselator tokens were present, then translate the m_dwRegisterIn
// in the the StreamIndex and Offset for the tesselator tokens.
if( bStreamTess )
{
for( i=0; i<m_dwNumElements; i++ )
{
RDVElement& ve = m_VertexElements[i];
if( ve.m_bIsTessGen )
{
for( DWORD j=0; j<m_dwNumElements; j++ )
{
if( m_VertexElements[j].m_dwRegister == ve.m_dwRegisterIn )
{
ve.m_dwStreamIndexIn =
m_VertexElements[j].m_dwStreamIndex;
ve.m_dwOffsetIn = m_VertexElements[j].m_dwOffsetIn;
break;
}
}
if( j == m_dwNumElements )
{
DPFERR( "Tesselator input register is not defined in the"
" declaration" );
return E_FAIL;
}
}
}
}
// Validate input for the fixed-function pipeline
if( bFixedFunction )
{
// Pull out the number of blend weights
BOOL bIsTransformed = (qwFVF & D3DFVF_XYZRHW);
if( bIsTransformed )
{
if( dwNumBetas != 0 )
{
DPFERR( "Cannot have blend weights along with "
"transformed position" );
return E_FAIL;
}
}
else if( (qwFVF & D3DFVF_XYZ) == 0 )
{
// Position must be set
DPFERR( "Position register must be set" );
return E_FAIL;
}
DWORD dwPosMask = bIsTransformed ? 0x2 : 0x1;
if( dwNumBetas )
{
dwPosMask += (dwNumBetas + 1);
}
m_qwInputFVF |= (qwFVF |
((DWORD)(D3DFVF_POSITION_MASK) & (dwPosMask << 1)));
// Compute number of texture coordinates
DWORD nTexCoord = 0;
DWORD dwTexturePresenceBits = qwFVF2 & 0xFF;
while( dwTexturePresenceBits & 1 )
{
dwTexturePresenceBits >>= 1;
nTexCoord++;
}
// There should be no gaps in texture coordinates
if( dwTexturePresenceBits )
{
DPFERR( "Texture coordinates should have no gaps" );
return E_FAIL;
}
m_qwInputFVF |= (nTexCoord << D3DFVF_TEXCOUNT_SHIFT);
}
return hr;
}
/////////////////////////////////////////////////////////////////////////
//
// class RDVShader
//
/////////////////////////////////////////////////////////////////////////
RDVShader::RDVShader()
{
m_pCode = NULL;
}
//-----------------------------------------------------------------------------
// RDVShader::Destructor
//-----------------------------------------------------------------------------
RDVShader::~RDVShader()
{
delete m_pCode;
}
/////////////////////////////////////////////////////////////////////////
//
// class RefDev
//
/////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// RefDev::DrawDX8Prim
//-----------------------------------------------------------------------------
HRESULT
RefDev::DrawDX8Prim( LPD3DHAL_DP2DRAWPRIMITIVE pDP )
{
HRESULT hr = S_OK;
// Ignore D3DRS_PATCHSEGMENTS for non-triangle primitive types
if( GetRSf()[D3DRS_PATCHSEGMENTS] > 1.f &&
pDP->primType >= D3DPT_TRIANGLELIST)
{
// Save current data stream pointers and replace with
// pointer to tessellation output
hr = LinkTessellatorOutput();
if(FAILED(hr))
{
return hr;
}
hr = ProcessTessPrimitive( pDP );
// Restore back saved pointer
UnlinkTessellatorOutput();
return hr;
}
// If there is any tesselator output in this vertex-shader
// then you cannot use DrawPrim. DrawRect/Tri is required.
if( m_pCurrentVShader->m_Declaration.m_dwStreamTessStride != 0 )
{
DPFERR( "Cannot call DrawPrim when the current vertex shader has"
" tesselator output." );
return D3DERR_INVALIDCALL;
}
DWORD cVertices = GetVertexCount( pDP->primType, pDP->PrimitiveCount );
if( RDVSD_ISLEGACY( m_CurrentVShaderHandle ) )
{
//
// The legacy FVF style: The Zero'th Stream is implied
//
UINT64 qwFVF = m_CurrentVShaderHandle;
RDVStream& Stream = m_VStream[0];
DWORD dwStride = Stream.m_dwStride;
DWORD dwFVFSize = GetFVFVertexSize( qwFVF );
if( Stream.m_pData == NULL || dwStride == 0 )
{
DPFERR( "Zero'th stream doesnt have valid VB set" );
return DDERR_INVALIDPARAMS;
}
if( dwStride < dwFVFSize )
{
DPFERR( "The stride set for the vertex stream is less than"
" the FVF vertex size" );
return E_FAIL;
}
if( FVF_TRANSFORMED(m_CurrentVShaderHandle) )
{
HR_RET( GrowTLVArray( cVertices ) );
FvfToRDVertex( (Stream.m_pData + pDP->VStart * dwStride),
GetTLVArray(), qwFVF, dwStride, cVertices );
if( GetRS()[D3DRENDERSTATE_CLIPPING] )
{
m_qwFVFOut = qwFVF;
HR_RET( UpdateClipper() );
HR_RET(m_Clipper.DrawOnePrimitive( GetTLVArray(),
0,
pDP->primType,
cVertices ));
}
else
{
HR_RET(DrawOnePrimitive( GetTLVArray(),
0,
pDP->primType,
cVertices ));
}
return S_OK;
}
}
if( m_pCurrentVShader->IsFixedFunction() )
{
//
// With declaration for Fixed Function pipeline, DX8 style
//
HR_RET(ProcessPrimitive( pDP->primType, pDP->VStart,
cVertices, 0, 0 ));
}
else
{
//
// Pure Vertex Shader
//
HR_RET(ProcessPrimitiveVVM( pDP->primType, pDP->VStart,
cVertices, 0, 0 ));
}
return hr;
}
//-----------------------------------------------------------------------------
// RefDev::DrawDX8Prim2
//-----------------------------------------------------------------------------
HRESULT
RefDev::DrawDX8Prim2( LPD3DHAL_DP2DRAWPRIMITIVE2 pDP )
{
HRESULT hr = S_OK;
DWORD cVertices = GetVertexCount( pDP->primType, pDP->PrimitiveCount );
if( !RDVSD_ISLEGACY ( m_CurrentVShaderHandle ) ||
!FVF_TRANSFORMED( m_CurrentVShaderHandle ) )
{
DPFERR( "DrawPrimitives2 should be called with transformed legacy vertices" );
return E_FAIL;
}
//
// The legacy FVF style: The Zero'th Stream is implied
//
UINT64 qwFVF = m_CurrentVShaderHandle;
RDVStream& Stream = m_VStream[0];
DWORD dwStride = Stream.m_dwStride;
DWORD dwFVFSize = GetFVFVertexSize( qwFVF );
if( Stream.m_pData == NULL || dwStride == 0 )
{
DPFERR( "Zero'th stream doesnt have valid VB set" );
return DDERR_INVALIDPARAMS;
}
if( dwStride < dwFVFSize )
{
DPFERR( "The stride set for the vertex stream is less than"
" the FVF vertex size" );
return E_FAIL;
}
HR_RET( GrowTLVArray( cVertices ) );
FvfToRDVertex( (Stream.m_pData + pDP->FirstVertexOffset),
GetTLVArray(), qwFVF, dwStride, cVertices );
HR_RET(DrawOnePrimitive( GetTLVArray(), 0, pDP->primType,
cVertices ));
return S_OK;
}
//-----------------------------------------------------------------------------
// RefVP::DrawDX8IndexedPrim
//-----------------------------------------------------------------------------
HRESULT
RefDev::DrawDX8IndexedPrim(
LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE pDIP )
{
HRESULT hr = S_OK;
if( GetRSf()[D3DRS_PATCHSEGMENTS] > 1.f )
{
// Save current data stream pointers and replace with
// pointer to tessellation output
hr = LinkTessellatorOutput();
if(FAILED(hr))
{
return hr;
}
hr = ProcessTessIndexedPrimitive( pDIP );
// Restore back saved pointer
UnlinkTessellatorOutput();
return hr;
}
// If there is any tesselator output in this vertex-shader
// then you cannot use DrawPrim. DrawRect/Tri is required.
if( m_pCurrentVShader->m_Declaration.m_dwStreamTessStride != 0 )
{
DPFERR( "Cannot call DrawIndexedPrim when the current vertex shader"
" has tesselator output." );
return D3DERR_INVALIDCALL;
}
DWORD cIndices = GetVertexCount( pDIP->primType, pDIP->PrimitiveCount );
if( RDVSD_ISLEGACY( m_CurrentVShaderHandle ) )
{
//
// The legacy FVF style: The Zero'th Stream is implied
//
UINT64 qwFVF = m_CurrentVShaderHandle;
RDVStream& Stream = m_VStream[0];
DWORD dwStride = Stream.m_dwStride;
DWORD dwFVFSize = GetFVFVertexSize( qwFVF );
if( Stream.m_pData == NULL || dwStride == 0 )
{
DPFERR( "Zero'th stream doesnt have valid VB set" );
return DDERR_INVALIDPARAMS;
}
if( dwStride < dwFVFSize )
{
DPFERR( "The stride set for the vertex stream is less than"
" the FVF vertex size" );
return E_FAIL;
}
if( m_IndexStream.m_pData == NULL )
{
DPFERR( "Indices are not available" );
return E_FAIL;
}
if( FVF_TRANSFORMED(m_CurrentVShaderHandle) )
{
DWORD cVertices = pDIP->NumVertices + pDIP->MinIndex;
HR_RET( GrowTLVArray( cVertices ) );
FvfToRDVertex( (Stream.m_pData + pDIP->BaseVertexIndex * dwStride),
GetTLVArray(), qwFVF, dwStride, cVertices );
if( GetRS()[D3DRENDERSTATE_CLIPPING] )
{
m_qwFVFOut = qwFVF;
HR_RET( UpdateClipper() );
if( m_IndexStream.m_dwStride == 4 )
{
HR_RET( m_Clipper.DrawOneIndexedPrimitive(
GetTLVArray(),
0,
(LPDWORD)m_IndexStream.m_pData,
pDIP->StartIndex,
cIndices,
pDIP->primType ));
}
else
{
HR_RET( m_Clipper.DrawOneIndexedPrimitive(
GetTLVArray(),
0,
(LPWORD)m_IndexStream.m_pData,
pDIP->StartIndex,
cIndices,
pDIP->primType ));
}
}
else
{
if( m_IndexStream.m_dwStride == 4 )
{
HR_RET(DrawOneIndexedPrimitive(
GetTLVArray(),
0,
(LPDWORD)m_IndexStream.m_pData,
pDIP->StartIndex,
cIndices,
pDIP->primType ));
}
else
{
HR_RET(DrawOneIndexedPrimitive(
GetTLVArray(),
0,
(LPWORD)m_IndexStream.m_pData,
pDIP->StartIndex,
cIndices,
pDIP->primType ));
}
}
return S_OK;
}
}
if( m_pCurrentVShader->IsFixedFunction() )
{
//
// With declaration for Fixed Function pipeline, DX8 style
//
HR_RET(ProcessPrimitive( pDIP->primType,
pDIP->BaseVertexIndex,
pDIP->NumVertices + pDIP->MinIndex,
pDIP->StartIndex,
cIndices ));
}
else
{
//
// Pure Vertex Shader
//
HR_RET(ProcessPrimitiveVVM( pDIP->primType,
pDIP->BaseVertexIndex,
pDIP->NumVertices + pDIP->MinIndex,
pDIP->StartIndex,
cIndices ));
}
return hr;
}
//-----------------------------------------------------------------------------
// RefVP::DrawDX8IndexedPrim2
//-----------------------------------------------------------------------------
HRESULT
RefDev::DrawDX8IndexedPrim2(
LPD3DHAL_DP2DRAWINDEXEDPRIMITIVE2 pDIP )
{
HRESULT hr = S_OK;
DWORD cIndices = GetVertexCount( pDIP->primType, pDIP->PrimitiveCount );
if( !RDVSD_ISLEGACY ( m_CurrentVShaderHandle ) ||
!FVF_TRANSFORMED( m_CurrentVShaderHandle ) )
{
DPFERR( "DrawIndexedPrimitive2 should be called with transformed legacy vertices" );
return E_FAIL;
}
//
// The legacy FVF style: The Zero'th Stream is implied
//
UINT64 qwFVF = m_CurrentVShaderHandle;
RDVStream& Stream = m_VStream[0];
DWORD dwStride = Stream.m_dwStride;
DWORD dwFVFSize = GetFVFVertexSize( qwFVF );
if( Stream.m_pData == NULL || dwStride == 0)
{
DPFERR( "Zero'th stream doesnt have valid VB set" );
return DDERR_INVALIDPARAMS;
}
if( dwStride < dwFVFSize )
{
DPFERR( "The stride set for the vertex stream is less than"
" the FVF vertex size" );
return E_FAIL;
}
if( m_IndexStream.m_pData == NULL )
{
DPFERR( "Indices are not available" );
return E_FAIL;
}
DWORD cVertices = pDIP->NumVertices;
HR_RET( GrowTLVArray( cVertices ) );
FvfToRDVertex( (Stream.m_pData + pDIP->BaseVertexOffset +
pDIP->MinIndex * dwStride),
GetTLVArray(),
qwFVF, dwStride,
cVertices );
if( m_IndexStream.m_dwStride == 4 )
{
HR_RET(DrawOneIndexedPrimitive(
GetTLVArray(),
-(int)pDIP->MinIndex,
(LPDWORD)( m_IndexStream.m_pData + pDIP->StartIndexOffset),
0,
cIndices,
pDIP->primType ));
}
else
{
HR_RET(DrawOneIndexedPrimitive(
GetTLVArray(),
-(int)pDIP->MinIndex,
(LPWORD)( m_IndexStream.m_pData + pDIP->StartIndexOffset),
0,
cIndices,
pDIP->primType ));
}
return S_OK;
}
//-----------------------------------------------------------------------------
// RefVP::DrawDX8ClippedTriangleFan
//-----------------------------------------------------------------------------
HRESULT
RefDev::DrawDX8ClippedTriFan(
LPD3DHAL_CLIPPEDTRIANGLEFAN pCTF )
{
BOOL bWireframe =
GetRS()[D3DRENDERSTATE_FILLMODE] == D3DFILL_WIREFRAME;
HRESULT hr = S_OK;
DWORD cVertices = GetVertexCount( D3DPT_TRIANGLEFAN,
pCTF->PrimitiveCount );
if( !RDVSD_ISLEGACY ( m_CurrentVShaderHandle ) ||
!FVF_TRANSFORMED( m_CurrentVShaderHandle ) )
{
DPFERR( "DrawPrimitives2 should be called with transformed legacy"
" vertices" );
return E_FAIL;
}
//
// The legacy FVF style: The Zero'th Stream is implied
//
UINT64 qwFVF = m_CurrentVShaderHandle;
RDVStream& Stream = m_VStream[0];
DWORD dwStride = Stream.m_dwStride;
DWORD dwFVFSize = GetFVFVertexSize( qwFVF );
if( Stream.m_pData == NULL || dwStride == 0 )
{
DPFERR( "Zero'th stream doesnt have valid VB set" );
return DDERR_INVALIDPARAMS;
}
if( dwStride < dwFVFSize )
{
DPFERR( "The stride set for the vertex stream is less than"
" the FVF vertex size" );
return E_FAIL;
}
HR_RET( GrowTLVArray( cVertices ) );
FvfToRDVertex( (Stream.m_pData + pCTF->FirstVertexOffset),
GetTLVArray(), qwFVF, dwStride, cVertices );
if( bWireframe )
{
HR_RET(DrawOneEdgeFlagTriangleFan( GetTLVArray(), cVertices,
pCTF->dwEdgeFlags ));
}
else
{
HR_RET(DrawOnePrimitive( GetTLVArray(), 0, D3DPT_TRIANGLEFAN,
cVertices ));
}
return S_OK;
}