diff options
Diffstat (limited to 'materialsystem/shaderapidx9/vertexdecl.cpp')
| -rw-r--r-- | materialsystem/shaderapidx9/vertexdecl.cpp | 576 |
1 files changed, 576 insertions, 0 deletions
diff --git a/materialsystem/shaderapidx9/vertexdecl.cpp b/materialsystem/shaderapidx9/vertexdecl.cpp new file mode 100644 index 0000000..3d70dbc --- /dev/null +++ b/materialsystem/shaderapidx9/vertexdecl.cpp @@ -0,0 +1,576 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#undef PROTECTED_THINGS_ENABLE +#include "vertexdecl.h" // this includes <windows.h> inside the dx headers +#define PROTECTED_THINGS_ENABLE +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "shaderapidx8_global.h" +#include "tier0/dbg.h" +#include "utlrbtree.h" +#include "recording.h" +#include "tier1/strtools.h" +#include "tier0/vprof.h" +#include "materialsystem/imesh.h" +#include "shaderdevicedx8.h" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + +//----------------------------------------------------------------------------- +// Computes the DX8 vertex specification +//----------------------------------------------------------------------------- +static const char *DeclTypeToString( BYTE type ) +{ + switch( type ) + { + case D3DDECLTYPE_FLOAT1: + return "D3DDECLTYPE_FLOAT1"; + case D3DDECLTYPE_FLOAT2: + return "D3DDECLTYPE_FLOAT2"; + case D3DDECLTYPE_FLOAT3: + return "D3DDECLTYPE_FLOAT3"; + case D3DDECLTYPE_FLOAT4: + return "D3DDECLTYPE_FLOAT4"; + case D3DDECLTYPE_D3DCOLOR: + return "D3DDECLTYPE_D3DCOLOR"; + case D3DDECLTYPE_UBYTE4: + return "D3DDECLTYPE_UBYTE4"; + case D3DDECLTYPE_SHORT2: + return "D3DDECLTYPE_SHORT2"; + case D3DDECLTYPE_SHORT4: + return "D3DDECLTYPE_SHORT4"; + case D3DDECLTYPE_UBYTE4N: + return "D3DDECLTYPE_UBYTE4N"; + case D3DDECLTYPE_SHORT2N: + return "D3DDECLTYPE_SHORT2N"; + case D3DDECLTYPE_SHORT4N: + return "D3DDECLTYPE_SHORT4N"; + case D3DDECLTYPE_USHORT2N: + return "D3DDECLTYPE_USHORT2N"; + case D3DDECLTYPE_USHORT4N: + return "D3DDECLTYPE_USHORT4N"; + case D3DDECLTYPE_UDEC3: + return "D3DDECLTYPE_UDEC3"; + case D3DDECLTYPE_DEC3N: + return "D3DDECLTYPE_DEC3N"; + case D3DDECLTYPE_FLOAT16_2: + return "D3DDECLTYPE_FLOAT16_2"; + case D3DDECLTYPE_FLOAT16_4: + return "D3DDECLTYPE_FLOAT16_4"; + default: + Assert( 0 ); + return "ERROR"; + } +} + +static const char *DeclMethodToString( BYTE method ) +{ + switch( method ) + { + case D3DDECLMETHOD_DEFAULT: + return "D3DDECLMETHOD_DEFAULT"; + case D3DDECLMETHOD_PARTIALU: + return "D3DDECLMETHOD_PARTIALU"; + case D3DDECLMETHOD_PARTIALV: + return "D3DDECLMETHOD_PARTIALV"; + case D3DDECLMETHOD_CROSSUV: + return "D3DDECLMETHOD_CROSSUV"; + case D3DDECLMETHOD_UV: + return "D3DDECLMETHOD_UV"; + case D3DDECLMETHOD_LOOKUP: + return "D3DDECLMETHOD_LOOKUP"; + case D3DDECLMETHOD_LOOKUPPRESAMPLED: + return "D3DDECLMETHOD_LOOKUPPRESAMPLED"; + default: + Assert( 0 ); + return "ERROR"; + } +} + +static const char *DeclUsageToString( BYTE usage ) +{ + switch( usage ) + { + case D3DDECLUSAGE_POSITION: + return "D3DDECLUSAGE_POSITION"; + case D3DDECLUSAGE_BLENDWEIGHT: + return "D3DDECLUSAGE_BLENDWEIGHT"; + case D3DDECLUSAGE_BLENDINDICES: + return "D3DDECLUSAGE_BLENDINDICES"; + case D3DDECLUSAGE_NORMAL: + return "D3DDECLUSAGE_NORMAL"; + case D3DDECLUSAGE_PSIZE: + return "D3DDECLUSAGE_PSIZE"; + case D3DDECLUSAGE_COLOR: + return "D3DDECLUSAGE_COLOR"; + case D3DDECLUSAGE_TEXCOORD: + return "D3DDECLUSAGE_TEXCOORD"; + case D3DDECLUSAGE_TANGENT: + return "D3DDECLUSAGE_TANGENT"; + case D3DDECLUSAGE_BINORMAL: + return "D3DDECLUSAGE_BINORMAL"; + case D3DDECLUSAGE_TESSFACTOR: + return "D3DDECLUSAGE_TESSFACTOR"; +// case D3DDECLUSAGE_POSITIONTL: +// return "D3DDECLUSAGE_POSITIONTL"; + default: + Assert( 0 ); + return "ERROR"; + } +} + +static D3DDECLTYPE VertexElementToDeclType( VertexElement_t element, VertexCompressionType_t compressionType ) +{ + Detect_VertexElement_t_Changes( element ); + + if ( compressionType == VERTEX_COMPRESSION_ON ) + { + // Compressed-vertex element sizes + switch ( element ) + { +#if ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_SEPARATETANGENTS_SHORT2 ) + case VERTEX_ELEMENT_NORMAL: return D3DDECLTYPE_SHORT2; + case VERTEX_ELEMENT_USERDATA4: return D3DDECLTYPE_SHORT2; +#else //( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) + case VERTEX_ELEMENT_NORMAL: return D3DDECLTYPE_UBYTE4; + case VERTEX_ELEMENT_USERDATA4: return D3DDECLTYPE_UBYTE4; +#endif + case VERTEX_ELEMENT_BONEWEIGHTS1: return D3DDECLTYPE_SHORT2; + case VERTEX_ELEMENT_BONEWEIGHTS2: return D3DDECLTYPE_SHORT2; + default: + break; + } + } + + // Uncompressed-vertex element sizes + switch ( element ) + { + case VERTEX_ELEMENT_POSITION: return D3DDECLTYPE_FLOAT3; + case VERTEX_ELEMENT_NORMAL: return D3DDECLTYPE_FLOAT3; + case VERTEX_ELEMENT_COLOR: return D3DDECLTYPE_D3DCOLOR; + case VERTEX_ELEMENT_SPECULAR: return D3DDECLTYPE_D3DCOLOR; + case VERTEX_ELEMENT_TANGENT_S: return D3DDECLTYPE_FLOAT3; + case VERTEX_ELEMENT_TANGENT_T: return D3DDECLTYPE_FLOAT3; + case VERTEX_ELEMENT_WRINKLE: + // Wrinkle is packed into Position.W, it is not specified as a separate vertex element + Assert( 0 ); + return D3DDECLTYPE_UNUSED; +#if !defined( _X360 ) + case VERTEX_ELEMENT_BONEINDEX: return D3DDECLTYPE_D3DCOLOR; +#else + // UBYTE4 comes in as [0,255] in the shader, which is ideal for bone indices + // (unfortunately, UBYTE4 is not universally supported on PC DX8 GPUs) + case VERTEX_ELEMENT_BONEINDEX: return D3DDECLTYPE_UBYTE4; +#endif + case VERTEX_ELEMENT_BONEWEIGHTS1: return D3DDECLTYPE_FLOAT1; + case VERTEX_ELEMENT_BONEWEIGHTS2: return D3DDECLTYPE_FLOAT2; + case VERTEX_ELEMENT_BONEWEIGHTS3: return D3DDECLTYPE_FLOAT3; + case VERTEX_ELEMENT_BONEWEIGHTS4: return D3DDECLTYPE_FLOAT4; + case VERTEX_ELEMENT_USERDATA1: return D3DDECLTYPE_FLOAT1; + case VERTEX_ELEMENT_USERDATA2: return D3DDECLTYPE_FLOAT2; + case VERTEX_ELEMENT_USERDATA3: return D3DDECLTYPE_FLOAT3; + case VERTEX_ELEMENT_USERDATA4: return D3DDECLTYPE_FLOAT4; + case VERTEX_ELEMENT_TEXCOORD1D_0: return D3DDECLTYPE_FLOAT1; + case VERTEX_ELEMENT_TEXCOORD1D_1: return D3DDECLTYPE_FLOAT1; + case VERTEX_ELEMENT_TEXCOORD1D_2: return D3DDECLTYPE_FLOAT1; + case VERTEX_ELEMENT_TEXCOORD1D_3: return D3DDECLTYPE_FLOAT1; + case VERTEX_ELEMENT_TEXCOORD1D_4: return D3DDECLTYPE_FLOAT1; + case VERTEX_ELEMENT_TEXCOORD1D_5: return D3DDECLTYPE_FLOAT1; + case VERTEX_ELEMENT_TEXCOORD1D_6: return D3DDECLTYPE_FLOAT1; + case VERTEX_ELEMENT_TEXCOORD1D_7: return D3DDECLTYPE_FLOAT1; + case VERTEX_ELEMENT_TEXCOORD2D_0: return D3DDECLTYPE_FLOAT2; + case VERTEX_ELEMENT_TEXCOORD2D_1: return D3DDECLTYPE_FLOAT2; + case VERTEX_ELEMENT_TEXCOORD2D_2: return D3DDECLTYPE_FLOAT2; + case VERTEX_ELEMENT_TEXCOORD2D_3: return D3DDECLTYPE_FLOAT2; + case VERTEX_ELEMENT_TEXCOORD2D_4: return D3DDECLTYPE_FLOAT2; + case VERTEX_ELEMENT_TEXCOORD2D_5: return D3DDECLTYPE_FLOAT2; + case VERTEX_ELEMENT_TEXCOORD2D_6: return D3DDECLTYPE_FLOAT2; + case VERTEX_ELEMENT_TEXCOORD2D_7: return D3DDECLTYPE_FLOAT2; + case VERTEX_ELEMENT_TEXCOORD3D_0: return D3DDECLTYPE_FLOAT3; + case VERTEX_ELEMENT_TEXCOORD3D_1: return D3DDECLTYPE_FLOAT3; + case VERTEX_ELEMENT_TEXCOORD3D_2: return D3DDECLTYPE_FLOAT3; + case VERTEX_ELEMENT_TEXCOORD3D_3: return D3DDECLTYPE_FLOAT3; + case VERTEX_ELEMENT_TEXCOORD3D_4: return D3DDECLTYPE_FLOAT3; + case VERTEX_ELEMENT_TEXCOORD3D_5: return D3DDECLTYPE_FLOAT3; + case VERTEX_ELEMENT_TEXCOORD3D_6: return D3DDECLTYPE_FLOAT3; + case VERTEX_ELEMENT_TEXCOORD3D_7: return D3DDECLTYPE_FLOAT3; + case VERTEX_ELEMENT_TEXCOORD4D_0: return D3DDECLTYPE_FLOAT4; + case VERTEX_ELEMENT_TEXCOORD4D_1: return D3DDECLTYPE_FLOAT4; + case VERTEX_ELEMENT_TEXCOORD4D_2: return D3DDECLTYPE_FLOAT4; + case VERTEX_ELEMENT_TEXCOORD4D_3: return D3DDECLTYPE_FLOAT4; + case VERTEX_ELEMENT_TEXCOORD4D_4: return D3DDECLTYPE_FLOAT4; + case VERTEX_ELEMENT_TEXCOORD4D_5: return D3DDECLTYPE_FLOAT4; + case VERTEX_ELEMENT_TEXCOORD4D_6: return D3DDECLTYPE_FLOAT4; + case VERTEX_ELEMENT_TEXCOORD4D_7: return D3DDECLTYPE_FLOAT4; + default: + Assert(0); + return D3DDECLTYPE_UNUSED; + }; +} + +void PrintVertexDeclaration( const D3DVERTEXELEMENT9 *pDecl ) +{ + int i; + static D3DVERTEXELEMENT9 declEnd = D3DDECL_END(); + for ( i = 0; ; i++ ) + { + if ( memcmp( &pDecl[i], &declEnd, sizeof( declEnd ) ) == 0 ) + { + Warning( "D3DDECL_END\n" ); + break; + } + Msg( "%d: Stream: %d, Offset: %d, Type: %s, Method: %s, Usage: %s, UsageIndex: %d\n", + i, ( int )pDecl[i].Stream, ( int )pDecl[i].Offset, + DeclTypeToString( pDecl[i].Type ), + DeclMethodToString( pDecl[i].Method ), + DeclUsageToString( pDecl[i].Usage ), + ( int )pDecl[i].UsageIndex ); + } +} + +//----------------------------------------------------------------------------- +// Converts format to a vertex decl +//----------------------------------------------------------------------------- +void ComputeVertexSpec( VertexFormat_t fmt, D3DVERTEXELEMENT9 *pDecl, bool bStaticLit, bool bUsingFlex, bool bUsingMorph ) +{ + int i = 0; + int offset = 0; + + VertexCompressionType_t compressionType = CompressionType( fmt ); + + if ( IsX360() ) + { + // On 360, there's a performance penalty for reading more than 2 streams in the vertex shader + // (we don't do this yet, but we should be aware if we start doing it) +#ifdef _DEBUG + int numStreams = 1 + ( bStaticLit ? 1 : 0 ) + ( bUsingFlex ? 1 : 0 ) + ( bUsingMorph ? 1 : 0 ); + Assert( numStreams <= 2 ); +#endif + } + + if ( fmt & VERTEX_POSITION ) + { + pDecl[i].Stream = 0; + pDecl[i].Offset = offset; + pDecl[i].Method = D3DDECLMETHOD_DEFAULT; + pDecl[i].Usage = D3DDECLUSAGE_POSITION; + pDecl[i].UsageIndex = 0; + pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_POSITION, compressionType ); + offset += GetVertexElementSize( VERTEX_ELEMENT_POSITION, compressionType ); + ++i; + } + + int numBones = NumBoneWeights(fmt); + if ( numBones > 0 ) + { + pDecl[i].Stream = 0; + pDecl[i].Offset = offset; + pDecl[i].Method = D3DDECLMETHOD_DEFAULT; + pDecl[i].Usage = D3DDECLUSAGE_BLENDWEIGHT; + pDecl[i].UsageIndex = 0; + + // Always exactly two weights + pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_BONEWEIGHTS2, compressionType ); + offset += GetVertexElementSize( VERTEX_ELEMENT_BONEWEIGHTS2, compressionType ); + ++i; + } + + if ( fmt & VERTEX_BONE_INDEX ) + { + // this isn't FVF!!!!! + pDecl[i].Stream = 0; + pDecl[i].Offset = offset; + pDecl[i].Method = D3DDECLMETHOD_DEFAULT; + pDecl[i].Usage = D3DDECLUSAGE_BLENDINDICES; + pDecl[i].UsageIndex = 0; + pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_BONEINDEX, compressionType ); + offset += GetVertexElementSize( VERTEX_ELEMENT_BONEINDEX, compressionType ); + ++i; + } + + int normalOffset = -1; + if ( fmt & VERTEX_NORMAL ) + { + pDecl[i].Stream = 0; + pDecl[i].Offset = offset; + normalOffset = offset; + pDecl[i].Method = D3DDECLMETHOD_DEFAULT; + pDecl[i].Usage = D3DDECLUSAGE_NORMAL; + pDecl[i].UsageIndex = 0; + pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_NORMAL, compressionType ); + offset += GetVertexElementSize( VERTEX_ELEMENT_NORMAL, compressionType ); + ++i; + } + + if ( fmt & VERTEX_COLOR ) + { + pDecl[i].Stream = 0; + pDecl[i].Offset = offset; + pDecl[i].Method = D3DDECLMETHOD_DEFAULT; + pDecl[i].Usage = D3DDECLUSAGE_COLOR; + pDecl[i].UsageIndex = 0; + pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_COLOR, compressionType ); + offset += GetVertexElementSize( VERTEX_ELEMENT_COLOR, compressionType ); + ++i; + } + + if ( fmt & VERTEX_SPECULAR ) + { + Assert( !bStaticLit ); + pDecl[i].Stream = 0; + pDecl[i].Offset = offset; + pDecl[i].Method = D3DDECLMETHOD_DEFAULT; + pDecl[i].Usage = D3DDECLUSAGE_COLOR; + pDecl[i].UsageIndex = 1; // SPECULAR goes in the second COLOR slot + pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_SPECULAR, compressionType ); + offset += GetVertexElementSize( VERTEX_ELEMENT_SPECULAR, compressionType ); + ++i; + } + + VertexElement_t texCoordDimensions[4] = { VERTEX_ELEMENT_TEXCOORD1D_0, + VERTEX_ELEMENT_TEXCOORD2D_0, + VERTEX_ELEMENT_TEXCOORD3D_0, + VERTEX_ELEMENT_TEXCOORD4D_0 }; + for ( int j = 0; j < VERTEX_MAX_TEXTURE_COORDINATES; ++j ) + { + int nCoordSize = TexCoordSize( j, fmt ); + if ( nCoordSize <= 0 ) + continue; + Assert( nCoordSize <= 4 ); + + pDecl[i].Stream = 0; + pDecl[i].Offset = offset; + pDecl[i].Method = D3DDECLMETHOD_DEFAULT; + pDecl[i].Usage = D3DDECLUSAGE_TEXCOORD; + pDecl[i].UsageIndex = j; + VertexElement_t texCoordElement = (VertexElement_t)( texCoordDimensions[ nCoordSize - 1 ] + j ); + pDecl[i].Type = VertexElementToDeclType( texCoordElement, compressionType ); + offset += GetVertexElementSize( texCoordElement, compressionType ); + ++i; + } + + if ( fmt & VERTEX_TANGENT_S ) + { + pDecl[i].Stream = 0; + pDecl[i].Offset = offset; + pDecl[i].Method = D3DDECLMETHOD_DEFAULT; + pDecl[i].Usage = D3DDECLUSAGE_TANGENT; + pDecl[i].UsageIndex = 0; + // NOTE: this is currently *not* compressed + pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_TANGENT_S, compressionType ); + offset += GetVertexElementSize( VERTEX_ELEMENT_TANGENT_S, compressionType ); + ++i; + } + + if ( fmt & VERTEX_TANGENT_T ) + { + pDecl[i].Stream = 0; + pDecl[i].Offset = offset; + pDecl[i].Method = D3DDECLMETHOD_DEFAULT; + pDecl[i].Usage = D3DDECLUSAGE_BINORMAL; + pDecl[i].UsageIndex = 0; + // NOTE: this is currently *not* compressed + pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_TANGENT_T, compressionType ); + offset += GetVertexElementSize( VERTEX_ELEMENT_TANGENT_T, compressionType ); + ++i; + } + + int userDataSize = UserDataSize(fmt); + if ( userDataSize > 0 ) + { + Assert( userDataSize == 4 ); // This is actually only ever used for tangents + pDecl[i].Stream = 0; + if ( ( compressionType == VERTEX_COMPRESSION_ON ) && + ( COMPRESSED_NORMALS_TYPE == COMPRESSED_NORMALS_COMBINEDTANGENTS_UBYTE4 ) ) + { + // FIXME: Normals and tangents are packed together into a single UBYTE4 element, + // so just point this back at the same data while we're testing UBYTE4 out. + pDecl[i].Offset = normalOffset; + } + else + { + pDecl[i].Offset = offset; + } + pDecl[i].Method = D3DDECLMETHOD_DEFAULT; + pDecl[i].Usage = D3DDECLUSAGE_TANGENT; + pDecl[i].UsageIndex = 0; + VertexElement_t userDataElement = (VertexElement_t)( VERTEX_ELEMENT_USERDATA1 + ( userDataSize - 1 ) ); + pDecl[i].Type = VertexElementToDeclType( userDataElement, compressionType ); + offset += GetVertexElementSize( userDataElement, compressionType ); + ++i; + } + + if ( bStaticLit ) + { + // force stream 1 to have specular color in it, which is used for baked static lighting + pDecl[i].Stream = 1; + pDecl[i].Offset = 0; + pDecl[i].Method = D3DDECLMETHOD_DEFAULT; + pDecl[i].Usage = D3DDECLUSAGE_COLOR; + pDecl[i].UsageIndex = 1; // SPECULAR goes into the second COLOR slot + pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_SPECULAR, compressionType ); + ++i; + } + + if ( HardwareConfig()->SupportsVertexAndPixelShaders() ) + { + // FIXME: There needs to be a better way of doing this + // In 2.0b, assume position is 4d, storing wrinkle in pos.w. + bool bUseWrinkle = HardwareConfig()->SupportsPixelShaders_2_b(); + + // Force stream 2 to have flex deltas in it + pDecl[i].Stream = 2; + pDecl[i].Offset = 0; + pDecl[i].Method = D3DDECLMETHOD_DEFAULT; + pDecl[i].Usage = D3DDECLUSAGE_POSITION; + pDecl[i].UsageIndex = 1; + // FIXME: unify this with VertexElementToDeclType(): + pDecl[i].Type = bUseWrinkle ? D3DDECLTYPE_FLOAT4 : D3DDECLTYPE_FLOAT3; + ++i; + + int normalOffset = GetVertexElementSize( VERTEX_ELEMENT_POSITION, compressionType ); + if ( bUseWrinkle ) + { + normalOffset += GetVertexElementSize( VERTEX_ELEMENT_WRINKLE, compressionType ); + } + + // Normal deltas + pDecl[i].Stream = 2; + pDecl[i].Offset = normalOffset; + pDecl[i].Method = D3DDECLMETHOD_DEFAULT; + pDecl[i].Usage = D3DDECLUSAGE_NORMAL; + pDecl[i].UsageIndex = 1; + // NOTE: this is currently *not* compressed + pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_NORMAL, VERTEX_COMPRESSION_NONE ); + ++i; + } + + if ( bUsingMorph ) + { + // force stream 3 to have vertex index in it, which is used for doing vertex texture reads + pDecl[i].Stream = 3; + pDecl[i].Offset = 0; + pDecl[i].Method = D3DDECLMETHOD_DEFAULT; + pDecl[i].Usage = D3DDECLUSAGE_POSITION; + pDecl[i].UsageIndex = 2; + pDecl[i].Type = VertexElementToDeclType( VERTEX_ELEMENT_USERDATA1, compressionType ); + ++i; + } + + static D3DVERTEXELEMENT9 declEnd = D3DDECL_END(); + pDecl[i] = declEnd; + + //PrintVertexDeclaration( pDecl ); +} + +//----------------------------------------------------------------------------- +// Gets the declspec associated with a vertex format +//----------------------------------------------------------------------------- +struct VertexDeclLookup_t +{ + enum LookupFlags_t + { + STATIC_LIT = 0x1, + USING_MORPH = 0x2, + USING_FLEX = 0x4, + }; + + VertexFormat_t m_VertexFormat; + int m_nFlags; + IDirect3DVertexDeclaration9 *m_pDecl; + + bool operator==( const VertexDeclLookup_t &src ) const + { + return ( m_VertexFormat == src.m_VertexFormat ) && ( m_nFlags == src.m_nFlags ); + } +}; + + +//----------------------------------------------------------------------------- +// Dictionary of vertex decls +// FIXME: stick this in the class? +// FIXME: Does anything cause this to get flushed? +//----------------------------------------------------------------------------- +static bool VertexDeclLessFunc( const VertexDeclLookup_t &src1, const VertexDeclLookup_t &src2 ) +{ + if ( src1.m_nFlags == src2.m_nFlags ) + return src1.m_VertexFormat < src2.m_VertexFormat; + + return ( src1.m_nFlags < src2.m_nFlags ); +} + +static CUtlRBTree<VertexDeclLookup_t, int> s_VertexDeclDict( 0, 256, VertexDeclLessFunc ); + +//----------------------------------------------------------------------------- +// Gets the declspec associated with a vertex format +//----------------------------------------------------------------------------- +IDirect3DVertexDeclaration9 *FindOrCreateVertexDecl( VertexFormat_t fmt, bool bStaticLit, bool bUsingFlex, bool bUsingMorph ) +{ + MEM_ALLOC_D3D_CREDIT(); + + VertexDeclLookup_t lookup; + lookup.m_VertexFormat = fmt; + lookup.m_nFlags = 0; + if ( bStaticLit ) + { + lookup.m_nFlags |= VertexDeclLookup_t::STATIC_LIT; + } + if ( bUsingMorph ) + { + lookup.m_nFlags |= VertexDeclLookup_t::USING_MORPH; + } + if ( bUsingFlex ) + { + lookup.m_nFlags |= VertexDeclLookup_t::USING_FLEX; + } + + int i = s_VertexDeclDict.Find( lookup ); + if ( i != s_VertexDeclDict.InvalidIndex() ) + { + // found + return s_VertexDeclDict[i].m_pDecl; + } + + D3DVERTEXELEMENT9 decl[32]; + ComputeVertexSpec( fmt, decl, bStaticLit, bUsingFlex, bUsingMorph ); + + HRESULT hr = + Dx9Device()->CreateVertexDeclaration( decl, &lookup.m_pDecl ); + + // NOTE: can't record until we have m_pDecl! + RECORD_COMMAND( DX8_CREATE_VERTEX_DECLARATION, 2 ); + RECORD_INT( ( int )lookup.m_pDecl ); + RECORD_STRUCT( decl, sizeof( decl ) ); + COMPILE_TIME_ASSERT( sizeof( decl ) == sizeof( D3DVERTEXELEMENT9 ) * 32 ); + + Assert( hr == D3D_OK ); + if ( hr != D3D_OK ) + { + Warning( " ERROR: failed to create vertex decl for vertex format 0x%08llX! You'll probably see messed-up mesh rendering - to diagnose, build shaderapidx9.dll in debug.\n", fmt ); + } + + s_VertexDeclDict.Insert( lookup ); + return lookup.m_pDecl; +} + + +//----------------------------------------------------------------------------- +// Clears out all declspecs +//----------------------------------------------------------------------------- +void ReleaseAllVertexDecl() +{ + int i = s_VertexDeclDict.FirstInorder(); + while ( i != s_VertexDeclDict.InvalidIndex() ) + { + if ( s_VertexDeclDict[i].m_pDecl ) + s_VertexDeclDict[i].m_pDecl->Release(); + i = s_VertexDeclDict.NextInorder( i ); + } +} + |