//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //============================================================================= #include "BaseVSShader.h" #include "compositor_ps20.inc" #include "compositor_ps20b.inc" #include "materialsystem/combineoperations.h" #include "tier0/memdbgon.h" struct CompositorInfo_t { static const int cTextureCount = 4; static const int cSelectorCount = 16; CompositorInfo_t( ) { memset( this, -1, sizeof( *this ) ); } int m_nCombineMode; int m_nTextureInputCount; int m_nTexTransform[ cTextureCount ]; int m_nTexAdjustLevels[ cTextureCount ]; int m_nSrcTexture[ cTextureCount ]; int m_nSelector[ cSelectorCount ]; int m_nTexturesPerPass; int m_bDebug; }; #ifdef STAGING_ONLY ConVar r_texcomp_debug_stickers( "r_texcomp_debug_stickers", "0" ); #endif static void DrawCompositorStage_ps20( CBaseVSShader *pShader, IMaterialVar **params, IShaderShadow* pShaderShadow, IShaderDynamicAPI* pShaderAPI, VertexCompressionType_t vertexCompression, const CompositorInfo_t &info ); static void DrawCompositorStage_ps20b( CBaseVSShader *pShader, IMaterialVar **params, IShaderShadow* pShaderShadow, IShaderDynamicAPI* pShaderAPI, VertexCompressionType_t vertexCompression, const CompositorInfo_t &info ); BEGIN_VS_SHADER( Compositor, "Help for Compositor" ) BEGIN_SHADER_PARAMS SHADER_PARAM( COMBINE_MODE, SHADER_PARAM_TYPE_INTEGER, "", "Which mode should the combiner operate in? 0: Mul, 1: Add, 2: Lerp, 3: Select" ) SHADER_PARAM( TEXTUREINPUTCOUNT, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( TEXTRANSFORM0, SHADER_PARAM_TYPE_MATRIX4X2, "", "" ) SHADER_PARAM( TEXTRANSFORM1, SHADER_PARAM_TYPE_MATRIX4X2, "", "" ) SHADER_PARAM( TEXTRANSFORM2, SHADER_PARAM_TYPE_MATRIX4X2, "", "" ) SHADER_PARAM( TEXTRANSFORM3, SHADER_PARAM_TYPE_MATRIX4X2, "", "" ) SHADER_PARAM( TEXADJUSTLEVELS0, SHADER_PARAM_TYPE_VEC3, "", "" ) SHADER_PARAM( TEXADJUSTLEVELS1, SHADER_PARAM_TYPE_VEC3, "", "" ) SHADER_PARAM( TEXADJUSTLEVELS2, SHADER_PARAM_TYPE_VEC3, "", "" ) SHADER_PARAM( TEXADJUSTLEVELS3, SHADER_PARAM_TYPE_VEC3, "", "" ) SHADER_PARAM( SRCTEXTURE0, SHADER_PARAM_TYPE_TEXTURE, "", "" ) SHADER_PARAM( SRCTEXTURE1, SHADER_PARAM_TYPE_TEXTURE, "", "" ) SHADER_PARAM( SRCTEXTURE2, SHADER_PARAM_TYPE_TEXTURE, "", "" ) SHADER_PARAM( SRCTEXTURE3, SHADER_PARAM_TYPE_TEXTURE, "", "" ) SHADER_PARAM( SELECTOR0, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( SELECTOR1, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( SELECTOR2, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( SELECTOR3, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( SELECTOR4, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( SELECTOR5, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( SELECTOR6, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( SELECTOR7, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( SELECTOR8, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( SELECTOR9, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( SELECTOR10, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( SELECTOR11, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( SELECTOR12, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( SELECTOR13, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( SELECTOR14, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( SELECTOR15, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( DEBUG_MODE, SHADER_PARAM_TYPE_BOOL, "", "" ) END_SHADER_PARAMS void SetupVarsCompositorInfo( CompositorInfo_t* pOutInfo ) { Assert( pOutInfo != NULL ); ( *pOutInfo ).m_nCombineMode = COMBINE_MODE; ( *pOutInfo ).m_nTextureInputCount = TEXTUREINPUTCOUNT; ( *pOutInfo ).m_nTexTransform[ 0 ] = TEXTRANSFORM0; ( *pOutInfo ).m_nTexTransform[ 1 ] = TEXTRANSFORM1; ( *pOutInfo ).m_nTexTransform[ 2 ] = TEXTRANSFORM2; ( *pOutInfo ).m_nTexTransform[ 3 ] = TEXTRANSFORM3; ( *pOutInfo ).m_nTexAdjustLevels[ 0 ] = TEXADJUSTLEVELS0; ( *pOutInfo ).m_nTexAdjustLevels[ 1 ] = TEXADJUSTLEVELS1; ( *pOutInfo ).m_nTexAdjustLevels[ 2 ] = TEXADJUSTLEVELS2; ( *pOutInfo ).m_nTexAdjustLevels[ 3 ] = TEXADJUSTLEVELS3; ( *pOutInfo ).m_nSrcTexture[ 0 ] = SRCTEXTURE0; ( *pOutInfo ).m_nSrcTexture[ 1 ] = SRCTEXTURE1; ( *pOutInfo ).m_nSrcTexture[ 2 ] = SRCTEXTURE2; ( *pOutInfo ).m_nSrcTexture[ 3 ] = SRCTEXTURE3; ( *pOutInfo ).m_nSelector[ 0 ] = SELECTOR0; ( *pOutInfo ).m_nSelector[ 1 ] = SELECTOR1; ( *pOutInfo ).m_nSelector[ 2 ] = SELECTOR2; ( *pOutInfo ).m_nSelector[ 3 ] = SELECTOR3; ( *pOutInfo ).m_nSelector[ 4 ] = SELECTOR4; ( *pOutInfo ).m_nSelector[ 5 ] = SELECTOR5; ( *pOutInfo ).m_nSelector[ 6 ] = SELECTOR6; ( *pOutInfo ).m_nSelector[ 7 ] = SELECTOR7; ( *pOutInfo ).m_nSelector[ 8 ] = SELECTOR8; ( *pOutInfo ).m_nSelector[ 9 ] = SELECTOR9; ( *pOutInfo ).m_nSelector[ 10 ] = SELECTOR10; ( *pOutInfo ).m_nSelector[ 11 ] = SELECTOR11; ( *pOutInfo ).m_nSelector[ 12 ] = SELECTOR12; ( *pOutInfo ).m_nSelector[ 13 ] = SELECTOR13; ( *pOutInfo ).m_nSelector[ 14 ] = SELECTOR14; ( *pOutInfo ).m_nSelector[ 15 ] = SELECTOR15; ( *pOutInfo ).m_bDebug = DEBUG_MODE; if ( g_pHardwareConfig->SupportsPixelShaders_2_b() ) ( *pOutInfo).m_nTexturesPerPass = 4; else ( *pOutInfo).m_nTexturesPerPass = 2; } SHADER_INIT { } SHADER_FALLBACK { // Requires DX9 + above if ( !g_pHardwareConfig->SupportsVertexAndPixelShaders() ) { Assert( 0 ); return "Wireframe"; } return 0; } SHADER_DRAW { CompositorInfo_t info; SetupVarsCompositorInfo( &info ); if ( g_pHardwareConfig->SupportsPixelShaders_2_b() ) DrawCompositorStage_ps20b( this, params, pShaderShadow, pShaderAPI, vertexCompression, info ); else DrawCompositorStage_ps20( this, params, pShaderShadow, pShaderAPI, vertexCompression, info ); } END_SHADER static void DrawCompositorStage_common( CBaseVSShader *pShader, IMaterialVar **params, IShaderShadow* pShaderShadow, IShaderDynamicAPI* pShaderAPI, VertexCompressionType_t vertexCompression, const CompositorInfo_t &info ) { int nCombineMode = params[ info.m_nCombineMode ]->GetIntValue(); SHADOW_STATE { pShader->SetInitialShadowState(); // It's a quad, don't cull me bro. pShaderShadow->EnableCulling( false ); pShaderShadow->EnablePolyOffset( SHADER_POLYOFFSET_DISABLE ); pShaderShadow->EnableDepthWrites( false ); pShaderShadow->EnableDepthTest( false ); // In 2.0b shaders, we use the skin shader and alpha carries specular mask information-- // so we need to write it // But with 2.0 shaders used by at least one customer in 2015, we fall back to // vertexlitgeneric and it doesn't do the same transforms as skin to the alpha shader // Since it won't be used anyways and it breaks the item model panel icons to write alpha // DON'T when we're running with 2.0 shaders. pShaderShadow->EnableAlphaWrites( g_pHardwareConfig->SupportsPixelShaders_2_b() ); pShaderShadow->EnableSRGBWrite( true ); pShaderShadow->EnableTexture( SHADER_SAMPLER0, true ); pShaderShadow->EnableTexture( SHADER_SAMPLER1, true ); pShaderShadow->EnableSRGBRead( SHADER_SAMPLER0, nCombineMode != ECO_Select ); pShaderShadow->EnableSRGBRead( SHADER_SAMPLER1, true ); int fmt = VERTEX_POSITION; pShaderShadow->VertexShaderVertexFormat( fmt, 1, 0, 0 ); pShaderShadow->SetVertexShader( "compositor_vs20", 0 ); } DYNAMIC_STATE { pShaderAPI->SetDefaultState(); pShaderAPI->SetVertexShaderIndex( 0 ); int textureCount = GetIntParam( info.m_nTextureInputCount, params ); int textureCountThisPass = Min( textureCount, info.m_nTexturesPerPass ); float f4TextureCountThisPass[] = { ( float ) textureCountThisPass, 0.0f, 0.0f, 0.0f }; Assert( ARRAYSIZE( f4TextureCountThisPass ) == 4 ); pShaderAPI->SetPixelShaderConstant( 6, f4TextureCountThisPass ); if ( textureCountThisPass > 0 ) pShader->BindTexture( SHADER_SAMPLER0, info.m_nSrcTexture[0] ); if ( textureCountThisPass > 0 ) pShader->SetVertexShaderMatrix2x4( 2, info.m_nTexTransform[0] ); if ( nCombineMode == ECO_Select ) { static const float cFac = 1.0f / 16.0f; float selectors[] = { cFac * GetIntParam( info.m_nSelector[ 0 ], params ), cFac * GetIntParam( info.m_nSelector[ 1 ], params ), cFac * GetIntParam( info.m_nSelector[ 2 ], params ), cFac * GetIntParam( info.m_nSelector[ 3 ], params ), cFac * GetIntParam( info.m_nSelector[ 4 ], params ), cFac * GetIntParam( info.m_nSelector[ 5 ], params ), cFac * GetIntParam( info.m_nSelector[ 6 ], params ), cFac * GetIntParam( info.m_nSelector[ 7 ], params ), cFac * GetIntParam( info.m_nSelector[ 8 ], params ), cFac * GetIntParam( info.m_nSelector[ 9 ], params ), cFac * GetIntParam( info.m_nSelector[ 10 ], params ), cFac * GetIntParam( info.m_nSelector[ 11 ], params ), cFac * GetIntParam( info.m_nSelector[ 12 ], params ), cFac * GetIntParam( info.m_nSelector[ 13 ], params ), cFac * GetIntParam( info.m_nSelector[ 14 ], params ), cFac * GetIntParam( info.m_nSelector[ 15 ], params ) }; pShaderAPI->SetPixelShaderConstant( 7, selectors, 4 ); } } } // Helper function when using ps20 and performing multiply and add operations. static void DrawCompositorStage_ps20_muladdblend( CBaseVSShader *pShader, IMaterialVar **params, IShaderShadow* pShaderShadow, IShaderDynamicAPI* pShaderAPI, VertexCompressionType_t vertexCompression, const CompositorInfo_t &info ) { int nCombineMode = params[ info.m_nCombineMode ]->GetIntValue(); SHADOW_STATE { { DECLARE_STATIC_PIXEL_SHADER( compositor_ps20 ); SET_STATIC_PIXEL_SHADER_COMBO( COMBINE_MODE, nCombineMode ); SET_STATIC_PIXEL_SHADER( compositor_ps20 ); } pShader->Draw(); // We can blend on top for second and subsequent writes. pShaderShadow->EnableBlending( true ); if ( nCombineMode == ECO_Multiply ) pShaderShadow->BlendFunc( SHADER_BLEND_DST_COLOR, SHADER_BLEND_ZERO ); else pShaderShadow->BlendFunc( SHADER_BLEND_ONE, SHADER_BLEND_ONE ); pShader->Draw(); } DYNAMIC_STATE { int textureCount = GetIntParam( info.m_nTextureInputCount, params ); int textureCountThisPass = Min( textureCount, info.m_nTexturesPerPass ); Assert( textureCount > 0 ); // Valid, but would be really weird. Assert( textureCountThisPass > 0 ); // That's bogus if ( textureCountThisPass > 0 ) pShader->SetPixelShaderConstantGammaToLinear( 2, info.m_nTexAdjustLevels[ 0 ] ); if ( textureCountThisPass > 1 ) pShader->BindTexture( SHADER_SAMPLER1, info.m_nSrcTexture[ 1 ] ); if ( textureCountThisPass > 1 ) pShader->SetVertexShaderMatrix2x4( 4, info.m_nTexTransform[ 1 ] ); if ( textureCountThisPass > 1 ) pShader->SetPixelShaderConstantGammaToLinear( 3, info.m_nTexAdjustLevels[ 1 ] ); { DECLARE_DYNAMIC_PIXEL_SHADER( compositor_ps20 ); SET_DYNAMIC_PIXEL_SHADER_COMBO( DEBUG_MODE, 0 ); SET_DYNAMIC_PIXEL_SHADER( compositor_ps20 ); } pShader->Draw(); textureCountThisPass = Max( 0, textureCount - textureCountThisPass ); Assert( textureCountThisPass <= info.m_nTexturesPerPass ); float f4TextureCountThisPass[] = { (float)textureCountThisPass, 0.0f, 0.0f, 0.0f }; Assert( ARRAYSIZE( f4TextureCountThisPass ) == 4 ); pShaderAPI->SetPixelShaderConstant( 6, f4TextureCountThisPass ); if ( textureCountThisPass > 0 ) pShader->BindTexture( SHADER_SAMPLER0, info.m_nSrcTexture[ 2 ] ); if ( textureCountThisPass > 0 ) pShader->SetVertexShaderMatrix2x4( 2, info.m_nTexTransform[ 2 ] ); if ( textureCountThisPass > 0 ) pShader->SetPixelShaderConstantGammaToLinear( 2, info.m_nTexAdjustLevels[ 2 ] ); if ( textureCountThisPass > 1 ) pShader->BindTexture( SHADER_SAMPLER1, info.m_nSrcTexture[ 3 ] ); if ( textureCountThisPass > 1 ) pShader->SetVertexShaderMatrix2x4( 4, info.m_nTexTransform[ 3 ] ); if ( textureCountThisPass > 1 ) pShader->SetPixelShaderConstantGammaToLinear( 3, info.m_nTexAdjustLevels[ 3 ] ); pShader->Draw( textureCountThisPass > 0 ); } } // Helper function when using ps20 and performing lerp operations. static void DrawCompositorStage_ps20_lerp( CBaseVSShader *pShader, IMaterialVar **params, IShaderShadow* pShaderShadow, IShaderDynamicAPI* pShaderAPI, VertexCompressionType_t vertexCompression, const CompositorInfo_t &info ) { SHADOW_STATE { { DECLARE_STATIC_PIXEL_SHADER( compositor_ps20 ); SET_STATIC_PIXEL_SHADER_COMBO( COMBINE_MODE, ECO_Legacy_Lerp_FirstPass ); SET_STATIC_PIXEL_SHADER( compositor_ps20 ); } pShader->Draw(); // We can blend on top for second write. pShaderShadow->EnableBlending( true ); pShaderShadow->BlendFunc( SHADER_BLEND_ONE, SHADER_BLEND_ONE ); { DECLARE_STATIC_PIXEL_SHADER( compositor_ps20 ); SET_STATIC_PIXEL_SHADER_COMBO( COMBINE_MODE, ECO_Legacy_Lerp_SecondPass ); SET_STATIC_PIXEL_SHADER( compositor_ps20 ); } pShader->Draw(); } DYNAMIC_STATE { Assert( GetIntParam( info.m_nTextureInputCount, params ) == 3 ); pShader->SetPixelShaderConstantGammaToLinear( 2, info.m_nTexAdjustLevels[ 0 ] ); pShader->BindTexture( SHADER_SAMPLER1, info.m_nSrcTexture[ 2 ] ); pShader->SetVertexShaderMatrix2x4( 4, info.m_nTexTransform[ 2 ] ); pShader->SetPixelShaderConstantGammaToLinear( 3, info.m_nTexAdjustLevels[ 2 ] ); { DECLARE_DYNAMIC_PIXEL_SHADER( compositor_ps20 ); SET_DYNAMIC_PIXEL_SHADER_COMBO( DEBUG_MODE, 0 ); SET_DYNAMIC_PIXEL_SHADER( compositor_ps20 ); } pShader->Draw(); pShader->BindTexture( SHADER_SAMPLER0, info.m_nSrcTexture[ 1 ] ); pShader->SetVertexShaderMatrix2x4( 2, info.m_nTexTransform[ 1 ] ); pShader->SetPixelShaderConstantGammaToLinear( 2, info.m_nTexAdjustLevels[ 1 ] ); pShader->Draw(); } } // Helper function when using ps20 and performing lerp operations. static void DrawCompositorStage_ps20_select( CBaseVSShader *pShader, IMaterialVar **params, IShaderShadow* pShaderShadow, IShaderDynamicAPI* pShaderAPI, VertexCompressionType_t vertexCompression, const CompositorInfo_t &info ) { int nCombineMode = params[ info.m_nCombineMode ]->GetIntValue(); SHADOW_STATE { { DECLARE_STATIC_PIXEL_SHADER( compositor_ps20 ); SET_STATIC_PIXEL_SHADER_COMBO( COMBINE_MODE, nCombineMode ); SET_STATIC_PIXEL_SHADER( compositor_ps20 ); } pShader->Draw(); } DYNAMIC_STATE { Assert( GetIntParam( info.m_nTextureInputCount, params ) == 1 ); pShader->SetPixelShaderConstantGammaToLinear( 2, info.m_nTexAdjustLevels[ 0 ] ); { DECLARE_DYNAMIC_PIXEL_SHADER( compositor_ps20 ); SET_DYNAMIC_PIXEL_SHADER_COMBO( DEBUG_MODE, 0 ); SET_DYNAMIC_PIXEL_SHADER( compositor_ps20 ); } pShader->Draw(); } } static void DrawCompositorStage_ps20( CBaseVSShader *pShader, IMaterialVar **params, IShaderShadow* pShaderShadow, IShaderDynamicAPI* pShaderAPI, VertexCompressionType_t vertexCompression, const CompositorInfo_t &info ) { DrawCompositorStage_common( pShader, params, pShaderShadow, pShaderAPI, vertexCompression, info ); int nCombineMode = params[ info.m_nCombineMode ]->GetIntValue(); switch ( nCombineMode ) { case ECO_Multiply: case ECO_Add: case ECO_Blend: DrawCompositorStage_ps20_muladdblend( pShader, params, pShaderShadow, pShaderAPI, vertexCompression, info ); return; case ECO_Lerp: DrawCompositorStage_ps20_lerp( pShader, params, pShaderShadow, pShaderAPI, vertexCompression, info ); return; case ECO_Select: DrawCompositorStage_ps20_select( pShader, params, pShaderShadow, pShaderAPI, vertexCompression, info ); return; default: Assert( !"Need to update DrawCompositoreStage_ps20 with how to draw this mode." ); break; } } static void DrawCompositorStage_ps20b( CBaseVSShader *pShader, IMaterialVar **params, IShaderShadow* pShaderShadow, IShaderDynamicAPI* pShaderAPI, VertexCompressionType_t vertexCompression, const CompositorInfo_t &info ) { int nCombineMode = params[ info.m_nCombineMode ]->GetIntValue(); DrawCompositorStage_common( pShader, params, pShaderShadow, pShaderAPI, vertexCompression, info ); SHADOW_STATE { pShaderShadow->EnableTexture( SHADER_SAMPLER2, true ); pShaderShadow->EnableTexture( SHADER_SAMPLER3, true ); pShaderShadow->EnableSRGBRead( SHADER_SAMPLER2, true ); pShaderShadow->EnableSRGBRead( SHADER_SAMPLER3, true ); DECLARE_STATIC_PIXEL_SHADER( compositor_ps20b ); SET_STATIC_PIXEL_SHADER_COMBO( COMBINE_MODE, nCombineMode ); SET_STATIC_PIXEL_SHADER( compositor_ps20b ); pShader->Draw(); } DYNAMIC_STATE { int textureCount = GetIntParam( info.m_nTextureInputCount, params ); int textureCountThisPass = Min( textureCount, info.m_nTexturesPerPass ); Assert( textureCount > 0 ); // Valid, but would be really weird. Assert( textureCountThisPass > 0 ); // That's bogus // Slot 0 is mostly already handled by common if ( textureCountThisPass > 0 ) pShader->SetPixelShaderConstant( 2, info.m_nTexAdjustLevels[ 0 ] ); if ( textureCountThisPass > 1 ) pShader->BindTexture( SHADER_SAMPLER1, info.m_nSrcTexture[ 1 ] ); if ( textureCountThisPass > 1 ) pShader->SetVertexShaderMatrix2x4( 4, info.m_nTexTransform[ 1 ] ); if ( textureCountThisPass > 1 ) pShader->SetPixelShaderConstant( 3, info.m_nTexAdjustLevels[ 1 ] ); if ( textureCountThisPass > 2 ) pShader->BindTexture( SHADER_SAMPLER2, info.m_nSrcTexture[ 2 ] ); if ( textureCountThisPass > 2 ) pShader->SetVertexShaderMatrix2x4( 6, info.m_nTexTransform[ 2 ] ); if ( textureCountThisPass > 2 ) pShader->SetPixelShaderConstant( 4, info.m_nTexAdjustLevels[ 2 ] ); if ( textureCountThisPass > 3 ) pShader->BindTexture( SHADER_SAMPLER3, info.m_nSrcTexture[ 3 ] ); if ( textureCountThisPass > 3 ) pShader->SetVertexShaderMatrix2x4( 8, info.m_nTexTransform[ 3 ] ); if ( textureCountThisPass > 3 ) pShader->SetPixelShaderConstant( 5, info.m_nTexAdjustLevels[ 3 ] ); DECLARE_DYNAMIC_PIXEL_SHADER( compositor_ps20b ); #ifdef STAGING_ONLY SET_DYNAMIC_PIXEL_SHADER_COMBO( DEBUG_MODE, r_texcomp_debug_stickers.GetBool() ? 1 : 0 ); #else SET_DYNAMIC_PIXEL_SHADER_COMBO( DEBUG_MODE, 0 ); #endif SET_DYNAMIC_PIXEL_SHADER( compositor_ps20b ); pShader->Draw(); } }