📄 vertexshaderdx8.cpp
字号:
//=========== (C) Copyright 1999 Valve, L.L.C. All rights reserved. ===========
//
// The copyright to the contents herein is the property of Valve, L.L.C.
// The contents may be used and/or copied only with the written permission of
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// $Header: $
// $NoKeywords: $
//
// Code for dealing with vertex shaders
//=============================================================================
#include <windows.h>
#include "VertexShaderDx8.h"
#include "UtlSymbol.h"
#include "UtlVector.h"
#include "UtlDict.h"
#include "locald3dtypes.h"
#include "ShaderAPIDX8_Global.h"
#include "recording.h"
#include "CMaterialSystemStats.h"
#include "tier0/vprof.h"
#include "materialsystem/imaterialsystem.h"
#include "materialsystem/imaterialsystemhardwareconfig.h"
#include "shaderapidx8.h"
#include "materialsystem/ishader.h"
#include "utllinkedlist.h"
#include "materialsystem/ishadersystem.h"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
//#define NO_AMBIENT_CUBE
#define MAX_BONES 3
#define MAX_LIGHTS 2
//-----------------------------------------------------------------------------
// Inserts the lighting block into the code
//-----------------------------------------------------------------------------
// If you change the number of lighting combinations, change this enum
enum
{
LIGHTING_COMBINATION_COUNT = 22
};
// NOTE: These should match g_lightType* in vsh_prep.pl!
static int g_LightCombinations[][MAX_LIGHTS+2] =
{
// static ambient local1 local2
// This is a special case for no lighting at all.
{ LIGHT_NONE, LIGHT_NONE, LIGHT_NONE, LIGHT_NONE },
// This is a special case so that we don't have to do the ambient cube
// when we only have static lighting
{ LIGHT_STATIC, LIGHT_NONE, LIGHT_NONE, LIGHT_NONE },
{ LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_NONE, LIGHT_NONE },
{ LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_SPOT, LIGHT_NONE },
{ LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_POINT, LIGHT_NONE },
{ LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_DIRECTIONAL, LIGHT_NONE },
{ LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_SPOT, LIGHT_SPOT },
{ LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_SPOT, LIGHT_POINT, },
{ LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_SPOT, LIGHT_DIRECTIONAL, },
{ LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_POINT, LIGHT_POINT, },
{ LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_POINT, LIGHT_DIRECTIONAL, },
{ LIGHT_NONE, LIGHT_AMBIENTCUBE, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL, },
{ LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_NONE, LIGHT_NONE },
{ LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_SPOT, LIGHT_NONE },
{ LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_POINT, LIGHT_NONE },
{ LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_DIRECTIONAL, LIGHT_NONE },
{ LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_SPOT, LIGHT_SPOT },
{ LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_SPOT, LIGHT_POINT, },
{ LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_SPOT, LIGHT_DIRECTIONAL, },
{ LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_POINT, LIGHT_POINT, },
{ LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_POINT, LIGHT_DIRECTIONAL, },
{ LIGHT_STATIC, LIGHT_AMBIENTCUBE, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL, },
/*
{ LIGHT_NONE, LIGHT_NONE }, // 0
{ LIGHT_SPOT, LIGHT_NONE },
{ LIGHT_POINT, LIGHT_NONE },
{ LIGHT_DIRECTIONAL, LIGHT_NONE },
{ LIGHT_SPOT, LIGHT_SPOT },
{ LIGHT_SPOT, LIGHT_POINT, }, // 5
{ LIGHT_SPOT, LIGHT_DIRECTIONAL, },
{ LIGHT_POINT, LIGHT_POINT, },
{ LIGHT_POINT, LIGHT_DIRECTIONAL, },
{ LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL, },
{ LIGHT_STATIC, LIGHT_NONE }, // 10
*/
/*
{ LIGHT_SPOT, LIGHT_SPOT, LIGHT_SPOT }, // 10
{ LIGHT_SPOT, LIGHT_SPOT, LIGHT_POINT },
{ LIGHT_SPOT, LIGHT_SPOT, LIGHT_DIRECTIONAL },
{ LIGHT_SPOT, LIGHT_POINT, LIGHT_POINT },
{ LIGHT_SPOT, LIGHT_POINT, LIGHT_DIRECTIONAL },
{ LIGHT_SPOT, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL }, // 15
{ LIGHT_POINT, LIGHT_POINT, LIGHT_POINT },
{ LIGHT_POINT, LIGHT_POINT, LIGHT_DIRECTIONAL },
{ LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL },
{ LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL, LIGHT_DIRECTIONAL },
*/
};
static const char *GetLightTypeName( VertexShaderLightTypes_t type )
{
static const char *s_VertexShaderLightTypeNames[] =
{
"LIGHT_NONE",
"LIGHT_SPOT",
"LIGHT_POINT",
"LIGHT_DIRECTIONAL",
"LIGHT_STATIC",
"LIGHT_AMBIENTCUBE",
};
return s_VertexShaderLightTypeNames[type+1];
}
//-----------------------------------------------------------------------------
// Computes the lighting type from the light types...
//-----------------------------------------------------------------------------
int ComputeLightIndex( int numLights, const VertexShaderLightTypes_t *pLightType,
bool bUseAmbientCube, bool bHasColorMesh )
{
COMPILE_TIME_ASSERT( LIGHTING_COMBINATION_COUNT ==
sizeof( g_LightCombinations ) / sizeof( g_LightCombinations[0] ) );
Assert( numLights <= MAX_LIGHTS );
if( numLights == 0 && !bUseAmbientCube )
{
if( bHasColorMesh )
{
// special case for static lighting only
return 1;
}
else
{
// special case for no lighting at all.
return 0;
}
}
int i;
// hack - skip the first two for now since we don't know if the ambient cube is needed or not.
for( i = 2; i < LIGHTING_COMBINATION_COUNT; ++i )
{
int j;
for( j = 0; j < numLights; ++j )
{
if( pLightType[j] != g_LightCombinations[i][j+2] )
break;
}
if( j == numLights )
{
while( j < MAX_LIGHTS )
{
if (g_LightCombinations[i][j+2] != LIGHT_NONE)
break;
++j;
}
if( j == MAX_LIGHTS )
{
if( bHasColorMesh )
{
return i + 10;
}
else
{
return i;
}
}
}
}
// should never get here!
Assert(0);
return 0;
}
//-----------------------------------------------------------------------------
// Gets the vertex shader index given a number of bones, lights...
// FIXME: Let's try to remove this and make the shaders set the index
//-----------------------------------------------------------------------------
static int ComputeVertexShader( int nBoneCount, int nLightCombo, int nFogType, int fShaderFlags )
{
Assert( nBoneCount <= MAX_BONES );
// uses some combination of skinning, lighting, and fogging
int nLightComboCount = LIGHTING_COMBINATION_COUNT;
if ( ( fShaderFlags & SHADER_USES_LIGHTING ) == 0 )
{
nLightComboCount = 1;
nLightCombo = 0;
}
bool bUsesHeightFog = ( nFogType == MATERIAL_FOG_LINEAR_BELOW_FOG_Z );
int nFogComboCount = 1;
int nFogCombo = 0;
if ( fShaderFlags & SHADER_USES_HEIGHT_FOG )
{
nFogComboCount = 2;
nFogCombo = bUsesHeightFog ? 1 : 0;
}
#ifdef _DEBUG
if ( bUsesHeightFog && !( fShaderFlags & SHADER_USES_HEIGHT_FOG ) )
{
// Doh! Trying to use height fog with a vertex shader that doesn't support it!
Assert( 0 );
}
#endif
int nSkinningComboCount = 1;
if ( fShaderFlags & SHADER_USES_SKINNING )
{
nSkinningComboCount = MAX_BONES + 1; // + 1 since we have a combo for 0 bones.
}
int offset = ( ( ( nBoneCount * nLightComboCount ) + nLightCombo ) * nFogComboCount ) + nFogCombo;
return offset;
}
//-----------------------------------------------------------------------------
// Shader dictionary
//-----------------------------------------------------------------------------
class CShaderDictionary
{
public:
// Static methods
static void CreateErrorPS();
static void DestroyErrorPS();
// Adds precompiled shader dictionaries
void AddShaderDictionary( IPrecompiledShaderDictionary *pDict, bool bPreloadShaders );
// Creates vertex + pixel shaders
VertexShader_t CreateVertexShader( const char *pVertexShaderFile, int nStaticVshIndex = 0 );
PixelShader_t CreatePixelShader( const char *pPixelShaderFile, int nStaticPshIndex = 0 );
// Destroys vertex shaders
void DestroyVertexShader( VertexShader_t shader );
void DestroyAllVertexShaders();
// Destroys pixel shaders
void DestroyPixelShader( PixelShader_t shader );
void DestroyAllPixelShaders();
// Gets the hardware vertex shader
HardwareVertexShader_t GetHardwareVertexShader( VertexShader_t shader, int vshIndex );
HardwarePixelShader_t GetHardwarePixelShader( PixelShader_t shader, int pshIndex );
private:
// Information associated with each VertexShader_t + PixelShader_t
struct VertexShaderInfo_t
{
HardwareVertexShader_t *m_HardwareShaders;
unsigned short m_nRefCount;
unsigned short m_nShaderCount;
unsigned char m_Flags;
};
struct PixelShaderInfo_t
{
// GR - for binding shader list with pre-compiled DX shaders
// for later shader creation
const PrecompiledShader_t *m_pPrecompiledDXShader;
HardwarePixelShader_t *m_HardwareShaders;
unsigned short m_nRefCount;
unsigned short m_nShaderCount;
};
private:
// Finds a precompiled shader
const PrecompiledShader_t *LookupPrecompiledShader( PrecompiledShaderType_t type, const char *pShaderName );
// Name-based lookup of vertex shaders
int FindVertexShader( char const* pFileName ) const;
// Initializes vertex shaders
bool InitializeVertexShaders( char const* pFileName, VertexShaderInfo_t& info );
// The low-level dx call to set the vertex shader state
void SetVertexShaderState( HardwareVertexShader_t shader );
// Name-based lookup of pixel shaders
int FindPixelShader( char const* pFileName ) const;
// Initializes pixel shaders
bool InitializePixelShader( const char *pFileName, PixelShaderInfo_t &info );
// The low-level dx call to set the pixel shader state
void SetPixelShaderState( HardwarePixelShader_t shader );
private:
// Precompiled shader dictionary
CUtlDict< const PrecompiledShader_t*, unsigned short > m_PrecompiledShaders[PRECOMPILED_SHADER_TYPE_COUNT];
// Used to lookup vertex shaders
CUtlDict< VertexShaderInfo_t, unsigned short > m_VertexShaders;
CUtlDict< PixelShaderInfo_t, unsigned short > m_PixelShaders;
// GR - hack for illegal materials
static HardwarePixelShader_t s_pIllegalMaterialPS;
};
//-----------------------------------------------------------------------------
// Globals
//-----------------------------------------------------------------------------
HardwarePixelShader_t CShaderDictionary::s_pIllegalMaterialPS = INVALID_HARDWARE_PIXEL_SHADER;
//-----------------------------------------------------------------------------
// Static methods
//-----------------------------------------------------------------------------
void CShaderDictionary::CreateErrorPS()
{
// GR - illegal material hack
if( HardwareConfig()->SupportsVertexAndPixelShaders() )
{
// GR - hack for illegal materials
const DWORD psIllegalMaterial[] =
{
0xffff0101, 0x00000051, 0xa00f0000, 0x00000000, 0x3f800000, 0x00000000,
0x3f800000, 0x00000001, 0x800f0000, 0xa0e40000, 0x0000ffff
};
// create default shader
D3DDevice()->CreatePixelShader( psIllegalMaterial, &s_pIllegalMaterialPS );
}
}
void CShaderDictionary::DestroyErrorPS()
{
// GR - invalid material hack
// destroy internal shader
if( s_pIllegalMaterialPS != INVALID_HARDWARE_PIXEL_SHADER )
{
s_pIllegalMaterialPS->Release();
s_pIllegalMaterialPS = INVALID_HARDWARE_PIXEL_SHADER;
}
}
//-----------------------------------------------------------------------------
// Adds precompiled shader dictionaries
//-----------------------------------------------------------------------------
void CShaderDictionary::AddShaderDictionary( IPrecompiledShaderDictionary *pDict, bool bPreloadShaders )
{
int nCount = pDict->ShaderCount();
for ( int i = 0; i < nCount; ++i )
{
const PrecompiledShader_t *pShader = pDict->GetShader(i);
m_PrecompiledShaders[pDict->GetType()].Insert( pShader->m_pName, pShader );
}
// Create these up front in dx9 since we don't care about the vertex format.
if ( bPreloadShaders )
{
VPROF( "PreloadVertexAndPixelShaders" );
// Preload shaders
switch ( pDict->GetType() )
{
case PRECOMPILED_VERTEX_SHADER:
{
for ( int i = 0; i < nCount; ++i )
{
CreateVertexShader( pDict->GetShader(i)->m_pName );
}
}
break;
case PRECOMPILED_PIXEL_SHADER:
{
for ( int i = 0; i < nCount; ++i )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -